diff --git a/.babelrc b/.babelrc new file mode 100644 index 00000000..e26ee76e --- /dev/null +++ b/.babelrc @@ -0,0 +1,18 @@ +{ + "presets": [ + [ + "@babel/preset-env", + { + "targets": { "node": "10" } + } + ], + "@babel/preset-react", + "@babel/preset-typescript" + ], + "plugins": [ + "@babel/plugin-transform-modules-commonjs", + ["@babel/plugin-transform-runtime", { "regenerator": true }], + "@babel/plugin-proposal-class-properties", + "@babel/plugin-proposal-object-rest-spread" + ] +} diff --git a/.cypress/integration/01-create.spec.ts b/.cypress/integration/01-create.spec.ts new file mode 100644 index 00000000..e493a9b9 --- /dev/null +++ b/.cypress/integration/01-create.spec.ts @@ -0,0 +1,78 @@ +/* + * Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +describe('Cypress', () => { + it('Visits Reporting homepage', () => { + cy.visit('http://localhost:5601/app/opendistro_kibana_reports#/'); + cy.location('pathname', { timeout: 60000 }).should( + 'include', + '/opendistro_kibana_reports' + ); + }); + + it('Visit Create page', () => { + cy.visit('http://localhost:5601/app/opendistro_kibana_reports#/'); + cy.location('pathname', { timeout: 60000 }).should( + 'include', + '/opendistro_kibana_reports' + ); + cy.wait(12500); // wait for the page to load + cy.get('#createReportHomepageButton').click({ force: true }); + }); + + it('Create a new on-demand report definition', () => { + cy.visit('http://localhost:5601/app/opendistro_kibana_reports#/'); + cy.location('pathname', { timeout: 60000 }).should( + 'include', + '/opendistro_kibana_reports' + ); + cy.wait(12500); + cy.get('#createReportHomepageButton').click(); + + // enter a report name + cy.get('#reportSettingsName').type('Create cypress test on-demand report'); + + // enter a report description + cy.get('#reportSettingsDescription').type('Description for cypress test'); + + // select a report source + cy.get('.euiComboBox').click({ force: true }); + + // create an on-demand report definition + cy.get('#createNewReportDefinition').click({ force: true }); + }); + + it('Create a new scheduled report definition', () => { + cy.visit('http://localhost:5601/app/opendistro_kibana_reports#/'); + cy.location('pathname', { timeout: 60000 }).should( + 'include', + '/opendistro_kibana_reports' + ); + cy.wait(12500); + cy.get('#createReportHomepageButton').click(); + + // enter a report name + cy.get('#reportSettingsName').type('Create cypress test scheduled report'); + + // enter a report description + cy.get('#reportSettingsDescription').type('Description for cypress test'); + + // set report trigger to Schedule option + cy.get('[type="radio"]').check({ force: true }); + + // create scheduled report definition + cy.get('#createNewReportDefinition').click({ force: true }); + }); +}); diff --git a/.cypress/integration/02-edit.spec.ts b/.cypress/integration/02-edit.spec.ts new file mode 100644 index 00000000..c38c902d --- /dev/null +++ b/.cypress/integration/02-edit.spec.ts @@ -0,0 +1,92 @@ +/* + * Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +describe('Cypress', () => { + it('Visit edit page, update name and description', () => { + cy.visit('http://localhost:5601/app/opendistro_kibana_reports#/'); + cy.location('pathname', { timeout: 60000 }).should( + 'include', + '/opendistro_kibana_reports' + ); + + cy.wait(12500); + + cy.get('#reportDefinitionDetailsLink').first().click(); + + cy.get('#editReportDefinitionButton').should('exist'); + + cy.get('#editReportDefinitionButton').click(); + + cy.url().should('include', 'edit'); + + cy.wait(1000); + + // update the report name + cy.get('#reportSettingsName').type(' update name'); + + // update report description + cy.get('#reportSettingsDescription').type(' update description'); + + cy.get('#editReportDefinitionButton').click({ force: true }); + }); + + it('Visit edit page, change report source and trigger', () => { + cy.visit('http://localhost:5601/app/opendistro_kibana_reports#/'); + cy.location('pathname', { timeout: 60000 }).should( + 'include', + '/opendistro_kibana_reports' + ); + + cy.wait(12500); + + cy.get('#reportDefinitionDetailsLink').first().click(); + + cy.get('#editReportDefinitionButton').should('exist'); + + cy.get('#editReportDefinitionButton').click(); + + cy.url().should('include', 'edit'); + + cy.wait(1000); + cy.get('#visualizationReportSource').check({ force: true }); + + cy.get('#Schedule').check({ force: true }); + cy.get('#editReportDefinitionButton').click({ force: true }); + }); + + it('Visit edit page, change report source back', () => { + cy.visit('http://localhost:5601/app/opendistro_kibana_reports#/'); + cy.location('pathname', { timeout: 60000 }).should( + 'include', + '/opendistro_kibana_reports' + ); + + cy.wait(12500); + + cy.get('#reportDefinitionDetailsLink').first().click(); + + cy.get('#editReportDefinitionButton').should('exist'); + + cy.get('#editReportDefinitionButton').click(); + + cy.url().should('include', 'edit'); + + cy.wait(1000); + + cy.get('#dashboardReportSource').check({ force: true }); + + cy.get('#editReportDefinitionButton').click({ force: true }); + }); +}); diff --git a/.cypress/integration/03-details.spec.ts b/.cypress/integration/03-details.spec.ts new file mode 100644 index 00000000..2144a3ef --- /dev/null +++ b/.cypress/integration/03-details.spec.ts @@ -0,0 +1,57 @@ +/* + * Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +describe('Cypress', () => { + it('Visit report definition details page', () => { + cy.visit('http://localhost:5601/app/opendistro_kibana_reports#/'); + cy.location('pathname', { timeout: 60000 }).should( + 'include', + '/opendistro_kibana_reports' + ); + + cy.wait(12500); + + cy.get('#reportDefinitionDetailsLink').first().click(); + + cy.url().should('include', 'report_definition_details'); + + cy.get('#deleteReportDefinitionButton').should('exist'); + + cy.get('#editReportDefinitionButton').should('exist'); + + if (cy.get('body').contains('Schedule details')) { + cy.wait(1000); + cy.get('#changeStatusFromDetailsButton').click(); + } else { + cy.wait(1000); + cy.get('#generateReportFromDetailsButton').click(); + } + + cy.get('#deleteReportDefinitionButton').click(); + }); + + it('Visit report details page', () => { + cy.visit('http://localhost:5601/app/opendistro_kibana_reports#/'); + cy.location('pathname', { timeout: 60000 }).should( + 'include', + '/opendistro_kibana_reports' + ); + + cy.wait(12500); + cy.get('#reportDetailsLink').first().click(); + + cy.url().should('include', 'report_details'); + }); +}); diff --git a/.cypress/integration/04-download.spec.ts b/.cypress/integration/04-download.spec.ts new file mode 100644 index 00000000..0c143fb8 --- /dev/null +++ b/.cypress/integration/04-download.spec.ts @@ -0,0 +1,117 @@ +/* + * Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +describe('Cypress', () => { + it('Download from reporting homepage', () => { + cy.visit('http://localhost:5601/app/opendistro_kibana_reports#/'); + cy.location('pathname', { timeout: 60000 }).should( + 'include', + '/opendistro_kibana_reports' + ); + + cy.wait(12500); + cy.get('#landingPageOnDemandDownload').click({ force: true }); + cy.get('body').then($body => { + if ($body.find('#downloadInProgressLoadingModal').length > 0) { + return; + } + else { + assert(false); + } + }) + }); + + it('Download pdf from in-context menu', () => { + cy.visit('http://localhost:5601/app/dashboards#'); + cy.wait(5000); + + // click first entry in dashboards page + cy.get('tr.euiTableRow:nth-child(1) > td:nth-child(2) > div:nth-child(2) > a:nth-child(1)').click({ force: true }); + + // click Reporting in-context menu + cy.get('#downloadReport > span:nth-child(1) > span:nth-child(1)').click({ force: true }); + + // download PDF + cy.get('#generatePDF > span:nth-child(1) > span:nth-child(2)').click({ force: true }); + + cy.get('#reportGenerationProgressModal'); + }); + + it('Download png from in-context menu', () => { + cy.visit('http://localhost:5601/app/dashboards#'); + cy.wait(5000); + + // click first entry in dashboards page + cy.get('tr.euiTableRow:nth-child(1) > td:nth-child(2) > div:nth-child(2) > a:nth-child(1)').click({ force: true }); + + // click Reporting in-context menu + cy.get('#downloadReport > span:nth-child(1) > span:nth-child(1)').click({ force: true }); + + cy.get('#generatePNG').click({ force: true }); + + cy.get('#reportGenerationProgressModal'); + }); + + it('Download csv from saved search in-context menu', () => { + cy.visit('http://localhost:5601/app/discover#'); + cy.wait(5000); + + // open saved search list + cy.get('button.euiButtonEmpty:nth-child(3) > span:nth-child(1) > span:nth-child(1)').click({ force: true }); + cy.wait(5000); + + // click first entry + cy.get('li.euiListGroupItem:nth-child(1) > button:nth-child(1)').click({ force: true }); + + // open reporting menu + cy.get('#downloadReport').click({ force: true }); + + cy.get('#generateCSV').click({ force: true }); + }); + + it('Download from Report definition details page', () => { + // create an on-demand report definition + + cy.visit('http://localhost:5601/app/opendistro_kibana_reports#/'); + cy.location('pathname', { timeout: 60000 }).should( + 'include', + '/opendistro_kibana_reports' + ); + cy.wait(12500); + cy.get('#createReportHomepageButton').click(); + + // enter a report name + cy.get('#reportSettingsName').type('Create cypress test on-demand report'); + + // enter a report description + cy.get('#reportSettingsDescription').type('Description for cypress test'); + + // create an on-demand report definition + cy.get('#createNewReportDefinition').click({ force: true }); + + cy.wait(10000); + + // visit the details page of the newly created on-demand definition + cy.get('#reportDefinitionDetailsLink').first().click(); + + cy.url().should('include', 'report_definition_details'); + + cy.get('#generateReportFromDetailsButton').should('exist'); + + cy.get('#generateReportFromDetailsButton').click({ force: true }); + + cy.get('#downloadInProgressLoadingModal'); + }); +}); \ No newline at end of file diff --git a/.cypress/plugins/index.js b/.cypress/plugins/index.js new file mode 100644 index 00000000..8c76f947 --- /dev/null +++ b/.cypress/plugins/index.js @@ -0,0 +1,36 @@ +/* + * Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT 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 example plugins/index.js can be used to load plugins +// +// You can change the location of this file or turn off loading +// the plugins file with the 'pluginsFile' configuration option. +// +// You can read more here: +// https://on.cypress.io/plugins-guide +// *********************************************************** + +// This function is called when a project is opened or re-opened (e.g. due to +// the project's config changing) + +/** + * @type {Cypress.PluginConfig} + */ +module.exports = (on, config) => { + // `on` is used to hook into various events Cypress emits + // `config` is the resolved Cypress config +} diff --git a/.cypress/support/commands.js b/.cypress/support/commands.js new file mode 100644 index 00000000..104bef84 --- /dev/null +++ b/.cypress/support/commands.js @@ -0,0 +1,40 @@ +/* + * Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT 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 example commands.js shows you how to +// create various custom commands and overwrite +// existing commands. +// +// For more comprehensive examples of custom +// commands please read more here: +// https://on.cypress.io/custom-commands +// *********************************************** +// +// +// -- This is a parent command -- +// Cypress.Commands.add("login", (email, password) => { ... }) +// +// +// -- This is a child command -- +// Cypress.Commands.add("drag", { prevSubject: 'element'}, (subject, options) => { ... }) +// +// +// -- This is a dual command -- +// Cypress.Commands.add("dismiss", { prevSubject: 'optional'}, (subject, options) => { ... }) +// +// +// -- This will overwrite an existing command -- +// Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... }) diff --git a/.cypress/support/index.js b/.cypress/support/index.js new file mode 100644 index 00000000..09218067 --- /dev/null +++ b/.cypress/support/index.js @@ -0,0 +1,35 @@ +/* + * Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT 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 example support/index.js is processed and +// loaded automatically before your test files. +// +// This is a great place to put global configuration and +// behavior that modifies Cypress. +// +// You can change the location of this file or turn off +// automatically serving support files with the +// 'supportFile' configuration option. +// +// You can read more here: +// https://on.cypress.io/configuration +// *********************************************************** + +// Import commands.js using ES2015 syntax: +import './commands' + +// Alternatively you can use CommonJS syntax: +// require('./commands') diff --git a/.cypress/tsconfig.json b/.cypress/tsconfig.json new file mode 100644 index 00000000..2d48dc0e --- /dev/null +++ b/.cypress/tsconfig.json @@ -0,0 +1,8 @@ +{ + "compilerOptions": { + "allowJs": true, + "baseUrl": "../node_modules", + "types": ["cypress"] + }, + "include": ["**/*.*"] +} \ No newline at end of file diff --git a/.eslintrc b/.eslintrc new file mode 100644 index 00000000..661af680 --- /dev/null +++ b/.eslintrc @@ -0,0 +1,9 @@ +--- +extends: '@elastic/kibana' + +settings: + import/resolver: + '@kbn/eslint-import-resolver-kibana': + rootPackageName: 'opendistro-kibana-reports' + pluginPaths: + - . diff --git a/.github/workflows/kibana-reports-release-workflow.yml b/.github/workflows/kibana-reports-release-workflow.yml deleted file mode 100644 index ef59742a..00000000 --- a/.github/workflows/kibana-reports-release-workflow.yml +++ /dev/null @@ -1,114 +0,0 @@ -name: Release Kibana Reports Artifacts - -on: - push: - tags: - - "v*" - -env: - PLUGIN_NAME: opendistroReportsKibana - OD_VERSION: 1.13.0.0 - -jobs: - build: - runs-on: ubuntu-latest - - steps: - - name: Configure AWS Credentials - uses: aws-actions/configure-aws-credentials@v1 - with: - aws-access-key-id: ${{ secrets.AWS_STAGING_ACCESS_KEY_ID }} - aws-secret-access-key: ${{ secrets.AWS_STAGING_SECRET_ACCESS_KEY }} - aws-region: us-east-1 - - - name: Checkout Plugin - uses: actions/checkout@v1 - - - name: Checkout Kibana - uses: actions/checkout@v1 - with: - repository: opendistro-for-elasticsearch/kibana-oss - ref: 7.10.2 - token: ${{secrets.OD_ACCESS}} - path: dashboards-reports/kibana - - - name: Setup Node - uses: actions/setup-node@v1 - with: - node-version: "10.23.1" - - - name: Move Kibana Reports to Plugins Dir - run: mv kibana-reports kibana/plugins/${{ env.PLUGIN_NAME }} - - - name: Add Chromium Binary to Reporting for Testing - run: | - sudo apt install -y libnss3-dev fonts-liberation libfontconfig1 - cd kibana/plugins/${{ env.PLUGIN_NAME }} - wget https://github.com/opendistro-for-elasticsearch/kibana-reports/releases/download/chromium-1.12.0.0/chromium-linux-x64.zip - unzip chromium-linux-x64.zip - rm chromium-linux-x64.zip - - - name: Kibana Plugin Bootstrap - uses: nick-invision/retry@v1 - with: - timeout_minutes: 30 - max_attempts: 3 - command: cd kibana/plugins/${{ env.PLUGIN_NAME }}; yarn kbn bootstrap - - - name: Test - uses: nick-invision/retry@v1 - with: - timeout_minutes: 30 - max_attempts: 3 - command: cd kibana/plugins/${{ env.PLUGIN_NAME }}; yarn test - - - name: Build Artifact and upload to S3 - run: | - cd kibana/plugins/${{ env.PLUGIN_NAME }} - yarn build - - cd build - mkdir -p ./{linux-x64,linux-arm64,windows-x64}/kibana/${{ env.PLUGIN_NAME }} - cp ./${{ env.PLUGIN_NAME }}-*.zip ./linux-x64/${{ env.PLUGIN_NAME }}-${{ env.OD_VERSION }}-linux-x64.zip - cp ./${{ env.PLUGIN_NAME }}-*.zip ./linux-arm64/${{ env.PLUGIN_NAME }}-${{ env.OD_VERSION }}-linux-arm64.zip - mv ./${{ env.PLUGIN_NAME }}-*.zip ./windows-x64/${{ env.PLUGIN_NAME }}-${{ env.OD_VERSION }}-windows-x64.zip - - s3_prefix="s3://staging.artifacts.opendistroforelasticsearch.amazon.com/snapshots/kibana-plugins/reports/" - - cd linux-x64 - wget https://github.com/opendistro-for-elasticsearch/kibana-reports/releases/download/chromium-1.12.0.0/chromium-linux-x64.zip - unzip chromium-linux-x64.zip -d ./kibana/${{ env.PLUGIN_NAME }} - rm chromium-linux-x64.zip - zip -ur ./${{ env.PLUGIN_NAME }}-*.zip ./kibana - linux_x64_artifact=`ls ./${{ env.PLUGIN_NAME }}-${{ env.OD_VERSION }}-linux-x64.zip` - - #Inject build number before the suffix and upload to S3 - linux_x64_artifact_outfile=`basename ${linux_x64_artifact%.zip}-build-${GITHUB_RUN_NUMBER}.zip` - echo "Copying $linux_x64_artifact to ${s3_prefix}${linux_x64_artifact_outfile}" - aws s3 cp --quiet $linux_x64_artifact ${s3_prefix}${linux_x64_artifact_outfile} - cd .. - - cd linux-arm64 - wget https://github.com/opendistro-for-elasticsearch/kibana-reports/releases/download/chromium-1.12.0.0/chromium-linux-arm64.zip - unzip chromium-linux-arm64.zip -d ./kibana/${{ env.PLUGIN_NAME }} - rm chromium-linux-arm64.zip - zip -ur ./${{ env.PLUGIN_NAME }}-*.zip ./kibana - linux_arm64_artifact=`ls ./${{ env.PLUGIN_NAME }}-${{ env.OD_VERSION }}-linux-arm64.zip` - - #Inject build number before the suffix and upload to S3 - linux_arm64_artifact_outfile=`basename ${linux_arm64_artifact%.zip}-build-${GITHUB_RUN_NUMBER}.zip` - echo "Copying $linux_arm64_artifact to ${s3_prefix}${linux_arm64_artifact_outfile}" - aws s3 cp --quiet $linux_arm64_artifact ${s3_prefix}${linux_arm64_artifact_outfile} - cd .. - - cd windows-x64 - wget https://github.com/opendistro-for-elasticsearch/kibana-reports/releases/download/chromium-1.12.0.0/chromium-windows-x64.zip - unzip chromium-windows-x64.zip -d ./kibana/${{ env.PLUGIN_NAME }} - rm chromium-windows-x64.zip - zip -ur ./${{ env.PLUGIN_NAME }}-*.zip ./kibana - windows_x64_artifact=`ls ./${{ env.PLUGIN_NAME }}-${{ env.OD_VERSION }}-windows-x64.zip` - - #Inject build number before the suffix and upload to S3 - windows_x64_artifact_outfile=`basename ${windows_x64_artifact%.zip}-build-${GITHUB_RUN_NUMBER}.zip` - echo "Copying $windows_x64_artifact to ${s3_prefix}${windows_x64_artifact_outfile}" - aws s3 cp --quiet $windows_x64_artifact ${s3_prefix}${windows_x64_artifact_outfile} diff --git a/.github/workflows/kibana-reports-test-and-build-workflow.yml b/.github/workflows/kibana-reports-test-and-build-workflow.yml index 5360e484..c9e9a316 100644 --- a/.github/workflows/kibana-reports-test-and-build-workflow.yml +++ b/.github/workflows/kibana-reports-test-and-build-workflow.yml @@ -10,9 +10,6 @@ jobs: build: runs-on: ubuntu-latest steps: - - name: Checkout Plugin - uses: actions/checkout@v1 - - name: Checkout Kibana uses: actions/checkout@v1 with: @@ -25,97 +22,37 @@ jobs: with: node-version: "10.23.1" - # bootstrap first to workaround errors caused by removing puppeteer-core from x-pack - - name: Kibana Plugin Bootstrap - uses: nick-invision/retry@v1 + - name: Checkout Plugin + uses: actions/checkout@v1 with: - timeout_minutes: 30 - max_attempts: 3 - command: cd ../kibana; yarn kbn bootstrap - - - name: Move Kibana Reports to Plugins Dir - run: mv kibana-reports ../kibana/plugins/${{ env.PLUGIN_NAME }} - - - name: Add Chromium Binary to Reporting for Testing - run: | - sudo apt install -y libnss3-dev fonts-liberation libfontconfig1 - cd ../kibana/plugins/${{ env.PLUGIN_NAME }} - wget https://github.com/opendistro-for-elasticsearch/kibana-reports/releases/download/chromium-1.12.0.0/chromium-linux-x64.zip - unzip chromium-linux-x64.zip - rm chromium-linux-x64.zip - - # reporting uses newer version of puppeteer-core than x-pack, removing it to avoid conflicts - - name: Remove x-pack puppeteer-core dependency - run: | - sed -i '/"puppeteer-core": "/d' ../kibana/x-pack/package.json + path: kibana/plugins/${{ env.PLUGIN_NAME }} - name: Kibana Plugin Bootstrap - uses: nick-invision/retry@v1 + uses: nick-fields/retry@v1 with: timeout_minutes: 30 max_attempts: 3 - command: cd ../kibana/plugins/${{ env.PLUGIN_NAME }}; yarn kbn bootstrap + command: yarn kbn bootstrap - name: Test - uses: nick-invision/retry@v1 + uses: nick-fields/retry@v1 with: timeout_minutes: 30 max_attempts: 3 - command: cd ../kibana/plugins/${{ env.PLUGIN_NAME }}; yarn test --coverage + command: yarn test --coverage - - name: Upload coverage + - name: Uploads coverage uses: codecov/codecov-action@v1 with: - flags: Kibana-reports - directory: ../kibana/plugins/ token: ${{ secrets.CODECOV_TOKEN }} - name: Build Artifact run: | - cd ../kibana/plugins/${{ env.PLUGIN_NAME }} yarn build + mv ./build/*.zip ./build/${{ env.PLUGIN_NAME }}-${{ env.OD_VERSION }}.zip || true - cd build - mkdir -p ./{linux-x64,linux-arm64,windows-x64}/kibana/${{ env.PLUGIN_NAME }} - cp ./${{ env.PLUGIN_NAME }}-*.zip ./linux-x64/${{ env.PLUGIN_NAME }}-${{ env.OD_VERSION }}-linux-x64.zip - cp ./${{ env.PLUGIN_NAME }}-*.zip ./linux-arm64/${{ env.PLUGIN_NAME }}-${{ env.OD_VERSION }}-linux-arm64.zip - mv ./${{ env.PLUGIN_NAME }}-*.zip ./windows-x64/${{ env.PLUGIN_NAME }}-${{ env.OD_VERSION }}-windows-x64.zip - - cd linux-x64 - wget https://github.com/opendistro-for-elasticsearch/kibana-reports/releases/download/chromium-1.12.0.0/chromium-linux-x64.zip - unzip chromium-linux-x64.zip -d ./kibana/${{ env.PLUGIN_NAME }} - zip -ur ./${{ env.PLUGIN_NAME }}-*.zip ./kibana - mv ./${{ env.PLUGIN_NAME }}-*.zip .. - cd .. - - cd linux-arm64 - wget https://github.com/opendistro-for-elasticsearch/kibana-reports/releases/download/chromium-1.12.0.0/chromium-linux-arm64.zip - unzip chromium-linux-arm64.zip -d ./kibana/${{ env.PLUGIN_NAME }} - zip -ur ./${{ env.PLUGIN_NAME }}-*.zip ./kibana - mv ./${{ env.PLUGIN_NAME }}-*.zip .. - cd .. - - cd windows-x64 - wget https://github.com/opendistro-for-elasticsearch/kibana-reports/releases/download/chromium-1.12.0.0/chromium-windows-x64.zip - unzip chromium-windows-x64.zip -d ./kibana/${{ env.PLUGIN_NAME }} - zip -ur ./${{ env.PLUGIN_NAME }}-*.zip ./kibana - mv ./${{ env.PLUGIN_NAME }}-*.zip .. - cd .. - - - name: Upload Artifact For Linux x64 - uses: actions/upload-artifact@v1 - with: - name: kibana-reports-linux-x64 - path: ../kibana/plugins/${{ env.PLUGIN_NAME }}/build/${{ env.PLUGIN_NAME }}-${{ env.OD_VERSION }}-linux-x64.zip - - - name: Upload Artifact For Linux arm64 - uses: actions/upload-artifact@v1 - with: - name: kibana-reports-linux-arm64 - path: ../kibana/plugins/${{ env.PLUGIN_NAME }}/build/${{ env.PLUGIN_NAME }}-${{ env.OD_VERSION }}-linux-arm64.zip - - - name: Upload Artifact For Windows + - name: Upload Artifact uses: actions/upload-artifact@v1 with: - name: kibana-reports-windows-x64 - path: ../kibana/plugins/${{ env.PLUGIN_NAME }}/build/${{ env.PLUGIN_NAME }}-${{ env.OD_VERSION }}-windows-x64.zip + name: kibana-reports + path: ./build/${{ env.PLUGIN_NAME }}-${{ env.OD_VERSION }}.zip diff --git a/.github/workflows/reports-scheduler-release-workflow.yml b/.github/workflows/reports-scheduler-release-workflow.yml deleted file mode 100644 index 3b1558b1..00000000 --- a/.github/workflows/reports-scheduler-release-workflow.yml +++ /dev/null @@ -1,55 +0,0 @@ -name: Release Reports Scheduler Artifacts -# This workflow is triggered on creating tags to master or an opendistro release branch -on: - push: - tags: - - "v*" - -jobs: - build: - runs-on: ubuntu-latest - - steps: - - name: Configure AWS Credentials - uses: aws-actions/configure-aws-credentials@v1 - with: - aws-access-key-id: ${{ secrets.AWS_STAGING_ACCESS_KEY_ID }} - aws-secret-access-key: ${{ secrets.AWS_STAGING_SECRET_ACCESS_KEY }} - aws-region: us-east-1 - - - name: Checkout Plugin - uses: actions/checkout@v1 - - - name: Set up JDK 1.14 - uses: actions/setup-java@v1 - with: - java-version: 1.14 - - - name: Run build - run: | - cd reports-scheduler - ./gradlew build buildDeb buildRpm --no-daemon --refresh-dependencies -Dbuild.snapshot=false - - - name: Upload to S3 - shell: bash - run: | - cd reports-scheduler - zip=`ls build/distributions/*.zip` - rpm=`ls build/distributions/*.rpm` - deb=`ls build/distributions/*.deb` - - # Inject the build number before the suffix - zip_outfile=`basename ${zip%.zip}-build-${GITHUB_RUN_NUMBER}.zip` - rpm_outfile=`basename ${rpm%.rpm}-build-${GITHUB_RUN_NUMBER}.rpm` - deb_outfile=`basename ${deb%.deb}-build-${GITHUB_RUN_NUMBER}.deb` - - s3_prefix="s3://staging.artifacts.opendistroforelasticsearch.amazon.com/snapshots/elasticsearch-plugins/reports-scheduler/" - - echo "Copying ${zip} to ${s3_prefix}${zip_outfile}" - aws s3 cp --quiet $zip ${s3_prefix}${zip_outfile} - - echo "Copying ${rpm} to ${s3_prefix}${rpm_outfile}" - aws s3 cp --quiet $rpm ${s3_prefix}${rpm_outfile} - - echo "Copying ${deb} to ${s3_prefix}${deb_outfile}" - aws s3 cp --quiet $deb ${s3_prefix}${deb_outfile} \ No newline at end of file diff --git a/.github/workflows/reports-scheduler-test-and-build-workflow.yml b/.github/workflows/reports-scheduler-test-and-build-workflow.yml deleted file mode 100644 index f61dbdea..00000000 --- a/.github/workflows/reports-scheduler-test-and-build-workflow.yml +++ /dev/null @@ -1,38 +0,0 @@ -name: Test and Build Reports Scheduler - -on: [push, pull_request] - -jobs: - build: - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v1 - - - name: Set up JDK 1.14 - uses: actions/setup-java@v1 - with: - java-version: 1.14 - - - name: Build with Gradle - run: | - cd reports-scheduler - ./gradlew build - - - name: Upload coverage - uses: codecov/codecov-action@v1 - with: - flags: reports-scheduler - directory: reports-scheduler/ - token: ${{ secrets.CODECOV_TOKEN }} - - - name: Create Artifact Path - run: | - mkdir -p reports-scheduler-builds - cp -r ./reports-scheduler/build/distributions/*.zip reports-scheduler-builds/ - - - name: Upload Artifacts - uses: actions/upload-artifact@v1 - with: - name: reports-scheduler - path: reports-scheduler-builds diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..77852916 --- /dev/null +++ b/.gitignore @@ -0,0 +1,21 @@ +.DS_Store + +*.iml +.gradle +out +local-test +.local-* + +npm-debug.log* +node_modules +/build/ +/public/app.css +.idea/ +.vscode/ +yarn-error.log +/coverage/ +.history/ +.eslintcache + +# Kibana +.empty \ No newline at end of file diff --git a/.gitignore.~1~ b/.gitignore.~1~ new file mode 100644 index 00000000..0bebbcb8 --- /dev/null +++ b/.gitignore.~1~ @@ -0,0 +1,12 @@ +npm-debug.log* +node_modules +/build/ +/public/app.css +.idea/ +yarn-error.log +/coverage/ +.DS_Store +.history/ +.eslintcache +package-lock.json +/target/ \ No newline at end of file diff --git a/.kibana-plugin-helpers.json b/.kibana-plugin-helpers.json new file mode 100644 index 00000000..cbfa2867 --- /dev/null +++ b/.kibana-plugin-helpers.json @@ -0,0 +1,12 @@ +{ + "serverSourcePatterns": [ + "package.json", + "tsconfig.json", + "yarn.lock", + "kibana.json", + "common/**/*", + "scripts/**/*", + "public/**/*", + "server/**/*" + ] +} diff --git a/.lintstagedrc b/.lintstagedrc new file mode 100644 index 00000000..e7e7db11 --- /dev/null +++ b/.lintstagedrc @@ -0,0 +1,3 @@ +{ + "*.{ts,tsx,js,jsx,json,css,md}": ["prettier --write", "git add"] +} diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 00000000..7dc413d2 --- /dev/null +++ b/.prettierignore @@ -0,0 +1,8 @@ +.vscode +build +coverage +node_modules +npm-debug.log +yarn.lock +*.md +*.lock \ No newline at end of file diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 00000000..f443e3cf --- /dev/null +++ b/.prettierrc @@ -0,0 +1,6 @@ +{ + "trailingComma": "es5", + "singleQuote": true, + "printWidth": 80, + "bracketSpacing": true +} diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 00000000..5b627cfa --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,4 @@ +## Code of Conduct +This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct). +For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact +opensource-codeofconduct@amazon.com with any additional questions or comments. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 00000000..cd94f03b --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,59 @@ +# Contributing Guidelines + +Thank you for your interest in contributing to our project. Whether it's a bug report, new feature, correction, or additional +documentation, we greatly value feedback and contributions from our community. + +Please read through this document before submitting any issues or pull requests to ensure we have all the necessary +information to effectively respond to your bug report or contribution. + +## Reporting Bugs/Feature Requests + +We welcome you to use the GitHub issue tracker to report bugs or suggest features. + +When filing an issue, please check existing open, or recently closed, issues to make sure somebody else hasn't already +reported the issue. Please try to include as much information as you can. Details like these are incredibly useful: + +- A reproducible test case or series of steps +- The version of our code being used +- Any modifications you've made relevant to the bug +- Anything unusual about your environment or deployment + +## Contributing via Pull Requests + +Contributions via pull requests are much appreciated. Before sending us a pull request, please ensure that: + +1. You are working against the latest source on the _dev_ branch. +2. You check existing open, and recently merged, pull requests to make sure someone else hasn't addressed the problem already. +3. You open an issue to discuss any significant work - we would hate for your time to be wasted. + +To send us a pull request, please: + +1. Fork the repository. +2. Modify the source; please focus on the specific change you are contributing. If you also reformat all the code, it will be hard for us to focus on your change. +3. Ensure local tests pass. +4. Commit to your fork using clear commit messages. +5. Send us a pull request, answering any default questions in the pull request interface. +6. Pay attention to any automated CI failures reported in the pull request, and stay involved in the conversation. + +GitHub provides additional document on [forking a repository](https://help.github.com/articles/fork-a-repo/) and +[creating a pull request](https://help.github.com/articles/creating-a-pull-request/). + +## Finding contributions to work on + +Looking at the existing issues is a great way to find something to contribute on. As our projects, by default, use the default GitHub issue labels (enhancement/bug/duplicate/help wanted/invalid/question/wontfix), looking at any 'help wanted' issues is a great place to start. + +## Code of Conduct + +This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct). +For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact +opensource-codeofconduct@amazon.com with any additional questions or comments. + +## Security issue notifications + +If you discover a potential security issue in this project we ask that you notify AWS/Amazon Security via our [vulnerability reporting page](http://aws.amazon.com/security/vulnerability-reporting/). Please do **not** create a public github issue. + +## Licensing + +See the [LICENSE](LICENSE) file for our project's licensing. We will ask you to confirm the licensing of your contribution. + +We may ask you to sign a [Contributor License Agreement (CLA)](http://en.wikipedia.org/wiki/Contributor_License_Agreement) for larger changes. diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 00000000..67db8588 --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,175 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. diff --git a/NOTICE.txt b/NOTICE.txt new file mode 100644 index 00000000..6ba6ecfb --- /dev/null +++ b/NOTICE.txt @@ -0,0 +1,2 @@ +kibana-reports +Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. diff --git a/README.md b/README.md new file mode 100644 index 00000000..6222e4f4 --- /dev/null +++ b/README.md @@ -0,0 +1,52 @@ +[![Kibana Reports CI](https://github.com/opendistro-for-elasticsearch/kibana-reports/workflows/Test%20and%20Build%20Kibana%20Reports/badge.svg)](https://github.com/opendistro-for-elasticsearch/kibana-reports/actions?query=workflow%3A%22Test+and+Build+Kibana+Reports%22) +[![Reports Scheduler CI](https://github.com/opendistro-for-elasticsearch/kibana-reports/workflows/Test%20and%20Build%20Reports%20Scheduler/badge.svg)](https://github.com/opendistro-for-elasticsearch/kibana-reports/actions?query=workflow%3A%22Test+and+Build+Reports+Scheduler%22) +[![codecov](https://codecov.io/gh/opendistro-for-elasticsearch/kibana-reports/branch/dev/graph/badge.svg?token=FBVYQSZD3B)](https://codecov.io/gh/opendistro-for-elasticsearch/kibana-reports) +[![Documentation](https://img.shields.io/badge/documentation-blue.svg)](https://opendistro.github.io/for-elasticsearch-docs/docs/kibana/reporting/) +![PRs welcome!](https://img.shields.io/badge/PRs-welcome!-success) + +# Kibana Reports for Open Distro + +Kibana Reports for Open Distro allows ‘Report Owner’ (engineers, including but not limited to developers, DevOps, IT Engineer, and IT admin) export and share reports from Kibana dashboards, saved search, alerts and visualizations. It helps automate the process of scheduling reports on an on-demand or a periodical basis (on cron schedules as well). Further, it also automates the process of exporting and sharing reports triggered for various alerts. The feature is present in the Dashboard, Discover, and Visualization tabs. Scheduled reports can be sent to (shared with) self or various stakeholders within the organization such as, including but not limited to, executives, managers, engineers (developers, DevOps, IT Engineer) in the form of pdf, hyperlinks, csv, excel via various channels such as email, slack, Amazon Chime. However, in order to export, schedule and share reports, report owners should have the necessary permissions as defined under Roles and Privileges. + +# Request for Comments ( RFC ) + +Please add your feature requests here [ New Requests ](https://github.com/opendistro-for-elasticsearch/kibana-reports/issues) and view project progress here [RFCs](https://github.com/opendistro-for-elasticsearch/kibana-reports/projects/1). + +## Setup & Build + +Complete Kibana Report feature is composed of 2 plugins. Refer to README in each plugin folder for more details. + +- [Kibana reports plugin](./kibana-reports/README.md) +- [Reports scheduler ES plugin](./reports-scheduler/README.md)(TODO) + +## Troubleshooting + +#### Fail to launch Chromium + +There could be two reasons for this problem + +1. You are not having the correct version of headless-chrome matching to the OS that your Kibana is running. Different versions of headless-chrome can be found [here](https://github.com/opendistro-for-elasticsearch/kibana-reports/releases/tag/chromium-1.12.0.0) + +2. Missing additional dependencies. Please refer to [additional dependencies section](./kibana-reports/rendering-engine/headless-chrome/README.md#additional-libaries) to install required dependencies according to your operating system. + +## Contributing to Kibana reports for Open Distro + +We welcome you to get involved in development, documentation, testing the kibana reports plugin. See our [CONTRIBUTING.md](./CONTRIBUTING.md) and join in. + +Since this is a Kibana plugin, it can be useful to review the [Kibana contributing guide](https://github.com/elastic/kibana/blob/master/CONTRIBUTING.md) alongside the documentation around [Kibana plugins](https://www.elastic.co/guide/en/kibana/master/kibana-plugins.html) and [plugin development](https://www.elastic.co/guide/en/kibana/master/plugin-development.html). + +## Code of Conduct + +This project has adopted an [Open Source Code of Conduct](https://opendistro.github.io/for-elasticsearch/codeofconduct.html). + +## Security issue notifications + +If you discover a potential security issue in this project we ask that you notify AWS/Amazon Security via our [vulnerability reporting page](http://aws.amazon.com/security/vulnerability-reporting/). Please do **not** create a public GitHub issue. + +## License + +See the [LICENSE](./LICENSE.txt) file for our project's licensing. We will ask you to confirm the licensing of your contribution. + +## Copyright + +Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. diff --git a/README.md.~1~ b/README.md.~1~ new file mode 100644 index 00000000..51bd9964 --- /dev/null +++ b/README.md.~1~ @@ -0,0 +1,74 @@ +# Kibana Reports for Open Distro + +Kibana Reports for Open Distro allows ‘Report Owner’ (engineers, including but not limited to developers, DevOps, IT Engineer, and IT admin) export and share reports from Kibana dashboards, saved search, alerts and visualizations. It helps automate the process of scheduling reports on an on-demand or a periodical basis (on cron schedules as well). Further, it also automates the process of exporting and sharing reports triggered for various alerts. The feature is present in the Dashboard, Discover, and Visualization tabs. Scheduled reports can be sent to (shared with) self or various stakeholders within the organization such as, including but not limited to, executives, managers, engineers (developers, DevOps, IT Engineer) in the form of pdf, hyperlinks, csv, excel via various channels such as email, slack, Amazon Chime. However, in order to export, schedule and share reports, report owners should have the necessary permissions as defined under Roles and Privileges. + +# Request for Comments ( RFC ) + +Please add your feature requests here [ New Requests ](https://github.com/opendistro-for-elasticsearch/kibana-reports/issues) and view project progress here [RFCs](https://github.com/opendistro-for-elasticsearch/kibana-reports/projects/1). + +## Setup + +1. Download Elasticsearch for the version that matches the [Kibana version specified in package.json](./package.json#L7). +1. Download the Kibana source code for the [version specified in package.json](./package.json#L7) you want to set up. + + See the [Kibana contributing guide](https://github.com/elastic/kibana/blob/master/CONTRIBUTING.md#setting-up-your-development-environment) for more instructions on setting up your development environment. + +1. Change your node version to the version specified in `.node-version` inside the Kibana root directory. +1. Create a `plugins` directory inside the Kibana source code directory, if `plugins` directory doesn't exist. +1. Check out this package from version control into the `plugins` directory. + ``` + git clone git@github.com:opendistro-for-elasticsearch/kibana-reports.git plugins --no-checkout + cd plugins + echo 'kibana-reports/*' >> .git/info/sparse-checkout + git config core.sparseCheckout true + git checkout dev + ``` +1. Run `yarn kbn bootstrap` inside `kibana/plugins/kibana-reports`. + +Ultimately, your directory structure should look like this: + + +```md +. +├── kibana +│ └──plugins +│ └── kibana-reports +``` + +## Build + +To build the plugin's distributable zip simply run `yarn build`. + +Example output: `./build/opendistro-kibana-reports-0.0.1.zip` + +## Run + +- `yarn start` + + Starts Kibana and includes this plugin. Kibana will be available on `localhost:5601`. + +- `yarn test:jest` + + Runs the plugin tests. + +## Contributing to Kibana reports for Open Distro + +We welcome you to get involved in development, documentation, testing the kibana reports plugin. See our [CONTRIBUTING.md](./CONTRIBUTING.md) and join in. + +Since this is a Kibana plugin, it can be useful to review the [Kibana contributing guide](https://github.com/elastic/kibana/blob/master/CONTRIBUTING.md) alongside the documentation around [Kibana plugins](https://www.elastic.co/guide/en/kibana/master/kibana-plugins.html) and [plugin development](https://www.elastic.co/guide/en/kibana/master/plugin-development.html). + +## Code of Conduct + +This project has adopted an [Open Source Code of Conduct](https://opendistro.github.io/for-elasticsearch/codeofconduct.html). + +## Security issue notifications + +If you discover a potential security issue in this project we ask that you notify AWS/Amazon Security via our [vulnerability reporting page](http://aws.amazon.com/security/vulnerability-reporting/). Please do **not** create a public GitHub issue. + +## License + +See the [LICENSE](./LICENSE.txt) file for our project's licensing. We will ask you to confirm the licensing of your contribution. + +## Copyright + +Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. diff --git a/THIRD-PARTY b/THIRD-PARTY new file mode 100644 index 00000000..ee9ee3fd --- /dev/null +++ b/THIRD-PARTY @@ -0,0 +1,203 @@ +** @elastic/eui; version 5.1.0 -- https://elastic.github.io/eui/#/ + +Apache License + +Version 2.0, January 2004 + +http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND +DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, and + distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by the + copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all other + entities that control, are controlled by, or are under common control + with that entity. For the purposes of this definition, "control" means + (i) the power, direct or indirect, to cause the direction or management + of such entity, whether by contract or otherwise, or (ii) ownership of + fifty percent (50%) or more of the outstanding shares, or (iii) + beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity exercising + permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation source, + and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but not limited + to compiled object code, generated documentation, and conversions to + other media types. + + "Work" shall mean the work of authorship, whether in Source or Object + form, made available under the License, as indicated by a copyright + notice that is included in or attached to the work (an example is + provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object form, + that is based on (or derived from) the Work and for which the editorial + revisions, annotations, elaborations, or other modifications represent, + as a whole, an original work of authorship. For the purposes of this + License, Derivative Works shall not include works that remain separable + from, or merely link (or bind by name) to the interfaces of, the Work and + Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including the original + version of the Work and any modifications or additions to that Work or + Derivative Works thereof, that is intentionally submitted to Licensor for + inclusion in the Work by the copyright owner or by an individual or Legal + Entity authorized to submit on behalf of the copyright owner. For the + purposes of this definition, "submitted" means any form of electronic, + verbal, or written communication sent to the Licensor or its + representatives, including but not limited to communication on electronic + mailing lists, source code control systems, and issue tracking systems + that are managed by, or on behalf of, the Licensor for the purpose of + discussing and improving the Work, but excluding communication that is + conspicuously marked or otherwise designated in writing by the copyright + owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity on + behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of this + License, each Contributor hereby grants to You a perpetual, worldwide, + non-exclusive, no-charge, royalty-free, irrevocable copyright license to + reproduce, prepare Derivative Works of, publicly display, publicly perform, + sublicense, and distribute the Work and such Derivative Works in Source or + Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of this + License, each Contributor hereby grants to You a perpetual, worldwide, + non-exclusive, no-charge, royalty-free, irrevocable (except as stated in + this section) patent license to make, have made, use, offer to sell, sell, + import, and otherwise transfer the Work, where such license applies only to + those patent claims licensable by such Contributor that are necessarily + infringed by their Contribution(s) alone or by combination of their + Contribution(s) with the Work to which such Contribution(s) was submitted. + If You institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work or a + Contribution incorporated within the Work constitutes direct or contributory + patent infringement, then any patent licenses granted to You under this + License for that Work shall terminate as of the date such litigation is + filed. + + 4. Redistribution. You may reproduce and distribute copies of the Work or + Derivative Works thereof in any medium, with or without modifications, and + in Source or Object form, provided that You meet the following conditions: + + (a) You must give any other recipients of the Work or Derivative Works a + copy of this License; and + + (b) You must cause any modified files to carry prominent notices stating + that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works that You + distribute, all copyright, patent, trademark, and attribution notices + from the Source form of the Work, excluding those notices that do not + pertain to any part of the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must include + a readable copy of the attribution notices contained within such NOTICE + file, excluding those notices that do not pertain to any part of the + Derivative Works, in at least one of the following places: within a + NOTICE text file distributed as part of the Derivative Works; within the + Source form or documentation, if provided along with the Derivative + Works; or, within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents of the + NOTICE file are for informational purposes only and do not modify the + License. You may add Your own attribution notices within Derivative Works + that You distribute, alongside or as an addendum to the NOTICE text from + the Work, provided that such additional attribution notices cannot be + construed as modifying the License. + + You may add Your own copyright statement to Your modifications and may + provide additional or different license terms and conditions for use, + reproduction, or distribution of Your modifications, or for any such + Derivative Works as a whole, provided Your use, reproduction, and + distribution of the Work otherwise complies with the conditions stated in + this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, any + Contribution intentionally submitted for inclusion in the Work by You to the + Licensor shall be under the terms and conditions of this License, without + any additional terms or conditions. Notwithstanding the above, nothing + herein shall supersede or modify the terms of any separate license agreement + you may have executed with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, except + as required for reasonable and customary use in describing the origin of the + Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in + writing, Licensor provides the Work (and each Contributor provides its + Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, either express or implied, including, without limitation, any + warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or + FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining + the appropriateness of using or redistributing the Work and assume any risks + associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, whether + in tort (including negligence), contract, or otherwise, unless required by + applicable law (such as deliberate and grossly negligent acts) or agreed to + in writing, shall any Contributor be liable to You for damages, including + any direct, indirect, special, incidental, or consequential damages of any + character arising as a result of this License or out of the use or inability + to use the Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all other + commercial damages or losses), even if such Contributor has been advised of + the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing the Work + or Derivative Works thereof, You may choose to offer, and charge a fee for, + acceptance of support, warranty, indemnity, or other liability obligations + and/or rights consistent with this License. However, in accepting such + obligations, You may act only on Your own behalf and on Your sole + responsibility, not on behalf of any other Contributor, and only if You + agree to indemnify, defend, and hold each Contributor harmless for any + liability incurred by, or claims asserted against, such Contributor by + reason of your accepting any such warranty or additional liability. END OF + TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + +To apply the Apache License to your work, attach the following boilerplate +notice, with the fields enclosed by brackets "[]" replaced with your own +identifying information. (Don't include the brackets!) The text should be +enclosed in the appropriate comment syntax for the file format. We also +recommend that a file or class name and description of purpose be included on +the same "printed page" as the copyright notice for easier identification +within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); + +you may not use this file except in compliance with the License. + +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software + +distributed under the License is distributed on an "AS IS" BASIS, + +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + +See the License for the specific language governing permissions and + +limitations under the License. + +* For kibana-reports see also this required NOTICE: + kibana-reports + Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. \ No newline at end of file diff --git a/common/index.ts b/common/index.ts new file mode 100644 index 00000000..2ba8d437 --- /dev/null +++ b/common/index.ts @@ -0,0 +1,34 @@ +/* + * Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT 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 PLUGIN_ID = 'opendistroReportsKibana'; +export const PLUGIN_NAME = 'opendistro_kibana_reports'; + +export const API_PREFIX = '/api/reporting'; + +export const NOTIFICATION_API = { + SEND: '/_opendistro/_notifications/send', +}; + +const BASE_REPORTS_URI = '/_opendistro/_reports'; + +export const ES_REPORTS_API = { + ON_DEMAND_REPORT: `${BASE_REPORTS_URI}/on_demand`, + REPORT_INSTANCE: `${BASE_REPORTS_URI}/instance`, + LIST_REPORT_INSTANCES: `${BASE_REPORTS_URI}/instances`, + REPORT_DEFINITION: `${BASE_REPORTS_URI}/definition`, + LIST_REPORT_DEFINITIONS: `${BASE_REPORTS_URI}/definitions`, + POLL_REPORT_INSTANCE: `${BASE_REPORTS_URI}/poll_instance`, +}; diff --git a/cypress.json b/cypress.json new file mode 100644 index 00000000..d91f38d7 --- /dev/null +++ b/cypress.json @@ -0,0 +1,10 @@ +{ + "baseUrl": "http://localhost:5601", + "video": false, + "fixturesFolder": ".cypress/fixtures", + "integrationFolder": ".cypress/integration", + "pluginsFile": ".cypress/plugins/index.js", + "screenshotsFolder": ".cypress/screenshots", + "supportFile": ".cypress/support/index.js", + "videosFolder": ".cypress/videos" +} diff --git a/docs/dev/Kibana-Reporting-Design-Proposal.md b/docs/dev/Kibana-Reporting-Design-Proposal.md new file mode 100644 index 00000000..d1c0bbe2 --- /dev/null +++ b/docs/dev/Kibana-Reporting-Design-Proposal.md @@ -0,0 +1,492 @@ +# Kibana Reporting +### You don’t have to go a dashboard, we will bring dashboards to you. + +--- + +## 1. Overview + +### 1.1 Motivation + +The ability to generate reports from dashboards and views on Kibana is a highly requested feature . +This plugin will introduce the ability to generate reports, as well as enable the user to customize them, receive them on a schedule or monitor, and have the reports received on external channels such as email, Slack and Chime. + +- https://discuss.opendistrocommunity.dev/t/reporting-module/153 +- https://github.com/opendistro-for-elasticsearch/community/issues/16 + +### 1.2 Introduction + +Kibana Reports for Open Distro allows ‘Report Owner’ (engineers, including but not limited to developers, DevOps, IT Engineer, and IT admin) export and share reports from Kibana dashboards, saved search, alerts and visualizations. It helps automate the process of scheduling reports on an on-demand or a periodical basis (on cron schedules as well). Further, it also automates the process of exporting and sharing reports triggered for various alerts. The feature is present in the Dashboard, Discover, and Visualization tabs. Scheduled reports can be sent to (shared with) self or various stakeholders within the organization such as, including but not limited to, executives, managers, engineers (developers, DevOps, IT Engineer) in the form of pdf, hyperlinks, csv, excel via various channels such as email, slack, Amazon Chime. However, in order to export, schedule and share reports, report owners should have the necessary permissions as defined under Roles and Privileges. + + +## 2. Requirements + + +1. As a user, I want to see a 'Share >' 'As a report' on the share menu, and a 'Download > ' 'PDF, CSV, PNG' contextually button in the Dashboard, Visualizations, and Discover Tabs. +1. As a user, I should be able to export and share reports only if I have the permissions to do so. Else, an error should be thrown. +1. As a user, when I click ‘Share > As a report’ I should be able to configure, save, export and share the report. +1. As a user, when I click ‘Share > As a report’, the system should allow me to share the dashboard or saved search or visualizations that I am currently working on as a report. + + Here is the matrix showing various panels and what kind of export option should be available. + Kibana panel | PDF | PNG |Hyperlink (HTML) | CSV/Excel + ------------ | ------------- | ------------- | ------------- | ------------- + Dashboards | Yes | Yes | Yes | No + Visualizations | Yes | Yes |Yes | No + Discover (saved search) | No | No | Yes | Yes + +### In-context reports +1. As a user, I can download a PDF, PNG, CSV, XLS file in-context from any available panel (e.g. Dashboards, visualizations, saved searches, etc). +1. As a user, any time I download a report from any available panel (e.g. Dashboards, visualizations, saved searches, etc), a report will be auto-generated in the reports list. +1. As a user, I can create a report definition from the share menu of any available panel (e.g. Dashboards, visualizations, saved searches, etc). + +### Reporting Landing Page +#### Reports +1. As a user, I should see Name, Type, Sender, Recepient(s), Source, Last updated, State, Download on the `Reports` list. +1. As a user, I should be able to filter my reports list by sender, receiver, status, and type. +1. As a user, I should be able to search my reports by report name. +1. As a user, I should be able to view a report details page for any report on the list. +1. As a user, I should see my reports ordered in reverse chronological order by default. +1. As a user, I should be able to download the default file format from the reports list. +1. As a user, I should be able to see a list of reports for the past 100 days. +1. As a user, archived reports should not be visible by default (the default filter should exclude archived reports) (p2) + + +#### Report definitions +1. As a user, I should see Name, Type, Owner, Source, Last updated, Details, Status (active/disabled) on the `Report definitions` list. +1. As a user, I should be able to view, edit and delete a report definition. +1. As a user, I should be able to enable/disable a report definition +1. As a user, I should be able to export and import one or more report definitions (as xml or some other format) via APIs + +### Create, View, Edit +#### Create report definition +##### Report settings +1. As a user, I should be able to set the report name. +1. As a user, I should be able to set an optional report descritption. +1. As a user, I should be able to select a report source type (Dashboard, Visualization, Saved Search) +1. As a user, I should be able to select a specific source (Dashboard, Visualization, or Saved search, contextually). +1. As a user, I should be able to select the default file format for my report, contextual to my selected source (PDF, PNG, CSV, Excel, etc) +1. As a user, I should be able to add a `Header` and `Footer` to PDF and PNG reports. + 1. As a user, I should see Report title and a sample paragraph in the `header` by Default. + 1. As a user, I should see date, time and report name in the `footer` by Default. +1. As a user, I should be able to select which charts/visualizations I can include in a PDF or PNG report. (p2) + +##### Report trigger +1. As a user, I should be able to select a report trigger type that belongs to one of two categories: `Schedule`, and `Alert`. +1. As a user, when I select `Schedule`, I should be able to select a request time of now, future date, recurring, or custom cron expression (similar to alerting). + 1. As a user, if I select `now`, I should be able to generate a report immediately after saving the report definition. + 1. As a user, if I select `future date`, I should be able to configure the date and time the report will be generated. + 1. As a user, if I select `recurring`, I should be able to configure a recurring schedule. + 1. As a user, if I select `custom cron`, I should be able to configure a cron-based schedule. + 1. As a user, if I select `recurring` or `custom cron`, I should be able to configure an end date. +1. As a user, when I select `Alert`, I should be able to select the alert a report gets triggered from. + +##### Delivery settings +1. As a user, I should be able to deliver a report to Kibana and/or Email recepients. +1. As a user, when I set Kibana as a delivery channel, I should be able to select which Kibana users the report gets delivered to. +1. As a user, when I set email as a delivery channel, I should be able to set recepients, email subject, and email body. +1. As a user, I should be able to insert a file URL refecence to the email body. +1. As a user, I should be able to insert the report source URL reference to the email body. +1. As a user, I should be able to attach the report file to an email. +1. As a user, I should be able to set the file format of report attachment (pdf, png | csv, excel, depending on the source). + +#### Report creation +1. As a user, when I create a report definition, the definition settings are saved and show up as a list item in the ‘Report definitions’ list. +1. As a user, when a report definition has been triggered via schedule or alert, I should be able to see an instance of the report in my "Reports" list, and any users I send the report to, will also see a report instance in their repective "Reports" list page. +1. As a user, when a report is created from a triggered definition condition, I should receive a notification on all configured delivery channels (Email, chime, slack, etc) +1. As a user, when a new report is available I should see a notification status in the reporting icon in the sidebar +1. As a user, when a report fails due to an error, I should see the report with a failed status on the `Reports` list. +1. As a report definition owner, when a report fails to trigger due to an error, I should receive a kibana toast alert letting me know that the report failed. + +#### View report definition details +1. As a user, I should be able to view all my saved definition settings. +1. As a user, I should be able to edit, duplicate or delete a report definition. + 1. As a user, when I delete a report definition, any schedule or alert based triggers will automatically stop. + +#### Edit report definition +1. As a user, I should be able to edit the report settings, triggers and delivery settings. +1. As a user, I should be able to save my updated report definition. + +#### View report details +1. As a user, I should be able to see both created date, and last updated date. +1. As a user, I should be able to share an existing report. +1. As a user, I should be able to archive an existing report. (p2) +1. As a user, I should be able to downlaod available report files (PDF, PNG, CSV, Excel, etc) +1. As a user, I should be able to copy the permalink to a report source. +1. As a user, I should be able to view the report shared with me via email as an embedded HTML. + +##### Sharing or archiving an existing report +1. As a report owner, I should be able to share or archive a report. + 1. As report owner, I should be able to add new email recepients, and new kibana recepients to an existing report. + 1. As a report owner, I sholud not be able to remove existing email or kibana recepients from an existing report. + 1. As a report owner, I should receive a Kibana toast notification when a report has been delivered to new recepients. + 1. As a report recepient, I should not get new notifications or emails when additional users have been added to an existing report. +1. As a report recepient, I can only archive a report. + + + +### Functional +* The user should be able to create/modify reports both through the Kibana UI or programmatically through APIs. +* Ability to schedule/trigger reports periodically (a cron based schedule) or at a given frequency continuously or within certain time range. +* Ability on instantly create downloadable reports or deliver scheduled reports via external channels. +* Ability to enable/disable report generation +* Ability to generate download logs as part of fine-grained audit logs. + +### Non-functional + +* In the absence of missing subsystems such as a Elasticsearch report scheduler plugin, the scheduling UI should be hidden or present the user with correct messaging (for example limited functionality) +* The service should be reliable - we should be able to generate a report in an acceptable time frame or else abort. +* **Security** - a user should not be allowed to create reports of resources they don’t have access to. For example, if a user should not be able to generate report of dashboard with index-pattern they do not have read permissions to. + + + +## 3. Design + +From implementation point of view need to answer/solve four problems: + +### 3.1 What: (Report Configuration) + +We will provide user to generate two kind of reports : + +1. Based on Kibana dashboards **TODO**: Investigate how dashboards are defined +2. Based on queries + 1. SQL queries + 2. Elasticsearch DSL (Out of Scope) - Though this will be a great feature to have, we will have to scope down what kind of Elasticsearch queries can be supported (depending on whether how easily it can be CSV formatted) and re-implement the CSV formatting logic from Elasticsearch JSON response. + + + +![Dashboard Reports](img/dashboard_reports.png) + +*Figure -1* + +![SQL Reports](img/SQL_query_report.png) + +*Figure -2* + +### 3.2 When: (Schedule or Trigger) + +We should expose the APIs to generate reports on-demand (instantly) and to schedule periodically (cron like) or continuously with fixed intervals. Any external or integrated scheduler/trigger will be a consumer of instant report generation API with a mandatory report delivery channel. + + +### 3.3 Where: (Notification) + +Storing the reports **TODO: why we don’t want to store reports, kibana detached mode, ; kibana locally on each node** + +1. For instant on-demand reports, if requested through browser or any HTTP client the reports +2. For reports triggered by non-browser clients (ODFE Report scheduler plugin , ODFE plugin), it will be mandatory to provide delivery channels such as email, Chime or Slack endpoints. + + +![Delivery channels](img/delivery.png) + +*Figure - 3* + +### 3.4 How: + +**(I)** We want to reduce time to market and avoid reinventing the wheel. To create PDF/PNG based reports for dashboard we will be relying on open source headless browser libraries. + +List of curated headless browsers https://github.com/dhamaniasad/HeadlessBrowsers + +|Binding |Library |Comments/Info | +|--- |--- |--- | +|NodeJS |[Puppeteer](https://developers.google.com/web/tools/puppeteer) |[Github](https://github.com/puppeteer/puppeteer), [NPM](https://www.npmjs.com/package/puppeteer) | +| |[Horseman](https://www.npmjs.com/package/node-horseman) | | +| | | | +|Java |[Selenium](https://www.selenium.dev/) |No support for PDF generation | +| |[jBrowserDriver](https://github.com/MachinePublishers/jBrowserDriver) |No support for PDF generation | + +**(II)** To generate CSV reports based on SQL queries, we will be leveraging OpenDistro SQL plugin with **`format=csv`** + +``` +POST _opendistro/_sql?format=csv +{ + "query" : "SELECT ... FROM ... WHERE ... ORDER BY ..." +} +``` + + +Based on the above technical requirements, we propose the following architectures. + +### 3.5 Architecture Considerations + +### 3.5.1 Architecture - 1 + +In this architecture , the Kibana backend plugin will handle both the report generation logic as well as scheduling mechanism. + +![Architecture 1](img/arch_1.png) + + +**Pros:** + +* Easy to manage in terms of release and distribution since all the report generation, notification and scheduling are embedded in a single application. + +**Cons:** + +* Kibana is not distributed by nature. In the absence of leader election capabilities where multiple Kibana instances are running with reporting plugin, the same report will be generated per instance of Kibana. +* Effort to create integration scheduling module. + +### 3.5.2 Architecture - 2 + +In this architecture , the Kibana backend plugin will handle only the report generation logic and the scheduling functionality will be delegated to a separate Elasticsearch plugin + +![Architecture 2](img/arch_2.png) + + +**Pros:** + +* No need to reinvent the integrated scheduling mechanism, since we can leverage ODFE Job scheduler plugin. +* Extending job scheduler plugin will allow us to make sure that only one instance of Kibana handles report generation and thus eliminate coordination among Kibana instances. + +**Cons:** + +* This will introduce hard dependency on report scheduler plugin. +* Multiple indices to manage. + +### 3.5.3 Architecture - 3 + +In this architecture , the whole report generation and scheduling functionality will implemented as Elasticsearch plugin. Kibana backend will act as a proxy between Kibana UI and ES plugin. + +![Architecture 3](img/arch_3.png) + +**Pros:** + + +* Since Kibana server plugin will act as proxy, the Kibana APIs will have chances of modification and in the future +* Reduced interprocess communication between Kibana server and Elasticsearch, thus reduced latency and minimal coordination errors. + +**Cons:** + +* Lack of Java based headless browser that can generate PDF’s. + + + +### **3.5.4 Decision:** + +Because of the limited distributed nature of Kibana sever and added effort to develop a stable scheduling mechanism as part of Kibana server plugin, we need to eliminate option ***3.5.1. ***Though ***3.5.3*** would be an idle choice to go with, lack of core functionality (to generate PDFs) as Java/Kotlin binding prohibits to go with that approach. ***3.5.2 ***allows to reuse existing libraries and plugin extensions, and would be the choice of implementation. + + +## 4. Detail Design + +### 4.1 Data Model + +TODO: write-up + +![Data Model](img/data_model.png) + +TODO: Add index mappings . + +### 4.2 Kibana Server APIs + +All the Kibana Server APIs will be exposed as HTTP(S) RESTFul APIs. + +API calls are stateless. Each request that you make happens in isolation from other calls and must include all of the necessary information for Kibana to fulfill the request. APIs may optionally take JSON formatted request body. +API requests return JSON output, which is a format that is machine-readable and works well for automation. + +List of existing [Kibana REST APIs](https://www.elastic.co/guide/en/kibana/master/using-api.html) + +**(A) generateReport** + +To create one-time reports + +``` +# used to create one-time instant report from browser which will be downloaded +#in the browser (user might be prompted for download location) +generateReport(report_config) + + +``` + +To create one time reports will external delivery channel + +``` +# used to create one-time instant report delivered to a destination +# useful to non-browser usecases, for example ad hoc command line report creation +# via curl or scripts +generateReport(report_config, destination) +``` + +Used by external triggers such as Reporting Scheduler Plugin and Alerting plugin, with delivery predefined as part of report definition + +``` +# this will be used by job scheduler +generateReport(report_id) + +``` + +**(B) createReport** + +Create a schedule report with destination + +``` +# to create schedule reports - report configuration , schedule and destination +# are all mandatory +createReport(report_config, schedule, destination) + +``` + + +**(C) listReports** + +``` +# list report details for a specific report +listReports(report_id) + +``` + +``` +# list all reports +listReports() + +``` + + +**(D) updateReport** + +Update different attributes of the report like report configuration and/or schedule and/or destination + +``` +# updates report config , for example changes in custom header , footer, layout, +# format (pdf -> png) etc +updateReport(report_config) + +``` + +``` +# updates schedule frequency or disable temporarily +updateReport(schedule) + +``` + +``` +# update deleivery methods for example from chimr to email +updateReport(destination) + +``` + +``` +# update report configuartion and/or schedule and/or destination or +# a combination thereof +updateReport(report_config x schedule x destination) + +``` + + +**(E) deleteReport** + +``` +# delete report definition by report_id, this will delete report definition +# and associated schedule, but will leave report config and destination intact +deleteReport(report_id) + +``` + + +**(F) createDestination** + +``` +# create a new destination +createDestination() +``` + + +**(G) listDestination** + +``` +# useful API for use in Kibana UI to help resuse destinations (via dropdown) +listDestination() +``` + + +**(H) updateDestination** + +``` +# modify an existing destination +updateDestination(destination_id, updated paramter values) +``` + + +**(I) deleteDestination** + +``` +# delete an existing destination by destination_id +deleteDestination(destination_id) +``` + + +**(F) listReportEvents** + +List all the instances of report generation/failure for audit/testing/security inspection + +``` +listReportEvents() + +# filtered API +listReportEvents() +``` + +### 4.3 Job Scheduler APIs + +https://github.com/opendistro-for-elasticsearch/job-scheduler + +**(A) createSchedule** + +**(B) updateSchedule** + +**(C) deleteSchedule** + +### 4.4 Workflows + +Scheduled Report Creation workflow + +![Scheduled Report Creation workflow ](img/workflows.png) + +### 4.4 Alerting Integration + +https://opendistro.github.io/for-elasticsearch-docs/docs/alerting/ + +ODFE Alerting can be used as an external trigger. To generate the report the `generateReport()` API can be utilized as `custom_webhook` destination. + +``` +POST _opendistro/_alerting/destinations + +{ + "type": "custom_webhook", + "name": "my-custom-destination", + "custom_webhook": { + "path": "/api/kibana/generateReport/", <----- + "header_params": { + "Content-Type": "application/json" + }, + "scheme": "HTTPS", + "port": , + "query_params": { + "token": "R2x1UlN4ZHF8MXxxVFJpelJNVDgzdGNwXXXXXXXXX" + }, + "host": + } +} + +``` + + + +### 4.5 Security Considerations + +TODO + + + +* * * + +## Appendix + +### (I) Resources for API Design principles/best practices + +* https://www.toptal.com/api-developers/5-golden-rules-for-designing-a-great-web-api +* https://docs.microsoft.com/en-us/azure/architecture/best-practices/api-design +* [Designing RESTFul APIs - Lynda.com](https://www.lynda.com/Web-Development-tutorials/Designing-RESTful-APIs/642497-2.html?srchtrk=index%3a38%0alinktypeid%3a2%0aq%3arestful%0apage%3a1%0as%3arelevance%0asa%3atrue%0aproducttypeid%3a2) (Access for free with free KCLS membership https://kcls.org/library-cards/) +* OpenAPI - https://swagger.io/ + +### (II) Security reference + +* https://opendistro.github.io/for-elasticsearch-docs/docs/security-configuration/concepts/ +* https://opendistro.github.io/for-elasticsearch-docs/docs/security-access-control/ +* https://opendistro.github.io/for-elasticsearch-docs/docs/security-access-control/api/ + diff --git a/docs/dev/img/SQL_query_report.png b/docs/dev/img/SQL_query_report.png new file mode 100644 index 00000000..36c631b3 Binary files /dev/null and b/docs/dev/img/SQL_query_report.png differ diff --git a/docs/dev/img/arch_1.png b/docs/dev/img/arch_1.png new file mode 100644 index 00000000..6c2f35d4 Binary files /dev/null and b/docs/dev/img/arch_1.png differ diff --git a/docs/dev/img/arch_2.png b/docs/dev/img/arch_2.png new file mode 100644 index 00000000..c406ee1f Binary files /dev/null and b/docs/dev/img/arch_2.png differ diff --git a/docs/dev/img/arch_3.png b/docs/dev/img/arch_3.png new file mode 100644 index 00000000..67b14161 Binary files /dev/null and b/docs/dev/img/arch_3.png differ diff --git a/docs/dev/img/dashboard_reports.png b/docs/dev/img/dashboard_reports.png new file mode 100644 index 00000000..5a13cde4 Binary files /dev/null and b/docs/dev/img/dashboard_reports.png differ diff --git a/docs/dev/img/data_model.png b/docs/dev/img/data_model.png new file mode 100644 index 00000000..4dad7cde Binary files /dev/null and b/docs/dev/img/data_model.png differ diff --git a/docs/dev/img/delivery.png b/docs/dev/img/delivery.png new file mode 100644 index 00000000..7509798b Binary files /dev/null and b/docs/dev/img/delivery.png differ diff --git a/docs/dev/img/matrix.png b/docs/dev/img/matrix.png new file mode 100644 index 00000000..b8953dea Binary files /dev/null and b/docs/dev/img/matrix.png differ diff --git a/docs/dev/img/workflows.png b/docs/dev/img/workflows.png new file mode 100644 index 00000000..ee109c65 Binary files /dev/null and b/docs/dev/img/workflows.png differ diff --git a/docs/dev/resources/SQL_query_report.drawio b/docs/dev/resources/SQL_query_report.drawio new file mode 100644 index 00000000..78d3caf2 --- /dev/null +++ b/docs/dev/resources/SQL_query_report.drawio @@ -0,0 +1 @@ +1VhJk9soFP41OmZKK20fvSWZqsxUp1yTZW4IkEw1FhqE23Z+/YAE2u2oE02S6T5YfG/hbTw95ASb4+WNgPnhD44Jc3wXX5xg6/i+7wKgfjRyrRDPi8IKSQXFBmuAPf1CDOga9EQxKTqMknMmad4FEc8ygmQHg0Lwc5ct4ay7aw5TMgD2CLIh+pFiebBuuG5DeEtoejBbLyJDOELLbIDiADE/t6Bg5wQbwbmsno6XDWE6ejYuldzrG9TaMEEyOUXgcbHb4cz78CTfgViCt38//fX6VVBpeYbsZBze7D84PoDH3AnWWVzoH2O/vNqgCH7KMNF6PUU+H6gk+xwiTT2rOlDYQR6ZISeUsQ1nXJSyQZIkPkIKL6TgT6RFwSAGEagpNtxBbUHbV+P+MxGSXFqQ8f0N4UcixVWxGGq4NHkwlegvzPrcSqvN1aGVUWAwaCoprVU3wVYPJt4viD0YxH4QaJLhlS5itUIMFgVF3diqcIjrJ7Vw7eKzXvwW2eX20iZur3Z1ofKT1aGeW1Jq1QjpRVvmkQiqnCfCYDfzIqFIifx64RHcOX7D7LWyE40kx2KCMCjpc/fQjmXM7PDIqbK4Lg6/VxwBiLoqCn4SiBip9iHrKYrcG1VmFVWBGSgqC6h2+9tryvNGigowFa21hLEqK9+NucCkOnLgn5PuPmuveeyEvKZrr6IOE1LG5BBjmqUd1rDD1ZSyBY3ylSJarVUh1WkdIVUmv0KcMZgXpOKpV60NQWp+K49jrt47fVCM2hVD9JSWfU1vo1uS3kN1JfiAlqFfm9IlJuVfz07jQn7RG3Gm8lXyLhdx4nt3rD3oMmE0zTqGMZLIoVAGj8QKqkLRst+hrZBQzqhOe3xHlwbF1LR8V0SxRVZxrA5ga398m/fjavj+myToh3cZX+T2rWokMPFxMFPB1SZuDiSb6OTmW6PjgfmiM4/XW/jcrdQ71v/+bqqb/nxu/tgieCSqlU9z8s/PU49E9PJoaHCscWu8eoVZvDcsqUFQ463xaDBiIlf/O2NDqe7jwZqrgTJh5cClWRTSzLp3B57pg6gX9mYNf2QQHZt1lv/VIOoNJ9HdBemb3IxzP4ZkkYzO/QAtSJw4/bk/nCfc/bk/WEY/ee73Hv5fg//NJFRD8YRp9Ku3AVuBv8h1IOhN8cHDTNeB0P/B14HFoNT279WrzH1/ImU8y9u+CldxYnJCQ7UTIFKloF85a30OKYJsZQhHirEWXyuV9EvZrqsiyrWLpdPR2om2WtdJ8qL63jPSLgBePIBwrF0EqygMSgmeybEePkuPjsbz1m4a4UgB9vM7oWmoZfMRqEp88y0t2P0L \ No newline at end of file diff --git a/docs/dev/resources/arch_1.drawio b/docs/dev/resources/arch_1.drawio new file mode 100644 index 00000000..3a864a07 --- /dev/null +++ b/docs/dev/resources/arch_1.drawio @@ -0,0 +1 @@ +7Zhdb5swFIZ/TaTtohXgQJLLNO22ap0WtcvWXRpwwKrBzJiG9NfvEAwBTNSsC92krTfF5/gDv8/rDzJCiyh/L3ASfuI+YSPL8PMRuhxZlmU4DvwrItsyYpr2uIwEgvoqtg/c0SeigoaKZtQnaaui5JxJmrSDHo9j4slWDAvBN+1qa87aoyY4IFrgzsNMj36jvgyraRjGPvGB0CBUQ09tlYhwVVkF0hD7fNMIoasRWgjOZfkU5QvCCvUqXcp27w5k6xcTJJbHNCCG7U+Wyf02d1f56ot8vH36eobKXh4xy9SEP167OMYQW7IsoDE8vLnlmSTirZqG3FbaCJ7FPim6N0foYhNSSe4S7BXZDdgBYqGMmEqvKWMLzrjYtUXr9dryPIinUvAH0sj4juvYTp2pVEcQUS9LhCT5QRXMWltwJeERkWILVVQD21E4lCEtZJflTYNuhSxsgDWRCmLlqKDuey86PCjdf4GBozHQlAbvJMWjt2UUJBfPy+2WbG7cOoC9h2BH7HMmoRdygMvUI/1c3Kk9BnMPxGUy63CxjuUyHorLROMy9ySocQhOFrGyAroopKCwidxgl7AlT6mkPIYqLpeSR1CBFYmLGkl7YcBfo485o0HRVvIOYl5yXNQ7n6HjJKZvk0kfzpkzQdg5DTxz2oHn6PBQDztnKHSmddS+RhIOGscBFFbXp93fjhB+kHWE0F+3v5l9G5zDZLEpwUMgdzMvA2sO02xCcH5kvEqcpbvrwRwqmCjJ98mql5rx6rrqEN647LM9DoQbY3e4g/qyDbcNMebF7tkirkJYrVUPaBHRs4gj6vvFML1u2vvNOJEZbLuzLg3NDJMeL1iDWUHfU4eyAlVWuCMCNPxvh+LuM+lu07od6ovt6/hh9vzdh8T+vLjIFzoynKa0vJ1gIfVwgxFoIrb3Srxd4XtROLer4mXeTF5uWzoTX/ss6KgM3yFYBEQ+ewrpOBpy2z1qVzFBGJb0sf0efQjUCEtOdyum+vgy27SR0aGY8kx4RLVqfjh0OkId24y7diiF0DraOaKe9stNUk19AJMcC/tPMRzbnRU7m53bL6PY/fDR7DA0Rf1K9q9QdLrX45dT7H4mvTpF/QeD3z/Ax30H+BWQhrMyJVh44f/jGzJTo3Obm+nH9+w0pzcU9z9Mld7Z/76Hrn4C \ No newline at end of file diff --git a/docs/dev/resources/arch_2.drawio b/docs/dev/resources/arch_2.drawio new file mode 100644 index 00000000..e02a4895 --- /dev/null +++ b/docs/dev/resources/arch_2.drawio @@ -0,0 +1 @@ +7Vnbcts2EP0azbQP9pCEBVKPtuK0nrpTTVy36SNEQiQaiGBB0BLz9QEIgHdZSiw66SR+MXGwWBB7FnuhZmC53f/CUZb8ziJMZ54T7WfgzczzPAdC+U8hpUZc15lrJOYkMlgDPJCP2ICOQQsS4bwjKBijgmRdMGRpikPRwRDnbNcV2zDa3TVDMR4ADyGiQ/RvEomkPobTTPyKSZyYrYO5mdgiK2yAPEER27UgcDsDS86Y0E/b/RJTZT1rF73u7YHZ+sU4TsUpC7Azj/xV9r7crx/3j3+Kp3cf/7rwFlrNE6KFObF5W1FaE+BIWsQMGRcJi1mK6G2D3nBWpBFW+zhy1MjcM5ZJ0JXgv1iI0tCLCsEklIgtNbN6T7XRwcMZKGcFD/EzJwLGSRCPsXhGzvVqDqT3YrbFgpdyIccUCfLUfRFkvCiu5RpDywdj68+wOxiY/be7NUqRxFa0iEkqH356xwqB+c8DQhpzK9vtEiLwQ4Yqq+zkNeyadkMoXTLKeLUWbDYbLwwlngvOPuDWTATXcA7rGevtoKbnCXOB988TNLSnWXBl74UJBB4wcWDXuVUaS1oXygXORBzA464v72ymHsOSEmlyftzca83N/boGUPghrhj7oxBSCz7ASxDicV7WwVwZbyJeAr/Hi3cqL1dT8eIPeLkOhbTGIXKKLdUC4EaZgsjgfY/WmK5YTgRhqRRZMyHYVgpQNXFTU9K9GPKvpeOaklitFaxHMdM8LuuM4wzpxG40x/4YnQvoAwTPQ54b9MiDQ/LACHdwKuq8IXf/83TieifmE/A104l9yyP5BGfSmCSN5eDx7rx55QSHnyR+ef0rMJZXvFfNK+5YYoFUqGQgH2JRnVwDGyaP2SYB/lcwO3GRVw5+LQVckO2bSaul5vjxziqUb6x1dveRcGvvHu/S+qJLbpfElKms1WHcQMjEyFCyhflI8NySKKru9Jg3de/5GZwB2ObCOoMtOlrO4I/4gjeZK4zFw2lcgRhXeMBc2vCHO1Q153F3qBu51/GHU9qtNLpWjauyI0V5TnRViLgYwl+Q84bWalljPmIMi52cycwOK0Yqh7aB2u0GauD0jKxTsVnV7mP7ioIjinSqHiiqCKuP/YIax/1uObxyzsRhvxt8dQ6H9dK5OMR7It6r50sHQDP+R8W0y8AJzPjN3gS5alDaQSoPpZZeOJeO51vELPYWFmhWV6OypWuFOZG2UbG3keiDp3rZGT+2wK/ptbAfeWyX9Lle63sDRZc9VVP77fC70cvriauxeuJW+rZM3TlGPEx+VBNyJuh3GothNbF4zWLCG/YZPdYc3fGpqjBMcFRQVRjWDeEZu78I4WAz+vUKhgFeb6bq/iDsd38jFd7YF5BgKlLA91sdzCHokuEHXxZn1WfoZxVNHGXBhNWBzfF1dtbpHSzAsfT+slT+badof9G7x/37earrBP2Wr6/ogOtI0lDZEsuUQH74hQN3fJ/GE7XGE/1SDpsfArV483squP0E \ No newline at end of file diff --git a/docs/dev/resources/arch_3.drawio b/docs/dev/resources/arch_3.drawio new file mode 100644 index 00000000..47ff1c53 --- /dev/null +++ b/docs/dev/resources/arch_3.drawio @@ -0,0 +1 @@ +7Vlbc5s4FP41ntl96A4gg+3HxHXbTLOzmbpp91XAMagRiAoR2/31ewBxJ4k3sd3ppHlw4NORjnS+c5M9Icto917SJPxb+MAnluHvJuTtxLIsw3HwX47sS8Q0DbtEAsl8jTXAmv0ADRoazZgPaUdQCcEVS7qgJ+IYPNXBqJRi2xXbCN7VmtAABsDao3yIfmW+CutjGM3AB2BBqFXPbT0Q0UpYA2lIfbFtQWQ1IUsphCqfot0SeG69yi7lvHcPjNYbkxCrQyaAYfuzm+Tf/c693d1+Vveffnx5Yy3KZe4pz/SJ9W7VvjIB+GgR/SqkCkUgYspXDXopRRb7kOsx8K2RuRYiQdBE8Bsotdf00kwJhEIVcT1a6swVPXg4DaUikx48ciKinYTKANQjcqZVc4DeCyICJfc4UQKnit13N0K1FwW1XGNofNC2/h92JwOzf7xyaUwRu+FZwGJ8+OOrkHdpqR1tIcUO9S6LLfpM5s6OQ4UqCd8zSFVaBAd+rNb5BL1OPiOlEVQLfWRa0Vu4/4yhlP45YLzhMydnGzIF64QWZt9inHe52zDOl4ILWcwlm83G8jzEUyXFHbRGfMd1bKceqcKJIOLTNKz1adOAVLB73B2G7OkJ0yoKddqxiM4621YMT7VM2ApfkxgnYtx5OtAwQyT5o7fnDO0vn7a9WxJ17dYA9e6Cgr5/MoWrwAMkzT0YJ8md27nxxkg6Ai/zWY8Xa4QXc4yX6al4mQ14ufAUWuMhcrKIlwLkMjcFw1JxTV3gNyJliokYRVyhlIhQgOcDlzUl3SjBv9YaF5wF+VwlehSLksdlXd+MIZ1g+jbMxuhcODNCneOQZ8575DlD8sgId86pqLOG3P3ixcu0Dqxe5GcWr2qXj1evT5CgMVkc4Mvt1XGLzAEOf5L8ZfVDYKyuWGetK+ZYYXG4yosBPgSqOHkJbESsOiQ43zNRDbxJCwe/QAGTJLtmsFql5vj2qloQd1yu2dWDcEt3j3e0vuqS2yUxFnnV6jCuIapzpIdsgRxJnhHz/SKmx7ypG+dHcAZSXWUqZ6iajpYzzEZ8wTqZK4zlw9O4QtVDrkGiDX+7Q95z9nub6UhuMM7qD4dc7mL/Ir8m53bkNE1Z2RVSqYbwM2re0Fota9gjxqiwgyuZ1nAjWOHQVaI2u2QQo2fkshTrWe1bc3+h+RMLlaV6sFBBWH3sF/Q45qvlcGocicP+bfDsHA5v+y/Py9OxvLxCnjEFpkClF/7Oyjgy73dsi2GRXpwzKVtn69d6zmC0G/KqTX++h7ykffcpzDejXz843hzczanad8fpt+9DZzDHrrCna9/J683v9qIfmou/7Odl+D6x587w5PV2WrPjsTj4dnC41LN5xNfmp5ZSvPnFiqz+Aw== \ No newline at end of file diff --git a/docs/dev/resources/dashboard_reports.drawio b/docs/dev/resources/dashboard_reports.drawio new file mode 100644 index 00000000..a6f34399 --- /dev/null +++ b/docs/dev/resources/dashboard_reports.drawio @@ -0,0 +1 @@ +7VhNc5swEP01PsYDCAg+xnY+DvlwJ5k2PXUEkkGtQETINu6vrwTCgHDGScaJL50cwr6VdqW3D7TyCMzS8prDPLljCNORY6FyBOYjx3Es35f/FLKtEdu2vBqJOUEaa4FH8hdr0NLoiiBc9AYKxqggeR+MWJbhSPQwyDnb9IctGe1nzWGMB8BjBOkQ/UGQSHbbsFrHDSZxolMHnnaksBmsgSKBiG06ELgcgRlnTNRPaTnDVLHX8FLPu3rFu1sYx5l4y4Ttb39y9rD49f1lcj/5dp9/f9o8nDl1lDWkK71hvVixbRjIGckE5pdrmUeRaY/AdLcXSxoIFglG2khESptBgrM/eMYo4xLJWCYDTikMMV2wggjCMglHWAWXjjXmgkjeb40BIROCpZ0BF5TEyiFYLlGorV2cJaG0yTlygGepv3rJudpRWsZKquO0iCAes7QYq/WHDHKkuZB5cPkqyfaudFL0mKVY8K0c0kzwdbW13kFT/U1HPEBjSUc3E41Brdd4F7otqXzQVX1HhcGgwov51aDInK0yVBVRVW6TEIEfcxgp70bS1S+sQTHycIDcQcGlJ3BCIL8Ajad5gYBEjsC1O+lz7bh7uHb2cO1/FtfukOv766NyvVwunSjaxzXyQ9/7Mq4B8E7MtTfg+ubp7va4ZAcR3k92GHhu/VXpke1+DtnuyYV9fviYwBm6UOet+hZTWBQk6nMr9863z/qUqIyfyhh7jTkvu875Vlt1IowGx7TBpuwLII+xOPQpHLLeYdXbQ2qDcUyhIOv+MvYxrTMs1LnZFtUx3yCzWAVb8QjrWd1z3AgEXCOQbQSqeRgEqgq/2/bHtRCcTgu4JOK5iSGfO7Ok1U5SRnfOAnMit636g3dqqi7K4QbqoPbcU2oPWIZkzj+oPc8I5ARfq73Jf+19QHveSbVnG9ozJfNm7RmBBi3zJ2uvSd8Tn08lW9NQPsSiKm4NLFm18laW/suKNY6zorrlXsgBtpeXrbOJMm8vJHU4ud46Yj+LhDuZjfdAth+ir/zBVcm8UaUEITV9yrFcIgyrUEqz1RWwYtmbjry5irUSrN5GFfoITY8dGE2PPewwJ3tk6ry/55Fme+2u5dH+egEu/wE= \ No newline at end of file diff --git a/docs/dev/resources/data_model.drawio b/docs/dev/resources/data_model.drawio new file mode 100644 index 00000000..89f32321 --- /dev/null +++ b/docs/dev/resources/data_model.drawio @@ -0,0 +1 @@ +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 \ No newline at end of file diff --git a/docs/dev/resources/delivery.drawio b/docs/dev/resources/delivery.drawio new file mode 100644 index 00000000..0776fdac --- /dev/null +++ b/docs/dev/resources/delivery.drawio @@ -0,0 +1 @@ +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 \ No newline at end of file diff --git a/docs/dev/resources/workflows.drawio b/docs/dev/resources/workflows.drawio new file mode 100644 index 00000000..a46e2fd9 --- /dev/null +++ b/docs/dev/resources/workflows.drawio @@ -0,0 +1 @@ +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 \ No newline at end of file diff --git a/docs/ux/Kibana-Reporting-UX-documentation.md b/docs/ux/Kibana-Reporting-UX-documentation.md new file mode 100644 index 00000000..f14c62d9 --- /dev/null +++ b/docs/ux/Kibana-Reporting-UX-documentation.md @@ -0,0 +1,118 @@ +# Kibana Reporting +## Overview +Kibana Reports for Open Distro allows `report owners` (including but not limited to Developers, DevOps, IT Engineers, and IT admins) to export and share reports from Kibana dashboards, saved queries, alerts and visualizations. It helps automate the process of scheduling reports via on-demand or periodic basis (including cron schedules). It also automates exporting and sharing reports from triggers, such as alerts. The feature is present in the Dashboard, Discover, and Visualization tabs. Scheduled reports can be sent to (shared with) self or various stakeholders within the organization such as, including but not limited to, executives, managers, engineers (developers, DevOps, IT Engineer) in the form of pdf, hyperlinks, csv, excel via various channels such as email or the Kibana reporting plugin. + +## Key user flows +### From source +These cover downloading a PDF or PNG report from a Dashboard or Visualization, downloading a CSV or Excel report from Discover, as well as creating a new Report Definition from the Dashboard, Visualization, or Discover tabs. + +### From report definitions list +This flow covers creating a new report definition from the `Report definitions` list. + +--- + +### Share a report +This flow covers sharing a report from the `report details` page. + +![Key user flows](img/flows/0.0.1_key-user-flows.png) + +--- + +## Key screens +These cover the key connections between Reports, Report details, Report definitions, Report definition details, the Dashboard, Visualization and Discover tabs, as well as Emails. + +![Key screens](img/flows/0.0.2_key-screens.png) + +--- + +## Mockups +### Dashboard +This is representative of the `Dashboard`, `Visualization` and `Discover` tabs. There is a new `Download` context menu that has been added to this view. + +![Dashboard](img/screens/0.1.0_dashboard.png) + +--- + +From the share menu, you can create a new report definition. + +![Dashboard - Share](img/screens/0.1.02_dashboard-share.png) + +--- + +The download menu allows users to generate a report (PDF, PNG, CSV, XLS, depending on the source type) + +![Dashboard - Download](img/screens/0.1.01_dashboard-download.png) + +--- + +Triggering a download will start the generation / download process. + +![Supporting information - Download modals](img/supporting/0.1.04_modals_generating-downloading.png) + +--- + +After successfully creating or downloading a report, you are returned to the context where you were working from, and a toast alert notifies you that your report, or report definition is ready. From the alert you can navigate to the report details, report definition, or the Reports landing page. In the case of a report download failure, this is where the failure notification is also delivered. + +![Dashboard - Toasts](img/screens/0.1.03_dashboard-toasts.png) + +### Reporting plugin landing page + +The reporting landing page displays a list of available reports, as well as a list of configured report definitions. From here you can create a new report, link directly to the report source, download the report file (which will trigger the same download flow as above, with the exception that a new report will not be generated), or view the report details. + +![Reporting - Landing page](img/screens/0.2.1_reporting.png) + +--- + +An empty state view is also available when there are no reports or report definitions in the list. + +![Reporting - Empty state](img/screens/0.2.0_reporting_empty-state.png) + +--- + +### Report details + +Here you can view the details of a report that's been generated. From the report details, you can download the report file, share a report, archive a report, and visit the report source or copy it's permalink. + +![Reporting - Report details](img/screens/0.3.0_report.png) + +--- + +### Report details - sharing a report + +Sharing a report allows you to add kibana recepients, optionally add new email recepients, as well as configure the email subject, body and optionally include the report as an attachment to the email. + +![Reporting - Report details - Share](img/screens/0.3.1_report_share.png) + +--- + +### Report definition + +Here you can view the details of a report definition. From the report definition page, you can edit your report definition, and enable or disable it (so it's not triggered by the set schedule or alert). You can also visit or copy the report source URL. + +![Reporting - Report definition](img/screens/0.4.0_report-definition.png) + +--- + +### Create Report definition + +Creating a report definition allows you to define how a report will be triggered or configured. Here you can generate a one-time report to be delivered immediately (Similar to sharing a report from a dashboard), or at a later date, as well as set recurring and cron-based schedules, or select an alert that will trigger the report generation. You can also configure delivery to yourself and other Kibana users, email recepients, and optionally include the report as part of the email attachment. + +![Reporting - Create Report definition](img/screens/0.5.0_create-report-definition.png) + +--- + +#### Supporting view: Report settings + +![Report settings](img/supporting/0.5.1_report-settings.png) + +--- + +#### Supporting view: Report trigger + +![Report trigger](img/supporting/0.5.2_report-trigger.png) + +--- + +#### Supporting view: Delivery settings + +![Delivery settings](img/supporting/0.5.3_delivery-settings.png) \ No newline at end of file diff --git a/docs/ux/img/flows/0.0.1_key-user-flows.png b/docs/ux/img/flows/0.0.1_key-user-flows.png new file mode 100644 index 00000000..6bd16d22 Binary files /dev/null and b/docs/ux/img/flows/0.0.1_key-user-flows.png differ diff --git a/docs/ux/img/flows/0.0.1_key-user-flows@2x.png b/docs/ux/img/flows/0.0.1_key-user-flows@2x.png new file mode 100644 index 00000000..ce541814 Binary files /dev/null and b/docs/ux/img/flows/0.0.1_key-user-flows@2x.png differ diff --git a/docs/ux/img/flows/0.0.2_key-screens.png b/docs/ux/img/flows/0.0.2_key-screens.png new file mode 100644 index 00000000..9c3c0468 Binary files /dev/null and b/docs/ux/img/flows/0.0.2_key-screens.png differ diff --git a/docs/ux/img/flows/0.0.2_key-screens@2x.png b/docs/ux/img/flows/0.0.2_key-screens@2x.png new file mode 100644 index 00000000..372409df Binary files /dev/null and b/docs/ux/img/flows/0.0.2_key-screens@2x.png differ diff --git a/docs/ux/img/screens/0.1.01_dashboard-download.png b/docs/ux/img/screens/0.1.01_dashboard-download.png new file mode 100644 index 00000000..f38ad105 Binary files /dev/null and b/docs/ux/img/screens/0.1.01_dashboard-download.png differ diff --git a/docs/ux/img/screens/0.1.01_dashboard-download@2x.png b/docs/ux/img/screens/0.1.01_dashboard-download@2x.png new file mode 100644 index 00000000..4078eb8e Binary files /dev/null and b/docs/ux/img/screens/0.1.01_dashboard-download@2x.png differ diff --git a/docs/ux/img/screens/0.1.02_dashboard-share.png b/docs/ux/img/screens/0.1.02_dashboard-share.png new file mode 100644 index 00000000..a41f4c47 Binary files /dev/null and b/docs/ux/img/screens/0.1.02_dashboard-share.png differ diff --git a/docs/ux/img/screens/0.1.02_dashboard-share@2x.png b/docs/ux/img/screens/0.1.02_dashboard-share@2x.png new file mode 100644 index 00000000..de9578a4 Binary files /dev/null and b/docs/ux/img/screens/0.1.02_dashboard-share@2x.png differ diff --git a/docs/ux/img/screens/0.1.03_dashboard-toasts.png b/docs/ux/img/screens/0.1.03_dashboard-toasts.png new file mode 100644 index 00000000..40a9aae5 Binary files /dev/null and b/docs/ux/img/screens/0.1.03_dashboard-toasts.png differ diff --git a/docs/ux/img/screens/0.1.03_dashboard-toasts@2x.png b/docs/ux/img/screens/0.1.03_dashboard-toasts@2x.png new file mode 100644 index 00000000..63ff5a42 Binary files /dev/null and b/docs/ux/img/screens/0.1.03_dashboard-toasts@2x.png differ diff --git a/docs/ux/img/screens/0.1.0_dashboard.png b/docs/ux/img/screens/0.1.0_dashboard.png new file mode 100644 index 00000000..d895dac8 Binary files /dev/null and b/docs/ux/img/screens/0.1.0_dashboard.png differ diff --git a/docs/ux/img/screens/0.1.0_dashboard@2x.png b/docs/ux/img/screens/0.1.0_dashboard@2x.png new file mode 100644 index 00000000..1012bd6a Binary files /dev/null and b/docs/ux/img/screens/0.1.0_dashboard@2x.png differ diff --git a/docs/ux/img/screens/0.2.0_reporting_empty-state.png b/docs/ux/img/screens/0.2.0_reporting_empty-state.png new file mode 100644 index 00000000..3f8a7f79 Binary files /dev/null and b/docs/ux/img/screens/0.2.0_reporting_empty-state.png differ diff --git a/docs/ux/img/screens/0.2.0_reporting_empty-state@2x.png b/docs/ux/img/screens/0.2.0_reporting_empty-state@2x.png new file mode 100644 index 00000000..3d3987fa Binary files /dev/null and b/docs/ux/img/screens/0.2.0_reporting_empty-state@2x.png differ diff --git a/docs/ux/img/screens/0.2.1_reporting.png b/docs/ux/img/screens/0.2.1_reporting.png new file mode 100644 index 00000000..f8b912cc Binary files /dev/null and b/docs/ux/img/screens/0.2.1_reporting.png differ diff --git a/docs/ux/img/screens/0.2.1_reporting@2x.png b/docs/ux/img/screens/0.2.1_reporting@2x.png new file mode 100644 index 00000000..0261e122 Binary files /dev/null and b/docs/ux/img/screens/0.2.1_reporting@2x.png differ diff --git a/docs/ux/img/screens/0.3.0_report.png b/docs/ux/img/screens/0.3.0_report.png new file mode 100644 index 00000000..5a88c557 Binary files /dev/null and b/docs/ux/img/screens/0.3.0_report.png differ diff --git a/docs/ux/img/screens/0.3.0_report@2x.png b/docs/ux/img/screens/0.3.0_report@2x.png new file mode 100644 index 00000000..6cb741cc Binary files /dev/null and b/docs/ux/img/screens/0.3.0_report@2x.png differ diff --git a/docs/ux/img/screens/0.3.1_report_share.png b/docs/ux/img/screens/0.3.1_report_share.png new file mode 100644 index 00000000..228875d2 Binary files /dev/null and b/docs/ux/img/screens/0.3.1_report_share.png differ diff --git a/docs/ux/img/screens/0.3.1_report_share@2x.png b/docs/ux/img/screens/0.3.1_report_share@2x.png new file mode 100644 index 00000000..1ff8d893 Binary files /dev/null and b/docs/ux/img/screens/0.3.1_report_share@2x.png differ diff --git a/docs/ux/img/screens/0.4.0_report-definition.png b/docs/ux/img/screens/0.4.0_report-definition.png new file mode 100644 index 00000000..e4828a1b Binary files /dev/null and b/docs/ux/img/screens/0.4.0_report-definition.png differ diff --git a/docs/ux/img/screens/0.4.0_report-definition@2x.png b/docs/ux/img/screens/0.4.0_report-definition@2x.png new file mode 100644 index 00000000..a2a2ad27 Binary files /dev/null and b/docs/ux/img/screens/0.4.0_report-definition@2x.png differ diff --git a/docs/ux/img/screens/0.5.0_create-report-definition.png b/docs/ux/img/screens/0.5.0_create-report-definition.png new file mode 100644 index 00000000..453f0fcf Binary files /dev/null and b/docs/ux/img/screens/0.5.0_create-report-definition.png differ diff --git a/docs/ux/img/screens/0.5.0_create-report-definition@2x.png b/docs/ux/img/screens/0.5.0_create-report-definition@2x.png new file mode 100644 index 00000000..258e1b30 Binary files /dev/null and b/docs/ux/img/screens/0.5.0_create-report-definition@2x.png differ diff --git a/docs/ux/img/screens/0.6.0_edit-report-definition.png b/docs/ux/img/screens/0.6.0_edit-report-definition.png new file mode 100644 index 00000000..ed0df2c5 Binary files /dev/null and b/docs/ux/img/screens/0.6.0_edit-report-definition.png differ diff --git a/docs/ux/img/screens/0.6.0_edit-report-definition@2x.png b/docs/ux/img/screens/0.6.0_edit-report-definition@2x.png new file mode 100644 index 00000000..e46184c0 Binary files /dev/null and b/docs/ux/img/screens/0.6.0_edit-report-definition@2x.png differ diff --git a/docs/ux/img/supporting/0.1.04_modals_generating-downloading.png b/docs/ux/img/supporting/0.1.04_modals_generating-downloading.png new file mode 100644 index 00000000..1140cfa0 Binary files /dev/null and b/docs/ux/img/supporting/0.1.04_modals_generating-downloading.png differ diff --git a/docs/ux/img/supporting/0.1.04_modals_generating-downloading@2x.png b/docs/ux/img/supporting/0.1.04_modals_generating-downloading@2x.png new file mode 100644 index 00000000..66ddf5fb Binary files /dev/null and b/docs/ux/img/supporting/0.1.04_modals_generating-downloading@2x.png differ diff --git a/docs/ux/img/supporting/0.5.1_report-settings.png b/docs/ux/img/supporting/0.5.1_report-settings.png new file mode 100644 index 00000000..d5d9036a Binary files /dev/null and b/docs/ux/img/supporting/0.5.1_report-settings.png differ diff --git a/docs/ux/img/supporting/0.5.1_report-settings@2x.png b/docs/ux/img/supporting/0.5.1_report-settings@2x.png new file mode 100644 index 00000000..4260e217 Binary files /dev/null and b/docs/ux/img/supporting/0.5.1_report-settings@2x.png differ diff --git a/docs/ux/img/supporting/0.5.2_report-trigger.png b/docs/ux/img/supporting/0.5.2_report-trigger.png new file mode 100644 index 00000000..0e0395b9 Binary files /dev/null and b/docs/ux/img/supporting/0.5.2_report-trigger.png differ diff --git a/docs/ux/img/supporting/0.5.2_report-trigger@2x.png b/docs/ux/img/supporting/0.5.2_report-trigger@2x.png new file mode 100644 index 00000000..b07e8f0a Binary files /dev/null and b/docs/ux/img/supporting/0.5.2_report-trigger@2x.png differ diff --git a/docs/ux/img/supporting/0.5.3_delivery-settings.png b/docs/ux/img/supporting/0.5.3_delivery-settings.png new file mode 100644 index 00000000..c8c8ce93 Binary files /dev/null and b/docs/ux/img/supporting/0.5.3_delivery-settings.png differ diff --git a/docs/ux/img/supporting/0.5.3_delivery-settings@2x.png b/docs/ux/img/supporting/0.5.3_delivery-settings@2x.png new file mode 100644 index 00000000..f7b7875a Binary files /dev/null and b/docs/ux/img/supporting/0.5.3_delivery-settings@2x.png differ diff --git a/kibana.json b/kibana.json new file mode 100644 index 00000000..5bbd74df --- /dev/null +++ b/kibana.json @@ -0,0 +1,9 @@ +{ + "id": "opendistroReportsKibana", + "version": "1.13.0.0", + "kibanaVersion": "7.10.2", + "requiredPlugins": ["navigation", "data", "kibanaUtils"], + "optionalPlugins": ["share"], + "server": true, + "ui": true +} diff --git a/package.json b/package.json new file mode 100644 index 00000000..8173175d --- /dev/null +++ b/package.json @@ -0,0 +1,80 @@ +{ + "name": "opendistro_kibana_reports", + "version": "1.13.0.0", + "description": "Kibana Reporting Plugin", + "license": "Apache-2.0", + "main": "index.ts", + "kibana": { + "version": "7.10.2", + "templateVersion": "1.0.0" + }, + "scripts": { + "kbn": "node ../../scripts/kbn", + "es": "node ../../scripts/es", + "lint": "eslint .", + "start": "yarn plugin_helpers start", + "build": "yarn plugin_helpers build", + "test": "../../node_modules/.bin/jest --config ./test/jest.config.js", + "cypress:run": "cypress run", + "cypress:open": "cypress open", + "plugin_helpers": "node ../../scripts/plugin_helpers", + "postinstall": "node ./scripts/patch-html2canvas.js" + }, + "dependencies": { + "babel-polyfill": "^6.26.0", + "cheerio": "0.22.0", + "cron-validator": "^1.1.1", + "dompurify": "^2.3.8", + "elastic-builder": "^2.7.1", + "enzyme-adapter-react-16": "^1.15.2", + "html2canvas": "1.4.1", + "jest-fetch-mock": "^3.0.3", + "jquery": "^3.5.0", + "jsdom": "13.1.0", + "json-2-csv": "^3.7.6", + "jspdf": "^2.5.1", + "react-addons-test-utils": "^15.6.2", + "react-id-generator": "^3.0.1", + "react-markdown": "^4.3.1", + "react-mde": "^10.2.1", + "react-native-base64": "^0.0.2", + "react-native-i18n": "^2.0.15", + "react-navigation": "^4.3.9", + "react-router-dom": "^5.2.0", + "react-toast-notifications": "^2.4.0", + "set-interval-async": "1.0.33", + "showdown": "^1.9.1", + "svg-pathdata": "5.0.5", + "ws": "^7.2.3" + }, + "devDependencies": { + "@elastic/eslint-import-resolver-kibana": "link:../../packages/kbn-eslint-import-resolver-kibana", + "@types/dompurify": "^2.3.3", + "@types/enzyme-adapter-react-16": "^1.0.6", + "@types/jsdom": "^16.2.3", + "@types/react": "^16.9.36", + "@types/react-addons-test-utils": "^0.14.25", + "@types/react-dom": "^16.9.8", + "@types/react-test-renderer": "^16.9.1", + "@types/set-interval-async": "^1.0.0", + "@types/showdown": "^1.9.3", + "babel-jest": "^26.3.0", + "cypress": "^5.0.0", + "elastic-builder": "^2.7.1", + "eslint-plugin-babel": "^5.3.0", + "eslint-plugin-no-unsanitized": "^3.0.2", + "eslint-plugin-prefer-object-spread": "^1.2.1", + "identity-obj-proxy": "^3.0.0", + "jest-dom": "^4.0.0", + "react-test-renderer": "^16.12.0", + "replace-in-file": "^6.3.5", + "ts-jest": "^26.1.0", + "tsc": "^1.20150623.0" + }, + "resolutions": { + "trim": "^1.0.0", + "doc-path": "2.1.2", + "y18n": "^5.0.5", + "yargs": "16.2.0" + } +} diff --git a/public/app.scss b/public/app.scss new file mode 100644 index 00000000..e69de29b diff --git a/public/application.tsx b/public/application.tsx new file mode 100644 index 00000000..584f95d0 --- /dev/null +++ b/public/application.tsx @@ -0,0 +1,39 @@ +/* + * Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES 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 { AppMountParameters, CoreStart } from '../../../src/core/public'; +import { AppPluginStartDependencies } from './types'; +import { OpendistroKibanaReportsApp } from './components/app'; + +export const renderApp = ( + { notifications, http, chrome }: CoreStart, + { navigation }: AppPluginStartDependencies, + { appBasePath, element }: AppMountParameters +) => { + ReactDOM.render( + , + element + ); + + return () => ReactDOM.unmountComponentAtNode(element); +}; diff --git a/public/components/app.tsx b/public/components/app.tsx new file mode 100644 index 00000000..98a99519 --- /dev/null +++ b/public/components/app.tsx @@ -0,0 +1,144 @@ +/* + * Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES 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 { FormattedMessage, I18nProvider } from '@kbn/i18n/react'; +import { HashRouter as Router, Route, Switch } from 'react-router-dom'; + +import { + EuiPage, + EuiPageBody, + EuiPageContentBody, + EuiPageContentHeader, + EuiPageContentHeaderSection, +} from '@elastic/eui'; +import CSS from 'csstype'; +import { + CoreStart, + CoreSystem, + ChromeBreadcrumb, + IUiSettingsClient, +} from '../../../../src/core/public'; +import { NavigationPublicPluginStart } from '../../../../src/plugins/navigation/public'; + +import { CreateReport } from './report_definitions/create/create_report_definition'; +import { Main } from './main/main'; +import { ReportDetails } from './main/report_details/report_details'; +import { ReportDefinitionDetails } from './main/report_definition_details/report_definition_details'; +import { EditReportDefinition } from './report_definitions/edit/edit_report_definition'; + +export interface CoreInterface { + http: CoreStart['http']; + uiSettings: IUiSettingsClient; + setBreadcrumbs: (newBreadcrumbs: ChromeBreadcrumb[]) => void; +} + +interface OpendistroKibanaReportsAppDeps { + basename: string; + notifications: CoreStart['notifications']; + http: CoreStart['http']; + navigation: NavigationPublicPluginStart; + chrome: CoreStart['chrome']; +} + +const styles: CSS.Properties = { + float: 'left', + width: '100%', + maxWidth: '1600px', +}; + +export const OpendistroKibanaReportsApp = ({ + basename, + notifications, + http, + navigation, + chrome, +}: OpendistroKibanaReportsAppDeps) => { + // Render the application DOM. + return ( + + +
+ + + + + + + + ( + + )} + /> + ( + + )} + /> + ( + + )} + /> + ( + + )} + /> + ( +
+ )} + /> + + + + +
+
+
+ ); +}; diff --git a/public/components/context_menu/context_menu.js b/public/components/context_menu/context_menu.js new file mode 100644 index 00000000..87ebc44a --- /dev/null +++ b/public/components/context_menu/context_menu.js @@ -0,0 +1,405 @@ +/* + * Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT 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-restricted-globals */ +import $ from 'jquery'; +import dateMath from '@elastic/datemath'; +import { readStreamToFile } from '../main/main_utils'; +import { + GENERATE_REPORT_PARAM, + GENERATE_REPORT_PARAM_REGEX, +} from '../visual_report/constants'; +import { generateReport } from '../visual_report/generate_report'; +import { + addSuccessOrFailureToast, + contextMenuCreateReportDefinition, + contextMenuViewReports, + replaceQueryURL, + displayLoadingModal, + getTimeFieldsFromUrl +} from './context_menu_helpers'; +import { + popoverMenu, + popoverMenuDiscover, + getMenuItem, +} from './context_menu_ui'; +import { timeRangeMatcher } from '../utils/utils'; +import { parse } from 'url'; +import { unhashUrl } from '../../../../../src/plugins/kibana_utils/public'; + +const generateInContextReport = async ( + timeRanges, + queryUrl, + fileFormat, + rest = {} +) => { + displayLoadingModal(); + const baseUrl = queryUrl.substr(0, queryUrl.indexOf('?')); + // Add selected tenant info to url + try { + const tenant = await getTenantInfoIfExists(); + if (tenant) { + queryUrl = addTenantToURL(queryUrl, tenant); + } + } catch (error) { + addSuccessOrFailureToast('failure'); + console.log(`failed to get user tenant: ${error}`); + } + + let reportSource = ''; + if (baseUrl.includes('dashboard')) { + reportSource = 'Dashboard'; + } else if (baseUrl.includes('visualize')) { + reportSource = 'Visualization'; + } else if (baseUrl.includes('discover')) { + reportSource = 'Saved search'; + } + + // create query body + const contextMenuOnDemandReport = { + query_url: queryUrl, + time_from: timeRanges.time_from.valueOf(), + time_to: timeRanges.time_to.valueOf(), + report_definition: { + report_params: { + report_name: 'On_demand_report', + report_source: reportSource, + description: 'In-context report download', + core_params: { + base_url: baseUrl, + report_format: fileFormat, + time_duration: timeRanges.time_duration, + ...rest, + }, + }, + delivery: { + delivery_type: 'Kibana user', + delivery_params: { + kibana_recipients: [], + }, + }, + trigger: { + trigger_type: 'On demand', + }, + }, + }; + + fetch( + `../api/reporting/generateReport?timezone=${ + Intl.DateTimeFormat().resolvedOptions().timeZone + }`, + { + headers: { + 'Content-Type': 'application/json', + 'kbn-version': '7.10.2', + accept: '*/*', + 'accept-language': 'en-US,en;q=0.9,zh-CN;q=0.8,zh;q=0.7,zh-TW;q=0.6', + pragma: 'no-cache', + 'sec-fetch-dest': 'empty', + 'sec-fetch-mode': 'cors', + 'sec-fetch-site': 'same-origin', + }, + method: 'POST', + body: JSON.stringify(contextMenuOnDemandReport), + referrerPolicy: 'strict-origin-when-cross-origin', + mode: 'cors', + credentials: 'include', + } + ) + .then(async (response) => [response.status, await response.json()]) + .then(async ([status, data]) => { + if (status !== 200) { + if (status === 403) { + addSuccessOrFailureToast('permissionsFailure'); + } else if (status === 503) { + addSuccessOrFailureToast('timeoutFailure', reportSource); + } else { + addSuccessOrFailureToast('failure'); + } + } else if (fileFormat === 'pdf' || fileFormat === 'png') { + try { + await generateReport(data.reportId); + addSuccessOrFailureToast('success'); + } catch (error) { + console.error(error); + addSuccessOrFailureToast('failure'); + } + } else if (data.data) { + await readStreamToFile(data.data, fileFormat, data.filename); + } + $('#reportGenerationProgressModal').remove(); + }); +}; + +// try to match uuid followed by '?' in URL, which would be the saved search id for discover URL +const getUuidFromUrl = () => + window.location.href.match( + /(\b[0-9a-f]{8}\b-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-\b[0-9a-f]{12}\b)\?/ + ); +const isDiscover = () => window.location.href.includes('discover'); + +// open Download drop-down +$(function () { + $(document).on('click', '#downloadReport', function () { + const popoverScreen = document.querySelectorAll('body'); + if (popoverScreen) { + try { + const reportPopover = document.createElement('div'); + // eslint-disable-next-line no-unsanitized/property + reportPopover.innerHTML = isDiscover() + ? popoverMenuDiscover(getUuidFromUrl()) + : popoverMenu(getUuidFromUrl()); + popoverScreen[0].appendChild(reportPopover.children[0]); + $('#reportPopover').show(); + } catch (e) { + console.log('error displaying menu:', e); + } + } + }); + + // generate PDF onclick + $(document).on('click', '#generatePDF', function () { + const timeRanges = getTimeFieldsFromUrl(); + const queryUrl = replaceQueryURL(location.href); + generateInContextReport(timeRanges, queryUrl, 'pdf'); + }); + + // generate PNG onclick + $(document).on('click', '#generatePNG', function () { + const timeRanges = getTimeFieldsFromUrl(); + const queryUrl = replaceQueryURL(location.href); + generateInContextReport(timeRanges, queryUrl, 'png'); + }); + + // generate CSV onclick + $(document).on('click', '#generateCSV', function () { + const timeRanges = getTimeFieldsFromUrl(); + const queryUrl = replaceQueryURL(location.href); + const saved_search_id = getUuidFromUrl()[1]; + generateInContextReport(timeRanges, queryUrl, 'csv', { saved_search_id }); + }); + + // navigate to Create report definition page with report source and pre-set time range + $(document).on('click', '#createReportDefinition', function () { + contextMenuCreateReportDefinition(this.baseURI); + }); + + // redirect to Reporting home page + $(document).on('click', '#viewReports', function () { + contextMenuViewReports(); + }); + + // close popover menu on click outside + $('body').on('click', function (e) { + if ($(e.target).data('toggle') !== '#downloadReport') { + $('#reportPopover').remove(); + } + }); + + // close modal/toast + $(function () { + // close modal with 'x' in upper-right modal + $(document).on('click', '#closeReportGenerationModal', function () { + $('#reportGenerationProgressModal').remove(); + }); + + // close modal with the close EuiButton + $(document).on('click', '#closeReportGenerationModalButton', function () { + $('#reportGenerationProgressModal').remove(); + }); + + // close the toast that appears upon successful report generation + $(document).on('click', '#closeReportSuccessToast', function () { + $('#reportSuccessToast').remove(); + }); + + // close the toast that apepars upon failure of report generation + $(document).on('click', '#closeReportFailureToast', function () { + $('#reportFailureToast').remove(); + }); + + // close permissions failure toast + $(document).on('click', '#permissionsMissingErrorToast', function () { + $('#permissionsMissingErrorToast').remove(); + }); + }); + + checkURLParams(); + locationHashChanged(); +}); + +/* generate a report if flagged in URL params */ +const checkURLParams = async () => { + const [hash, query] = location.href.split('#')[1].split('?'); + const params = new URLSearchParams(query); + const id = params.get(GENERATE_REPORT_PARAM); + if (!id) return; + await new Promise((resolve) => setTimeout(resolve, 1000)); + displayLoadingModal(); + try { + await generateReport(id, 30000); + window.history.replaceState( + {}, + '', + `#${hash}?${query.replace(GENERATE_REPORT_PARAM_REGEX, '')}` + ); + addSuccessOrFailureToast('success'); + } catch (error) { + console.error(error); + addSuccessOrFailureToast('failure'); + } finally { + $('#reportGenerationProgressModal').remove(); + } +}; + +const isDiscoverNavMenu = (navMenu) => { + return ( + navMenu[0].children.length === 5 && + ($('[data-test-subj="breadcrumb first"]').prop('title') === 'Discover' || + $('[data-test-subj="breadcrumb first last"]').prop('title') === + 'Discover') + ); +}; + +const isDashboardNavMenu = (navMenu) => { + return ( + (navMenu[0].children.length === 4 || navMenu[0].children.length === 6) && + $('[data-test-subj="breadcrumb first"]').prop('title') === 'Dashboard' + ); +}; + +const isVisualizationNavMenu = (navMenu) => { + return ( + navMenu[0].children.length === 3 && + $('[data-test-subj="breadcrumb first"]').prop('title') === 'Visualize' + ); +}; + +function locationHashChanged() { + const observer = new MutationObserver(function (mutations) { + const navMenu = document.querySelectorAll( + 'span.kbnTopNavMenu__wrapper > nav.euiHeaderLinks > div.euiHeaderLinks__list' + ); + if ( + navMenu && + navMenu.length && + (isDiscoverNavMenu(navMenu) || + isDashboardNavMenu(navMenu) || + isVisualizationNavMenu(navMenu)) + ) { + try { + if ($('#downloadReport').length) { + return; + } + const menuItem = document.createElement('div'); + menuItem.innerHTML = getMenuItem('Reporting'); + navMenu[0].insertBefore(menuItem.children[0], navMenu[0].lastChild); + } catch (e) { + console.log(e); + } finally { + observer.disconnect(); + } + } + }); + + // Start observing + observer.observe(document.body, { + //document.body is node target to observe + childList: true, //This is a must have for the observer with subtree + subtree: true, //Set to true if changes must also be observed in descendants. + }); +} + +$(window).one('hashchange', function (e) { + locationHashChanged(); +}); +/** + * for navigating to tabs from Kibana sidebar, it uses history.pushState, which doesn't trigger onHashchange. + * https://stackoverflow.com/questions/4570093/how-to-get-notified-about-changes-of-the-history-via-history-pushstate/4585031 + */ +(function (history) { + const pushState = history.pushState; + history.pushState = function (state) { + if (typeof history.onpushstate === 'function') { + history.onpushstate({ state: state }); + } + return pushState.apply(history, arguments); + }; +})(window.history); + +window.onpopstate = history.onpushstate = () => { + locationHashChanged(); +}; + +async function getTenantInfoIfExists() { + const res = await fetch(`../api/v1/multitenancy/tenant`, { + headers: { + 'Content-Type': 'application/json', + 'kbn-version': '7.10.2', + accept: '*/*', + 'accept-language': 'en-US,en;q=0.9,zh-CN;q=0.8,zh;q=0.7,zh-TW;q=0.6', + pragma: 'no-cache', + 'sec-fetch-dest': 'empty', + 'sec-fetch-mode': 'cors', + 'sec-fetch-site': 'same-origin', + }, + method: 'GET', + referrerPolicy: 'strict-origin-when-cross-origin', + mode: 'cors', + credentials: 'include', + }) + .then((response) => { + if (response.status === 404) { + // endpoint doesn't exist, security plugin is not enabled. + return undefined; + } else { + return response.text(); + } + }) + .then((tenant) => { + if (tenant === '') { + tenant = 'global'; + } else if (tenant === '__user__') { + tenant = 'private'; + } + return tenant; + }); + + return res; +} + +// helper function to add tenant info to url(if tenant is available) +function addTenantToURL(url, userRequestedTenant) { + // build fake url from relative url + const fakeUrl = `http://opendistro.com${url}`; + const tenantKey = 'security_tenant'; + const tenantKeyAndValue = + tenantKey + '=' + encodeURIComponent(userRequestedTenant); + + const { pathname, search } = parse(fakeUrl); + const queryDelimiter = !search ? '?' : '&'; + // The url parser returns null if the search is empty. Change that to an empty + // string so that we can use it to build the values later + if (search && search.toLowerCase().indexOf(tenantKey) > -1) { + // If we for some reason already have a tenant in the URL we skip any updates + return url; + } + + // A helper for finding the part in the string that we want to extend/replace + const valueToReplace = pathname + (search || ''); + const replaceWith = valueToReplace + queryDelimiter + tenantKeyAndValue; + + return url.replace(valueToReplace, replaceWith); +} diff --git a/public/components/context_menu/context_menu_helpers.js b/public/components/context_menu/context_menu_helpers.js new file mode 100644 index 00000000..066370a4 --- /dev/null +++ b/public/components/context_menu/context_menu_helpers.js @@ -0,0 +1,149 @@ +/* + * Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +import dateMath from '@elastic/datemath'; +import moment from 'moment'; +import { + reportGenerationInProgressModal, + reportGenerationSuccess, + reportGenerationFailure, + permissionsMissingOnGeneration, +} from './context_menu_ui'; +import { timeRangeMatcher } from '../utils/utils'; +import { unhashUrl } from '../../../../../src/plugins/kibana_utils/public'; + +const getReportSourceURL = (baseURI) => { + const url = baseURI.substr(0, baseURI.indexOf('?')); + const reportSourceId = url.substr(url.lastIndexOf('/') + 1, url.length); + return reportSourceId; +}; + +export const contextMenuViewReports = () => + window.location.assign('opendistro_kibana_reports#/'); + +export const getTimeFieldsFromUrl = () => { + const url = unhashUrl(window.location.href); + + let [, fromDateString, toDateString] = url.match(timeRangeMatcher); + fromDateString = fromDateString.replace(/[']+/g, ''); + // convert time range to from date format in case time range is relative + const fromDateFormat = dateMath.parse(fromDateString); + toDateString = toDateString.replace(/[']+/g, ''); + const toDateFormat = dateMath.parse(toDateString); + + const timeDuration = moment.duration( + dateMath.parse(toDateString).diff(dateMath.parse(fromDateString)) + ); + + return { + time_from: fromDateFormat, + time_to: toDateFormat, + time_duration: timeDuration.toISOString(), + }; +}; + +export const contextMenuCreateReportDefinition = (baseURI) => { + const reportSourceId = getReportSourceURL(baseURI); + let reportSource = ''; + const timeRanges = getTimeFieldsFromUrl(); + + // check report source + if (baseURI.includes('dashboard')) { + reportSource = 'dashboard:'; + } else if (baseURI.includes('visualize')) { + reportSource = 'visualize:'; + } else if (baseURI.includes('discover')) { + reportSource = 'discover:'; + } + reportSource += reportSourceId.toString(); + window.location.assign( + `opendistro_kibana_reports#/create?previous=${reportSource}?timeFrom=${timeRanges.time_from.toISOString()}?timeTo=${timeRanges.time_to.toISOString()}` + ); +}; + +export const displayLoadingModal = () => { + const kibanaBody = document.getElementById('kibana-body'); + if (kibanaBody) { + try { + const loadingModal = document.createElement('div'); + loadingModal.innerHTML = reportGenerationInProgressModal(); + kibanaBody.appendChild(loadingModal.children[0]); + } catch (e) { + console.log('error displaying loading modal:', e); + } + } +}; + +export const addSuccessOrFailureToast = (status, reportSource) => { + const generateToast = document.querySelectorAll('.euiGlobalToastList'); + if (generateToast) { + try { + const generateInProgressToast = document.createElement('div'); + if (status === 'success') { + generateInProgressToast.innerHTML = reportGenerationSuccess(); + setTimeout(function () { + document.getElementById('reportSuccessToast').style.display = 'none'; + }, 6000); // closes toast automatically after 6s + } else if (status === 'failure') { + generateInProgressToast.innerHTML = reportGenerationFailure(); + setTimeout(function () { + document.getElementById('reportFailureToast').style.display = 'none'; + }, 6000); + } else if (status === 'timeoutFailure') { + generateInProgressToast.innerHTML = reportGenerationFailure( + 'Error generating report.', + `Timed out generating on-demand report from ${reportSource}. Try again later.` + ); + setTimeout(function () { + document.getElementById('reportFailureToast').style.display = 'none'; + }, 6000); + } else if (status === 'permissionsFailure') { + generateInProgressToast.innerHTML = permissionsMissingOnGeneration(); + setTimeout(function () { + document.getElementById( + 'permissionsMissingErrorToast' + ).style.display = 'none'; + }, 6000); + } + generateToast[0].appendChild(generateInProgressToast.children[0]); + } catch (e) { + console.log('error displaying toast', e); + } + } +}; + +export const replaceQueryURL = (pageUrl) => { + // we unhash the url in case Kibana advanced UI setting 'state:storeInSessionStorage' is turned on + const unhashedUrl = new URL(unhashUrl(pageUrl)); + let queryUrl = unhashedUrl.pathname + unhashedUrl.hash; + let [, fromDateString, toDateString] = queryUrl.match(timeRangeMatcher); + fromDateString = fromDateString.replace(/[']+/g, ''); + + // convert time range to from date format in case time range is relative + const fromDateFormat = dateMath.parse(fromDateString); + toDateString = toDateString.replace(/[']+/g, ''); + const toDateFormat = dateMath.parse(toDateString); + + // replace to and from dates with absolute date + queryUrl = queryUrl.replace( + fromDateString, + "'" + fromDateFormat.toISOString() + "'" + ); + queryUrl = queryUrl.replace( + toDateString + '))', + "'" + toDateFormat.toISOString() + "'))" + ); + return queryUrl; +}; diff --git a/public/components/context_menu/context_menu_ui.js b/public/components/context_menu/context_menu_ui.js new file mode 100644 index 00000000..7b094703 --- /dev/null +++ b/public/components/context_menu/context_menu_ui.js @@ -0,0 +1,321 @@ +/* + * Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT 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 getMenuItem = (name) => { + return ` + + `; +}; + +export const popoverMenu = (savedObjectAvailable) => { + const buttonClass = savedObjectAvailable + ? 'euiContextMenuItem' + : 'euiContextMenuItem euiContextMenuItem-isDisabled'; + const button = savedObjectAvailable ? 'button' : 'button disabled'; + const popoverHeight = savedObjectAvailable ? '395px' : '380px'; + const message = savedObjectAvailable + ? `Files can take a minute or two to generate depending on the size of your source data.` + : `Save this Visualization/Dashboard to enable PDF/PNG reports.`; + + const arrowRight = '100px'; + const popoverRight = '77px'; + + return ` +
+
+
+
+
+
+ +
+
+ `; +}; + +// TODO: merge this function and popoverMenu() into one +export const popoverMenuDiscover = (savedObjectAvailable) => { + const buttonClass = savedObjectAvailable + ? 'euiContextMenuItem' + : 'euiContextMenuItem euiContextMenuItem-isDisabled'; + const button = savedObjectAvailable ? 'button' : 'button disabled'; + const popoverHeight = savedObjectAvailable ? '354px' : '322px'; + const message = savedObjectAvailable + ? `Files can take a minute or two to generate depending on the size of your source data.` + : `Save this search to enable CSV reports.`; + const arrowRight = '60px'; + const popoverRight = '77px'; + + return ` +
+
+
+
+
+
+ +
+
+ `; +}; + +export const permissionsMissingOnGeneration = () => { + return ` +
+

A new notification appears

+
+ + Error generating report. +
+ +
+

Insufficient permissions. Reach out to your Kibana administrator.

+
+
+ `; +}; + +export const reportGenerationSuccess = () => { + return ` +
+

A new notification appears

+
+ + Successfully generated report. +
+ +
+

View + Reports.

+
+
+ `; +}; + +export const reportGenerationFailure = ( + title = 'Download error', + text = 'There was an error generating this report.' +) => { + return ` +
+

A new notification appears

+
+ + ${title} +
+ +
+

${text}

+
+
+ `; +}; + +export const reportGenerationInProgressModal = () => { + return ` +
+
+
+
+
+ +
+
+
+
+

Generating report

+
+
+
+
+
+
Preparing your file for download.
+
Please keep this dialog open while report is being generated.
+
+
+
+
+
+
+
+
+
+
+
+
+ `; +}; diff --git a/public/components/main/__tests__/__snapshots__/main.test.tsx.snap b/public/components/main/__tests__/__snapshots__/main.test.tsx.snap new file mode 100644 index 00000000..80d38251 --- /dev/null +++ b/public/components/main/__tests__/__snapshots__/main.test.tsx.snap @@ -0,0 +1,3854 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`
panel render component 1`] = ` +
+
+
+
+

+ Reports + +

+ ( + 0 + ) +

+

+
+ + + +
+
+
+
+
+
+
+ +
+ + + +
+
+
+
+
+
+
+
+ +
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+ + + + + + + + + + + + + + + + +
+
+
+ + Name + +
+
+
+ + Source + +
+
+ + +
+ + Creation time + +
+
+ + +
+ + Generate + +
+
+
+ +
+ +

+ No reports to display +

+
+
+
+
+ Create a report definition, or share/download a report from a dashboard, saved search or visualization. +
+ +
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+

+ Report definitions +

+ + ( + 0 + ) +

+

+
+
+ +
+ + + +
+
+
+
+
+
+
+
+ +
+ + + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+ + + + + + + + + + + + + + + + +
+
+
+ + Name + +
+
+
+ + Source + +
+
+ + +
+ + Schedule details + +
+
+
+ + Last Updated + +
+
+ +
+
+ +
+ +

+ No report definitions to display +

+
+
+
+
+ Create a new report definition to get started +
+ +
+
+ +
+
+
+ +
+
+ +
+
+
+
+
+
+
+
+
+`; + +exports[`
panel render component after create success 1`] = ` +
+
+
+
+

+ Reports + +

+ ( + 0 + ) +

+

+
+ + + +
+
+
+
+
+
+
+ +
+ + + +
+
+
+
+
+
+
+
+ +
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+ + + + + + + + + + + + + + + + +
+
+
+ + Name + +
+
+
+ + Source + +
+
+ + +
+ + Creation time + +
+
+ + +
+ + Generate + +
+
+
+ +
+ +

+ No reports to display +

+
+
+
+
+ Create a report definition, or share/download a report from a dashboard, saved search or visualization. +
+ +
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+

+ Report definitions +

+ + ( + 0 + ) +

+

+
+
+ +
+ + + +
+
+
+
+
+
+
+
+ +
+ + + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+ + + + + + + + + + + + + + + + +
+
+
+ + Name + +
+
+
+ + Source + +
+
+ + +
+ + Schedule details + +
+
+
+ + Last Updated + +
+
+ +
+
+ +
+ +

+ No report definitions to display +

+
+
+
+
+ Create a new report definition to get started +
+ +
+
+ +
+
+
+ +
+
+ +
+
+
+
+
+
+
+
+
+

+ A new notification appears +

+
+ + + Successfully created report definition. + +
+ +
+
+
+`; + +exports[`
panel render component after delete success 1`] = ` +
+
+
+
+

+ Reports + +

+ ( + 0 + ) +

+

+
+ + + +
+
+
+
+
+
+
+ +
+ + + +
+
+
+
+
+
+
+
+ +
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+ + + + + + + + + + + + + + + + +
+
+
+ + Name + +
+
+
+ + Source + +
+
+ + +
+ + Creation time + +
+
+ + +
+ + Generate + +
+
+
+ +
+ +

+ No reports to display +

+
+
+
+
+ Create a report definition, or share/download a report from a dashboard, saved search or visualization. +
+ +
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+

+ Report definitions +

+ + ( + 0 + ) +

+

+
+
+ +
+ + + +
+
+
+
+
+
+
+
+ +
+ + + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+ + + + + + + + + + + + + + + + +
+
+
+ + Name + +
+
+
+ + Source + +
+
+ + +
+ + Schedule details + +
+
+
+ + Last Updated + +
+
+ +
+
+ +
+ +

+ No report definitions to display +

+
+
+
+
+ Create a new report definition to get started +
+ +
+
+ +
+
+
+ +
+
+ +
+
+
+
+
+
+
+
+
+

+ A new notification appears +

+
+ + + Successfully deleted report definition. + +
+ +
+
+
+`; + +exports[`
panel render component after edit success 1`] = ` +
+
+
+
+

+ Reports + +

+ ( + 0 + ) +

+

+
+ + + +
+
+
+
+
+
+
+ +
+ + + +
+
+
+
+
+
+
+
+ +
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+ + + + + + + + + + + + + + + + +
+
+
+ + Name + +
+
+
+ + Source + +
+
+ + +
+ + Creation time + +
+
+ + +
+ + Generate + +
+
+
+ +
+ +

+ No reports to display +

+
+
+
+
+ Create a report definition, or share/download a report from a dashboard, saved search or visualization. +
+ +
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+

+ Report definitions +

+ + ( + 0 + ) +

+

+
+
+ +
+ + + +
+
+
+
+
+
+
+
+ +
+ + + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+ + + + + + + + + + + + + + + + +
+
+
+ + Name + +
+
+
+ + Source + +
+
+ + +
+ + Schedule details + +
+
+
+ + Last Updated + +
+
+ +
+
+ +
+ +

+ No report definitions to display +

+
+
+
+
+ Create a new report definition to get started +
+ +
+
+ +
+
+
+ +
+
+ +
+
+
+
+
+
+
+
+
+

+ A new notification appears +

+
+ + + Successfully updated report definition. + +
+ +
+
+
+`; diff --git a/public/components/main/__tests__/__snapshots__/report_definitions_table.test.tsx.snap b/public/components/main/__tests__/__snapshots__/report_definitions_table.test.tsx.snap new file mode 100644 index 00000000..c9e0a889 --- /dev/null +++ b/public/components/main/__tests__/__snapshots__/report_definitions_table.test.tsx.snap @@ -0,0 +1,961 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[` panel render component 1`] = ` +
+
+
+
+
+
+ +
+ + + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + Name + +
+
+
+ + Source + +
+
+ + +
+ + Schedule details + +
+
+
+ + Last Updated + +
+
+ +
+
+ Name +
+
+ +
+
+
+ Source +
+
+ +
+
+
+ Type +
+
+ + Download + +
+
+
+ Schedule details +
+
+ +
+
+
+ Last Updated +
+
+
+ Invalid Date @ Invalid Date +
+
+
+
+ Status +
+
+ + Created + +
+
+
+ Name +
+
+ +
+
+
+ Source +
+
+ +
+
+
+ Type +
+
+ + Download + +
+
+
+ Schedule details +
+
+ +
+
+
+ Last Updated +
+
+
+ Invalid Date @ Invalid Date +
+
+
+
+ Status +
+
+ + Created + +
+
+
+
+
+
+
+
+
+ +
+
+
+
+ +
+
+
+
+
+
+`; + +exports[` panel render empty table 1`] = ` +
+
+
+
+
+
+ +
+ + + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+ + + + + + + + + + + + + + + + +
+
+
+ + Name + +
+
+
+ + Source + +
+
+ + +
+ + Schedule details + +
+
+
+ + Last Updated + +
+
+ +
+
+ +
+ +

+ No report definitions to display +

+
+
+
+
+ Create a new report definition to get started +
+ +
+
+ +
+
+
+ +
+
+ +
+
+
+
+
+
+`; diff --git a/public/components/main/__tests__/__snapshots__/reports_table.test.tsx.snap b/public/components/main/__tests__/__snapshots__/reports_table.test.tsx.snap new file mode 100644 index 00000000..fda8016c --- /dev/null +++ b/public/components/main/__tests__/__snapshots__/reports_table.test.tsx.snap @@ -0,0 +1,1006 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[` panel render component 1`] = ` +
+
+
+
+
+ +
+ + + +
+
+
+
+
+
+
+
+ +
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + +
+
+
+ + Name + +
+
+
+ + Source + +
+
+ + +
+ + Creation time + +
+
+ + +
+ + Generate + +
+
+
+ Name +
+
+ +
+
+
+ Source +
+ +
+
+ Type +
+
+ + Test type + +
+
+
+ Creation time +
+
+
+ Invalid Date @ Invalid Date +
+
+
+
+ State +
+
+ + Created + +
+
+
+ Generate +
+
+ +
+
+
+
+
+
+
+
+
+ +
+
+
+
+ +
+
+
+
+
+`; + +exports[` panel render empty component 1`] = ` +
+
+
+
+
+ +
+ + + +
+
+
+
+
+
+
+
+ +
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+ + + + + + + + + + + + + + + + +
+
+
+ + Name + +
+
+
+ + Source + +
+
+ + +
+ + Creation time + +
+
+ + +
+ + Generate + +
+
+
+ +
+ +

+ No reports to display +

+
+
+
+
+ Create a report definition, or share/download a report from a dashboard, saved search or visualization. +
+ +
+
+ +
+
+
+
+
+
+
+`; diff --git a/public/components/main/__tests__/__utils__/main_utils_test_utils.tsx b/public/components/main/__tests__/__utils__/main_utils_test_utils.tsx new file mode 100644 index 00000000..75a54040 --- /dev/null +++ b/public/components/main/__tests__/__utils__/main_utils_test_utils.tsx @@ -0,0 +1,132 @@ +/* + * Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT 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 reportTableMockResponse = [ + { + _id: '123456', + _index: 'test', + _score: 1, + _source: { + last_updated: 123456789, + query_url: 'test_query_url_value.com', + report_definition: { + delivery: { + delivery_type: 'Kibana user', + delivery_params: { + kibana_recipients: [], + }, + }, + report_params: { + report_name: 'Test report table response', + description: 'description', + report_source: 'Dashboard', + core_params: { + base_url: 'test_base_url.com', + header: '', + footer: '', + report_format: 'pdf', + time_duration: 'PT30M', + window_height: 800, + window_width: 1200, + }, + }, + trigger: { + trigger_type: 'On demand', + }, + state: 'Created', + time_created: 123456780, + time_from: 123456780, + time_to: 123456799, + }, + }, + _type: 'doc', + }, +]; + +export const mockReportsTableItems = [ + { + id: '123456', + reportName: 'Test report table response', + type: 'On demand', + sender: '—', + kibanaRecipients: '—', + emailRecipients: '—', + reportSource: 'Dashboard', + timeCreated: undefined, + state: undefined, + url: 'test_query_url_value.com', + format: 'pdf', + }, +]; + +export const reportDefinitionsTableMockResponse = [ + { + _index: 'report_definition', + _type: '_doc', + _id: '42MmKXUBDW-VXnk7pa6d', + _score: 1, + _source: { + report_definition: { + report_params: { + report_name: 'schedule definition', + report_source: 'Dashboard', + description: 'description', + core_params: { + base_url: 'test_base_url.com', + report_format: 'pdf', + header: '', + footer: '', + time_duration: 'PT30M', + window_width: 1200, + window_height: 800, + }, + }, + delivery: { + delivery_type: 'Kibana user', + delivery_params: { kibana_recipients: [] }, + }, + trigger: { + trigger_type: 'Schedule', + trigger_params: { + enabled_time: 1602713178321, + schedule: { + period: 1, + interval: 'DAYS', + }, + schedule_type: 'Recurring', + enabled: false, + }, + }, + time_created: 1602713199604, + last_updated: 1602713211007, + status: 'Disabled', + }, + }, + }, +]; + +export const reportDefinitionsTableMockContent = [ + { + id: '42MmKXUBDW-VXnk7pa6d', + reportName: 'schedule definition', + type: 'Schedule', + owner: '—', + source: 'Dashboard', + baseUrl: 'test_base_url.com', + lastUpdated: 1602713211007, + details: 'Recurring', + status: 'Disabled', + }, +]; diff --git a/public/components/main/__tests__/main.test.tsx b/public/components/main/__tests__/main.test.tsx new file mode 100644 index 00000000..447773b6 --- /dev/null +++ b/public/components/main/__tests__/main.test.tsx @@ -0,0 +1,224 @@ +/* + * Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES 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 { Main } from '../main'; +import httpClientMock from '../../../../test/httpMockClient'; +import { configure, mount } from 'enzyme'; +import Adapter from 'enzyme-adapter-react-16'; +import { act } from 'react-dom/test-utils'; + +function setBreadcrumbs(array: []) { + jest.fn(); +} + +describe('
panel', () => { + configure({ adapter: new Adapter() }); + test('render component', async (done) => { + window = Object.create(window); + Object.defineProperty(window, 'location', { + configurable: true, + value: { + assign: jest.fn(), + href: 'opendistro_kibana_reports#/', + }, + }); + + const { container } = await render( +
+ ); + + expect(container.firstChild).toMatchSnapshot(); + done(); + }); + + test('render component after create success', async () => { + delete window.location; + + Object.defineProperty(window, 'location', { + configurable: true, + value: { + assign: jest.fn(), + href: 'opendistro_kibana_reports#/create=success', + }, + }); + + const { container } = render( +
+ ); + + expect(container.firstChild).toMatchSnapshot(); + }); + + test('render component after edit success', async () => { + delete window.location; + + Object.defineProperty(window, 'location', { + configurable: true, + value: { + assign: jest.fn(), + href: 'opendistro_kibana_reports#/edit=success', + }, + }); + + const { container } = render( +
+ ); + + expect(container.firstChild).toMatchSnapshot(); + }); + + test('render component after delete success', async () => { + delete window.location; + + Object.defineProperty(window, 'location', { + configurable: true, + value: { + assign: jest.fn(), + href: 'opendistro_kibana_reports#/delete=success', + }, + }); + + const { container } = render( +
+ ); + + expect(container.firstChild).toMatchSnapshot(); + }) + + test('test refresh reports definitions button', async () => { + const promise = Promise.resolve(); + const data = [ + { + _id: 'abcdefg', + _source: { + query_url: '/app/visualize/edit/1234567890', + state: 'Created', + time_created: 123456789, + time_from: 123456789, + time_to: 1234567890, + report_definition: { + report_params: { + report_name: 'test create report definition trigger', + report_source: 'Dashboard', + description: '', + core_params: { + base_url: 'http://localhost:5601', + report_format: 'png', + header: '', + footer: '', + time_duration: 'PT30M', + }, + }, + delivery: { + delivery_type: '', + delivery_params: {}, + }, + trigger: { + trigger_type: 'Schedule', + trigger_params: {}, + }, + }, + }, + }, + ]; + + httpClientMock.get = jest.fn().mockResolvedValue({ + data, + }); + + const component = mount( +
+ ); + await act(() => promise); + + const generate = component.find('button').at(7); + generate.simulate('click'); + await act(() => promise); + }); + + test('test refresh reports table button', async () => { + const promise = Promise.resolve(); + const data = [ + { + _id: 'abcdefg', + _source: { + query_url: '/app/visualize/edit/1234567890', + state: 'Created', + time_created: 123456789, + time_from: 123456789, + time_to: 1234567890, + report_definition: { + report_params: { + report_name: 'test create report definition trigger', + report_source: 'Dashboard', + description: '', + core_params: { + base_url: 'http://localhost:5601', + report_format: 'png', + header: '', + footer: '', + time_duration: 'PT30M', + }, + }, + delivery: { + delivery_type: '', + delivery_params: {}, + }, + trigger: { + trigger_type: 'Schedule', + trigger_params: {}, + }, + }, + }, + }, + ]; + + httpClientMock.get = jest.fn().mockResolvedValue({ + data, + }); + + const component = mount( +
+ ); + await act(() => promise); + + const generate = component.find('button').at(0); + generate.simulate('click'); + await act(() => promise); + }); + + // TODO: mock catch() error response to contain status code + test.skip('test error toasts posted', async () => { + jest.spyOn(console, 'log').mockImplementation(() => {}); // silence console log error from main + const promise = Promise.resolve(); + + httpClientMock.get = jest.fn().mockResolvedValue({ + response: null, + }); + + const component = mount( +
+ ); + const generate = component.find('button').at(7); + try { + generate.simulate('click'); + await act(() => promise); + } catch (e) { + await act(() => promise); + } + }); +}); diff --git a/public/components/main/__tests__/main_utils.test.tsx b/public/components/main/__tests__/main_utils.test.tsx new file mode 100644 index 00000000..27e0b7d8 --- /dev/null +++ b/public/components/main/__tests__/main_utils.test.tsx @@ -0,0 +1,156 @@ +/* + * Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +import { + humanReadableDate, + extractFilename, + extractFileFormat, + getFileFormatPrefix, + addReportsTableContent, + addReportDefinitionsTableContent, + removeDuplicatePdfFileFormat, + readStreamToFile, + generateReportFromDefinitionId, + generateReportById, +} from '../main_utils'; +import { + reportDefinitionsTableMockResponse, + mockReportsTableItems, + reportTableMockResponse, + reportDefinitionsTableMockContent, +} from './__utils__/main_utils_test_utils'; +import sinon from 'sinon'; +import httpClientMock from '../../../../test/httpMockClient'; + +describe('main_utils tests', () => { + global.URL.createObjectURL = jest.fn(); + let mockElement = document.createElement('a'); + mockElement.download = 'string'; + mockElement.click = function name() {}; + sinon.stub(document, 'createElement').returns(mockElement); + + test('test humanReadableDate', () => { + const readableDate = new Date(2018, 11, 24, 10, 33, 30); + const humanReadable = humanReadableDate(readableDate); + + expect(humanReadable).toBe('Mon Dec 24 2018 @ 10:33:30 AM'); + }); + + test('test extractFileName', () => { + const fullFile = 'test_file_name_extracted_correctly.pdf'; + const fileName = extractFilename(fullFile); + + expect(fileName).toBe('test_file_name_extracted_correctly'); + }); + + test('test extractFileFormat', () => { + const fullFile = 'test_file_format_extracted_correctly.png'; + const fileFormat = extractFileFormat(fullFile); + + expect(fileFormat).toBe('png'); + }); + + test('test getFileFormatPrefix', () => { + const fileFormat = 'pdf'; + const fileFormatPrefix = getFileFormatPrefix(fileFormat); + + expect(fileFormatPrefix).toBe('data:pdf;base64,'); + }); + + test('test addReportsTableContent', () => { + const reportsTableItems = addReportsTableContent(reportTableMockResponse); + + expect(reportsTableItems).toStrictEqual(mockReportsTableItems); + }); + + test('test addReportDefinitionsTableContent', () => { + const reportDefinitionsTableItems = addReportDefinitionsTableContent( + reportDefinitionsTableMockResponse + ); + + expect(reportDefinitionsTableItems).toStrictEqual( + reportDefinitionsTableMockContent + ); + }); + + test('test removeDuplicatePdfFileFormat', () => { + const duplicateFormat = 'test_duplicate_remove.pdf.pdf'; + const duplicateRemoved = removeDuplicatePdfFileFormat(duplicateFormat); + + expect(duplicateRemoved).toBe('test_duplicate_remove.pdf'); + }); + + test('test readStreamToFile csv compile', () => { + const stream = + 'category,customer_gender\n' + + 'c1,Male\n' + + 'c2,Male\n' + + 'c3,Male\n' + + 'c4,Male\n' + + 'c5,Male'; + + const fileFormat = 'csv'; + const fileName = 'test_data_report.csv'; + readStreamToFile(stream, fileFormat, fileName); + }); + + test('test readStreamToFile pdf compile', () => { + const stream = 'data:pdf;base64,zxvniaorbguw40absdoanlsdf'; + const fileFormat = 'pdf'; + const fileName = 'test_pdf_report.pdf'; + readStreamToFile(stream, fileFormat, fileName); + }); + + test('test generateReport compile', () => { + const reportDefinitionId = '1'; + generateReportFromDefinitionId(reportDefinitionId, httpClientMock); + }); + + test('test generateReportById compile', () => { + const reportId = '1'; + const handleSuccessToast = jest.fn(); + const handleErrorToast = jest.fn(); + generateReportById( + reportId, + httpClientMock, + handleSuccessToast, + handleErrorToast + ); + }); + + test('test generateReportById timeout error handling', async () => { + expect.assertions(1); + const reportId = '1'; + const handleSuccessToast = jest.fn(); + const handleErrorToast = jest.fn(); + const handlePermissionsMissingToast = jest.fn(); + + httpClientMock.get.mockReturnValue( + Promise.reject({ body: { statusCode: 503 } }) + ); + + await generateReportById( + reportId, + httpClientMock, + handleSuccessToast, + handleErrorToast, + handlePermissionsMissingToast + ); + expect(handleErrorToast).toHaveBeenCalledWith( + 'Error generating report.', + 'Timed out generating report ID 1. Try again later.' + ); + }); +}); diff --git a/public/components/main/__tests__/report_definitions_table.test.tsx b/public/components/main/__tests__/report_definitions_table.test.tsx new file mode 100644 index 00000000..d0bb56a5 --- /dev/null +++ b/public/components/main/__tests__/report_definitions_table.test.tsx @@ -0,0 +1,109 @@ +/* + * Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES 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 { ReportDefinitions } from '../report_definitions_table'; +import { configure, mount } from 'enzyme'; +import Adapter from 'enzyme-adapter-react-16'; + +const pagination = { + initialPageSize: 10, + pageSizeOptions: [8, 10, 13], +}; + +describe(' panel', () => { + configure({ adapter: new Adapter() }); + test('render component', () => { + let reportDefinitionsTableContent = [ + { + reportName: 'test report name', + type: 'Download', + owner: 'davidcui', + source: 'Dashboard', + lastUpdated: 'test updated time', + details: '', + status: 'Created', + }, + { + reportName: 'test report name 2', + type: 'Download', + owner: 'davidcui', + source: 'Dashboard', + lastUpdated: 'test updated time', + details: '', + status: 'Created', + }, + ]; + const { container } = render( + + ); + expect(container.firstChild).toMatchSnapshot(); + }); + + test('render empty table', () => { + const { container } = render( + + ); + expect(container.firstChild).toMatchSnapshot(); + }); + + test('test click on report definition row', async () => { + window = Object.create(window); + Object.defineProperty(window, 'location', { + configurable: true, + value: { + assign: jest.fn(), + }, + }); + let promise = Promise.resolve(); + let reportDefinitionsTableContent = [ + { + reportName: 'test report name', + type: 'Download', + owner: 'davidcui', + source: 'Dashboard', + lastUpdated: 'test updated time', + details: '', + status: 'Created', + }, + { + reportName: 'test report name 2', + type: 'Download', + owner: 'davidcui', + source: 'Dashboard', + lastUpdated: 'test updated time', + details: '', + status: 'Created', + }, + ]; + + const component = mount( + + ); + + const nameLink = component.find('button').at(3); + nameLink.simulate('click'); + }); +}); diff --git a/public/components/main/__tests__/reports_table.test.tsx b/public/components/main/__tests__/reports_table.test.tsx new file mode 100644 index 00000000..30bea823 --- /dev/null +++ b/public/components/main/__tests__/reports_table.test.tsx @@ -0,0 +1,95 @@ +/* + * Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES 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 { ReportsTable } from '../reports_table'; +import httpClientMock from '../../../../test/httpMockClient'; +import { configure, mount } from 'enzyme'; +import Adapter from 'enzyme-adapter-react-16'; +import { act } from 'react-dom/test-utils'; + +const pagination = { + initialPageSize: 10, + pageSizeOptions: [8, 10, 13], +}; + +describe(' panel', () => { + configure({ adapter: new Adapter() }); + test('render component', () => { + let reportsTableItems = [ + { + id: '1', + reportName: 'test report table item', + type: 'Test type', + sender: 'N/A', + recipients: 'N/A', + reportSource: 'Test report source', + lastUpdated: 'test updated time', + state: 'Created', + url: 'Test url', + }, + ]; + const { container } = render( + + ); + expect(container.firstChild).toMatchSnapshot(); + }); + + test('render empty component', async () => { + const { container } = render( + + ); + expect(container.firstChild).toMatchSnapshot(); + }); + + test('click on generate button', async () => { + const promise = Promise.resolve(); + let reportsTableItems = [ + { + id: '1', + reportName: 'test report table item', + type: 'Test type', + sender: 'N/A', + recipients: 'N/A', + reportSource: 'Test report source', + lastUpdated: 'test updated time', + state: 'Created', + url: 'Test url', + }, + ]; + + const component = mount( + + ); + + const generateClick = component.find('button').at(6); + // console.log(generateClick.debug()); + generateClick.simulate('click'); + await act(() => promise); + }); +}); diff --git a/public/components/main/index.ts b/public/components/main/index.ts new file mode 100644 index 00000000..9fb73281 --- /dev/null +++ b/public/components/main/index.ts @@ -0,0 +1,17 @@ +/* + * Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT 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 { Main } from './main'; +export { ReportDetails } from './report_details/report_details'; diff --git a/public/components/main/loading_modal/index.ts b/public/components/main/loading_modal/index.ts new file mode 100644 index 00000000..f553d6cc --- /dev/null +++ b/public/components/main/loading_modal/index.ts @@ -0,0 +1,16 @@ +/* + * Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT 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 { GenerateReportLoadingModal } from './loading_modal'; \ No newline at end of file diff --git a/public/components/main/loading_modal/loading_modal.tsx b/public/components/main/loading_modal/loading_modal.tsx new file mode 100644 index 00000000..dd7a1f0e --- /dev/null +++ b/public/components/main/loading_modal/loading_modal.tsx @@ -0,0 +1,79 @@ +/* + * Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +import { + EuiOverlayMask, + EuiModal, + EuiModalHeader, + EuiTitle, + EuiText, + EuiModalBody, + EuiSpacer, + EuiFlexGroup, + EuiFlexItem, + EuiLoadingSpinner, + EuiButton +} from "@elastic/eui"; +import React, { useState } from "react"; + +export function GenerateReportLoadingModal(props: { setShowLoading: any; }) { + const { + setShowLoading + } = props; + + const [isModalVisible, setIsModalVisible] = useState(true); + + const closeModal = () => { + setIsModalVisible(false); + setShowLoading(false); + }; + const showModal = () => setIsModalVisible(true); + + return ( +
+ + + + + +

Generating report

+
+
+
+ + Preparing your file for download. + + Please keep this dialog open while report is being generated. + + + + + + + + + +
+
+
+ ); +}; \ No newline at end of file diff --git a/public/components/main/main.tsx b/public/components/main/main.tsx new file mode 100644 index 00000000..9f2c5545 --- /dev/null +++ b/public/components/main/main.tsx @@ -0,0 +1,337 @@ +/* + * Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES 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, { Fragment, useState, useEffect } from 'react'; +import { + EuiFlexGroup, + EuiFlexItem, + EuiButton, + EuiTitle, + // @ts-ignore + EuiHorizontalRule, + EuiSpacer, + EuiPanel, + EuiGlobalToastList, +} from '@elastic/eui'; +import { ReportsTable } from './reports_table'; +import { ReportDefinitions } from './report_definitions_table'; +import { + addReportsTableContent, + addReportDefinitionsTableContent, +} from './main_utils'; +import CSS from 'csstype'; +import { + permissionsMissingToast, + permissionsMissingActions, +} from '../utils/utils'; + +const reportCountStyles: CSS.Properties = { + color: 'gray', + display: 'inline', +}; + +export function Main(props) { + const [reportsTableContent, setReportsTableContent] = useState([]); + const [ + reportDefinitionsTableContent, + setReportDefinitionsTableContent, + ] = useState([]); + const [toasts, setToasts] = useState([]); + + const addPermissionsMissingDownloadToastHandler = () => { + const toast = permissionsMissingToast( + permissionsMissingActions.GENERATING_REPORT + ); + setToasts(toasts.concat(toast)); + }; + + const handlePermissionsMissingDownloadToast = () => { + addPermissionsMissingDownloadToastHandler(); + }; + + const addReportsTableContentErrorToastHandler = (errorType: string) => { + let toast = {}; + if (errorType === 'permissions') { + toast = permissionsMissingToast( + permissionsMissingActions.LOADING_REPORTS_TABLE + ); + } else if (errorType === 'API') { + toast = { + title: 'Error generating reports table.', + color: 'danger', + iconType: 'alert', + id: 'reportsTableErrorToast', + }; + } + setToasts(toasts.concat(toast)); + }; + + const handleReportsTableErrorToast = (errorType: string) => { + addReportsTableContentErrorToastHandler(errorType); + }; + + const addReportDefinitionsTableErrorToastHandler = (errorType: string) => { + let toast = {}; + if (errorType === 'permissions') { + toast = permissionsMissingToast( + permissionsMissingActions.LOADING_DEFINITIONS_TABLE + ); + } else if (errorType === 'API') { + toast = { + title: 'Error generating report definitions table.', + color: 'danger', + iconType: 'alert', + id: 'reportDefinitionsTableErrorToast', + }; + } + setToasts(toasts.concat(toast)); + }; + + const handleReportDefinitionsTableErrorToast = (errorType: string) => { + addReportDefinitionsTableErrorToastHandler(errorType); + }; + + const addErrorOnDemandDownloadToastHandler = (title = 'Error downloading report.', text = '') => { + const errorToast = { + title, + text, + color: 'danger', + iconType: 'alert', + id: 'onDemandDownloadErrorToast', + }; + setToasts(toasts.concat(errorToast)); + }; + + const handleOnDemandDownloadErrorToast = (title?: string, text?: string) => { + addErrorOnDemandDownloadToastHandler(title, text); + }; + + const addSuccessOnDemandDownloadToastHandler = () => { + const successToast = { + title: 'Successfully downloaded report.', + color: 'success', + iconType: 'check', + id: 'onDemandDownloadSuccessToast', + }; + setToasts(toasts.concat(successToast)); + }; + + const handleOnDemandDownloadSuccessToast = () => { + addSuccessOnDemandDownloadToastHandler(); + }; + + const addCreateReportDefinitionSuccessToastHandler = () => { + const successToast = { + title: 'Successfully created report definition.', + color: 'success', + iconType: 'check', + id: 'createReportDefinitionSuccessToast', + }; + setToasts(toasts.concat(successToast)); + }; + + const handleCreateReportDefinitionSuccessToast = () => { + addCreateReportDefinitionSuccessToastHandler(); + }; + + const addEditReportDefinitionSuccessToastHandler = () => { + const successToast = { + title: 'Successfully updated report definition.', + color: 'success', + iconType: 'check', + id: 'editReportDefinitionSuccessToast', + }; + setToasts(toasts.concat(successToast)); + }; + + const handleEditReportDefinitionSuccessToast = () => { + addEditReportDefinitionSuccessToastHandler(); + }; + + const addDeleteReportDefinitionSuccessToastHandler = () => { + const successToast = { + title: 'Successfully deleted report definition.', + color: 'success', + iconType: 'check', + id: 'deleteReportDefinitionSuccessToast' + }; + setToasts(toasts.concat(successToast)); + } + + const handleDeleteReportDefinitionSuccessToast = () => { + addDeleteReportDefinitionSuccessToastHandler(); + } + + const removeToast = (removedToast) => { + setToasts(toasts.filter((toast) => toast.id !== removedToast.id)); + }; + + const pagination = { + initialPageSize: 10, + pageSizeOptions: [5, 10, 20], + }; + + useEffect(() => { + props.setBreadcrumbs([ + { + text: 'Reporting', + href: '#', + }, + ]); + refreshReportsTable(); + refreshReportsDefinitionsTable(); + + if (window.location.href.includes('create=success')) { + handleCreateReportDefinitionSuccessToast(); + // refresh might not fetch the latest changes when coming from create or edit page + // workaround to wait 1 second and refresh again + setTimeout(() => { + refreshReportsTable(); + refreshReportsDefinitionsTable(); + }, 1000); + } else if (window.location.href.includes('edit=success')) { + handleEditReportDefinitionSuccessToast(); + setTimeout(() => { + refreshReportsTable(); + refreshReportsDefinitionsTable(); + }, 1000); + } else if (window.location.href.includes('delete=success')) { + handleDeleteReportDefinitionSuccessToast(); + setTimeout(() => { + refreshReportsTable(); + refreshReportsDefinitionsTable(); + }, 1000); + } + window.location.href = 'opendistro_kibana_reports#/'; + }, []); + + const refreshReportsTable = async () => { + const { httpClient } = props; + await httpClient + .get('../api/reporting/reports') + .then((response) => { + setReportsTableContent(addReportsTableContent(response.data)); + }) + .catch((error) => { + console.log('error when fetching all reports: ', error); + // permission denied error + if (error.body.statusCode === 403) { + handleReportsTableErrorToast('permissions'); + } else { + handleReportsTableErrorToast('API'); + } + }); + }; + + const refreshReportsDefinitionsTable = async () => { + const { httpClient } = props; + await httpClient + .get('../api/reporting/reportDefinitions') + .then((response) => { + setReportDefinitionsTableContent( + addReportDefinitionsTableContent(response.data) + ); + }) + .catch((error) => { + console.log('error when fetching all report definitions: ', error); + if (error.body.statusCode === 403) { + handleReportDefinitionsTableErrorToast('permissions'); + } else { + handleReportDefinitionsTableErrorToast('API'); + } + }); + }; + + return ( +
+ + + + +

+ Reports{' '} +

({reportsTableContent.length})

+

+
+
+ + + Refresh + + +
+ + +
+ + + + + +

+ Report definitions +

+ {' '} + ({reportDefinitionsTableContent.length}) +

+

+
+
+ + + Refresh + + + + { + window.location.assign('opendistro_kibana_reports#/create'); + }} + id={'createReportHomepageButton'} + > + Create + + +
+ + +
+ +
+ ); +} diff --git a/public/components/main/main_utils.tsx b/public/components/main/main_utils.tsx new file mode 100644 index 00000000..4c7e1cfe --- /dev/null +++ b/public/components/main/main_utils.tsx @@ -0,0 +1,234 @@ +/* + * Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +import 'babel-polyfill'; +import { HttpSetup } from '../../../../../src/core/public'; +import { GENERATE_REPORT_PARAM } from '../visual_report/constants'; + +export const fileFormatsUpper = { + csv: 'CSV', + pdf: 'PDF', + png: 'PNG', +}; + +export const humanReadableDate = (date) => { + let readableDate = new Date(date); + return ( + readableDate.toDateString() + ' @ ' + readableDate.toLocaleTimeString() + ); +}; + +export const extractFilename = (filename: string) => { + return filename.substring(0, filename.length - 4); +}; + +export const extractFileFormat = (filename: string) => { + const fileFormat = filename; + return fileFormat.substring(filename.length - 3, filename.length); +}; + +export const getFileFormatPrefix = (fileFormat: string) => { + var fileFormatPrefix = 'data:' + fileFormat + ';base64,'; + return fileFormatPrefix; +}; + +export const addReportsTableContent = (data) => { + let reportsTableItems = []; + for (let index = 0; index < data.length; ++index) { + let item = data[index]; + let report = item._source; + let reportDefinition = report.report_definition; + let reportParams = reportDefinition.report_params; + let trigger = reportDefinition.trigger; + + let reportsTableEntry = { + id: item._id, + reportName: reportParams.report_name, + type: trigger.trigger_type, + sender: `\u2014`, + kibanaRecipients: `\u2014`, + emailRecipients: `\u2014`, + reportSource: reportParams.report_source, + //TODO: wrong name + timeCreated: report.time_created, + state: report.state, + url: report.query_url, + format: reportParams.core_params.report_format, + }; + reportsTableItems.push(reportsTableEntry); + } + return reportsTableItems; +}; + +export const addReportDefinitionsTableContent = (data: any) => { + let reportDefinitionsTableItems = []; + for (let index = 0; index < data.length; ++index) { + let item = data[index]; + let reportDefinition = item._source.report_definition; + let reportParams = reportDefinition.report_params; + let trigger = reportDefinition.trigger; + let triggerParams = trigger.trigger_params; + let reportDefinitionsTableEntry = { + id: item._id, + reportName: reportParams.report_name, + type: trigger.trigger_type, + owner: `\u2014`, // Todo: replace + source: reportParams.report_source, + baseUrl: reportParams.core_params.base_url, + lastUpdated: reportDefinition.last_updated, + details: + trigger.trigger_type === 'On demand' + ? `\u2014` + : triggerParams.schedule_type, // e.g. recurring, cron based + status: reportDefinition.status, + }; + reportDefinitionsTableItems.push(reportDefinitionsTableEntry); + } + return reportDefinitionsTableItems; +}; + +export const removeDuplicatePdfFileFormat = (filename) => { + return filename.substring(0, filename.length - 4); +}; + +export const readDataReportToFile = async ( + stream: string, + fileFormat: string, + fileName: string +) => { + const blob = new Blob([stream]); + const url = URL.createObjectURL(blob); + let link = document.createElement('a'); + link.setAttribute('href', url); + link.setAttribute('download', fileName); + document.body.appendChild(link); + link.click(); + document.body.removeChild(link); +}; + +export const readStreamToFile = async ( + stream: string, + fileFormat: string, + fileName: string +) => { + let link = document.createElement('a'); + if (fileName.includes('csv')) { + readDataReportToFile(stream, fileFormat, fileName); + return; + } + let fileFormatPrefix = getFileFormatPrefix(fileFormat); + let url = fileFormatPrefix + stream; + if (typeof link.download !== 'string') { + window.open(url, '_blank'); + return; + } + link.download = fileName; + link.href = url; + document.body.appendChild(link); + link.click(); + document.body.removeChild(link); +}; + +export const generateReportFromDefinitionId = async ( + reportDefinitionId, + httpClient: HttpSetup +) => { + let status = false; + let permissionsError = false; + await httpClient + .post(`../api/reporting/generateReport/${reportDefinitionId}`, { + headers: { + 'Content-Type': 'application/json', + }, + query: { timezone: Intl.DateTimeFormat().resolvedOptions().timeZone }, + }) + .then(async (response: any) => { + // for emailing a report, this API response doesn't have response body + if (!response) return; + const fileFormat = extractFileFormat(response['filename']); + const fileName = response['filename']; + if (fileFormat === 'csv') { + await readStreamToFile(await response['data'], fileFormat, fileName); + status = true; + return; + } + + // generate reports in browser is memory intensive, do it in a new process by removing referrer + const a = document.createElement('a'); + a.href = + window.location.origin + + `${response.queryUrl}&${GENERATE_REPORT_PARAM}=${response.reportId}`; + a.target = '_blank'; + a.rel = 'noreferrer'; + a.click(); + status = true; + }) + .catch((error) => { + console.log('error on generating report:', error); + if (error.body.statusCode === 403) { + permissionsError = true; + } + status = false; + }); + return { + status: status, + permissionsError: permissionsError, + }; +}; + +export const generateReportById = async ( + reportId, + httpClient: HttpSetup, + handleSuccessToast, + handleErrorToast, + handlePermissionsMissingToast +) => { + await httpClient + .get(`../api/reporting/generateReport/${reportId}`, { + query: { timezone: Intl.DateTimeFormat().resolvedOptions().timeZone }, + }) + .then(async (response) => { + //TODO: duplicate code, extract to be a function that can reuse. e.g. handleResponse(response) + const fileFormat = extractFileFormat(response['filename']); + const fileName = response['filename']; + if (fileFormat === 'csv') { + await readStreamToFile(await response['data'], fileFormat, fileName); + handleSuccessToast(); + return response; + } + + // generate reports in browser is memory intensive, do it in a new process by removing referrer + const a = document.createElement('a'); + a.href = + window.location.origin + + `${response.queryUrl}&${GENERATE_REPORT_PARAM}=${reportId}`; + a.target = '_blank'; + a.rel = 'noreferrer'; + a.click(); + }) + .catch((error) => { + console.log('error on generating report by id:', error); + if (error.body.statusCode === 403) { + handlePermissionsMissingToast(); + } else if (error.body.statusCode === 503) { + handleErrorToast( + 'Error generating report.', + `Timed out generating report ID ${reportId}. Try again later.` + ); + } else { + handleErrorToast(); + } + }); +}; diff --git a/public/components/main/report_definition_details/__tests__/__snapshots__/report_definition_details.test.tsx.snap b/public/components/main/report_definition_details/__tests__/__snapshots__/report_definition_details.test.tsx.snap new file mode 100644 index 00000000..e72a317e --- /dev/null +++ b/public/components/main/report_definition_details/__tests__/__snapshots__/report_definition_details.test.tsx.snap @@ -0,0 +1,1197 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[` panel render 5 hours recurring definition details 1`] = ` +
+
+

+ Report definition details +

+
+
+
+
+
+
+

+

+
+
+
+
+ +
+
+ +
+
+ +
+
+
+
+

+ Report settings +

+
+
+`; + +exports[` panel render disabled daily definition, click 1`] = ` + +`; + +exports[` panel render on demand definition details 1`] = ` + +`; diff --git a/public/components/main/report_definition_details/__tests__/report_definition_details.test.tsx b/public/components/main/report_definition_details/__tests__/report_definition_details.test.tsx new file mode 100644 index 00000000..66fc1d4d --- /dev/null +++ b/public/components/main/report_definition_details/__tests__/report_definition_details.test.tsx @@ -0,0 +1,409 @@ +/* + * Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES 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 { act, render } from '@testing-library/react'; +import { ReportDefinitionDetails } from '../report_definition_details'; +import httpClientMock from '../../../../../test/httpMockClient'; +import 'babel-polyfill'; +import { configure, mount } from 'enzyme'; +import Adapter from 'enzyme-adapter-react-16'; + +function setBreadcrumbs(array: []) { + jest.fn(); +} + +describe(' panel', () => { + let propsMock = { + match: { + params: { + reportDefinitionId: jest.fn(), + }, + }, + }; + + const match = { + params: { + reportDefinitionId: '1', + }, + }; + beforeEach(() => { + jest.clearAllMocks(); + }); + + configure({ adapter: new Adapter() }); + test('render on demand definition details', async () => { + const promise = Promise.resolve(); + const report_definition = { + report_params: { + report_name: 'test create report definition trigger', + report_source: 'Dashboard', + description: '', + core_params: { + base_url: '', + report_format: '', + header: '', + footer: '', + time_duration: '', + }, + }, + delivery: { + delivery_type: '', + delivery_params: {}, + }, + trigger: { + trigger_type: 'On demand', + }, + }; + + httpClientMock.get = jest.fn().mockResolvedValue({ + report_definition, + }); + + const { container } = render( + + ); + expect(container.firstChild).toMatchSnapshot(); + await act(() => promise); + }); + + test('render 5 hours recurring definition details', async () => { + const promise = Promise.resolve(); + const report_definition = { + report_params: { + report_name: 'test create report definition trigger', + report_source: 'Dashboard', + description: '', + core_params: { + base_url: '', + report_format: '', + header: '', + footer: '', + time_duration: '', + }, + }, + delivery: { + delivery_type: '', + delivery_params: {}, + }, + trigger: { + trigger_type: 'Schedule', + trigger_params: { + schedule_type: 'Recurring', + schedule: { + interval: { + period: 5, + unit: 'HOURS', + timezone: 'PST8PDT', + }, + }, + enabled_time: 1114939203, + enabled: true, + }, + }, + }; + + httpClientMock.get = jest.fn().mockResolvedValue({ + report_definition, + }); + + const { container } = render( + + ); + expect(container.firstChild).toMatchSnapshot(); + await act(() => promise); + }); + + test('render disabled daily definition, click', async () => { + let promise = Promise.resolve(); + const report_definition = { + report_params: { + report_name: 'test create report definition trigger', + report_source: 'Dashboard', + description: '', + core_params: { + base_url: '', + report_format: '', + header: '', + footer: '', + time_duration: '', + }, + }, + delivery: { + delivery_type: '', + delivery_params: {}, + }, + trigger: { + trigger_type: 'Schedule', + trigger_params: { + schedule_type: 'Recurring', + schedule: { + interval: { + period: 1, + unit: 'DAYS', + timezone: 'PST8PDT', + }, + }, + enabled_time: 1114939203, + enabled: false, + }, + }, + }; + + httpClientMock.get = jest.fn().mockResolvedValue({ + report_definition, + }); + + const { container } = render( + + ); + + expect(container.firstChild).toMatchSnapshot(); + await act(() => promise); + }); + + test('simulate click on generateReport', async () => { + let promise = Promise.resolve(); + const report_definition = { + report_params: { + report_name: null, + report_source: 'Dashboard', + description: '', + core_params: { + base_url: '', + report_format: '', + header: '', + footer: '', + time_duration: '', + }, + }, + delivery: { + delivery_type: '', + delivery_params: {}, + }, + trigger: { + trigger_type: 'On demand', + }, + }; + + httpClientMock.get = jest.fn().mockResolvedValue({ + report_definition, + }); + + const component = mount( + + ); + await act(() => promise); + component.update(); + const statusButton = component.find('button').at(1); + + statusButton.simulate('click'); + await act(() => promise); + }); + + test('simulate click on delete', async () => { + let promise = Promise.resolve(); + const report_definition = { + report_params: { + report_name: null, + report_source: 'Dashboard', + description: '', + core_params: { + base_url: '', + report_format: '', + header: '', + footer: '', + time_duration: '', + }, + }, + delivery: { + delivery_type: '', + delivery_params: {}, + }, + trigger: { + trigger_type: 'Schedule', + trigger_params: { + schedule_type: 'Recurring', + schedule: { + interval: { + period: 1, + unit: 'DAYS', + timezone: 'PST8PDT', + }, + }, + enabled_time: 1114939203, + enabled: false, + }, + }, + }; + + httpClientMock.get = jest.fn().mockResolvedValue({ + report_definition, + }); + + const component = mount( + + ); + + const statusButton = component.find('button').at(0); + statusButton.update(); + statusButton.simulate('click'); + + await act(() => promise); + }); + + test('simulate click to enable', async () => { + let promise = Promise.resolve(); + const report_definition = { + status: 'Disabled', + report_params: { + report_name: 'test click on enable disable', + report_source: 'Dashboard', + description: '', + core_params: { + base_url: '', + report_format: '', + header: '', + footer: '', + time_duration: '', + }, + }, + delivery: { + delivery_type: '', + delivery_params: {}, + }, + trigger: { + trigger_type: 'Schedule', + trigger_params: { + schedule_type: 'Recurring', + schedule: { + interval: { + period: 1, + unit: 'DAYS', + timezone: 'PST8PDT', + }, + }, + enabled_time: 1114939203, + enabled: false, + }, + }, + }; + + httpClientMock.get = jest.fn().mockResolvedValue({ + report_definition, + }); + + httpClientMock.put = jest.fn().mockResolvedValue({}); + + const component = mount( + + ); + await act(() => promise); + component.update(); + const statusButton = component.find('button').at(1); + + statusButton.simulate('click'); + await act(() => promise); + }); + + test('simulate click to disable', async () => { + let promise = Promise.resolve(); + const report_definition = { + status: 'Active', + report_params: { + report_name: 'test click on enable disable', + report_source: 'Dashboard', + description: '', + core_params: { + base_url: '', + report_format: '', + header: '', + footer: '', + time_duration: '', + }, + }, + delivery: { + delivery_type: '', + delivery_params: {}, + }, + trigger: { + trigger_type: 'Schedule', + trigger_params: { + schedule_type: 'Recurring', + schedule: { + interval: { + period: 1, + unit: 'DAYS', + timezone: 'PST8PDT', + }, + }, + enabled_time: 1114939203, + enabled: true, + }, + }, + }; + + httpClientMock.get = jest.fn().mockResolvedValue({ + report_definition, + }); + + httpClientMock.put = jest.fn().mockResolvedValue({}); + + const component = mount( + + ); + await act(() => promise); + component.update(); + const statusButton = component.find('button').at(1); + + statusButton.simulate('click'); + await act(() => promise); + }); +}); diff --git a/public/components/main/report_definition_details/report_definition_details.tsx b/public/components/main/report_definition_details/report_definition_details.tsx new file mode 100644 index 00000000..4f36589c --- /dev/null +++ b/public/components/main/report_definition_details/report_definition_details.tsx @@ -0,0 +1,711 @@ +/* + * Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES 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 } from 'react'; +import { + EuiFlexGroup, + EuiFlexItem, + EuiPage, + EuiPageHeader, + EuiTitle, + EuiPageBody, + EuiPageContent, + EuiHorizontalRule, + EuiSpacer, + EuiPageHeaderSection, + EuiButton, + EuiIcon, + EuiLink, + EuiGlobalToastList, + EuiOverlayMask, + EuiConfirmModal, +} from '@elastic/eui'; +import { + ReportDetailsComponent, + formatEmails, + trimAndRenderAsText, +} from '../report_details/report_details'; +import { fileFormatsUpper, generateReportFromDefinitionId } from '../main_utils'; +import { ReportDefinitionSchemaType } from '../../../../server/model'; +import moment from 'moment'; +import { converter } from '../../report_definitions/utils'; +import { + permissionsMissingToast, + permissionsMissingActions, +} from '../../utils/utils'; +import { GenerateReportLoadingModal } from '../loading_modal'; + +const ON_DEMAND = 'On demand'; + +export function ReportDefinitionDetails(props) { + const [reportDefinitionDetails, setReportDefinitionDetails] = useState({}); + const [ + reportDefinitionRawResponse, + setReportDefinitionRawResponse, + ] = useState({}); + const [toasts, setToasts] = useState([]); + const [showDeleteModal, setShowDeleteModal] = useState(false); + const [showLoading, setShowLoading] = useState(false); + const reportDefinitionId = props.match['params']['reportDefinitionId']; + + const handleLoading = (e) => { + setShowLoading(e); + } + + const handleShowDeleteModal = (e) => { + setShowDeleteModal(e); + }; + + const addPermissionsMissingStatusChangeToastHandler = () => { + const toast = permissionsMissingToast( + permissionsMissingActions.CHANGE_SCHEDULE_STATUS + ); + setToasts(toasts.concat(toast)); + }; + + const addPermissionsMissingDeleteToastHandler = () => { + const toast = permissionsMissingToast( + permissionsMissingActions.DELETE_REPORT_DEFINITION + ); + setToasts(toasts.concat(toast)); + }; + + const handlePermissionsMissingDeleteToast = () => { + addPermissionsMissingDeleteToastHandler(); + }; + + const addPermissionsMissingGenerateReportToastHandler = () => { + const toast = permissionsMissingToast( + permissionsMissingActions.GENERATING_REPORT + ); + setToasts(toasts.concat(toast)); + }; + + const addErrorLoadingDetailsToastHandler = () => { + const errorToast = { + title: 'Error loading report definition details.', + color: 'danger', + iconType: 'alert', + id: 'reportDefinitionDetailsErrorToast', + }; + setToasts(toasts.concat(errorToast)); + }; + + const handleDetailsErrorToast = () => { + addErrorLoadingDetailsToastHandler(); + }; + + const addSuccessGeneratingReportToastHandler = () => { + const successToast = { + title: 'Successfully generated report.', + color: 'success', + iconType: 'check', + id: 'generateReportSuccessToast', + }; + setToasts(toasts.concat(successToast)); + }; + + const handleSuccessGeneratingReportToast = () => { + addSuccessGeneratingReportToastHandler(); + }; + + const addErrorGeneratingReportToastHandler = () => { + const errorToast = { + title: 'Error generating report.', + color: 'danger', + iconType: 'alert', + id: 'generateReportErrorToast', + }; + setToasts(toasts.concat(errorToast)); + }; + + const handleErrorGeneratingReportToast = (errorType: string) => { + if (errorType === 'permissions') { + addPermissionsMissingGenerateReportToastHandler(); + } else if (errorType === 'API') { + addErrorGeneratingReportToastHandler(); + } + }; + + const addSuccessEnablingScheduleToastHandler = () => { + const successToast = { + title: 'Successfully enabled schedule.', + color: 'success', + iconType: 'check', + id: 'successEnableToast', + }; + setToasts(toasts.concat(successToast)); + }; + + const addErrorEnablingScheduleToastHandler = () => { + const errorToast = { + title: 'Error enabling schedule.', + color: 'danger', + iconType: 'alert', + id: 'errorToast', + }; + setToasts(toasts.concat(errorToast)); + }; + + const addSuccessDisablingScheduleToastHandler = () => { + const successToast = { + title: 'Successfully disabled schedule.', + color: 'success', + iconType: 'check', + id: 'successDisableToast', + }; + setToasts(toasts.concat(successToast)); + }; + + const handleSuccessChangingScheduleStatusToast = (statusChange: string) => { + if (statusChange === 'enable') { + addSuccessEnablingScheduleToastHandler(); + } else if (statusChange === 'disable') { + addSuccessDisablingScheduleToastHandler(); + } + }; + + const addErrorDisablingScheduleToastHandler = () => { + const errorToast = { + title: 'Error disabling schedule.', + color: 'danger', + iconType: 'alert', + id: 'errorDisableToast', + }; + setToasts(toasts.concat(errorToast)); + }; + + const handleErrorChangingScheduleStatusToast = (statusChange: string) => { + if (statusChange === 'enable') { + addErrorEnablingScheduleToastHandler(); + } else if (statusChange === 'disable') { + addErrorDisablingScheduleToastHandler(); + } else if (statusChange === 'permissions') { + addPermissionsMissingStatusChangeToastHandler(); + } + }; + + const addErrorDeletingReportDefinitionToastHandler = () => { + const errorToast = { + title: 'Error deleting report definition.', + color: 'danger', + iconType: 'alert', + id: 'errorDeleteToast', + }; + setToasts(toasts.concat(errorToast)); + }; + + const handleErrorDeletingReportDefinitionToast = () => { + addErrorDeletingReportDefinitionToastHandler(); + }; + + const removeToast = (removedToast) => { + setToasts(toasts.filter((toast) => toast.id !== removedToast.id)); + }; + + const handleReportDefinitionDetails = (e) => { + setReportDefinitionDetails(e); + }; + + const handleReportDefinitionRawResponse = (e) => { + setReportDefinitionRawResponse(e); + }; + + const DeleteConfirmationModal = () => { + const closeModal = () => { + setShowDeleteModal(false); + }; + + return ( +
+ + +

+ Are you sure you want to delete "{reportDefinitionDetails.name}"? +

+
+
+
+ ); + }; + + const humanReadableScheduleDetails = (trigger) => { + let scheduleDetails = ''; + if (trigger.trigger_type === 'Schedule') { + if (trigger.trigger_params.schedule_type === 'Recurring') { + // Daily + if ( + trigger.trigger_params.schedule.interval.unit === 'DAYS' && + trigger.trigger_params.schedule.interval.period === 1 + ) { + const date = new Date( + trigger.trigger_params.schedule.interval.start_time + ); + scheduleDetails = 'Daily @ ' + date.toTimeString(); + } + // By interval + else { + const date = new Date( + trigger.trigger_params.schedule.interval.start_time + ); + scheduleDetails = + 'By interval, every ' + + trigger.trigger_params.schedule.interval.period + + ' ' + + trigger.trigger_params.schedule.interval.unit.toLowerCase() + + ', starting @ ' + + date.toTimeString(); + } + } + // Cron + else if (trigger.trigger_params.schedule_type === 'Cron based') { + scheduleDetails = + 'Cron based: ' + + trigger.trigger_params.schedule.cron.expression + + ' (' + + trigger.trigger_params.schedule.cron.timezone + + ')'; + } + } + return scheduleDetails; + }; + + const getReportDefinitionDetailsMetadata = (data) => { + const reportDefinition: ReportDefinitionSchemaType = data.report_definition; + const { + report_params: reportParams, + trigger, + delivery, + time_created: timeCreated, + last_updated: lastUpdated, + } = reportDefinition; + const { + trigger_type: triggerType, + trigger_params: triggerParams, + } = trigger; + const { + delivery_type: deliveryType, + delivery_params: deliveryParams, + } = delivery; + const { + core_params: { + base_url: baseUrl, + report_format: reportFormat, + time_duration: timeDuration, + }, + } = reportParams; + + let readableDate = new Date(timeCreated); + let displayCreatedDate = + readableDate.toDateString() + ' ' + readableDate.toLocaleTimeString(); + + let readableUpdatedDate = new Date(lastUpdated); + let displayUpdatedDate = + readableUpdatedDate.toDateString() + + ' ' + + readableUpdatedDate.toLocaleTimeString(); + + let reportDefinitionDetails = { + name: reportParams.report_name, + description: + reportParams.description === '' ? `\u2014` : reportParams.description, + created: displayCreatedDate, + lastUpdated: displayUpdatedDate, + source: reportParams.report_source, + baseUrl: baseUrl, + // TODO: need better display + timePeriod: moment.duration(timeDuration).humanize(), + fileFormat: reportFormat, + reportHeader: reportParams.core_params.hasOwnProperty('header') && reportParams.core_params.header != "" + ? converter.makeMarkdown(reportParams.core_params.header) + : `\u2014`, + reportFooter: reportParams.core_params.hasOwnProperty('footer') && reportParams.core_params.footer != "" + ? converter.makeMarkdown(reportParams.core_params.footer) + : `\u2014`, + triggerType: triggerType, + scheduleDetails: triggerParams + ? humanReadableScheduleDetails(data.report_definition.trigger) + : `\u2014`, + channel: deliveryType, + status: reportDefinition.status, + kibanaRecipients: deliveryParams.kibana_recipients + ? deliveryParams.kibana_recipients + : `\u2014`, + emailRecipients: + deliveryType === 'Channel' ? deliveryParams.recipients : `\u2014`, + emailSubject: + deliveryType === 'Channel' ? deliveryParams.title : `\u2014`, + emailBody: + deliveryType === 'Channel' ? deliveryParams.textDescription : `\u2014`, + }; + return reportDefinitionDetails; + }; + + useEffect(() => { + const { httpClient } = props; + httpClient + .get(`../api/reporting/reportDefinitions/${reportDefinitionId}`) + .then((response) => { + handleReportDefinitionRawResponse(response); + handleReportDefinitionDetails( + getReportDefinitionDetailsMetadata(response) + ); + props.setBreadcrumbs([ + { + text: 'Reporting', + href: '#', + }, + { + text: `Report definition details: ${response.report_definition.report_params.report_name}`, + }, + ]); + }) + .catch((error) => { + console.error('error when getting report definition details:', error); + handleDetailsErrorToast(); + }); + }, []); + + const downloadIconDownload = async () => { + handleLoading(true); + await generateReportFromDetails(); + handleLoading(false); + } + + const fileFormatDownload = (data) => { + let formatUpper = data['fileFormat']; + formatUpper = fileFormatsUpper[formatUpper]; + return ( + + {formatUpper + ' '} + + + ); + }; + + const sourceURL = (data) => { + return ( + + {data['source']} + + ); + }; + + const getRelativeStartDate = (duration) => { + duration = moment.duration(duration); + let time_difference = moment.now() - duration; + return new Date(time_difference); + }; + + const changeScheduledReportDefinitionStatus = (statusChange) => { + let updatedReportDefinition = reportDefinitionRawResponse.report_definition; + if (statusChange === 'Disable') { + updatedReportDefinition.trigger.trigger_params.enabled = false; + updatedReportDefinition.status = 'Disabled'; + } else if (statusChange === 'Enable') { + updatedReportDefinition.trigger.trigger_params.enabled = true; + updatedReportDefinition.status = 'Active'; + } + + const { httpClient } = props; + httpClient + .put(`../api/reporting/reportDefinitions/${reportDefinitionId}`, { + body: JSON.stringify(updatedReportDefinition), + params: reportDefinitionId.toString(), + }) + .then(() => { + const updatedRawResponse = { report_definition: {} }; + updatedRawResponse.report_definition = updatedReportDefinition; + handleReportDefinitionRawResponse(updatedRawResponse); + setReportDefinitionDetails( + getReportDefinitionDetailsMetadata(updatedRawResponse) + ); + if (statusChange === 'Enable') { + handleSuccessChangingScheduleStatusToast('enable'); + } else if (statusChange === 'Disable') { + handleSuccessChangingScheduleStatusToast('disable'); + } + }) + .catch((error) => { + console.error('error in updating report definition status:', error); + if (error.body.statusCode === 403) { + handleErrorChangingScheduleStatusToast('permissions'); + } else { + if (statusChange === 'Enable') { + handleErrorChangingScheduleStatusToast('enable'); + } else if (statusChange === 'Disable') { + handleErrorChangingScheduleStatusToast('disable'); + } + } + }); + }; + + const ScheduledDefinitionStatus = () => { + const status = + reportDefinitionDetails.status === 'Active' ? 'Disable' : 'Enable'; + + return ( + changeScheduledReportDefinitionStatus(status)} + id={'changeStatusFromDetailsButton'} + > + {status} + + ); + }; + + const generateReportFromDetails = async () => { + const { httpClient } = props; + handleLoading(true); + let generateReportSuccess = await generateReportFromDefinitionId( + reportDefinitionId, + httpClient + ); + handleLoading(false); + if (generateReportSuccess.status) { + handleSuccessGeneratingReportToast(); + } else { + if (generateReportSuccess.permissionsError) { + handleErrorGeneratingReportToast('permissions'); + } else { + handleErrorGeneratingReportToast('API'); + } + } + }; + + const deleteReportDefinition = () => { + const { httpClient } = props; + httpClient + .delete(`../api/reporting/reportDefinitions/${reportDefinitionId}`) + .then(() => { + window.location.assign(`opendistro_kibana_reports#/delete=success`); + }) + .catch((error) => { + console.log('error when deleting report definition:', error); + if (error.body.statusCode === 403) { + handlePermissionsMissingDeleteToast(); + } else { + handleErrorDeletingReportDefinitionToast(); + } + }); + }; + + const showActionButton = + reportDefinitionDetails.triggerType === ON_DEMAND ? ( + generateReportFromDetails()} + id={'generateReportFromDetailsButton'} + > + Generate report + + ) : ( + + ); + + const triggerSection = + reportDefinitionDetails.triggerType === ON_DEMAND ? ( + + ) : ( + + + + + + + ); + + const showDeleteConfirmationModal = showDeleteModal ? ( + + ) : null; + + const showLoadingModal = showLoading ? + : null; + + return ( + + + +

Report definition details

+
+ + + + + + + +

{reportDefinitionDetails.name}

+
+
+
+
+ + + + Delete + + + {showActionButton} + + { + window.location.assign( + `opendistro_kibana_reports#/edit/${reportDefinitionId}` + ); + }} + id={'editReportDefinitionButton'} + > + Edit + + + +
+ + +

Report settings

+
+ + + + + + + + + + + + + + + + + + + + + + + +

Report trigger

+
+ + {triggerSection} + + {/* +

Notification settings

+
+ + + + + + + */} +
+ + {showDeleteConfirmationModal} + {showLoadingModal} +
+
+ ); +} diff --git a/public/components/main/report_definitions_table.tsx b/public/components/main/report_definitions_table.tsx new file mode 100644 index 00000000..7bebe9f7 --- /dev/null +++ b/public/components/main/report_definitions_table.tsx @@ -0,0 +1,170 @@ +/* + * Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES 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 { + EuiLink, + EuiInMemoryTable, + EuiButton, + EuiEmptyPrompt, + EuiText, + EuiIcon, +} from '@elastic/eui'; +import { humanReadableDate } from './main_utils'; + +const emptyMessageReportDefinitions = ( + No report definitions to display} + titleSize="xs" + body={ +
+ Create a new report definition to get started + + To learn more, see{' '} + + Get started with Kibana reporting + + +
+ } + actions={ +
+ { + window.location.assign('opendistro_kibana_reports#/create'); + }} + > + Create report definition + +
+ } + /> +); + +const reportDefinitionsSearch = { + box: { + incremental: true, + }, + filters: [], +}; + +export function ReportDefinitions(props) { + const { pagination, reportDefinitionsTableContent } = props; + + const [sortField, setSortField] = useState('lastUpdated'); + const [sortDirection, setSortDirection] = useState('des'); + + const sorting = { + sort: { + field: sortField, + direction: sortDirection, + }, + }; + + const getDefinitionTableItemId = (name) => { + let index; + for ( + index = 0; + index < props.reportDefinitionsTableContent.length; + ++index + ) { + if (name === reportDefinitionsTableContent[index].reportName) { + return reportDefinitionsTableContent[index].id; + } + } + }; + + const navigateToDefinitionDetails = (name: any) => { + let id = getDefinitionTableItemId(name); + window.location.assign( + `opendistro_kibana_reports#/report_definition_details/${id}` + ); + }; + + const reportDefinitionsColumns = [ + { + field: 'reportName', + name: 'Name', + render: (name) => ( + navigateToDefinitionDetails(name)} + id={'reportDefinitionDetailsLink'} + > + {name} + + ), + }, + { + field: 'source', + name: 'Source', + render: (value, item) => ( + + {value} + + ), + }, + { + field: 'type', + name: 'Type', + sortable: true, + truncateText: false, + }, + { + field: 'details', + name: 'Schedule details', + sortable: false, + truncateText: true, + }, + { + field: 'lastUpdated', + name: 'Last Updated', + render: (date) => { + let readable = humanReadableDate(date); + return {readable}; + }, + }, + { + field: 'status', + name: 'Status', + sortable: true, + truncateText: false, + }, + ]; + + const displayMessage = + reportDefinitionsTableContent.length === 0 + ? emptyMessageReportDefinitions + : '0 report definitions match the search criteria. Search again.'; + + return ( +
+ +
+ ); +} diff --git a/public/components/main/report_details/__tests__/__snapshots__/report_details.test.tsx.snap b/public/components/main/report_details/__tests__/__snapshots__/report_details.test.tsx.snap new file mode 100644 index 00000000..e46cc598 --- /dev/null +++ b/public/components/main/report_details/__tests__/__snapshots__/report_details.test.tsx.snap @@ -0,0 +1,797 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[` panel render 5 hours recurring component 1`] = ` +
+`; + +exports[` panel render on-demand component 1`] = ` + +`; diff --git a/public/components/main/report_details/__tests__/report_details.test.tsx b/public/components/main/report_details/__tests__/report_details.test.tsx new file mode 100644 index 00000000..716ec492 --- /dev/null +++ b/public/components/main/report_details/__tests__/report_details.test.tsx @@ -0,0 +1,128 @@ +/* + * Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES 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 { ReportDetails } from '../report_details'; +import propsMock from '../../../../../test/propsMock'; +import httpClientMock from '../../../../../test/httpMockClient'; +import 'babel-polyfill'; +import { act } from 'react-dom/test-utils'; + +function setBreadcrumbs(array: []) { + jest.fn(); +} + +describe(' panel', () => { + const match = { + params: { + reportId: '1', + }, + }; + + test('render on-demand component', async () => { + const promise = Promise.resolve(); + const report_definition = { + report_params: { + report_name: 'test create report definition trigger', + report_source: 'Dashboard', + description: '', + core_params: { + base_url: '', + report_format: '', + header: '', + footer: '', + time_duration: 'PT30M', + }, + }, + delivery: { + delivery_type: '', + delivery_params: {}, + }, + trigger: { + trigger_type: 'On demand', + }, + }; + + httpClientMock.get = jest.fn().mockResolvedValue({ + report_definition, + query_url: `http://localhost:5601/app/dashboards#/view/7adfa750-4c81-11e8-b3d7-01146121b73d?_g=(time:(from:'2020-10-23T20:53:35.315Z',to:'2020-10-23T21:23:35.316Z'))`, + }); + + const { container } = render( + + ); + await act(() => promise); + await expect(container.firstChild).toMatchSnapshot(); + }); + + test('render 5 hours recurring component', async () => { + const promise = Promise.resolve(); + const report_definition = { + report_params: { + report_name: 'test create report definition trigger', + report_source: 'Dashboard', + description: '', + core_params: { + base_url: '', + report_format: '', + header: '', + footer: '', + time_duration: 'PT30M', + }, + }, + delivery: { + delivery_type: '', + delivery_params: {}, + }, + trigger: { + trigger_type: 'Schedule', + trigger_params: { + schedule_type: 'Recurring', + schedule: { + interval: { + period: 5, + unit: 'HOURS', + timezone: 'PST8PDT', + }, + }, + enabled_time: 1114939203, + enabled: true, + }, + }, + }; + + httpClientMock.get = jest.fn().mockResolvedValue({ + report_definition, + query_url: `http://localhost:5601/app/dashboards#/view/7adfa750-4c81-11e8-b3d7-01146121b73d?_g=(time:(from:'2020-10-23T20:53:35.315Z',to:'2020-10-23T21:23:35.316Z'))`, + }); + + const { container } = render( + + ); + await act(() => promise); + await expect(container.firstChild).toMatchSnapshot(); + }); +}); diff --git a/public/components/main/report_details/report_details.tsx b/public/components/main/report_details/report_details.tsx new file mode 100644 index 00000000..10aa4a56 --- /dev/null +++ b/public/components/main/report_details/report_details.tsx @@ -0,0 +1,404 @@ +/* + * Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES 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 } from 'react'; +import { + EuiFlexGroup, + EuiFlexItem, + EuiPage, + EuiPageHeader, + EuiTitle, + EuiPageBody, + EuiPageContent, + EuiHorizontalRule, + EuiSpacer, + EuiDescriptionList, + EuiDescriptionListTitle, + EuiDescriptionListDescription, + EuiPageHeaderSection, + EuiButton, + EuiLink, + EuiIcon, + EuiGlobalToastList, +} from '@elastic/eui'; +import { fileFormatsUpper, generateReportById } from '../main_utils'; +import { GenerateReportLoadingModal } from '../loading_modal'; +import { ReportSchemaType } from '../../../../server/model'; +import { converter } from '../../report_definitions/utils'; +import dateMath from '@elastic/datemath'; +import { + permissionsMissingActions, + permissionsMissingToast, + timeRangeMatcher, +} from '../../utils/utils'; + +export const ReportDetailsComponent = (props) => { + const { reportDetailsComponentTitle, reportDetailsComponentContent } = props; + + return ( + + + + {reportDetailsComponentTitle} + + + {reportDetailsComponentContent} + + + + ); +}; + +// convert markdown to plain text, trim it if it's longer than 3 lines +export const trimAndRenderAsText = (markdown: string) => { + if (!markdown) return markdown; + const lines = markdown.split('\n').filter((line) => line); + const elements = lines.slice(0, 3).map((line, i) =>

{line}

); + return lines.length <= 3 ? elements : elements.concat(

...

); +}; + +export const formatEmails = (emails: string[]) => { + return Array.isArray(emails) ? emails.join(', ') : emails; +}; + +export function ReportDetails(props) { + const [reportDetails, setReportDetails] = useState({}); + const [toasts, setToasts] = useState([]); + const [showLoading, setShowLoading] = useState(false); + + const reportId = props.match['params']['reportId']; + + const handleLoading = (e) => { + setShowLoading(e); + }; + + const addPermissionsMissingDownloadToastHandler = () => { + const toast = permissionsMissingToast( + permissionsMissingActions.GENERATING_REPORT + ); + setToasts(toasts.concat(toast)); + }; + + const handlePermissionsMissingDownloadToast = () => { + addPermissionsMissingDownloadToastHandler(); + }; + + const addErrorToastHandler = (title = 'Error loading report details.', text = '') => { + const errorToast = { + title, + text, + color: 'danger', + iconType: 'alert', + id: 'reportDetailsErrorToast', + }; + setToasts(toasts.concat(errorToast)); + }; + + const handleErrorToast = (title?: string, text?: string) => { + addErrorToastHandler(title, text); + }; + + const addSuccessToastHandler = () => { + const successToast = { + title: 'Success', + color: 'success', + text:

Report successfully downloaded!

, + id: 'onDemandDownloadSuccessToast', + }; + setToasts(toasts.concat(successToast)); + }; + + const handleSuccessToast = () => { + addSuccessToastHandler(); + }; + + const removeToast = (removedToast) => { + setToasts(toasts.filter((toast) => toast.id !== removedToast.id)); + }; + + const handleReportDetails = (e) => { + setReportDetails(e); + }; + + const convertTimestamp = (timestamp: number) => { + let displayDate = `\u2014`; + if (timestamp) { + let readableDate = new Date(timestamp); + displayDate = readableDate.toLocaleString(); + } + return displayDate; + }; + + const parseTimePeriod = (queryUrl: string) => { + let [timeStringRegEx, fromDateString, toDateString] = queryUrl.match( + timeRangeMatcher + ); + + fromDateString = fromDateString.replace(/[']+/g, ''); + toDateString = toDateString.replace(/[']+/g, ''); + + let fromDateParsed = dateMath.parse(fromDateString); + let toDateParsed = dateMath.parse(toDateString); + + const fromTimePeriod = fromDateParsed?.toDate(); + const toTimePeriod = toDateParsed?.toDate(); + return ( + fromTimePeriod?.toLocaleString() + ' -> ' + toTimePeriod?.toLocaleString() + ); + }; + + const getReportDetailsData = (report: ReportSchemaType) => { + const { + report_definition: reportDefinition, + last_updated: lastUpdated, + state, + query_url: queryUrl, + } = report; + const { report_params: reportParams, trigger, delivery } = reportDefinition; + const { + trigger_type: triggerType, + trigger_params: triggerParams, + } = trigger; + const { + delivery_type: deliveryType, + delivery_params: deliveryParams, + } = delivery; + const coreParams = reportParams.core_params; + // covert timestamp to local date-time string + let reportDetails = { + reportName: reportParams.report_name, + description: + reportParams.description === '' ? `\u2014` : reportParams.description, + created: convertTimestamp(report.time_created), + lastUpdated: convertTimestamp(report.last_updated), + source: reportParams.report_source, + // TODO: we have all data needed, time_from, time_to, time_duration, + // think of a way to better display + time_period: parseTimePeriod(queryUrl), + defaultFileFormat: coreParams.report_format, + state: state, + reportHeader: reportParams.core_params.hasOwnProperty('header') && reportParams.core_params.header != "" + ? converter.makeMarkdown(reportParams.core_params.header) + : `\u2014`, + reportFooter: reportParams.core_params.hasOwnProperty('footer') && reportParams.core_params.footer != "" + ? converter.makeMarkdown(reportParams.core_params.footer) + : `\u2014`, + triggerType: triggerType, + scheduleType: triggerParams ? triggerParams.schedule_type : `\u2014`, + scheduleDetails: `\u2014`, + alertDetails: `\u2014`, + channel: deliveryType, + emailRecipients: + deliveryType === 'Channel' ? deliveryParams.recipients : `\u2014`, + emailSubject: + deliveryType === 'Channel' ? deliveryParams.title : `\u2014`, + emailBody: + deliveryType === 'Channel' ? deliveryParams.textDescription : `\u2014`, + queryUrl: queryUrl, + }; + return reportDetails; + }; + + useEffect(() => { + const { httpClient } = props; + httpClient + .get('../api/reporting/reports/' + reportId) + .then((response) => { + handleReportDetails(getReportDetailsData(response)); + props.setBreadcrumbs([ + { + text: 'Reporting', + href: '#', + }, + { + text: + 'Report details: ' + + response.report_definition.report_params.report_name, + }, + ]); + }) + .catch((error) => { + console.log('Error when fetching report details: ', error); + handleErrorToast(); + }); + }, []); + + const downloadIconDownload = async () => { + handleLoading(true); + await generateReportById( + reportId, + props.httpClient, + handleSuccessToast, + handleErrorToast, + handlePermissionsMissingDownloadToast + ); + handleLoading(false); + }; + + const fileFormatDownload = (data) => { + let formatUpper = data['defaultFileFormat']; + formatUpper = fileFormatsUpper[formatUpper]; + return ( + + {formatUpper + ' '} + + + ); + }; + + const sourceURL = (data) => { + return ( + + {data['source']} + + ); + }; + + const showLoadingModal = showLoading ? + : null; + + return ( + + + +

Report details

+
+ + + + + + + +

{reportDetails['reportName']}

+
+
+
+
+
+ + +

Report Settings

+
+ + + + + + + + + + + + + + + + + + + + + + + +

Report trigger

+
+ + + + + + + + + {/* +

Notification settings

+
+ + + + + + + */} +
+ + {showLoadingModal} +
+
+ ); +} diff --git a/public/components/main/reports_table.tsx b/public/components/main/reports_table.tsx new file mode 100644 index 00000000..68330997 --- /dev/null +++ b/public/components/main/reports_table.tsx @@ -0,0 +1,226 @@ +/* + * Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES 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, { Fragment, useState } from 'react'; +import { + EuiButton, + // @ts-ignore + EuiLink, + EuiText, + EuiIcon, + EuiEmptyPrompt, + EuiInMemoryTable, +} from '@elastic/eui'; +import { + fileFormatsUpper, + humanReadableDate, + generateReportById, +} from './main_utils'; +import { GenerateReportLoadingModal } from './loading_modal'; + +const reportStatusOptions = [ + 'Created', + 'Error', + 'Pending', + 'Shared', + 'Archived', +]; +const reportTypeOptions = ['Schedule', 'On demand']; + +const emptyMessageReports = ( + No reports to display} + titleSize="xs" + body={ +
+ + Create a report definition, or share/download a report from a + dashboard, saved search or visualization. + + + To learn more, see{' '} + + Get started with Kibana reporting + + +
+ } + /> +); + +export function ReportsTable(props) { + const { + pagination, + reportsTableItems, + httpClient, + handleSuccessToast, + handleErrorToast, + handlePermissionsMissingToast, + } = props; + + const [sortField, setSortField] = useState('timeCreated'); + const [sortDirection, setSortDirection] = useState('des'); + const [showLoading, setShowLoading] = useState(false); + const [message, setMessage] = useState(''); + + const handleLoading = (e) => { + setShowLoading(e); + }; + + const onDemandDownload = async (id: any) => { + handleLoading(true); + await generateReportById( + id, + httpClient, + handleSuccessToast, + handleErrorToast, + handlePermissionsMissingToast + ); + handleLoading(false); + }; + + const reportsTableColumns = [ + { + field: 'reportName', + name: 'Name', + render: (reportName, item) => ( + { + window.location.assign( + `opendistro_kibana_reports#/report_details/${item.id}` + ); + }} + id={'reportDetailsLink'} + > + {reportName} + + ), + }, + { + // TODO: link to dashboard/visualization snapshot, use "queryUrl" field. Display dashboard name? + field: 'reportSource', + name: 'Source', + render: (source, item) => + item.state === 'Pending' ? ( + {source} + ) : ( + + {source} + + ), + }, + { + field: 'type', + name: 'Type', + sortable: true, + truncateText: false, + }, + { + field: 'timeCreated', + name: 'Creation time', + render: (date) => { + let readable = humanReadableDate(date); + return {readable}; + }, + }, + { + field: 'state', + name: 'State', + sortable: true, + truncateText: false, + }, + { + field: 'id', + name: 'Generate', + render: (id, item) => + item.state === 'Pending' ? ( + + {fileFormatsUpper[item.format]} + + ) : ( + onDemandDownload(id)} id="landingPageOnDemandDownload"> + {fileFormatsUpper[item.format]} + + ), + }, + ]; + + const sorting = { + sort: { + field: sortField, + direction: sortDirection, + }, + }; + + const reportsListSearch = { + box: { + incremental: true, + }, + filters: [ + { + type: 'field_value_selection', + field: 'type', + name: 'Type', + multiSelect: 'or', + options: reportTypeOptions.map((type) => ({ + value: type, + name: type, + view: type, + })), + }, + { + type: 'field_value_selection', + field: 'state', + name: 'State', + multiSelect: 'or', + options: reportStatusOptions.map((state) => ({ + value: state, + name: state, + view: state, + })), + }, + ], + }; + + const displayMessage = + reportsTableItems.length === 0 + ? emptyMessageReports + : '0 reports match the search criteria. Search again'; + + const showLoadingModal = showLoading ? + : null; + + return ( + + + {showLoadingModal} + + ); +} diff --git a/public/components/report_definitions/create/create_report_definition.tsx b/public/components/report_definitions/create/create_report_definition.tsx new file mode 100644 index 00000000..dcba2522 --- /dev/null +++ b/public/components/report_definitions/create/create_report_definition.tsx @@ -0,0 +1,360 @@ +/* + * Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES 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 } from 'react'; +import { + EuiButtonEmpty, + EuiFlexGroup, + EuiFlexItem, + EuiGlobalToastList, + EuiButton, + EuiTitle, + EuiPageBody, + EuiSpacer, +} from '@elastic/eui'; +import { ReportSettings } from '../report_settings'; +import { ReportDelivery } from '../delivery'; +import { ReportTrigger } from '../report_trigger'; +import { generateReportFromDefinitionId } from '../../main/main_utils'; +import { converter } from '../utils'; +import { + permissionsMissingToast, + permissionsMissingActions, +} from '../../utils/utils'; +import { definitionInputValidation } from '../utils/utils'; + +interface reportParamsType { + report_name: string; + report_source: string; + description: string; + core_params: visualReportParams | dataReportParams; +} +interface visualReportParams { + base_url: string; + report_format: string; + header: string; + footer: string; + time_duration: string; +} + +interface dataReportParams { + saved_search_id: number; + base_url: string; + report_format: string; + time_duration: string; +} +interface triggerType { + trigger_type: string; + trigger_params?: any; +} + +interface deliveryType { + delivery_type: string; + delivery_params: any; +} + +export interface TriggerParamsType { + schedule_type: string; + schedule: Recurring | Cron; + enabled_time: number; + enabled: boolean; +} + +interface Recurring { + interval: { + period: number; + unit: string; + start_time: number; + }; +} + +interface Cron { + cron: { + cron_expression: string; + time_zone: string; + }; +} + +export interface reportDefinitionParams { + report_params: reportParamsType; + delivery: deliveryType; + trigger: triggerType; +} + +export interface timeRangeParams { + timeFrom: Date; + timeTo: Date; +} + +export function CreateReport(props) { + let createReportDefinitionRequest: reportDefinitionParams = { + report_params: { + report_name: '', + report_source: '', + description: '', + core_params: { + base_url: '', + report_format: '', + time_duration: '', + }, + }, + delivery: { + delivery_type: '', + delivery_params: {}, + }, + trigger: { + trigger_type: '', + }, + }; + + const [toasts, setToasts] = useState([]); + const [comingFromError, setComingFromError] = useState(false); + const [preErrorData, setPreErrorData] = useState({}); + + const [ + showSettingsReportNameError, + setShowSettingsReportNameError, + ] = useState(false); + const [ + settingsReportNameErrorMessage, + setSettingsReportNameErrorMessage, + ] = useState(''); + const [ + showSettingsReportSourceError, + setShowSettingsReportSourceError + ] = useState(false); + const [ + settingsReportSourceErrorMessage, + setSettingsReportSourceErrorMessage + ] = useState(''); + const [ + showTriggerIntervalNaNError, + setShowTriggerIntervalNaNError, + ] = useState(false); + const [showCronError, setShowCronError] = useState(false); + const [showEmailRecipientsError, setShowEmailRecipientsError] = useState( + false + ); + const [ + emailRecipientsErrorMessage, + setEmailRecipientsErrorMessage, + ] = useState(''); + const [showTimeRangeError, setShowTimeRangeError] = useState(false); + + // preserve the state of the request after an invalid create report definition request + if (comingFromError) { + createReportDefinitionRequest = preErrorData; + } + + const addInputValidationErrorToastHandler = () => { + const errorToast = { + title: 'One or more fields have an error. Please check and try again.', + color: 'danger', + iconType: 'alert', + id: 'errorToast', + }; + setToasts(toasts.concat(errorToast)); + }; + + const handleInputValidationErrorToast = () => { + addInputValidationErrorToastHandler(); + }; + + const addErrorOnCreateToastHandler = (errorType: string) => { + let toast = {}; + if (errorType === 'permissions') { + toast = permissionsMissingToast( + permissionsMissingActions.CREATING_REPORT_DEFINITION + ); + } else if (errorType === 'API') { + toast = { + title: 'Error creating report definition.', + color: 'danger', + iconType: 'alert', + id: 'errorToast', + }; + } + setToasts(toasts.concat(toast)); + }; + + const handleErrorOnCreateToast = (errorType: string) => { + addErrorOnCreateToastHandler(errorType); + }; + + const addInvalidTimeRangeToastHandler = () => { + const errorToast = { + title: 'Invalid time range selected.', + color: 'danger', + iconType: 'alert', + id: 'timeRangeErrorToast', + }; + setToasts(toasts.concat(errorToast)); + }; + + const handleInvalidTimeRangeToast = () => { + addInvalidTimeRangeToastHandler(); + }; + + const removeToast = (removedToast) => { + setToasts(toasts.filter((toast) => toast.id !== removedToast.id)); + }; + + let timeRange = { + timeFrom: new Date(), + timeTo: new Date(), + }; + + const createNewReportDefinition = async ( + metadata: reportDefinitionParams, + timeRange: timeRangeParams + ) => { + const { httpClient } = props; + //TODO: need better handle + if ( + metadata.trigger.trigger_type === 'On demand' && + metadata.trigger.trigger_params !== undefined + ) { + delete metadata.trigger.trigger_params; + } + + let error = false; + await definitionInputValidation( + metadata, + error, + setShowSettingsReportNameError, + setSettingsReportNameErrorMessage, + setShowSettingsReportSourceError, + setSettingsReportSourceErrorMessage, + setShowTriggerIntervalNaNError, + timeRange, + setShowTimeRangeError, + setShowCronError, + setShowEmailRecipientsError, + setEmailRecipientsErrorMessage + ).then((response) => { + error = response; + }); + if (error) { + handleInputValidationErrorToast(); + setPreErrorData(metadata); + setComingFromError(true); + } else { + httpClient + .post('../api/reporting/reportDefinition', { + body: JSON.stringify(metadata), + headers: { + 'Content-Type': 'application/json', + }, + }) + .then(async (resp) => { + //TODO: consider handle the on demand report generation from server side instead + if (metadata.trigger.trigger_type === 'On demand') { + const reportDefinitionId = resp.scheduler_response.reportDefinitionId; + generateReportFromDefinitionId(reportDefinitionId, httpClient); + } + window.location.assign(`opendistro_kibana_reports#/create=success`); + }) + .catch((error) => { + console.log('error in creating report definition: ' + error); + if (error.body.statusCode === 403) { + handleErrorOnCreateToast('permissions'); + } else { + handleErrorOnCreateToast('API'); + } + }); + } + }; + + useEffect(() => { + window.scrollTo(0, 0); + props.setBreadcrumbs([ + { + text: 'Reporting', + href: '#', + }, + { + text: 'Create report definition', + href: '#/create', + }, + ]); + }, []); + + return ( +
+ + +

Create report definition

+
+ + + + + + + + + + { + window.location.assign(`opendistro_kibana_reports#/`); + }} + > + Cancel + + + + + createNewReportDefinition( + createReportDefinitionRequest, + timeRange + ) + } + id={'createNewReportDefinition'} + > + Create + + + + +
+
+ ); +} diff --git a/public/components/report_definitions/create/index.ts b/public/components/report_definitions/create/index.ts new file mode 100644 index 00000000..4aa74347 --- /dev/null +++ b/public/components/report_definitions/create/index.ts @@ -0,0 +1,16 @@ +/* + * Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT 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 { CreateReport } from './create_report_definition'; diff --git a/public/components/report_definitions/delivery/__tests__/__snapshots__/delivery.test.tsx.snap b/public/components/report_definitions/delivery/__tests__/__snapshots__/delivery.test.tsx.snap new file mode 100644 index 00000000..d70dbdde --- /dev/null +++ b/public/components/report_definitions/delivery/__tests__/__snapshots__/delivery.test.tsx.snap @@ -0,0 +1,91 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[` panel render create component 1`] = ` + +
+
+`; + +exports[` panel visualization create from in-context 1`] = ` +
+
+

+ Report Settings +

+
+
+
+
+
+
+
+ +
+
+
+
+ +
+
+
+ Valid characters are a-z, A-Z, 0-9, (), [], _ (underscore), - (hyphen) and (space). +
+
+
+
+
+
+
+
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+
+ +
+
+
+
+
+ + +
+
    +
  • + +
  • +
  • + +
  • +
  • + +
  • +
  • + +
  • +
+
    +
  • + +
  • +
  • + +
  • +
  • + +
  • +
+
+
+
+ +
+
+ +
+
+
+
+
+
+
+
+
+`; diff --git a/public/components/report_definitions/report_settings/__tests__/report_settings.test.tsx b/public/components/report_definitions/report_settings/__tests__/report_settings.test.tsx new file mode 100644 index 00000000..7407dc84 --- /dev/null +++ b/public/components/report_definitions/report_settings/__tests__/report_settings.test.tsx @@ -0,0 +1,706 @@ +/* + * Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES 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 { ReportSettings } from '../report_settings'; +import 'babel-polyfill'; +import 'regenerator-runtime'; +import httpClientMock from '../../../../../test/httpMockClient'; +import { configure, mount, shallow } from 'enzyme'; +import Adapter from 'enzyme-adapter-react-16'; +import { act } from 'react-dom/test-utils'; + +const emptyRequest = { + report_params: { + report_name: '', + report_source: '', + description: '', + core_params: { + base_url: '', + report_format: '', + time_duration: '', + }, + }, + delivery: { + delivery_type: '', + delivery_params: {}, + }, + trigger: { + trigger_type: '', + trigger_params: {}, + }, + time_created: 0, + last_updated: 0, + status: '', +}; + +let timeRange = { + timeFrom: new Date(123456789), + timeTo: new Date(1234567890), +}; + +const dashboardHits = { + hits: [ + { + _id: 'dashboard:abcdefghijklmnop12345', + _source: { + dashboard: { + description: 'mock dashboard value', + hits: 0, + timeFrom: 'now-24h', + timeTo: 'now', + title: 'Mock Dashboard', + }, + }, + }, + ], +}; + +const visualizationHits = { + hits: [ + { + _id: 'visualization:abcdefghijklmnop12345', + _source: { + visualization: { + description: 'mock visualization value', + title: 'Mock Visualization', + }, + }, + }, + ], +}; + +const savedSearchHits = { + hits: [ + { + _id: 'search:abcdefghijklmnop12345', + _source: { + search: { + title: 'Mock saved search value', + }, + }, + }, + ], +}; + +describe(' panel', () => { + jest.spyOn(console, 'log').mockImplementation(() => {}); + configure({ adapter: new Adapter() }); + test('render component', () => { + const { container } = render( + + ); + + expect(container.firstChild).toMatchSnapshot(); + }); + + test('render edit, dashboard source', async () => { + const promise = Promise.resolve(); + let report_definition = { + report_params: { + report_name: 'test create report definition trigger', + report_source: 'Dashboard', + description: 'test description', + core_params: { + base_url: 'http://localhost:5601/dashboard/abcdefghijklmnop12345', + report_format: 'pdf', + header: 'header content', + footer: 'footer content', + time_duration: 'PT30M', + }, + }, + delivery: { + delivery_type: '', + delivery_params: {}, + }, + trigger: { + trigger_type: 'Schedule', + trigger_params: {}, + }, + }; + + httpClientMock.get = jest.fn().mockResolvedValue({ + report_definition, + hits: dashboardHits, + }); + + const { container } = render( + + ); + + expect(container.firstChild).toMatchSnapshot(); + await act(() => promise); + }); + + test('render edit, visualization source', async () => { + const promise = Promise.resolve(); + let report_definition = { + report_params: { + report_name: 'test create report definition trigger', + report_source: 'Visualization', + description: 'test description', + core_params: { + base_url: 'http://localhost:5601/edit/abcdefghijklmnop12345', + report_format: 'png', + header: 'header content', + footer: 'footer content', + time_duration: 'PT30M', + }, + }, + delivery: { + delivery_type: '', + delivery_params: {}, + }, + trigger: { + trigger_type: 'Schedule', + trigger_params: {}, + }, + }; + + httpClientMock.get = jest.fn().mockResolvedValue({ + report_definition, + hits: visualizationHits, + }); + + const { container } = render( + + ); + + expect(container.firstChild).toMatchSnapshot(); + await act(() => promise); + }); + + test('render edit, saved search source', async () => { + const promise = Promise.resolve(); + let report_definition = { + report_params: { + report_name: 'test create report definition trigger', + report_source: 'Saved search', + description: 'test description', + core_params: { + base_url: 'http://localhost:5601/discover/abcdefghijklmnop12345', + report_format: 'csv', + header: 'test header content', + footer: 'test footer content', + time_duration: 'PT30M', + saved_search_id: 'abcdefghijk', + limit: 10000, + excel: true, + }, + }, + delivery: { + delivery_type: '', + delivery_params: {}, + }, + trigger: { + trigger_type: 'Schedule', + trigger_params: {}, + }, + }; + + httpClientMock.get = jest.fn().mockResolvedValue({ + report_definition, + hits: savedSearchHits, + }); + + const { container } = render( + + ); + + expect(container.firstChild).toMatchSnapshot(); + await act(() => promise); + }); + + test('render edit, dashboard source', async () => { + const promise = Promise.resolve(); + let report_definition = { + report_params: { + report_name: 'test create report definition trigger', + report_source: 'Saved search', + description: 'test description', + core_params: { + base_url: 'http://localhost:5601', + report_format: 'csv', + header: 'test header content', + footer: 'test footer content', + time_duration: 'PT30M', + saved_search_id: 'abcdefghijk', + limit: 10000, + excel: true, + }, + }, + delivery: { + delivery_type: '', + delivery_params: {}, + }, + trigger: { + trigger_type: 'Schedule', + trigger_params: {}, + }, + }; + + httpClientMock.get = jest.fn().mockResolvedValue({ + report_definition, + hits: dashboardHits, + }); + + const { container } = render( + + ); + + expect(container.firstChild).toMatchSnapshot(); + await act(() => promise); + }); + + test('render edit, visualization source', async () => { + const promise = Promise.resolve(); + let report_definition = { + report_params: { + report_name: 'test create report definition trigger', + report_source: 'Saved search', + description: 'test description', + core_params: { + base_url: 'http://localhost:5601', + report_format: 'csv', + header: 'test header content', + footer: 'test footer content', + time_duration: 'PT30M', + saved_search_id: 'abcdefghijk', + limit: 10000, + excel: true, + }, + }, + delivery: { + delivery_type: '', + delivery_params: {}, + }, + trigger: { + trigger_type: 'Schedule', + trigger_params: {}, + }, + }; + + httpClientMock.get = jest.fn().mockResolvedValue({ + report_definition, + hits: visualizationHits, + }); + + const { container } = render( + + ); + + expect(container.firstChild).toMatchSnapshot(); + await act(() => promise); + }); + + + test('dashboard create from in-context', async () => { + window = Object.create(window); + Object.defineProperty(window, 'location', { + configurable: true, + value: { + href: + 'http://localhost:5601/app/opendistro_kibana_reports#/create?previous=dashboard:abcdefghijklmnop12345?timeFrom=2020-10-26T20:52:56.382Z?timeTo=2020-10-27T20:52:56.384Z', + }, + }); + + const promise = Promise.resolve(); + + let report_definition = { + report_params: { + report_name: 'test create report definition trigger', + report_source: 'Dashboard', + description: '', + core_params: { + base_url: 'http://localhost:5601/dashboard/abcdefghijklmnop12345', + report_format: 'png', + header: '', + footer: '', + time_duration: 'PT30M', + }, + }, + delivery: { + delivery_type: '', + delivery_params: {}, + }, + trigger: { + trigger_type: 'Schedule', + trigger_params: {}, + }, + }; + + httpClientMock.get = jest.fn().mockResolvedValue({ + report_definition, + hits: dashboardHits, + }); + + const { container } = render( + + ); + + expect(container.firstChild).toMatchSnapshot(); + await act(() => promise); + }); + + test('visualization create from in-context', async () => { + // @ts-ignore + delete window.location; // reset window.location.href for in-context testing + + window = Object.create(window); + Object.defineProperty(window, 'location', { + configurable: true, + value: { + href: + 'http://localhost:5601/app/opendistro_kibana_reports#/create?previous=visualize:abcdefghijklmnop12345?timeFrom=2020-10-26T20:52:56.382Z?timeTo=2020-10-27T20:52:56.384Z', + }, + }); + + const promise = Promise.resolve(); + + let report_definition = { + report_params: { + report_name: 'test create report definition trigger', + report_source: 'Visualization', + description: '', + core_params: { + base_url: 'http://localhost:5601/edit/abcdefghijklmnop12345', + report_format: 'pdf', + header: '', + footer: '', + time_duration: 'PT30M', + }, + }, + delivery: { + delivery_type: '', + delivery_params: {}, + }, + trigger: { + trigger_type: 'Schedule', + trigger_params: {}, + }, + }; + + httpClientMock.get = jest.fn().mockResolvedValue({ + report_definition, + hits: visualizationHits, + }); + + const { container } = render( + + ); + + expect(container.firstChild).toMatchSnapshot(); + await act(() => promise); + }); + + test('saved search create from in-context', async () => { + // @ts-ignore + delete window.location; // reset window.location.href for in-context testing + + window = Object.create(window); + Object.defineProperty(window, 'location', { + value: { + href: + 'http://localhost:5601/app/opendistro_kibana_reports#/create?previous=discover:abcdefghijklmnop12345?timeFrom=2020-10-26T20:52:56.382Z?timeTo=2020-10-27T20:52:56.384Z', + }, + }); + + const promise = Promise.resolve(); + + let report_definition = { + report_params: { + report_name: 'test create report definition trigger', + report_source: 'Saved search', + description: '', + core_params: { + base_url: 'http://localhost:5601/discover/abcdefghijklmnop12345', + report_format: 'csv', + header: '', + footer: '', + time_duration: 'PT30M', + saved_search_id: 'abcdefghijk', + limit: 10000, + excel: true, + }, + }, + delivery: { + delivery_type: '', + delivery_params: {}, + }, + trigger: { + trigger_type: 'Schedule', + trigger_params: {}, + }, + }; + + httpClientMock.get = jest.fn().mockResolvedValue({ + report_definition, + hits: savedSearchHits, + }); + + const { container } = render( + + ); + + expect(container.firstChild).toMatchSnapshot(); + await act(() => promise); + }); + + test('simulate click on dashboard combo box', async () => { + const promise = Promise.resolve(); + let report_definition = { + report_params: { + report_name: 'test create report definition trigger', + report_source: 'Saved search', + description: 'test description', + core_params: { + base_url: 'http://localhost:5601', + report_format: 'csv', + header: 'test header content', + footer: 'test footer content', + time_duration: 'PT30M', + saved_search_id: 'abcdefghijk', + limit: 10000, + excel: true, + }, + }, + delivery: { + delivery_type: '', + delivery_params: {}, + }, + trigger: { + trigger_type: 'Schedule', + trigger_params: {}, + }, + }; + + httpClientMock.get = jest.fn().mockResolvedValue({ + report_definition, + hits: dashboardHits, + }); + + const component = shallow( + + , {disableLifecycleMethods: true}); + await act(() => promise); + + const comboBox = component.find('EuiComboBox').at(0); + comboBox.simulate('change', [{value: 'test', label: 'test'}]); + + await act(() => promise); + }); + + test('simulate click on visualization combo box', async () => { + const promise = Promise.resolve(); + let report_definition = { + report_params: { + report_name: 'test create report definition trigger', + report_source: 'Visualization', + description: 'test description', + core_params: { + base_url: 'http://localhost:5601', + report_format: 'pdf', + header: 'test header content', + footer: 'test footer content', + time_duration: 'PT30M', + }, + }, + delivery: { + delivery_type: '', + delivery_params: {}, + }, + trigger: { + trigger_type: 'Schedule', + trigger_params: {}, + }, + }; + + httpClientMock.get = jest.fn().mockResolvedValue({ + report_definition, + hits: visualizationHits, + }); + + const component = mount( + + ); + await act(() => promise); + + const reportSourceRadio = component.find('EuiRadioGroup').at(0); + const visualizationRadio = reportSourceRadio.find('EuiRadio').at(1); + + visualizationRadio.find('input').simulate('change', 'visualizationReportSource'); + await act(() => promise); + const comboBox = component.find('EuiComboBox').at(0); + + act(() => { + comboBox.props().onChange([{ value: 'test', label: 'test' }]); + }); + component.update(); + + await act(() => promise); + }); + + test('simulate click on saved search combo box', async () => { + const promise = Promise.resolve(); + let report_definition = { + report_params: { + report_name: 'test create report definition trigger', + report_source: 'Saved search', + description: 'test description', + core_params: { + base_url: 'http://localhost:5601', + report_format: 'pdf', + header: 'test header content', + footer: 'test footer content', + time_duration: 'PT30M', + }, + }, + delivery: { + delivery_type: '', + delivery_params: {}, + }, + trigger: { + trigger_type: 'Schedule', + trigger_params: {}, + }, + }; + + httpClientMock.get = jest.fn().mockResolvedValue({ + report_definition, + hits: savedSearchHits, + }); + + const component = mount( + + ); + await act(() => promise); + + const reportSourceRadio = component.find('EuiRadioGroup').at(0); + const visualizationRadio = reportSourceRadio.find('EuiRadio').at(2); + + visualizationRadio.find('input').simulate('change', 'savedSearchReportSource'); + await act(() => promise); + const comboBox = component.find('EuiComboBox').at(0); + + act(() => { + comboBox.props().onChange([{ value: 'test', label: 'test' }]); + }) + component.update(); + + await act(() => promise); + }); + + test('display errors on create', async () => { + const promise = Promise.resolve(); + const { container } = render( + + ); + + expect(container.firstChild).toMatchSnapshot(); + await act(() => promise); + }); +}); diff --git a/public/components/report_definitions/report_settings/__tests__/report_settings_helpers.test.tsx b/public/components/report_definitions/report_settings/__tests__/report_settings_helpers.test.tsx new file mode 100644 index 00000000..8bdf12a0 --- /dev/null +++ b/public/components/report_definitions/report_settings/__tests__/report_settings_helpers.test.tsx @@ -0,0 +1,187 @@ +/* + * Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +import { + getDashboardBaseUrlCreate, + getDashboardOptions, + getSavedSearchBaseUrlCreate, + getSavedSearchOptions, + getVisualizationBaseUrlCreate, + getVisualizationOptions, + handleDataToVisualReportSourceChange, + parseInContextUrl, +} from '../report_settings_helpers'; + +const TEST_DEFINITION_ID = '12345'; + +describe('report_settings_helpers tests', () => { + test('parseInContextUrl', () => { + const urlString = + 'http://localhost:5601/app/opendistro_kibana_reports#/create?previous=dashboard:7adfa750-4c81-11e8-b3d7-01146121b73d?timeFrom=2020-10-26T20:52:56.382Z?timeTo=2020-10-27T20:52:56.384Z'; + + const id = parseInContextUrl(urlString, 'id'); + expect(id).toBe('7adfa750-4c81-11e8-b3d7-01146121b73d'); + + const timeFrom = parseInContextUrl(urlString, 'timeFrom'); + expect(timeFrom).toBe('2020-10-26T20:52:56.382Z'); + + const timeTo = parseInContextUrl(urlString, 'timeTo'); + expect(timeTo).toBe('2020-10-27T20:52:56.384Z'); + + const error = parseInContextUrl(urlString, 'invalid'); + expect(error).toBe('error: invalid parameter'); + }); + + test('getDashboardBaseUrlCreate', () => { + const baseUrl = getDashboardBaseUrlCreate(true, TEST_DEFINITION_ID, true); + expect(baseUrl).toBe('/app/dashboards#/view/'); + + const baseUrlNotFromEdit = getDashboardBaseUrlCreate( + false, + TEST_DEFINITION_ID, + true + ); + expect(baseUrlNotFromEdit).toBe('/app/dashboards#/view/'); + }); + + test('getDashboardBaseUrlCreate not from in-context', () => { + const baseUrl = getDashboardBaseUrlCreate(false, TEST_DEFINITION_ID, false); + expect(baseUrl).toBe('/'); + }) + + test('getVisualizationBaseUrlCreate', () => { + const baseUrl = getVisualizationBaseUrlCreate( + true, + TEST_DEFINITION_ID, + true + ); + expect(baseUrl).toBe('/app/visualize#/edit/'); + + const baseUrlNotFromEdit = getVisualizationBaseUrlCreate( + false, + TEST_DEFINITION_ID, + true + ); + expect(baseUrlNotFromEdit).toBe('/app/visualize#/edit/'); + }); + + test('getVisualizationBaseUrlCreate not from in-context', () => { + const baseUrl = getVisualizationBaseUrlCreate( + false, + TEST_DEFINITION_ID, + false + ); + expect(baseUrl).toBe('/'); + }) + + test('getSavedSearchBaseUrlCreate', () => { + const baseUrl = getSavedSearchBaseUrlCreate(true, TEST_DEFINITION_ID, true); + expect(baseUrl).toBe('/app/discover#/view/'); + + const baseUrlNotFromEdit = getSavedSearchBaseUrlCreate( + false, + TEST_DEFINITION_ID, + true + ); + expect(baseUrlNotFromEdit).toBe('/app/discover#/view/'); + }); + + test('getSavedSearchBaseUrlCreate not from in-context', () => { + const baseUrl = getSavedSearchBaseUrlCreate(false, TEST_DEFINITION_ID, false); + expect(baseUrl).toBe('/'); + }) + + test('getDashboardOptions', () => { + const mockData = [ + { + _id: 'dashboard:1234567890abcdefghijk', + _source: { + dashboard: { + title: 'Mock dashboard title', + }, + }, + }, + ]; + + const options = getDashboardOptions(mockData); + expect(options[0].value).toBe('1234567890abcdefghijk'); + expect(options[0].label).toBe('Mock dashboard title'); + }); + + test('getVisualizationOptions', () => { + const mockData = [ + { + _id: 'visualization:1234567890abcdefghijk', + _source: { + visualization: { + title: 'Mock visualization title', + }, + }, + }, + ]; + + const options = getVisualizationOptions(mockData); + expect(options[0].value).toBe('1234567890abcdefghijk'); + expect(options[0].label).toBe('Mock visualization title'); + }); + + test('getSavedSearchOptions', () => { + const mockData = [ + { + _id: 'search:1234567890abcdefghijk', + _source: { + search: { + title: 'Mock saved search title', + }, + }, + }, + ]; + const options = getSavedSearchOptions(mockData); + expect(options[0].value).toBe('1234567890abcdefghijk'); + expect(options[0].label).toBe('Mock saved search title'); + }); + + test('handleDataToVisualReportSourceChange', () => { + let reportDefinitionRequest = { + report_params: { + report_name: 'test create report definition trigger', + report_source: 'Dashboard', + description: '', + core_params: { + report_format: '', + saved_search_id: '', + limit: 10, + excel: true, + }, + }, + delivery: { + delivery_type: '', + delivery_params: {}, + }, + trigger: { + trigger_type: 'Schedule', + trigger_params: {}, + }, + }; + + handleDataToVisualReportSourceChange(reportDefinitionRequest); + expect( + reportDefinitionRequest.report_params.core_params.report_format + ).toBe('pdf'); + expect(reportDefinitionRequest.report_params.core_params).toMatchObject({ + report_format: 'pdf', + }); + }); +}); diff --git a/public/components/report_definitions/report_settings/index.ts b/public/components/report_definitions/report_settings/index.ts new file mode 100644 index 00000000..45e87d4a --- /dev/null +++ b/public/components/report_definitions/report_settings/index.ts @@ -0,0 +1,16 @@ +/* + * Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT 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 { ReportSettings } from './report_settings'; diff --git a/public/components/report_definitions/report_settings/report_settings.tsx b/public/components/report_definitions/report_settings/report_settings.tsx new file mode 100644 index 00000000..8fa8bb0e --- /dev/null +++ b/public/components/report_definitions/report_settings/report_settings.tsx @@ -0,0 +1,741 @@ +/* + * Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES 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 } from 'react'; +import { + EuiFieldText, + EuiFlexGroup, + EuiFlexItem, + EuiFormRow, + EuiPageHeader, + EuiTitle, + EuiPageContent, + EuiPageContentBody, + EuiHorizontalRule, + EuiText, + EuiSpacer, + EuiRadioGroup, + EuiSelect, + EuiTextArea, + EuiCheckboxGroup, + EuiComboBox +} from '@elastic/eui'; +import { + REPORT_SOURCE_RADIOS, + PDF_PNG_FILE_FORMAT_OPTIONS, + HEADER_FOOTER_CHECKBOX, + REPORT_SOURCE_TYPES, +} from './report_settings_constants'; +import Showdown from 'showdown'; +import ReactMde from 'react-mde'; +import 'react-mde/lib/styles/css/react-mde-all.css'; +import { + reportDefinitionParams, + timeRangeParams, +} from '../create/create_report_definition'; +import { + parseInContextUrl, + getSavedSearchBaseUrlCreate, + getVisualizationBaseUrlCreate, + getSavedSearchOptions, + getVisualizationOptions, + getDashboardBaseUrlCreate, + getDashboardOptions, + handleDataToVisualReportSourceChange, +} from './report_settings_helpers'; +import { TimeRangeSelect } from './time_range'; +import { converter } from '../utils'; +import { ReportDefinitionSchemaType } from 'server/model'; + +type ReportSettingProps = { + edit: boolean; + editDefinitionId: string; + reportDefinitionRequest: reportDefinitionParams; + httpClientProps: any; + timeRange: timeRangeParams; + showSettingsReportNameError: boolean; + settingsReportNameErrorMessage: string; + showSettingsReportSourceError: boolean; + settingsReportSourceErrorMessage: string; + showTimeRangeError: boolean; +}; + +export function ReportSettings(props: ReportSettingProps) { + const { + edit, + editDefinitionId, + reportDefinitionRequest, + httpClientProps, + timeRange, + showSettingsReportNameError, + settingsReportNameErrorMessage, + showSettingsReportSourceError, + settingsReportSourceErrorMessage, + showTimeRangeError, + } = props; + + const [reportName, setReportName] = useState(''); + const [reportDescription, setReportDescription] = useState(''); + const [reportSourceId, setReportSourceId] = useState('dashboardReportSource'); + + const [dashboardSourceSelect, setDashboardSourceSelect] = useState([] as any); + const [dashboards, setDashboards] = useState([] as any); + + const [visualizationSourceSelect, setVisualizationSourceSelect] = useState([] as any); + const [visualizations, setVisualizations] = useState([] as any); + + const [savedSearchSourceSelect, setSavedSearchSourceSelect] = useState([] as any); + const [savedSearches, setSavedSearches] = useState([] as any); + + const [fileFormat, setFileFormat] = useState('pdf'); + + const handleDashboards = (e) => { + setDashboards(e); + }; + + const handleVisualizations = (e) => { + setVisualizations(e); + }; + + const handleSavedSearches = (e) => { + setSavedSearches(e); + }; + + const handleReportName = (e: { + target: { value: React.SetStateAction }; + }) => { + setReportName(e.target.value); + reportDefinitionRequest.report_params.report_name = e.target.value.toString(); + }; + + const handleReportDescription = (e: { + target: { value: React.SetStateAction }; + }) => { + setReportDescription(e.target.value); + reportDefinitionRequest.report_params.description = e.target.value.toString(); + }; + + const handleReportSource = (e: React.SetStateAction) => { + setReportSourceId(e); + let fromInContext = false; + if (window.location.href.includes('?')) { + fromInContext = true; + } + if (e === 'dashboardReportSource') { + reportDefinitionRequest.report_params.report_source = 'Dashboard'; + reportDefinitionRequest.report_params.core_params.base_url = + getDashboardBaseUrlCreate(edit, editDefinitionId, fromInContext) + + dashboards[0].value; + + // set params to visual report params after switch from saved search + handleDataToVisualReportSourceChange(reportDefinitionRequest); + setFileFormat('pdf'); + } else if (e === 'visualizationReportSource') { + reportDefinitionRequest.report_params.report_source = 'Visualization'; + reportDefinitionRequest.report_params.core_params.base_url = + getVisualizationBaseUrlCreate(edit, editDefinitionId, fromInContext) + + visualizations[0].value; + + // set params to visual report params after switch from saved search + handleDataToVisualReportSourceChange(reportDefinitionRequest); + setFileFormat('pdf'); + } else if (e === 'savedSearchReportSource') { + reportDefinitionRequest.report_params.report_source = 'Saved search'; + reportDefinitionRequest.report_params.core_params.base_url = + getSavedSearchBaseUrlCreate(edit, editDefinitionId, fromInContext) + + savedSearches[0].value; + reportDefinitionRequest.report_params.core_params.saved_search_id = + savedSearches[0].value; + reportDefinitionRequest.report_params.core_params.report_format = 'csv'; + reportDefinitionRequest.report_params.core_params.limit = 10000; + reportDefinitionRequest.report_params.core_params.excel = true; + } + }; + + const handleDashboardSelect = (e: string | any[]) => { + setDashboardSourceSelect(e); + + let fromInContext = false; + if (window.location.href.includes('?')) { + fromInContext = true; + } + + if (e.length > 0) { + reportDefinitionRequest.report_params.core_params.base_url = + getDashboardBaseUrlCreate(edit, editDefinitionId, fromInContext) + + e[0].value; + } + else { + reportDefinitionRequest.report_params.core_params.base_url = ""; + } + }; + + const handleVisualizationSelect = (e) => { + setVisualizationSourceSelect(e); + let fromInContext = false; + if (window.location.href.includes('?')) { + fromInContext = true; + } + + if (e.length > 0) { + reportDefinitionRequest.report_params.core_params.base_url = + getVisualizationBaseUrlCreate(edit, editDefinitionId, fromInContext) + + e[0].value; + } + else { + reportDefinitionRequest.report_params.core_params.base_url = ""; + } + }; + + const handleSavedSearchSelect = (e) => { + setSavedSearchSourceSelect(e); + let fromInContext = false; + if (window.location.href.includes('?')) { + fromInContext = true; + } + if (e.length > 0) { + reportDefinitionRequest.report_params.core_params.saved_search_id = + e[0].value; + + reportDefinitionRequest.report_params.core_params.base_url = + getSavedSearchBaseUrlCreate(edit, editDefinitionId, fromInContext) + + e[0].value; + } + else { + reportDefinitionRequest.report_params.core_params.base_url = ""; + } + }; + + const handleFileFormat = (e: React.SetStateAction) => { + setFileFormat(e); + reportDefinitionRequest.report_params.core_params.report_format = e.toString(); + }; + + const PDFandPNGFileFormats = () => { + return ( +
+ + + +
+ ); + }; + + const SettingsMarkdown = () => { + const [ + checkboxIdSelectHeaderFooter, + setCheckboxIdSelectHeaderFooter, + ] = useState({ ['header']: false, ['footer']: false }); + + const [footer, setFooter] = useState(''); + const [selectedTabFooter, setSelectedTabFooter] = React.useState< + 'write' | 'preview' + >('write'); + + const [header, setHeader] = useState(''); + const [selectedTabHeader, setSelectedTabHeader] = React.useState< + 'write' | 'preview' + >('write'); + + const handleHeader = (e) => { + setHeader(e); + reportDefinitionRequest.report_params.core_params.header = e; + }; + + const handleFooter = (e) => { + setFooter(e); + reportDefinitionRequest.report_params.core_params.footer = e; + }; + + const handleCheckboxHeaderFooter = (optionId) => { + const newCheckboxIdToSelectedMap = { + ...checkboxIdSelectHeaderFooter, + ...{ + [optionId]: !checkboxIdSelectHeaderFooter[optionId], + }, + }; + setCheckboxIdSelectHeaderFooter(newCheckboxIdToSelectedMap); + }; + + const showFooter = checkboxIdSelectHeaderFooter.footer ? ( + + + Promise.resolve(converter.makeHtml(markdown)) + } + /> + + ) : null; + + const showHeader = checkboxIdSelectHeaderFooter.header ? ( + + + Promise.resolve(converter.makeHtml(markdown)) + } + /> + + ) : null; + + useEffect(() => { + let unmounted = false; + if (edit) { + httpClientProps + .get(`../api/reporting/reportDefinitions/${editDefinitionId}`) + .then(async (response: {}) => { + const reportDefinition: ReportDefinitionSchemaType = + response.report_definition; + const { + report_params: { + core_params: { header, footer }, + }, + } = reportDefinition; + // set header/footer default + if (header) { + checkboxIdSelectHeaderFooter.header = true; + if (!unmounted) { + setHeader(header); + } + } + if (footer) { + checkboxIdSelectHeaderFooter.footer = true; + if (!unmounted) { + setFooter(footer); + } + } + }) + .catch((error: any) => { + console.error( + 'error in fetching report definition details:', + error + ); + }); + } else { + // keeps header/footer from re-rendering empty when other fields in Report Settings are changed + checkboxIdSelectHeaderFooter.header = + 'header' in reportDefinitionRequest.report_params.core_params; + checkboxIdSelectHeaderFooter.footer = + 'footer' in reportDefinitionRequest.report_params.core_params; + if (checkboxIdSelectHeaderFooter.header) { + setHeader(reportDefinitionRequest.report_params.core_params.header); + } + if (checkboxIdSelectHeaderFooter.footer) { + setFooter(reportDefinitionRequest.report_params.core_params.footer); + } + } + return () => { + unmounted = true; + }; + }, []); + + return ( +
+ + + {showHeader} + {showFooter} +
+ ); + }; + + const VisualReportFormatAndMarkdown = () => { + return ( +
+ + +
+ ); + }; + + const setReportSourceDropdownOption = (options, reportSource, url) => { + let index = 0; + if (reportSource === REPORT_SOURCE_TYPES.dashboard) { + for (index = 0; index < options.dashboard.length; ++index) { + if (url.includes(options.dashboard[index].value)) { + setDashboardSourceSelect([options.dashboard[index]]); + } + } + } else if (reportSource === REPORT_SOURCE_TYPES.visualization) { + for (index = 0; index < options.visualizations.length; ++index) { + if (url.includes(options.visualizations[index].value)) { + setVisualizationSourceSelect([options.visualizations[index]]); + } + } + } else if (reportSource === REPORT_SOURCE_TYPES.savedSearch) { + for (index = 0; index < options.savedSearch.length; ++index) { + if (url.includes(options.savedSearch[index].value)) { + setSavedSearchSourceSelect([options.savedSearch[index]]); + } + } + } + }; + + const setDefaultFileFormat = (fileFormat) => { + let index = 0; + for (index = 0; index < PDF_PNG_FILE_FORMAT_OPTIONS.length; ++index) { + if ( + fileFormat.toUpperCase() === PDF_PNG_FILE_FORMAT_OPTIONS[index].label + ) { + setFileFormat(PDF_PNG_FILE_FORMAT_OPTIONS[index].id); + } + } + }; + + const setDashboardFromInContextMenu = (response, id) => { + let index; + for (index = 0; index < response.dashboard.length; ++index) { + if (id === response.dashboard[index].value) { + setDashboardSourceSelect([response.dashboard[index]]); + } + } + } + + const setVisualizationFromInContextMenu = (response, id) => { + let index; + for (index = 0; index < response.visualizations.length; ++index) { + if (id === response.visualizations[index].value) { + setVisualizationSourceSelect([response.visualizations[index]]); + } + } + } + + const setSavedSearchFromInContextMenu = (response, id) => { + let index; + for (index = 0; index < response.savedSearch.length; ++index) { + if (id === response.savedSearch[index].value) { + setSavedSearchSourceSelect([response.savedSearch[index]]); + } + } + } + + const setInContextDefaultConfiguration = (response) => { + const url = window.location.href; + const id = parseInContextUrl(url, 'id'); + if (url.includes('dashboard')) { + setReportSourceId('dashboardReportSource'); + reportDefinitionRequest.report_params.report_source = + REPORT_SOURCE_RADIOS[0].label; + + setDashboardFromInContextMenu(response, id); + reportDefinitionRequest.report_params.core_params.base_url = + getDashboardBaseUrlCreate(edit, id, true) + id; + } else if (url.includes('visualize')) { + setReportSourceId('visualizationReportSource'); + reportDefinitionRequest.report_params.report_source = + REPORT_SOURCE_RADIOS[1].label; + + setVisualizationFromInContextMenu(response, id); + reportDefinitionRequest.report_params.core_params.base_url = + getVisualizationBaseUrlCreate(edit, editDefinitionId, true) + id; + } else if (url.includes('discover')) { + setReportSourceId('savedSearchReportSource'); + reportDefinitionRequest.report_params.core_params.report_format = 'csv'; + reportDefinitionRequest.report_params.core_params.saved_search_id = id; + reportDefinitionRequest.report_params.report_source = + REPORT_SOURCE_RADIOS[2].label; + + setSavedSearchFromInContextMenu(response, id) + reportDefinitionRequest.report_params.core_params.base_url = + getSavedSearchBaseUrlCreate(edit, editDefinitionId, true) + id; + } + }; + + const setDefaultEditValues = async (response, reportSourceOptions) => { + setReportName(response.report_definition.report_params.report_name); + setReportDescription(response.report_definition.report_params.description); + reportDefinitionRequest.report_params.report_name = + response.report_definition.report_params.report_name; + reportDefinitionRequest.report_params.description = + response.report_definition.report_params.description; + reportDefinitionRequest.report_params = + response.report_definition.report_params; + const reportSource = response.report_definition.report_params.report_source; + REPORT_SOURCE_RADIOS.map((radio) => { + if (radio.label === reportSource) { + setReportSourceId(radio.id); + reportDefinitionRequest.report_params.report_source = reportSource; + } + }); + setDefaultFileFormat( + response.report_definition.report_params.core_params.report_format + ); + setReportSourceDropdownOption( + reportSourceOptions, + reportSource, + response.report_definition.report_params.core_params.base_url + ); + }; + + const defaultConfigurationEdit = async (httpClientProps) => { + let editData = {}; + await httpClientProps + .get(`../api/reporting/reportDefinitions/${editDefinitionId}`) + .then(async (response: {}) => { + editData = response; + }) + .catch((error: any) => { + console.error('error in fetching report definition details:', error); + }); + return editData; + }; + + const defaultConfigurationCreate = async (httpClientProps) => { + let reportSourceOptions = { + dashboard: [], + visualizations: [], + savedSearch: [], + }; + reportDefinitionRequest.report_params.core_params.report_format = fileFormat; + await httpClientProps + .get('../api/reporting/getReportSource/dashboard') + .then(async (response) => { + let dashboardOptions = getDashboardOptions(response['hits']['hits']); + reportSourceOptions.dashboard = dashboardOptions; + handleDashboards(dashboardOptions); + if (!edit) { + reportDefinitionRequest.report_params.report_source = 'Dashboard'; + } + }) + .catch((error) => { + console.log('error when fetching dashboards:', error); + }); + + await httpClientProps + .get('../api/reporting/getReportSource/visualization') + .then(async (response) => { + let visualizationOptions = getVisualizationOptions( + response['hits']['hits'] + ); + reportSourceOptions.visualizations = visualizationOptions; + await handleVisualizations(visualizationOptions); + }) + .catch((error) => { + console.log('error when fetching visualizations:', error); + }); + + await httpClientProps + .get('../api/reporting/getReportSource/search') + .then(async (response) => { + let savedSearchOptions = getSavedSearchOptions( + response['hits']['hits'] + ); + reportSourceOptions.savedSearch = savedSearchOptions; + await handleSavedSearches(savedSearchOptions); + }) + .catch((error) => { + console.log('error when fetching saved searches:', error); + }); + return reportSourceOptions; + }; + + useEffect(() => { + let reportSourceOptions = {}; + let editData = {}; + if (edit) { + defaultConfigurationEdit(httpClientProps).then(async (response) => { + editData = response; + }); + } + defaultConfigurationCreate(httpClientProps).then(async (response) => { + reportSourceOptions = response; + // if coming from in-context menu + if (window.location.href.indexOf('?') > -1) { + setInContextDefaultConfiguration(response); + } + if (edit) { + setDefaultEditValues(editData, reportSourceOptions); + } + }); + }, []); + + const displayDashboardSelect = + reportSourceId === 'dashboardReportSource' ? ( + ( +
+ + + + +
+ ) + ) : null; + + const displayVisualizationSelect = + reportSourceId === 'visualizationReportSource' ? ( + ( +
+ + + + +
+ ) + ) : null; + + const displaySavedSearchSelect = + reportSourceId === 'savedSearchReportSource' ? ( + ( +
+ + + + +
+ ) + ) : null; + + const displayVisualReportsFormatAndMarkdown = + reportSourceId != 'savedSearchReportSource' ? ( +
+ + +
+ ) : ( +
+ + +

CSV

+
+
+
+ ); + + + + return ( + + + +

Report Settings

+
+
+ + + + + + + + + + + + + + + + + + + + + + {displayDashboardSelect} + {displayVisualizationSelect} + {displaySavedSearchSelect} + + + {displayVisualReportsFormatAndMarkdown} + +
+ ); +} diff --git a/public/components/report_definitions/report_settings/report_settings_constants.tsx b/public/components/report_definitions/report_settings/report_settings_constants.tsx new file mode 100644 index 00000000..edad8b43 --- /dev/null +++ b/public/components/report_definitions/report_settings/report_settings_constants.tsx @@ -0,0 +1,90 @@ +/* + * Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT 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 REPORT_SOURCE_RADIOS = [ + { + id: 'dashboardReportSource', + label: 'Dashboard', + }, + { + id: 'visualizationReportSource', + label: 'Visualization', + }, + { + id: 'savedSearchReportSource', + label: 'Saved search', + }, +]; + +export const PDF_PNG_FILE_FORMAT_OPTIONS = [ + { + id: 'pdf', + label: 'PDF', + }, + { + id: 'png', + label: 'PNG', + }, +]; + +export const SAVED_SEARCH_FORMAT_OPTIONS = [ + { + id: 'csvFormat', + label: 'CSV', + }, + { + id: 'xlsFormat', + label: 'XLS', + }, +]; + +export const HEADER_FOOTER_CHECKBOX = [ + { + id: 'header', + label: 'Add header', + }, + { + id: 'footer', + label: 'Add footer', + }, +]; +export const REPORT_SOURCE_TYPES = { + dashboard: 'Dashboard', + visualization: 'Visualization', + savedSearch: 'Saved search', +}; + +export const commonTimeRanges = [ + { + start: 'now/d', + end: 'now', + label: 'Today so far' + }, + { + start: 'now/w', + end: 'now', + label: 'Week to date' + }, + { + start: 'now/M', + end: 'now', + label: 'Month to date' + }, + { + start: 'now/y', + end: 'now', + label: 'Year to date' + } +] \ No newline at end of file diff --git a/public/components/report_definitions/report_settings/report_settings_helpers.tsx b/public/components/report_definitions/report_settings/report_settings_helpers.tsx new file mode 100644 index 00000000..0e80a56d --- /dev/null +++ b/public/components/report_definitions/report_settings/report_settings_helpers.tsx @@ -0,0 +1,149 @@ +/* + * Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT 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 parseInContextUrl = (url: string, parameter: string) => { + const info = url.split('?'); + if (parameter === 'id') { + return info[1].substring(info[1].indexOf(':') + 1, info[1].length); + } else if (parameter === 'timeFrom') { + return info[2].substring(info[2].indexOf('=') + 1, info[2].length); + } else if (parameter === 'timeTo') { + return info[3].substring(info[3].indexOf('=') + 1, info[3].length); + } + return 'error: invalid parameter'; +}; + +export const getDashboardBaseUrlCreate = ( + edit: boolean, + editDefinitionId: string, + fromInContext: boolean +) => { + let baseUrl; + if (!fromInContext) { + baseUrl = location.pathname + location.hash; + } else { + baseUrl = '/app/dashboards#/view/'; + } + if (edit) { + return baseUrl.replace( + `opendistro_kibana_reports#/edit/${editDefinitionId}`, + 'dashboards#/view/' + ); + } else if (fromInContext) { + return baseUrl; + } + return baseUrl.replace( + 'opendistro_kibana_reports#/create', + 'dashboards#/view/' + ); +}; + +export const getVisualizationBaseUrlCreate = ( + edit: boolean, + editDefinitionId: string, + fromInContext: boolean +) => { + let baseUrl; + if (!fromInContext) { + baseUrl = location.pathname + location.hash; + } else { + baseUrl = '/app/visualize#/edit/'; + } + if (edit) { + return baseUrl.replace( + `opendistro_kibana_reports#/edit/${editDefinitionId}`, + 'visualize#/edit/' + ); + } else if (fromInContext) { + return baseUrl; + } + return baseUrl.replace( + 'opendistro_kibana_reports#/create', + 'visualize#/edit/' + ); +}; + +export const getSavedSearchBaseUrlCreate = ( + edit: boolean, + editDefinitionId: string, + fromInContext: boolean +) => { + let baseUrl; + if (!fromInContext) { + baseUrl = location.pathname + location.hash; + } else { + baseUrl = '/app/discover#/view/'; + } + if (edit) { + return baseUrl.replace( + `opendistro_kibana_reports#/edit/${editDefinitionId}`, + 'discover#/view/' + ); + } else if (fromInContext) { + return baseUrl; + } + return baseUrl.replace( + 'opendistro_kibana_reports#/create', + 'discover#/view/' + ); +}; + +export const getDashboardOptions = (data) => { + let index; + let dashboard_options = []; + for (index = 0; index < data.length; ++index) { + let entry = { + value: data[index]['_id'].substring(10), + label: data[index]['_source']['dashboard']['title'], + }; + dashboard_options.push(entry); + } + return dashboard_options; +}; + +export const getVisualizationOptions = (data: string | any[]) => { + let index; + let options = []; + for (index = 0; index < data.length; ++index) { + let entry = { + value: data[index]['_id'].substring(14), + label: data[index]['_source']['visualization']['title'], + }; + options.push(entry); + } + return options; +}; + +export const getSavedSearchOptions = (data: string | any[]) => { + let index; + let options = []; + for (index = 0; index < data.length; ++index) { + let entry = { + value: data[index]['_id'].substring(7), + label: data[index]['_source']['search']['title'], + }; + options.push(entry); + } + return options; +}; + +export const handleDataToVisualReportSourceChange = ( + reportDefinitionRequest +) => { + delete reportDefinitionRequest.report_params.core_params.saved_search_id; + delete reportDefinitionRequest.report_params.core_params.limit; + delete reportDefinitionRequest.report_params.core_params.excel; + reportDefinitionRequest.report_params.core_params.report_format = 'pdf'; +}; diff --git a/public/components/report_definitions/report_settings/time_range.tsx b/public/components/report_definitions/report_settings/time_range.tsx new file mode 100644 index 00000000..f5517731 --- /dev/null +++ b/public/components/report_definitions/report_settings/time_range.tsx @@ -0,0 +1,225 @@ +/* + * Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +import moment from 'moment'; +import React, { useState, useEffect } from 'react'; +import { parseInContextUrl } from './report_settings_helpers'; +import dateMath from '@elastic/datemath'; +import { + EuiFormRow, + EuiGlobalToastList, + EuiSuperDatePicker, +} from '@elastic/eui'; +import { commonTimeRanges } from './report_settings_constants'; + +export function TimeRangeSelect(props) { + const { + reportDefinitionRequest, + timeRange, + edit, + id, + httpClientProps, + showTimeRangeError, + } = props; + + const [recentlyUsedRanges, setRecentlyUsedRanges] = useState([]); + const [isLoading, setIsLoading] = useState(false); + const [start, setStart] = useState('now-30m'); + const [end, setEnd] = useState('now'); + + const [toasts, setToasts] = useState([]); + + const addInvalidTimeRangeToastHandler = () => { + const errorToast = { + title: 'Invalid time range selected', + color: 'danger', + iconType: 'alert', + id: 'timeRangeErrorToast', + }; + setToasts(toasts.concat(errorToast)); + }; + + const handleInvalidTimeRangeToast = () => { + addInvalidTimeRangeToastHandler(); + }; + + const removeToast = (removedToast) => { + setToasts(toasts.filter((toast) => toast.id !== removedToast.id)); + }; + + const isValidTimeRange = ( + timeRangeMoment: number | moment.Moment, + limit: string, + handleInvalidTimeRangeToast: any + ) => { + if (limit === 'start') { + if (!timeRangeMoment || !timeRangeMoment.isValid()) { + handleInvalidTimeRangeToast(); + } + } else if (limit === 'end') { + if ( + !timeRangeMoment || + !timeRangeMoment.isValid() || + timeRangeMoment > moment.now() + ) { + handleInvalidTimeRangeToast(); + } + } + }; + + const setDefaultEditTimeRange = (duration, unmounted) => { + let time_difference = moment.now() - duration; + const fromDate = new Date(time_difference); + parseTimeRange(fromDate, end, reportDefinitionRequest); + if (!unmounted) { + setStart(fromDate.toISOString()); + setEnd(end); + } + }; + + // valid time range check for absolute time end date + const checkValidAbsoluteEndDate = (end) => { + let endDate = new Date(end); + let nowDate = new Date(moment.now()); + let valid = true; + if (endDate.getTime() > nowDate.getTime()) { + end = 'now'; + valid = false; + } + return valid; + }; + + useEffect(() => { + let unmounted = false; + // if we are coming from the in-context menu + if (window.location.href.indexOf('?') > -1) { + const url = window.location.href; + const timeFrom = parseInContextUrl(url, 'timeFrom'); + const timeTo = parseInContextUrl(url, 'timeTo'); + parseTimeRange(timeFrom, timeTo, reportDefinitionRequest); + if (!unmounted) { + setStart(timeFrom); + setEnd(timeTo); + } + } else { + if (edit) { + httpClientProps + .get(`../api/reporting/reportDefinitions/${id}`) + .then(async (response: {}) => { + let duration = + response.report_definition.report_params.core_params + .time_duration; + duration = moment.duration(duration); + setDefaultEditTimeRange(duration, unmounted); + }) + .catch((error) => { + console.error( + 'error in fetching report definition details:', + error + ); + }); + } else { + parseTimeRange(start, end, reportDefinitionRequest); + } + } + return () => { + unmounted = true; + }; + }, []); + + const onTimeChange = ({ start, end }) => { + isValidTimeRange( + dateMath.parse(start), + 'start', + handleInvalidTimeRangeToast + ); + isValidTimeRange( + dateMath.parse(end, { roundUp: true }), + 'end', + handleInvalidTimeRangeToast + ); + + const recentlyUsedRange = recentlyUsedRanges.filter((recentlyUsedRange) => { + const isDuplicate = + recentlyUsedRange.start === start && recentlyUsedRange.end === end; + return !isDuplicate; + }); + const validEndDate = checkValidAbsoluteEndDate(end); + if (!validEndDate) { + handleInvalidTimeRangeToast(); + return; + } + + recentlyUsedRange.unshift({ start, end }); + setStart(start); + setEnd(end); + setRecentlyUsedRanges( + recentlyUsedRange.length > 10 + ? recentlyUsedRange.slice(0, 9) + : recentlyUsedRange + ); + setIsLoading(true); + startLoading(); + parseTimeRange(start, end, reportDefinitionRequest); + }; + + const parseTimeRange = (start, end, reportDefinitionRequest) => { + timeRange.timeFrom = dateMath.parse(start); + timeRange.timeTo = dateMath.parse(end); + const timeDuration = moment.duration( + dateMath.parse(end).diff(dateMath.parse(start)) + ); + reportDefinitionRequest.report_params.core_params.time_duration = timeDuration.toISOString(); + }; + + const startLoading = () => { + setTimeout(stopLoading, 1000); + }; + + const stopLoading = () => { + setIsLoading(false); + }; + + + return ( +
+
+ + + +
+
+ +
+
+ ); +} diff --git a/public/components/report_definitions/report_trigger/__tests__/__snapshots__/report_trigger.test.tsx.snap b/public/components/report_definitions/report_trigger/__tests__/__snapshots__/report_trigger.test.tsx.snap new file mode 100644 index 00000000..1f9f20a9 --- /dev/null +++ b/public/components/report_definitions/report_trigger/__tests__/__snapshots__/report_trigger.test.tsx.snap @@ -0,0 +1,529 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[` panel Render edit on-demand component 1`] = ` +
+
+

+ Report trigger +

+
+
+
+
+
+ +
+
+
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+`; + +exports[` panel render create component 1`] = ` +
+
+

+ Report trigger +

+
+
+
+
+
+ +
+
+
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+`; + +exports[` panel render edit Cron schedule component 1`] = ` +
+
+

+ Report trigger +

+
+
+
+
+
+ +
+
+
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+`; + +exports[` panel render edit recurring 5 hours schedule component 1`] = ` +
+
+

+ Report trigger +

+
+
+
+
+
+ +
+
+
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+`; + +exports[` panel render edit recurring 10 minutes schedule component 1`] = ` +
+
+

+ Report trigger +

+
+
+
+
+
+ +
+
+
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+`; + +exports[` panel render edit recurring daily schedule component 1`] = ` +
+
+

+ Report trigger +

+
+
+
+
+
+ +
+
+
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+`; diff --git a/public/components/report_definitions/report_trigger/__tests__/report_trigger.test.tsx b/public/components/report_definitions/report_trigger/__tests__/report_trigger.test.tsx new file mode 100644 index 00000000..7f5c75fe --- /dev/null +++ b/public/components/report_definitions/report_trigger/__tests__/report_trigger.test.tsx @@ -0,0 +1,390 @@ +/* + * Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES 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, + waitFor, + waitForElement, + waitForElementToBeRemoved, +} from '@testing-library/react'; +import { ReportTrigger } from '../report_trigger'; +import 'babel-polyfill'; +import 'regenerator-runtime'; +import httpClientMock from '../../../../../test/httpMockClient'; +import { act } from 'react-dom/test-utils'; +import moment from 'moment-timezone'; + +const names = jest.fn(); + +const emptyRequest = { + report_params: { + report_name: '', + report_source: '', + description: '', + core_params: { + base_url: '', + report_format: '', + time_duration: '', + }, + }, + delivery: { + delivery_type: '', + delivery_params: {}, + }, + trigger: { + trigger_type: '', + trigger_params: {}, + }, + time_created: 0, + last_updated: 0, + status: '', +}; + +describe(' panel', () => { + beforeEach(() => { + jest.clearAllMocks(); + }); + test('render create component', () => { + let createReportDefinitionRequest = { + report_params: { + report_name: 'test create report definition trigger', + report_source: 'Dashboard', + description: '', + core_params: { + base_url: '', + report_format: '', + header: '', + footer: '', + time_duration: '', + }, + }, + delivery: { + delivery_type: '', + delivery_params: {}, + }, + trigger: { + trigger_type: 'Schedule', + trigger_params: {}, + }, + }; + + let timeRange = { + timeFrom: new Date(), + timeTo: new Date(), + }; + + const { container } = render( + + ); + + expect(container.firstChild).toMatchSnapshot(); + }); + + // edit test + test('render edit recurring 5 hours schedule component', async () => { + const promise = Promise.resolve(); + let report_definition = { + report_params: { + report_name: 'test create report definition trigger', + report_source: 'Dashboard', + description: '', + core_params: { + base_url: '', + report_format: '', + header: '', + footer: '', + time_duration: '', + }, + }, + delivery: { + delivery_type: '', + delivery_params: {}, + }, + trigger: { + trigger_type: 'Schedule', + trigger_params: { + schedule_type: 'Recurring', + schedule: { + interval: { + period: 5, + unit: 'HOURS', + timezone: 'PST8PDT', + }, + }, + enabled_time: 1114939203, + enabled: true, + }, + }, + }; + + let timeRange = { + timeFrom: new Date(), + timeTo: new Date(), + }; + + httpClientMock.get = jest.fn().mockResolvedValue({ + report_definition, + }); + + const { container } = render( + + ); + + expect(container.firstChild).toMatchSnapshot(); + await act(() => promise); + }); + + test('render edit recurring daily schedule component', async () => { + const promise = Promise.resolve(); + let editReportDefinitionRequest = { + report_params: { + report_name: 'test create report definition trigger', + report_source: 'Dashboard', + description: '', + core_params: { + base_url: '', + report_format: '', + header: '', + footer: '', + time_duration: '', + }, + }, + delivery: { + delivery_type: '', + delivery_params: {}, + }, + trigger: { + trigger_type: 'Schedule', + trigger_params: { + schedule_type: 'Recurring', + schedule: { + interval: { + period: 1, + unit: 'DAYS', + start_time: 1114939203, + }, + }, + enabled_time: 1114939203, + enabled: true, + }, + }, + }; + + let timeRange = { + timeFrom: new Date(), + timeTo: new Date(), + }; + + httpClientMock.get = jest.fn().mockResolvedValue({ + report_definition: editReportDefinitionRequest, + }); + + const { container } = render( + + ); + + expect(container.firstChild).toMatchSnapshot(); + await act(() => promise); + }); + + test('render edit Cron schedule component', async () => { + const promise = Promise.resolve(); + let cronReportDefinitionRequest = { + report_params: { + report_name: 'edit cron schedule component', + report_source: 'Dashboard', + description: '', + core_params: { + base_url: '', + report_format: '', + header: '', + footer: '', + time_duration: '', + }, + }, + delivery: { + delivery_type: '', + delivery_params: {}, + }, + trigger: { + trigger_type: 'Schedule', + trigger_params: { + schedule_type: 'Cron based', + schedule: { + cron: { + expression: '30 1 * * *', + timezone: 'PDT', + }, + }, + enabled_time: 1234567890, + enabled: true, + }, + }, + }; + + let timeRange = { + timeFrom: new Date(), + timeTo: new Date(), + }; + + httpClientMock.get = jest.fn().mockResolvedValue({ + report_definition: cronReportDefinitionRequest, + }); + + const { container } = render( + + ); + + expect(container.firstChild).toMatchSnapshot(); + await act(() => promise); + }); + + test('render edit recurring 10 minutes schedule component', async () => { + const promise = Promise.resolve(); + let editReportDefinitionRequest = { + report_params: { + report_name: 'test create report definition trigger', + report_source: 'Dashboard', + description: '', + core_params: { + base_url: '', + report_format: '', + header: '', + footer: '', + time_duration: '', + }, + }, + delivery: { + delivery_type: '', + delivery_params: {}, + }, + trigger: { + trigger_type: 'Schedule', + trigger_params: { + schedule_type: 'Recurring', + schedule: { + interval: { + period: 10, + unit: 'MINUTES', + start_time: 1114939203, + }, + }, + enabled_time: 1114939203, + enabled: true, + }, + }, + }; + + let timeRange = { + timeFrom: new Date(), + timeTo: new Date(), + }; + + httpClientMock.get = jest.fn().mockResolvedValue({ + report_definition: editReportDefinitionRequest, + }); + + const { container } = render( + + ); + + expect(container.firstChild).toMatchSnapshot(); + await act(() => promise); + }); + + test('Render edit on-demand component', async () => { + const promise = Promise.resolve(); + let editReportDefinitionRequest = { + report_params: { + report_name: 'edit cron schedule component', + report_source: 'Dashboard', + description: '', + core_params: { + base_url: '', + report_format: '', + header: '', + footer: '', + time_duration: '', + }, + }, + delivery: { + delivery_type: '', + delivery_params: {}, + }, + trigger: { + trigger_type: 'On demand', + }, + }; + + let timeRange = { + timeFrom: new Date(), + timeTo: new Date(), + }; + + httpClientMock.get = jest.fn().mockResolvedValue({ + report_definition: editReportDefinitionRequest, + }); + + const { container } = render( + + ); + + expect(container.firstChild).toMatchSnapshot(); + await act(() => promise); + }); +}); diff --git a/public/components/report_definitions/report_trigger/index.ts b/public/components/report_definitions/report_trigger/index.ts new file mode 100644 index 00000000..9fb2aaab --- /dev/null +++ b/public/components/report_definitions/report_trigger/index.ts @@ -0,0 +1,16 @@ +/* + * Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT 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 { ReportTrigger } from './report_trigger'; diff --git a/public/components/report_definitions/report_trigger/report_trigger.tsx b/public/components/report_definitions/report_trigger/report_trigger.tsx new file mode 100644 index 00000000..53320af1 --- /dev/null +++ b/public/components/report_definitions/report_trigger/report_trigger.tsx @@ -0,0 +1,672 @@ +/* + * Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES 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 } from 'react'; +import { + EuiPageHeader, + EuiTitle, + EuiPageContent, + EuiPageContentBody, + EuiHorizontalRule, + EuiFormRow, + EuiRadioGroup, + EuiDatePicker, + EuiSelect, + EuiSpacer, + EuiFlexGroup, + EuiFlexItem, + EuiText, + EuiFieldText, + EuiCheckboxGroup, + EuiTextArea, + EuiLink, + EuiButton, + EuiFieldNumber, +} from '@elastic/eui'; +import moment, { Moment } from 'moment'; +import { reportDefinitionParams } from '../create/create_report_definition'; +import { + SCHEDULE_RECURRING_OPTIONS, + INTERVAL_TIME_PERIODS, + WEEKLY_CHECKBOX_OPTIONS, + MONTHLY_ON_THE_OPTIONS, + TRIGGER_TYPE_OPTIONS, + SCHEDULE_TYPE_OPTIONS, + TIMEZONE_OPTIONS, +} from './report_trigger_constants'; +import { TimezoneSelect } from './timezone'; + +type ReportTriggerProps = { + edit: boolean; + editDefinitionId: string; + reportDefinitionRequest: reportDefinitionParams; + httpClientProps: any; + showTriggerIntervalNaNError: boolean; + showCronError: boolean; +}; + +export function ReportTrigger(props: ReportTriggerProps) { + const { + edit, + editDefinitionId, + reportDefinitionRequest, + httpClientProps, + showTriggerIntervalNaNError, + showCronError, + } = props; + + const [reportTriggerType, setReportTriggerType] = useState( + TRIGGER_TYPE_OPTIONS[0].id + ); + + const [scheduleType, setScheduleType] = useState( + SCHEDULE_TYPE_OPTIONS[0].label + ); + //TODO: should read local timezone and display + const [scheduleRecurringFrequency, setScheduleRecurringFrequency] = useState( + 'daily' + ); + const [recurring, setRecurringTime] = useState(moment()); + + const [weeklyCheckbox, setWeeklyCheckbox] = useState({ + ['monCheckbox']: true, + }); + const [monthlySelect, setMonthlySelect] = useState( + MONTHLY_ON_THE_OPTIONS[0].value + ); + + const handleReportTriggerType = (e: string) => { + setReportTriggerType(e); + reportDefinitionRequest.trigger.trigger_type = e; + if (e === 'On demand') { + delete reportDefinitionRequest.trigger.trigger_params; + } + }; + + const handleScheduleType = (e: React.SetStateAction) => { + setScheduleType(e); + if (e === SCHEDULE_TYPE_OPTIONS[1].label) { + delete reportDefinitionRequest.trigger.trigger_params.schedule.interval; + } else if (e === SCHEDULE_TYPE_OPTIONS[0].label) { + delete reportDefinitionRequest.trigger.trigger_params.schedule.cron; + } + }; + + const handleScheduleRecurringFrequency = (e: { + target: { value: React.SetStateAction }; + }) => { + setScheduleRecurringFrequency(e.target.value); + reportDefinitionRequest.trigger.trigger_params.schedule_type = + e.target.value; + }; + + const handleRecurringTime = (e: React.SetStateAction) => { + setRecurringTime(e); + }; + + const handleWeeklyCheckbox = (e) => { + const newCheckboxIdToSelectedMap = { + ...weeklyCheckbox, + ...{ + [e]: !weeklyCheckbox[e], + }, + }; + setWeeklyCheckbox(newCheckboxIdToSelectedMap); + }; + + const handleMonthlySelect = (e: { + target: { value: React.SetStateAction }; + }) => { + setMonthlySelect(e.target.value); + }; + + const RequestTime = () => { + useEffect(() => { + let recurringDaily = { + interval: { + period: 1, + unit: 'DAYS', + start_time: recurring.valueOf(), + }, + }; + reportDefinitionRequest.trigger.trigger_params = { + ...reportDefinitionRequest.trigger.trigger_params, + enabled_time: recurring.valueOf(), + schedule: recurringDaily, + }; + }, []); + + return ( +
+ + + + +
+ ); + }; + + const RecurringDaily = () => { + const [recurringDailyTime, setRecurringDailyTime] = useState(moment()); + + const handleRecurringDailyTime = (e) => { + setRecurringDailyTime(e); + reportDefinitionRequest.trigger.trigger_params.schedule.interval.start_time = e.valueOf(); + }; + + const setDailyParams = () => { + let recurringDaily = { + interval: { + period: 1, + unit: 'DAYS', + start_time: recurringDailyTime.valueOf(), + }, + }; + reportDefinitionRequest.trigger.trigger_params = { + ...reportDefinitionRequest.trigger.trigger_params, + enabled_time: recurringDailyTime.valueOf(), + schedule: recurringDaily, + }; + }; + + const isDailySchedule = (response) => { + return ( + response.report_definition.trigger.trigger_params.schedule_type === + SCHEDULE_TYPE_OPTIONS[0].id && + response.report_definition.trigger.trigger_params.schedule.interval + .period === 1 && + response.report_definition.trigger.trigger_params.schedule.interval === + 'DAYS' + ); + }; + + useEffect(() => { + let unmounted = false; + if (edit) { + httpClientProps + .get(`../api/reporting/reportDefinitions/${editDefinitionId}`) + .then(async (response) => { + // if switching from on demand to schedule + if ( + response.report_definition.trigger.trigger_type === 'On demand' + ) { + setDailyParams(); + } else if (isDailySchedule(response)) { + const date = moment( + response.report_definition.trigger.trigger_params.schedule + .interval.start_time + ); + if (!unmounted) { + setRecurringDailyTime(date); + } + } + // if switching from on-demand to schedule + else if ( + reportDefinitionRequest.trigger.trigger_params.schedule_type === + SCHEDULE_TYPE_OPTIONS[0].id + ) { + setDailyParams(); + } + }); + } else { + setDailyParams(); + } + return () => { + unmounted = true; + }; + }, []); + + return ( +
+ + + + +
+ ); + }; + + const RecurringInterval = () => { + const [intervalText, setIntervalText] = useState(''); + const [intervalTimePeriod, setIntervalTimePeriod] = useState( + INTERVAL_TIME_PERIODS[0].value + ); + const [recurringIntervalTime, setRecurringIntervalTime] = useState( + moment() + ); + + const handleRecurringIntervalTime = (e) => { + setRecurringIntervalTime(e); + reportDefinitionRequest.trigger.trigger_params.schedule.interval.start_time = e.valueOf(); + }; + + const handleIntervalText = (e: { + target: { value: React.SetStateAction }; + }) => { + setIntervalText(e.target.value); + }; + + const handleIntervalTimePeriod = (e: { + target: { value: React.SetStateAction }; + }) => { + setIntervalTimePeriod(e.target.value); + }; + + useEffect(() => { + let interval = { + interval: { + period: parseInt(intervalText, 10), + unit: intervalTimePeriod, + start_time: recurringIntervalTime.valueOf(), + }, + }; + reportDefinitionRequest.trigger.trigger_params = { + ...reportDefinitionRequest.trigger.trigger_params, + enabled_time: recurringIntervalTime.valueOf(), + schedule: interval, + }; + }, [intervalTimePeriod, intervalText]); + + // second useEffect() only to be triggered before render when on Edit + useEffect(() => { + let unmounted = false; + if (edit) { + httpClientProps + .get(`../api/reporting/reportDefinitions/${editDefinitionId}`) + .then(async (response) => { + if ( + response.report_definition.trigger.trigger_params + .schedule_type === SCHEDULE_TYPE_OPTIONS[0].id + ) { + const date = moment( + response.report_definition.trigger.trigger_params.schedule + .interval.start_time + ); + if (!unmounted) { + setRecurringIntervalTime(date); + setIntervalText( + response.report_definition.trigger.trigger_params.schedule.interval.period.toString() + ); + setIntervalTimePeriod( + response.report_definition.trigger.trigger_params.schedule + .interval.unit + ); + } + } + }); + } + return () => { + unmounted = true; + }; + }, []); + + return ( +
+ + + + + + + + + + + + + + + +
+ ); + }; + + const RecurringWeekly = () => { + return ( +
+ + + + + +
+ ); + }; + + const RecurringMonthly = () => { + const [monthlyDayNumber, setMonthlyDayNumber] = useState(''); + + const handleMonthlyDayNumber = (e: { + target: { value: React.SetStateAction }; + }) => { + setMonthlyDayNumber(e.target.value); + }; + + return ( +
+ + + + + + + + + + + + +
+ ); + }; + + const CronExpression = () => { + const [cronExpression, setCronExpression] = useState(''); + + const handleCronExpression = (e: { + target: { value: React.SetStateAction }; + }) => { + setCronExpression(e.target.value); + reportDefinitionRequest.trigger.trigger_params.schedule.cron.expression = + e.target.value; + }; + + const setCronParams = () => { + let cron = { + cron: { + expression: '', + timezone: TIMEZONE_OPTIONS[0].value, + }, + }; + reportDefinitionRequest.trigger.trigger_params = { + ...reportDefinitionRequest.trigger.trigger_params, + enabled_time: Date.now().valueOf(), + schedule: cron, + }; + }; + + useEffect(() => { + if (edit) { + httpClientProps + .get(`../api/reporting/reportDefinitions/${editDefinitionId}`) + .then(async (response) => { + // if switching from on demand to schedule + if ( + response.report_definition.trigger.trigger_type === 'On demand' + ) { + setCronParams(); + } else if ( + response.report_definition.trigger.trigger_params + .schedule_type === SCHEDULE_TYPE_OPTIONS[1].id + ) { + setCronExpression( + response.report_definition.trigger.trigger_params.schedule.cron + .expression + ); + } else { + setCronParams(); + } + }); + } else { + setCronParams(); + } + }, []); + + return ( +
+ + + Cron help + + + } + > + + + +
+ ); + }; + + const ScheduleTriggerRecurring = () => { + const display_daily = + scheduleRecurringFrequency === 'daily' ? : null; + + const display_interval = + scheduleRecurringFrequency === 'byInterval' ? ( + + ) : null; + + const display_weekly = + scheduleRecurringFrequency === 'weekly' ? : null; + + const display_monthly = + scheduleRecurringFrequency === 'monthly' ? : null; + + return ( +
+ + + + + {display_daily} + {display_interval} + {display_weekly} + {display_monthly} +
+ ); + }; + + const ScheduleTrigger = () => { + const display_recurring = + scheduleType === SCHEDULE_TYPE_OPTIONS[0].id ? ( + + ) : null; + + const display_cron = + scheduleType === SCHEDULE_TYPE_OPTIONS[1].id ? ( +
+ + +
+ ) : null; + + useEffect(() => { + // Set default trigger_type + SCHEDULE_TYPE_OPTIONS.map((item) => { + if (item.id === scheduleType) { + reportDefinitionRequest.trigger.trigger_params = { + ...reportDefinitionRequest.trigger.trigger_params, + schedule_type: item.id, + //TODO: need better handle + }; + if (!edit) { + reportDefinitionRequest.trigger.trigger_params.enabled = true; + } + if (!('enabled' in reportDefinitionRequest.trigger.trigger_params)) { + reportDefinitionRequest.trigger.trigger_params.enabled = true; + } + } + }); + }, [scheduleType]); + + return ( +
+ + + + + {display_recurring} + {display_cron} +
+ ); + }; + + const schedule = + reportTriggerType === 'Schedule' ? : null; + + const defaultEditTriggerType = (trigger_type) => { + let index = 0; + for (index; index < TRIGGER_TYPE_OPTIONS.length; ++index) { + if (TRIGGER_TYPE_OPTIONS[index].id === trigger_type) { + setReportTriggerType(TRIGGER_TYPE_OPTIONS[index].id); + } + } + }; + + const defaultEditRequestType = (trigger) => { + let index = 0; + for (index; index < SCHEDULE_TYPE_OPTIONS.length; ++index) { + if ( + SCHEDULE_TYPE_OPTIONS[index].id === trigger.trigger_params.schedule_type + ) { + setScheduleType(SCHEDULE_TYPE_OPTIONS[index].id); + } + } + }; + + const defaultEditScheduleFrequency = (trigger_params) => { + if (trigger_params.schedule_type === SCHEDULE_TYPE_OPTIONS[0].id) { + if (trigger_params.schedule.interval.unit === 'Days' && + trigger_params.schedule.interval.period === 1) { + setScheduleRecurringFrequency('daily'); + } else { + setScheduleRecurringFrequency('byInterval'); + } + } + }; + + const defaultConfigurationEdit = (trigger) => { + defaultEditTriggerType(trigger.trigger_type); + if (trigger.trigger_type === 'Schedule') { + defaultEditScheduleFrequency(trigger.trigger_params); + defaultEditRequestType(trigger); + } else if (trigger.trigger_type == 'On demand') { + setReportTriggerType('On demand'); + reportDefinitionRequest.trigger.trigger_type = 'On demand'; + } + }; + + useEffect(() => { + if (edit) { + httpClientProps + .get(`../api/reporting/reportDefinitions/${editDefinitionId}`) + .then(async (response) => { + defaultConfigurationEdit(response.report_definition.trigger); + reportDefinitionRequest.trigger = response.report_definition.trigger; + }); + } + // Set default trigger_type for create new report definition + else { + TRIGGER_TYPE_OPTIONS.map((item) => { + if (item.id === reportTriggerType) { + reportDefinitionRequest.trigger.trigger_type = item.id; + } + }); + } + }, []); + + return ( + + + +

Report trigger

+
+
+ + + + + + + {schedule} + +
+ ); +} diff --git a/public/components/report_definitions/report_trigger/report_trigger_constants.tsx b/public/components/report_definitions/report_trigger/report_trigger_constants.tsx new file mode 100644 index 00000000..de5ecb5e --- /dev/null +++ b/public/components/report_definitions/report_trigger/report_trigger_constants.tsx @@ -0,0 +1,115 @@ +/* + * Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +import moment from 'moment-timezone'; + +export const TRIGGER_TYPE_OPTIONS = [ + { + id: 'On demand', + label: 'On demand', + }, + { + id: 'Schedule', + label: 'Schedule', + }, +]; + +export const SCHEDULE_TYPE_OPTIONS = [ + { + id: 'Recurring', + label: 'Recurring', + }, + { + id: 'Cron based', + label: 'Cron-based', + }, +]; + +export const SCHEDULE_RECURRING_OPTIONS = [ + { + value: 'daily', + text: 'Daily', + }, + { + value: 'byInterval', + text: 'By interval', + }, + // TODO: disable on UI. Add them back once we support +// { +// value: 'weekly', +// text: 'Weekly', +// }, +// { +// value: 'monthly', +// text: 'Monthly', +// }, +]; + +export const INTERVAL_TIME_PERIODS = [ + { + value: 'MINUTES', + text: 'Minutes', + }, + { + value: 'HOURS', + text: 'Hours', + }, + { + value: 'DAYS', + text: 'Days', + }, +]; + +export const WEEKLY_CHECKBOX_OPTIONS = [ + { + id: 'monCheckbox', + label: 'Mon', + }, + { + id: 'tueCheckbox', + label: 'Tue', + }, + { + id: 'wedCheckbox', + label: 'Wed', + }, + { + id: 'thuCheckbox', + label: 'Thu', + }, + { + id: 'friCheckbox', + label: 'Fri', + }, + { + id: 'satCheckbox', + label: 'Sat', + }, + { + id: 'sunCheckbox', + label: 'Sun', + }, +]; + +export const MONTHLY_ON_THE_OPTIONS = [ + { + value: 'day', + text: 'Day', + }, +]; + +export const TIMEZONE_OPTIONS = moment.tz + .names() + .map((tz) => ({ value: tz, text: tz })); diff --git a/public/components/report_definitions/report_trigger/timezone.tsx b/public/components/report_definitions/report_trigger/timezone.tsx new file mode 100644 index 00000000..597adb14 --- /dev/null +++ b/public/components/report_definitions/report_trigger/timezone.tsx @@ -0,0 +1,75 @@ +/* + * Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +import { EuiFormRow, EuiSelect } from '@elastic/eui'; +import React, { useState, useEffect } from 'react'; +import { TIMEZONE_OPTIONS } from './report_trigger_constants'; + +export function TimezoneSelect(props) { + const { + reportDefinitionRequest, + httpClientProps, + edit, + editDefinitionId, + } = props; + const [timezone, setTimezone] = useState(TIMEZONE_OPTIONS[0].value); + + const handleTimezone = (e) => { + setTimezone(e.target.value); + if ( + reportDefinitionRequest.trigger.trigger_params.schedule_type === + 'Cron based' + ) { + reportDefinitionRequest.trigger.trigger_params.schedule.cron.timezone = + e.target.value; + } + }; + + useEffect(() => { + let unmounted = false; + if (edit) { + httpClientProps + .get(`../api/reporting/reportDefinitions/${editDefinitionId}`) + .then(async (response) => { + if ( + !unmounted && + reportDefinitionRequest.trigger.trigger_params.schedule_type === + 'Cron based' + ) { + setTimezone( + response.report_definition.trigger.trigger_params.schedule.cron + .timezone + ); + } + }); + } + return () => { + unmounted = true; + }; + }, []); + + return ( +
+ + + +
+ ); +} diff --git a/public/components/report_definitions/utils/index.ts b/public/components/report_definitions/utils/index.ts new file mode 100644 index 00000000..8d36e1c3 --- /dev/null +++ b/public/components/report_definitions/utils/index.ts @@ -0,0 +1,24 @@ +/* + * Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +import Showdown from 'showdown'; + +export const converter = new Showdown.Converter({ + tables: true, + simplifiedAutoLink: true, + strikethrough: true, + tasklists: true, + noHeaderId: true, +}); diff --git a/public/components/report_definitions/utils/utils.tsx b/public/components/report_definitions/utils/utils.tsx new file mode 100644 index 00000000..d463a193 --- /dev/null +++ b/public/components/report_definitions/utils/utils.tsx @@ -0,0 +1,111 @@ +/* + * Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +import { isValidCron } from "cron-validator"; +import moment from "moment"; + + export const definitionInputValidation = async ( + metadata, + error, + setShowSettingsReportNameError, + setSettingsReportNameErrorMessage, + setShowSettingsReportSourceError, + setSettingsReportSourceErrorMessage, + setShowTriggerIntervalNaNError, + timeRange, + setShowTimeRangeError, + setShowCronError, + setShowEmailRecipientsError, + setEmailRecipientsErrorMessage + ) => { + // check report name + // allow a-z, A-Z, 0-9, (), [], ',' - and _ and spaces + let regexp = /^[\w\-\s\(\)\[\]\,\_\-+]+$/; + if (metadata.report_params.report_name.search(regexp) === -1) { + setShowSettingsReportNameError(true); + if (metadata.report_params.report_name === '') { + setSettingsReportNameErrorMessage('Name must not be empty.'); + } else { + setSettingsReportNameErrorMessage('Invalid characters in report name.'); + } + error = true; + } + + // if recurring by interval and input is not a number + if ( + metadata.trigger.trigger_type === 'Schedule' && + metadata.trigger.trigger_params.schedule_type === 'Recurring' + ) { + let interval = parseInt( + metadata.trigger.trigger_params.schedule.interval.period + ); + if (isNaN(interval)) { + setShowTriggerIntervalNaNError(true); + error = true; + } + } + + // if report source is blank + if (metadata.report_params.core_params.base_url === "") { + setShowSettingsReportSourceError(true); + setSettingsReportSourceErrorMessage('Report source must not be empty.'); + error = true; + } + + // if time range is invalid + const nowDate = new Date(moment.now()); + if (timeRange.timeFrom > timeRange.timeTo || timeRange.timeTo > nowDate) { + setShowTimeRangeError(true); + error = true; + } + + // if cron based and cron input is invalid + if ( + metadata.trigger.trigger_type === 'Schedule' && + metadata.trigger.trigger_params.schedule_type === 'Cron based' + ) { + if ( + !isValidCron(metadata.trigger.trigger_params.schedule.cron.expression) + ) { + setShowCronError(true); + error = true; + } + } + // if email delivery + if (metadata.delivery.delivery_type === 'Channel') { + // no recipients are listed + if (metadata.delivery.delivery_params.recipients.length === 0) { + setShowEmailRecipientsError(true); + setEmailRecipientsErrorMessage( + 'Email recipients list cannot be empty.' + ); + error = true; + } + // recipients have invalid email addresses: regexp checks format xxxxx@yyyy.zzz + let emailRegExp = /\S+@\S+\.\S+/; + let index; + let recipients = metadata.delivery.delivery_params.recipients; + for (index = 0; index < recipients.length; ++index) { + if (recipients[0].search(emailRegExp) === -1) { + setShowEmailRecipientsError(true); + setEmailRecipientsErrorMessage( + 'Invalid email addresses in recipients list.' + ); + error = true; + } + } + } + return error; + }; \ No newline at end of file diff --git a/public/components/utils/settings_service.ts b/public/components/utils/settings_service.ts new file mode 100644 index 00000000..16ac00f9 --- /dev/null +++ b/public/components/utils/settings_service.ts @@ -0,0 +1,37 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { HttpStart, IUiSettingsClient } from '../../../../../src/core/public'; + +let uiSettings: IUiSettingsClient; +let http: HttpStart; + +export const uiSettingsService = { + init: (uiSettingsClient: IUiSettingsClient, httpClient: HttpStart) => { + uiSettings = uiSettingsClient; + http = httpClient; + }, + get: (key: string, defaultOverride?: any) => { + return uiSettings?.get(key, defaultOverride) || ''; + }, + getSearchParams: function () { + const rawTimeZone = this.get('dateFormat:tz'); + const timezone = + !rawTimeZone || rawTimeZone === 'Browser' + ? Intl.DateTimeFormat().resolvedOptions().timeZone + : rawTimeZone; + const dateFormat = this.get('dateFormat'); + const csvSeparator = this.get('csv:separator'); + const allowLeadingWildcards = this.get('query:allowLeadingWildcards'); + return { + timezone, + dateFormat, + csvSeparator, + allowLeadingWildcards, + }; + }, + getHttpClient: () => http, +}; + diff --git a/public/components/utils/utils.tsx b/public/components/utils/utils.tsx new file mode 100644 index 00000000..469da045 --- /dev/null +++ b/public/components/utils/utils.tsx @@ -0,0 +1,41 @@ +/* + * Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES 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 const permissionsMissingToast = (action: string) => { + return { + title: 'Error ' + action, + color: 'danger', + iconType: 'alert', + id: 'permissionsMissingErrorToast' + action.replace(' ', ''), + text: ( +

Insufficient permissions. Reach out to your Kibana administrator.

+ ), + }; +}; + +export const permissionsMissingActions = { + CHANGE_SCHEDULE_STATUS: 'changing schedule status.', + DELETE_REPORT_DEFINITION: 'deleting report definition.', + GENERATING_REPORT: 'generating report.', + LOADING_REPORTS_TABLE: 'loading reports table.', + LOADING_DEFINITIONS_TABLE: 'loading report definitions table.', + VIEWING_EDIT_PAGE: 'viewing edit page.', + UPDATING_DEFINITION: 'updating report definition', + CREATING_REPORT_DEFINITION: 'creating new report definition.', +}; + +export const timeRangeMatcher = /time:\(from:(.+?),to:(.+?)\)/; diff --git a/public/components/visual_report/assets/report_styles.ts b/public/components/visual_report/assets/report_styles.ts new file mode 100644 index 00000000..a78ee8a8 --- /dev/null +++ b/public/components/visual_report/assets/report_styles.ts @@ -0,0 +1,222 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +export const reportingStyle = ` +html, +body { + margin: 0; + padding: 0; +} + +iframe, embed, object { + display: none !important; +} + +/* nice padding + matches Kibana default UI colors you could also set this to inherit if + the wrapper gets inserted inside a kibana section. I might also remove the manual text color here as well, potentially */ +.reportWrapper { + padding: 8px; + background-color: #fafbfd; +} + +/* Notice that I'm using an ID of #reportingHeader, and #reportingFooter, instead of a classname (.reportingHeader, .reportingFooter). This is + in order to force specificity here higher in case any other styles would conflict */ +#reportingHeader, +#reportingFooter { + font-family: 'Inter UI', -apple-system, BlinkMacSystemFont, 'Segoe UI', + Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', + 'Segoe UI Symbol'; + background-color: #fff; + border: 1px solid #d3dae6; + box-shadow: 0 2px 2px -1px rgba(152, 162, 179, 0.3), + 0 1px 5px -2px rgba(152, 162, 179, 0.3); + border-radius: 4px; + padding: 1em; + margin-bottom: 1em; +} + +#reportingFooter { + margin-top: 1em; +} + +#reportingHeader p, +#reportingFooter p { + max-width: 960px; +} + +/* Adjust the margin when the header is the first item */ +#reportingHeader h1:first-child, +#reportingFooter h1:first-child, +#reportingHeader h2:first-child, +#reportingFooter h2:first-child, +#reportingHeader h3:first-child, +#reportingFooter h3:first-child, +#reportingHeader h4:first-child, +#reportingFooter h4:first-child, +#reportingHeader h5:first-child, +#reportingFooter h5:first-child, +#reportingHeader h6:first-child, +#reportingFooter h6:first-child { + margin-top: 0.25em; +} + +/* nicer list styles */ +#reportingHeader ul, +#reportingFooter ul, +#reportingHeader ol, +#reportingFooter ol { + max-width: 70rem; + margin-bottom: 1em; +} + +#reportingHeader ul li, +#reportingFooter ul li, +#reportingHeader ol li, +#reportingFooter ol li { + margin-bottom: 0.25em; + margin-left: -0.5em; + padding-left: 0.25em; +} + +#reportingHeader ul, +#reportingFooter ul { + list-style-type: disc; +} + +/* here we explicitly set nested paragraphs inside lists to inherit their styles from the list, in case markdown does funky things */ +#reportingHeader ul p, +#reportingFooter ul p, +#reportingHeader ol p, +#reportingFooter ol p { + font-family: inherit; + font-size: inherit; + font-weight: inherit; + /* We only inherit vertical spacing, not horizontal */ + margin-top: inherit; + margin-bottom: inherit; +} + + + + + + A new Kibana report is available                 +                                 +                                 +                                 +                               + + + + + + + + + + + \ No newline at end of file diff --git a/server/routes/utils/notification/notification_content_template/logo.png b/server/routes/utils/notification/notification_content_template/logo.png new file mode 100644 index 00000000..46aa560a Binary files /dev/null and b/server/routes/utils/notification/notification_content_template/logo.png differ diff --git a/server/routes/utils/savedSearchReportHelper.ts b/server/routes/utils/savedSearchReportHelper.ts new file mode 100644 index 00000000..d44c78e8 --- /dev/null +++ b/server/routes/utils/savedSearchReportHelper.ts @@ -0,0 +1,266 @@ +/* + * Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +import { + buildQuery, + convertToCSV, + getEsData, + getSelectedFields, + metaData, +} from './dataReportHelpers'; +import { + ILegacyClusterClient, + ILegacyScopedClusterClient, +} from '../../../../../src/core/server'; +import { getFileName, callCluster } from './helpers'; +import { CreateReportResultType } from './types'; +import { RequestParams } from '@elastic/elasticsearch'; +import esb from 'elastic-builder'; + +/** + * Specify how long scroll context should be maintained for scrolled search + */ +const scrollTimeout = '1m'; + +export async function createSavedSearchReport( + report: any, + client: ILegacyClusterClient | ILegacyScopedClusterClient, + isScheduledTask: boolean = true +): Promise { + const params = report.report_definition.report_params; + const reportFormat = params.core_params.report_format; + const reportName = params.report_name; + + await populateMetaData(client, report, isScheduledTask); + const data = await generateReportData( + client, + params.core_params, + isScheduledTask + ); + + const curTime = new Date(); + const timeCreated = curTime.valueOf(); + const fileName = getFileName(reportName, curTime) + '.' + reportFormat; + return { + timeCreated, + dataUrl: data, + fileName, + }; +} + +/** + * Populate parameters and saved search info related to meta data object. + * @param client ES client + * @param report Report input + */ +async function populateMetaData( + client: ILegacyClusterClient | ILegacyScopedClusterClient, + report: any, + isScheduledTask: boolean +) { + metaData.saved_search_id = + report.report_definition.report_params.core_params.saved_search_id; + metaData.report_format = + report.report_definition.report_params.core_params.report_format; + metaData.start = report.time_from; + metaData.end = report.time_to; + + // Get saved search info + let resIndexPattern: any = {}; + const ssParams = { + index: '.kibana', + id: 'search:' + metaData.saved_search_id, + }; + const ssInfos = await callCluster(client, 'get', ssParams, isScheduledTask); + + metaData.sorting = ssInfos._source.search.sort; + metaData.type = ssInfos._source.type; + metaData.filters = + ssInfos._source.search.kibanaSavedObjectMeta.searchSourceJSON; + + // Get the list of selected columns in the saved search.Otherwise select all the fields under the _source + await getSelectedFields(ssInfos._source.search.columns); + + // Get index name + for (const item of ssInfos._source.references) { + if (item.name === JSON.parse(metaData.filters).indexRefName) { + // Get index-pattern information + const indexPattern = await callCluster( + client, + 'get', + { + index: '.kibana', + id: 'index-pattern:' + item.id, + }, + isScheduledTask + ); + resIndexPattern = indexPattern._source['index-pattern']; + metaData.paternName = resIndexPattern.title; + (metaData.timeFieldName = resIndexPattern.timeFieldName), + (metaData.fields = resIndexPattern.fields); // Get all fields + // Getting fields of type Date + const dateFields = []; + for (const item of JSON.parse(metaData.fields)) { + if (item.type === 'date') { + dateFields.push(item.name); + } + } + metaData.dateFields = dateFields; + } + } +} + +/** + * Generate CSV data by query and convert ES data set. + * @param client ES client + * @param limit limit size of result data set + */ +async function generateReportData( + client: ILegacyClusterClient | ILegacyScopedClusterClient, + params: any, + isScheduledTask: boolean +) { + let esData: any = {}; + const arrayHits: any = []; + const report = { _source: metaData }; + const indexPattern: string = report._source.paternName; + const maxResultSize: number = await getMaxResultSize(); + const esCount = await getEsDataSize(); + + const total = Math.min(esCount.count, params.limit); + if (total === 0) { + return ''; + } + + const reqBody = buildRequestBody(buildQuery(report, 0)); + if (total > maxResultSize) { + await getEsDataByScroll(); + } else { + await getEsDataBySearch(); + } + return convertEsDataToCsv(); + + // Fetch ES query max size windows to decide search or scroll + async function getMaxResultSize() { + const settings = await callCluster( + client, + 'indices.getSettings', + { + index: indexPattern, + includeDefaults: true, + }, + isScheduledTask + ); + + let maxResultSize = Number.MAX_SAFE_INTEGER; + for (let indexName in settings) { + // The location of max result window differs if default overridden. + maxResultSize = Math.min( + maxResultSize, + settings[indexName].settings.index.max_result_window || + settings[indexName].defaults.index.max_result_window + ); + } + return maxResultSize; + } + + // Build the ES Count query to count the size of result + async function getEsDataSize() { + const countReq = buildQuery(report, 1); + return await callCluster( + client, + 'count', + { + index: indexPattern, + body: countReq.toJSON(), + }, + isScheduledTask + ); + } + + async function getEsDataByScroll() { + const searchParams: RequestParams.Search = { + index: report._source.paternName, + scroll: scrollTimeout, + body: reqBody, + size: maxResultSize, + }; + // Open scroll context by fetching first batch + esData = await callCluster(client, 'search', searchParams, isScheduledTask); + arrayHits.push(esData.hits); + + // Start scrolling till the end + const nbScroll = Math.floor(total / maxResultSize); + for (let i = 0; i < nbScroll; i++) { + const resScroll = await callCluster( + client, + 'scroll', + { + scrollId: esData._scroll_id, + scroll: scrollTimeout, + }, + isScheduledTask + ); + if (Object.keys(resScroll.hits.hits).length > 0) { + arrayHits.push(resScroll.hits); + } + } + + // Clear scroll context + await callCluster( + client, + 'clearScroll', + { + scrollId: esData._scroll_id, + }, + isScheduledTask + ); + } + + async function getEsDataBySearch() { + const searchParams: RequestParams.Search = { + index: report._source.paternName, + body: reqBody, + size: total, + }; + + esData = await callCluster(client, 'search', searchParams, isScheduledTask); + arrayHits.push(esData.hits); + } + + function buildRequestBody(query: esb.RequestBodySearch) { + const docvalues = []; + for (const dateType of report._source.dateFields) { + docvalues.push({ + field: dateType, + format: 'date_hour_minute', + }); + } + + // elastic-builder doesn't provide function to build docvalue_fields with format, + // this is a workaround which appends docvalues field to the request body. + return { + ...query.toJSON(), + docvalue_fields: docvalues, + }; + } + + // Parse ES data and convert to CSV + async function convertEsDataToCsv() { + const dataset: any = []; + dataset.push(getEsData(arrayHits, report, params)); + return await convertToCSV(dataset); + } +} diff --git a/server/routes/utils/types.ts b/server/routes/utils/types.ts new file mode 100644 index 00000000..ee599c70 --- /dev/null +++ b/server/routes/utils/types.ts @@ -0,0 +1,61 @@ +/* + * Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT 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 CreateReportResultType { + timeCreated: number; + dataUrl: string; + fileName: string; + reportId: string; + queryUrl: string; +} + +type ReportSourceType = 'dashboard' | 'visualization' | 'saved_search'; +type ReportFormatType = 'pdf' | 'png' | 'csv'; +type UsageActionType = 'download'; +export type EntityType = 'report' | 'report_definition' | 'report_source'; + +export type CountersNameType = + | 'count' + | 'system_error' + | 'user_error' + | 'total'; +export type ActionType = + | 'info' + | 'list' + | 'delete' + | 'create' + | 'download' + | 'update' + | 'create_from_definition'; + +export type CountersType = ActionCountersType & UsageCountersType; + +type ActionCountersType = { + [entity in EntityType]: { + [action in ActionType]?: { + [counter in CountersNameType]?: number; + }; + }; +}; + +type UsageCountersType = { + [source in ReportSourceType]: { + [format in ReportFormatType]?: { + [action in UsageActionType]: { + [counter in CountersNameType]?: number; + }; + }; + }; +}; diff --git a/server/types.ts b/server/types.ts new file mode 100644 index 00000000..026f758e --- /dev/null +++ b/server/types.ts @@ -0,0 +1,19 @@ +/* + * Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT 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 @typescript-eslint/no-empty-interface +export interface OpendistroKibanaReportsPluginSetup {} +// eslint-disable-next-line @typescript-eslint/no-empty-interface +export interface OpendistroKibanaReportsPluginStart {} diff --git a/server/utils/__tests__/validationHelper.test.ts b/server/utils/__tests__/validationHelper.test.ts new file mode 100644 index 00000000..f01c4cf4 --- /dev/null +++ b/server/utils/__tests__/validationHelper.test.ts @@ -0,0 +1,111 @@ +/* + * Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +import { ReportDefinitionSchemaType, ReportSchemaType } from '../../model'; +import { + DELIVERY_TYPE, + FORMAT, + REPORT_TYPE, + TRIGGER_TYPE, +} from '../../routes/utils/constants'; +import { validateReport, validateReportDefinition } from '../validationHelper'; + +const SAMPLE_SAVED_OBJECT_ID = '3ba638e0-b894-11e8-a6d9-e546fe2bba5f'; +const createReportDefinitionInput: ReportDefinitionSchemaType = { + report_params: { + report_name: 'test visual report', + report_source: REPORT_TYPE.dashboard, + description: 'Hi this is your Dashboard on demand', + core_params: { + base_url: `/app/dashboards#/view/${SAMPLE_SAVED_OBJECT_ID}`, + window_width: 1300, + window_height: 900, + report_format: FORMAT.pdf, + time_duration: 'PT5M', + origin: 'http://localhost:5601', + }, + }, + delivery: { + delivery_type: DELIVERY_TYPE.kibanaUser, + delivery_params: { + kibana_recipients: [], + }, + }, + trigger: { + trigger_type: TRIGGER_TYPE.onDemand, + }, +}; +const createReportInput: ReportSchemaType = { + query_url: `/app/dashboards#/view/${SAMPLE_SAVED_OBJECT_ID}`, + time_from: 1343576635300, + time_to: 1596037435301, + report_definition: createReportDefinitionInput, +}; + +describe('test input validation', () => { + test('create report with correct saved object id', async () => { + const savedObjectIds = [`dashboard:${SAMPLE_SAVED_OBJECT_ID}`]; + const client = mockEsClient(savedObjectIds); + const report = await validateReport(client, createReportInput); + expect(report).toBeDefined(); + }); + + test('create report with non-exist saved object id', async () => { + const savedObjectIds = ['dashboard:fake-id']; + const client = mockEsClient(savedObjectIds); + await expect( + validateReport(client, createReportInput) + ).rejects.toThrowError( + `saved object with id dashboard:${SAMPLE_SAVED_OBJECT_ID} does not exist` + ); + }); + + test('create report definition with correct saved object id', async () => { + const savedObjectIds = [`dashboard:${SAMPLE_SAVED_OBJECT_ID}`]; + const client = mockEsClient(savedObjectIds); + const report = await validateReportDefinition( + client, + createReportDefinitionInput + ); + expect(report).toBeDefined(); + }); + + test('create report definition with non-exist saved object id', async () => { + const savedObjectIds = ['dashboard:fake-id']; + const client = mockEsClient(savedObjectIds); + await expect( + validateReportDefinition(client, createReportDefinitionInput) + ).rejects.toThrowError( + `saved object with id dashboard:${SAMPLE_SAVED_OBJECT_ID} does not exist` + ); + }); +}); +// TODO: merge this with other mock clients used in testing, to create some mock helpers file +const mockEsClient = (mockSavedObjectIds: string[]) => { + const client = { + callAsCurrentUser: jest + .fn() + .mockImplementation((endpoint: string, params: any) => { + switch (endpoint) { + case 'exists': + return mockSavedObjectIds.includes(params.id); + default: + fail('Fail due to unexpected function call on client'); + } + }), + }; + + return client; +}; diff --git a/server/utils/constants.ts b/server/utils/constants.ts new file mode 100644 index 00000000..a6858ad3 --- /dev/null +++ b/server/utils/constants.ts @@ -0,0 +1,16 @@ +/* + * Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT 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 POLL_INTERVAL = 1000 * 60 * 5; // in milliseconds (5 min) diff --git a/server/utils/validationHelper.ts b/server/utils/validationHelper.ts new file mode 100644 index 00000000..d1921f61 --- /dev/null +++ b/server/utils/validationHelper.ts @@ -0,0 +1,114 @@ +/* + * Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +import { RequestParams } from '@elastic/elasticsearch'; +import path from 'path'; +import { ILegacyScopedClusterClient } from '../../../../src/core/server'; +import { + reportDefinitionSchema, + ReportDefinitionSchemaType, + reportSchema, + ReportSchemaType, +} from '../../server/model'; +import { REPORT_TYPE } from '../../server/routes/utils/constants'; + +export const isValidRelativeUrl = (relativeUrl: string) => { + const normalizedRelativeUrl = path.posix.normalize(relativeUrl); + // check pattern + // ODFE pattern: /app/dashboards#/view/7adfa750-4c81-11e8-b3d7-01146121b73d?_g + // AES pattern: /_plugin/kibana/app/dashboards#/view/7adfa750-4c81-11e8-b3d7-01146121b73d?_g + const isValid = regexRelativeUrl.test(normalizedRelativeUrl); + + return isValid; +}; + +/** + * moment.js isValid() API fails to validate time duration, so use regex + * https://github.com/moment/moment/issues/1805 + **/ +export const regexDuration = /^(-?)P(?=\d|T\d)(?:(\d+)Y)?(?:(\d+)M)?(?:(\d+)([DW]))?(?:T(?:(\d+)H)?(?:(\d+)M)?(?:(\d+(?:\.\d+)?)S)?)?$/; +export const regexEmailAddress = /\S+@\S+\.\S+/; +export const regexReportName = /^[\w\-\s\(\)\[\]\,\_\-+]+$/; +export const regexRelativeUrl = /^\/(_plugin\/kibana\/app|app)\/(dashboards|visualize|discover)(\?security_tenant=.+|)#\/(view|edit)\/[^\/]+$/; + +export const validateReport = async ( + client: ILegacyScopedClusterClient, + report: ReportSchemaType +) => { + // validate basic schema + report = reportSchema.validate(report); + // parse to retrieve data + const { + query_url: queryUrl, + report_definition: { + report_params: { report_source: reportSource }, + }, + } = report; + // Check if saved object actually exists + await validateSavedObject(client, queryUrl, reportSource); + return report; +}; + +export const validateReportDefinition = async ( + client: ILegacyScopedClusterClient, + reportDefinition: ReportDefinitionSchemaType +) => { + // validate basic schema + reportDefinition = reportDefinitionSchema.validate(reportDefinition); + // parse to retrieve data + const { + report_params: { + report_source: reportSource, + core_params: { base_url: baseUrl }, + }, + } = reportDefinition; + // Check if saved object actually exists + await validateSavedObject(client, baseUrl, reportSource); + return reportDefinition; +}; + +const validateSavedObject = async ( + client: ILegacyScopedClusterClient, + url: string, + source: REPORT_TYPE +) => { + const getId = (url: string) => { + return url + .split('/') + .pop() + ?.replace(/\?\S+$/, ''); + }; + const getType = (source: REPORT_TYPE) => { + switch (source) { + case REPORT_TYPE.dashboard: + return 'dashboard'; + case REPORT_TYPE.savedSearch: + return 'search'; + case REPORT_TYPE.visualization: + return 'visualization'; + } + }; + + const savedObjectId = `${getType(source)}:${getId(url)}`; + const params: RequestParams.Exists = { + index: '.kibana', + id: savedObjectId, + }; + + const exist = await client.callAsCurrentUser('exists', params); + if (!exist) { + throw Error(`saved object with id ${savedObjectId} does not exist`); + } +}; diff --git a/test/__mocks__/fileMock.js b/test/__mocks__/fileMock.js new file mode 100644 index 00000000..82cb5aa8 --- /dev/null +++ b/test/__mocks__/fileMock.js @@ -0,0 +1 @@ +module.exports = 'react-mde-all'; diff --git a/test/__mocks__/styleMock.js b/test/__mocks__/styleMock.js new file mode 100644 index 00000000..f053ebf7 --- /dev/null +++ b/test/__mocks__/styleMock.js @@ -0,0 +1 @@ +module.exports = {}; diff --git a/test/httpMockClient.js b/test/httpMockClient.js new file mode 100644 index 00000000..f38de1ac --- /dev/null +++ b/test/httpMockClient.js @@ -0,0 +1,40 @@ +/* + * Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +const httpClientMock = jest.fn(); + +httpClientMock.delete = jest.fn(() => ({ + then: jest.fn(() => ({ + catch: jest.fn(), + })), +})); +httpClientMock.get = jest.fn(() => ({ + then: jest.fn(() => ({ + catch: jest.fn(), + })), +})); +httpClientMock.head = jest.fn(); +httpClientMock.post = jest.fn(() => ({ + then: jest.fn(() => ({ + catch: jest.fn(), + })), +})); +httpClientMock.put = jest.fn(() => ({ + then: jest.fn(() => ({ + catch: jest.fn(), + })), +})); + +export default httpClientMock; diff --git a/test/jest.config.js b/test/jest.config.js new file mode 100644 index 00000000..94b890c2 --- /dev/null +++ b/test/jest.config.js @@ -0,0 +1,32 @@ +/* + * Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +process.env.TZ = 'America/Los_Angeles'; + +module.exports = { + rootDir: '../', + setupFiles: ['/test/setupTests.ts'], + setupFilesAfterEnv: ['/test/setup.jest.ts'], + roots: [''], + testMatch: ['**/*.test.js', '**/*.test.jsx', '**/*.test.ts', '**/*.test.tsx'], + clearMocks: true, + modulePathIgnorePatterns: ['/offline-module-cache/'], + testPathIgnorePatterns: ['/build/', '/node_modules/'], + transformIgnorePatterns: ['/node_modules'], + moduleNameMapper: { + '\\.(css|less|sass|scss)$': '/test/__mocks__/styleMock.js', + '\\.(gif|ttf|eot|svg)$': '/test/__mocks__/fileMock.js', + }, +}; diff --git a/test/propsMock.js b/test/propsMock.js new file mode 100644 index 00000000..06320f30 --- /dev/null +++ b/test/propsMock.js @@ -0,0 +1,23 @@ +/* + * Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + + const propsMock = { + match: { + params: { + reportId: jest.fn(), + } + } + }; + export default propsMock; diff --git a/test/setup.jest.ts b/test/setup.jest.ts new file mode 100644 index 00000000..af954f9c --- /dev/null +++ b/test/setup.jest.ts @@ -0,0 +1,29 @@ +/* + * Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +import '@testing-library/jest-dom/extend-expect'; +import { configure } from '@testing-library/react'; + +configure({ testIdAttribute: 'data-test-subj' }); + +jest.mock('@elastic/eui/lib/components/form/form_row/make_id', () => () => + 'random-id' +); + +jest.mock('@elastic/eui/lib/services/accessibility/html_id_generator', () => ({ + htmlIdGenerator: () => { + return () => 'random_html_id'; + }, +})); diff --git a/test/setupTests.ts b/test/setupTests.ts new file mode 100644 index 00000000..00466520 --- /dev/null +++ b/test/setupTests.ts @@ -0,0 +1,17 @@ +/* + * Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +require('babel-polyfill'); +require('core-js/stable'); diff --git a/translations/zh-CN.json b/translations/zh-CN.json new file mode 100644 index 00000000..25e95ca7 --- /dev/null +++ b/translations/zh-CN.json @@ -0,0 +1,80 @@ +{ + "formats": { + "number": { + "currency": { + "style": "currency" + }, + "percent": { + "style": "percent" + } + }, + "date": { + "short": { + "month": "numeric", + "day": "numeric", + "year": "2-digit" + }, + "medium": { + "month": "short", + "day": "numeric", + "year": "numeric" + }, + "long": { + "month": "long", + "day": "numeric", + "year": "numeric" + }, + "full": { + "weekday": "long", + "month": "long", + "day": "numeric", + "year": "numeric" + } + }, + "time": { + "short": { + "hour": "numeric", + "minute": "numeric" + }, + "medium": { + "hour": "numeric", + "minute": "numeric", + "second": "numeric" + }, + "long": { + "hour": "numeric", + "minute": "numeric", + "second": "numeric", + "timeZoneName": "short" + }, + "full": { + "hour": "numeric", + "minute": "numeric", + "second": "numeric", + "timeZoneName": "short" + } + }, + "relative": { + "years": { + "units": "year" + }, + "months": { + "units": "month" + }, + "days": { + "units": "day" + }, + "hours": { + "units": "hour" + }, + "minutes": { + "units": "minute" + }, + "seconds": { + "units": "second" + } + } + }, + "messages": { + } +} diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 00000000..c45ef7b0 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,32 @@ +{ + // extend Kibana's tsconfig, or use your own settings + "extends": "../../tsconfig.json", + "compilerOptions": { + "jsx": "react", + "allowJs": true, + "baseUrl": ".", + "target": "esnext", + "module": "commonjs", + "outDir": "./target", + "noEmit": true, + "esModuleInterop": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true, + "allowUnusedLabels": true, + "noUnusedLocals": false, + "noUnusedParameters": false, + "alwaysStrict": false, + "noImplicitUseStrict": false, + "types": ["jest", "node"] + }, + "include": [ + "test/**/*", + "index.ts", + "public/**/*.ts", + "public/**/*.tsx", + "server/**/*.ts", + "common/**/*.ts", + "../../typings/**/*" + ], + "exclude": ["node_modules", "*/node_modules/"] +} diff --git a/yarn.lock b/yarn.lock new file mode 100644 index 00000000..fba9f805 --- /dev/null +++ b/yarn.lock @@ -0,0 +1,6785 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.10.4.tgz#168da1a36e90da68ae8d49c0f1b48c7c6249213a" + integrity sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg== + dependencies: + "@babel/highlight" "^7.10.4" + +"@babel/core@^7.1.0", "@babel/core@^7.7.5": + version "7.12.3" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.12.3.tgz#1b436884e1e3bff6fb1328dc02b208759de92ad8" + integrity sha512-0qXcZYKZp3/6N2jKYVxZv0aNCsxTSVCiK72DTiTYZAu7sjg73W0/aynWjMbiGd87EQL4WyA8reiJVh92AVla9g== + dependencies: + "@babel/code-frame" "^7.10.4" + "@babel/generator" "^7.12.1" + "@babel/helper-module-transforms" "^7.12.1" + "@babel/helpers" "^7.12.1" + "@babel/parser" "^7.12.3" + "@babel/template" "^7.10.4" + "@babel/traverse" "^7.12.1" + "@babel/types" "^7.12.1" + 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" + +"@babel/generator@^7.12.1", "@babel/generator@^7.12.5": + version "7.12.5" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.12.5.tgz#a2c50de5c8b6d708ab95be5e6053936c1884a4de" + integrity sha512-m16TQQJ8hPt7E+OS/XVQg/7U184MLXtvuGbCdA7na61vha+ImkyyNM/9DDA0unYCVZn3ZOhng+qz48/KBOT96A== + dependencies: + "@babel/types" "^7.12.5" + jsesc "^2.5.1" + source-map "^0.5.0" + +"@babel/helper-function-name@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.10.4.tgz#d2d3b20c59ad8c47112fa7d2a94bc09d5ef82f1a" + integrity sha512-YdaSyz1n8gY44EmN7x44zBn9zQ1Ry2Y+3GTA+3vH6Mizke1Vw0aWDM66FOYEPw8//qKkmqOckrGgTYa+6sceqQ== + dependencies: + "@babel/helper-get-function-arity" "^7.10.4" + "@babel/template" "^7.10.4" + "@babel/types" "^7.10.4" + +"@babel/helper-get-function-arity@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.10.4.tgz#98c1cbea0e2332f33f9a4661b8ce1505b2c19ba2" + integrity sha512-EkN3YDB+SRDgiIUnNgcmiD361ti+AVbL3f3Henf6dqqUyr5dMsorno0lJWJuLhDhkI5sYEpgj6y9kB8AOU1I2A== + dependencies: + "@babel/types" "^7.10.4" + +"@babel/helper-member-expression-to-functions@^7.12.1": + version "7.12.1" + resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.12.1.tgz#fba0f2fcff3fba00e6ecb664bb5e6e26e2d6165c" + integrity sha512-k0CIe3tXUKTRSoEx1LQEPFU9vRQfqHtl+kf8eNnDqb4AUJEy5pz6aIiog+YWtVm2jpggjS1laH68bPsR+KWWPQ== + dependencies: + "@babel/types" "^7.12.1" + +"@babel/helper-module-imports@^7.0.0": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.10.4.tgz#4c5c54be04bd31670a7382797d75b9fa2e5b5620" + integrity sha512-nEQJHqYavI217oD9+s5MUBzk6x1IlvoS9WTPfgG43CbMEeStE0v+r+TucWdx8KFGowPGvyOkDT9+7DHedIDnVw== + dependencies: + "@babel/types" "^7.10.4" + +"@babel/helper-module-imports@^7.12.1": + version "7.12.5" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.12.5.tgz#1bfc0229f794988f76ed0a4d4e90860850b54dfb" + integrity sha512-SR713Ogqg6++uexFRORf/+nPXMmWIn80TALu0uaFb+iQIUoR7bOC7zBWyzBs5b3tBBJXuyD0cRu1F15GyzjOWA== + dependencies: + "@babel/types" "^7.12.5" + +"@babel/helper-module-transforms@^7.12.1": + version "7.12.1" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.12.1.tgz#7954fec71f5b32c48e4b303b437c34453fd7247c" + integrity sha512-QQzehgFAZ2bbISiCpmVGfiGux8YVFXQ0abBic2Envhej22DVXV9nCFaS5hIQbkyo1AdGb+gNME2TSh3hYJVV/w== + dependencies: + "@babel/helper-module-imports" "^7.12.1" + "@babel/helper-replace-supers" "^7.12.1" + "@babel/helper-simple-access" "^7.12.1" + "@babel/helper-split-export-declaration" "^7.11.0" + "@babel/helper-validator-identifier" "^7.10.4" + "@babel/template" "^7.10.4" + "@babel/traverse" "^7.12.1" + "@babel/types" "^7.12.1" + lodash "^4.17.19" + +"@babel/helper-optimise-call-expression@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.10.4.tgz#50dc96413d594f995a77905905b05893cd779673" + integrity sha512-n3UGKY4VXwXThEiKrgRAoVPBMqeoPgHVqiHZOanAJCG9nQUL2pLRQirUzl0ioKclHGpGqRgIOkgcIJaIWLpygg== + dependencies: + "@babel/types" "^7.10.4" + +"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.8.0": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz#2f75a831269d4f677de49986dff59927533cf375" + integrity sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg== + +"@babel/helper-replace-supers@^7.12.1": + version "7.12.5" + resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.12.5.tgz#f009a17543bbbbce16b06206ae73b63d3fca68d9" + integrity sha512-5YILoed0ZyIpF4gKcpZitEnXEJ9UoDRki1Ey6xz46rxOzfNMAhVIJMoune1hmPVxh40LRv1+oafz7UsWX+vyWA== + dependencies: + "@babel/helper-member-expression-to-functions" "^7.12.1" + "@babel/helper-optimise-call-expression" "^7.10.4" + "@babel/traverse" "^7.12.5" + "@babel/types" "^7.12.5" + +"@babel/helper-simple-access@^7.12.1": + version "7.12.1" + resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.12.1.tgz#32427e5aa61547d38eb1e6eaf5fd1426fdad9136" + integrity sha512-OxBp7pMrjVewSSC8fXDFrHrBcJATOOFssZwv16F3/6Xtc138GHybBfPbm9kfiqQHKhYQrlamWILwlDCeyMFEaA== + dependencies: + "@babel/types" "^7.12.1" + +"@babel/helper-split-export-declaration@^7.11.0": + version "7.11.0" + resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.11.0.tgz#f8a491244acf6a676158ac42072911ba83ad099f" + integrity sha512-74Vejvp6mHkGE+m+k5vHY93FX2cAtrw1zXrZXRlG4l410Nm9PxfEiVTn1PjDPV5SnmieiueY4AFg2xqhNFuuZg== + dependencies: + "@babel/types" "^7.11.0" + +"@babel/helper-validator-identifier@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.4.tgz#a78c7a7251e01f616512d31b10adcf52ada5e0d2" + integrity sha512-3U9y+43hz7ZM+rzG24Qe2mufW5KhvFg/NhnNph+i9mgCtdTCtMJuI1TMkrIUiK7Ix4PYlRF9I5dhqaLYA/ADXw== + +"@babel/helpers@^7.12.1": + version "7.12.5" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.12.5.tgz#1a1ba4a768d9b58310eda516c449913fe647116e" + integrity sha512-lgKGMQlKqA8meJqKsW6rUnc4MdUk35Ln0ATDqdM1a/UpARODdI4j5Y5lVfUScnSNkJcdCRAaWkspykNoFg9sJA== + dependencies: + "@babel/template" "^7.10.4" + "@babel/traverse" "^7.12.5" + "@babel/types" "^7.12.5" + +"@babel/highlight@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.10.4.tgz#7d1bdfd65753538fabe6c38596cdb76d9ac60143" + integrity sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA== + dependencies: + "@babel/helper-validator-identifier" "^7.10.4" + chalk "^2.0.0" + js-tokens "^4.0.0" + +"@babel/parser@^7.1.0", "@babel/parser@^7.10.4", "@babel/parser@^7.12.3", "@babel/parser@^7.12.5": + version "7.12.5" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.12.5.tgz#b4af32ddd473c0bfa643bd7ff0728b8e71b81ea0" + integrity sha512-FVM6RZQ0mn2KCf1VUED7KepYeUWoVShczewOCfm3nzoBybaih51h+sYVVGthW9M6lPByEPTQf+xm27PBdlpwmQ== + +"@babel/plugin-syntax-async-generators@^7.8.4": + version "7.8.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz#a983fb1aeb2ec3f6ed042a210f640e90e786fe0d" + integrity sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-bigint@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz#4c9a6f669f5d0cdf1b90a1671e9a146be5300cea" + integrity sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-class-properties@^7.8.3": + version "7.12.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.1.tgz#bcb297c5366e79bebadef509549cd93b04f19978" + integrity sha512-U40A76x5gTwmESz+qiqssqmeEsKvcSyvtgktrm0uzcARAmM9I1jR221f6Oq+GmHrcD+LvZDag1UTOTe2fL3TeA== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-import-meta@^7.8.3": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz#ee601348c370fa334d2207be158777496521fd51" + integrity sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-json-strings@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz#01ca21b668cd8218c9e640cb6dd88c5412b2c96a" + integrity sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-logical-assignment-operators@^7.8.3": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz#ca91ef46303530448b906652bac2e9fe9941f699" + integrity sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-nullish-coalescing-operator@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz#167ed70368886081f74b5c36c65a88c03b66d1a9" + integrity sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-numeric-separator@^7.8.3": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz#b9b070b3e33570cd9fd07ba7fa91c0dd37b9af97" + integrity sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-object-rest-spread@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz#60e225edcbd98a640332a2e72dd3e66f1af55871" + integrity sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-optional-catch-binding@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz#6111a265bcfb020eb9efd0fdfd7d26402b9ed6c1" + integrity sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-optional-chaining@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz#4f69c2ab95167e0180cd5336613f8c5788f7d48a" + integrity sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-top-level-await@^7.8.3": + version "7.12.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.12.1.tgz#dd6c0b357ac1bb142d98537450a319625d13d2a0" + integrity sha512-i7ooMZFS+a/Om0crxZodrTzNEPJHZrlMVGMTEpFAj6rYY/bKCddB0Dk/YxfPuYXOopuhKk/e1jV6h+WUU9XN3A== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/runtime@7.5.0": + version "7.5.0" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.5.0.tgz#49dcbcd637099a55d3a61e590a00d6861393b1b5" + integrity sha512-2xsuyZ0R0RBFwjgae5NpXk8FcfH4qovj5cEM5VEeB7KXnKqzaisIu2HSV/mCEISolJJuR4wkViUGYujA8MH9tw== + dependencies: + regenerator-runtime "^0.13.2" + +"@babel/runtime@^7.1.2", "@babel/runtime@^7.5.5", "@babel/runtime@^7.7.2", "@babel/runtime@^7.8.7": + version "7.11.2" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.11.2.tgz#f549c13c754cc40b87644b9fa9f09a6a95fe0736" + integrity sha512-TeWkU52so0mPtDcaCTxNBI/IHiz0pZgr8VEFqXFtZWpYD08ZB6FaSwVAS8MKRQAP3bYKiVjwysOJgMFY28o6Tw== + dependencies: + regenerator-runtime "^0.13.4" + +"@babel/runtime@^7.12.5", "@babel/runtime@^7.14.0": + version "7.20.7" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.20.7.tgz#fcb41a5a70550e04a7b708037c7c32f7f356d8fd" + integrity sha512-UF0tvkUtxwAgZ5W/KrkHf0Rn0fdnLDU9ScxBrEVNUprE/MzirjK4MJUX1/BVDv00Sv8cljtukVK1aky++X1SjQ== + dependencies: + regenerator-runtime "^0.13.11" + +"@babel/template@^7.10.4", "@babel/template@^7.3.3": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.10.4.tgz#3251996c4200ebc71d1a8fc405fba940f36ba278" + integrity sha512-ZCjD27cGJFUB6nmCB1Enki3r+L5kJveX9pq1SvAUKoICy6CZ9yD8xO086YXdYhvNjBdnekm4ZnaP5yC8Cs/1tA== + dependencies: + "@babel/code-frame" "^7.10.4" + "@babel/parser" "^7.10.4" + "@babel/types" "^7.10.4" + +"@babel/traverse@^7.12.1", "@babel/traverse@^7.12.5": + version "7.12.5" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.12.5.tgz#78a0c68c8e8a35e4cacfd31db8bb303d5606f095" + integrity sha512-xa15FbQnias7z9a62LwYAA5SZZPkHIXpd42C6uW68o8uTuua96FHZy1y61Va5P/i83FAAcMpW8+A/QayntzuqA== + dependencies: + "@babel/code-frame" "^7.10.4" + "@babel/generator" "^7.12.5" + "@babel/helper-function-name" "^7.10.4" + "@babel/helper-split-export-declaration" "^7.11.0" + "@babel/parser" "^7.12.5" + "@babel/types" "^7.12.5" + debug "^4.1.0" + globals "^11.1.0" + lodash "^4.17.19" + +"@babel/types@^7.0.0", "@babel/types@^7.11.0", "@babel/types@^7.12.1", "@babel/types@^7.12.5", "@babel/types@^7.3.0", "@babel/types@^7.3.3": + version "7.12.6" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.12.6.tgz#ae0e55ef1cce1fbc881cd26f8234eb3e657edc96" + integrity sha512-hwyjw6GvjBLiyy3W0YQf0Z5Zf4NpYejUnKFcfcUhZCSffoBBp30w6wP2Wn6pk31jMYZvcOrB/1b7cGXvEoKogA== + dependencies: + "@babel/helper-validator-identifier" "^7.10.4" + lodash "^4.17.19" + to-fast-properties "^2.0.0" + +"@babel/types@^7.10.4": + version "7.11.5" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.11.5.tgz#d9de577d01252d77c6800cee039ee64faf75662d" + integrity sha512-bvM7Qz6eKnJVFIn+1LPtjlBFPVN5jNDc1XmN15vWe7Q3DPBufWWsLiIvUu7xW87uTG6QoggpIDnUgLQvPheU+Q== + dependencies: + "@babel/helper-validator-identifier" "^7.10.4" + lodash "^4.17.19" + to-fast-properties "^2.0.0" + +"@cnakazawa/watch@^1.0.3": + version "1.0.4" + resolved "https://registry.yarnpkg.com/@cnakazawa/watch/-/watch-1.0.4.tgz#f864ae85004d0fcab6f50be9141c4da368d1656a" + integrity sha512-v9kIhKwjeZThiWrLmj0y17CWoyddASLj9O2yvbZkbvw/N3rWOYy9zkV66ursAoVr0mV15bL8g0c4QZUE6cdDoQ== + dependencies: + exec-sh "^0.3.2" + minimist "^1.2.0" + +"@cypress/listr-verbose-renderer@^0.4.1": + version "0.4.1" + resolved "https://registry.yarnpkg.com/@cypress/listr-verbose-renderer/-/listr-verbose-renderer-0.4.1.tgz#a77492f4b11dcc7c446a34b3e28721afd33c642a" + integrity sha1-p3SS9LEdzHxEajSz4ochr9M8ZCo= + dependencies: + chalk "^1.1.3" + cli-cursor "^1.0.2" + date-fns "^1.27.2" + figures "^1.7.0" + +"@cypress/request@^2.88.5": + version "2.88.5" + resolved "https://registry.yarnpkg.com/@cypress/request/-/request-2.88.5.tgz#8d7ecd17b53a849cfd5ab06d5abe7d84976375d7" + integrity sha512-TzEC1XMi1hJkywWpRfD2clreTa/Z+lOrXDCxxBTBPEcY5azdPi56A6Xw+O4tWJnaJH3iIE7G5aDXZC6JgRZLcA== + dependencies: + aws-sign2 "~0.7.0" + aws4 "^1.8.0" + caseless "~0.12.0" + combined-stream "~1.0.6" + extend "~3.0.2" + forever-agent "~0.6.1" + form-data "~2.3.2" + har-validator "~5.1.3" + http-signature "~1.2.0" + is-typedarray "~1.0.0" + isstream "~0.1.2" + json-stringify-safe "~5.0.1" + mime-types "~2.1.19" + oauth-sign "~0.9.0" + performance-now "^2.1.0" + qs "~6.5.2" + safe-buffer "^5.1.2" + tough-cookie "~2.5.0" + tunnel-agent "^0.6.0" + uuid "^3.3.2" + +"@cypress/xvfb@^1.2.4": + version "1.2.4" + resolved "https://registry.yarnpkg.com/@cypress/xvfb/-/xvfb-1.2.4.tgz#2daf42e8275b39f4aa53c14214e557bd14e7748a" + integrity sha512-skbBzPggOVYCbnGgV+0dmBdW/s77ZkAOXIC1knS8NagwDjBrNC1LuXtQJeiN6l+m7lzmHtaoUw/ctJKdqkG57Q== + dependencies: + debug "^3.1.0" + lodash.once "^4.1.1" + +"@elastic/eslint-import-resolver-kibana@link:../../packages/kbn-eslint-import-resolver-kibana": + version "0.0.0" + uid "" + +"@emotion/cache@^10.0.27": + version "10.0.29" + resolved "https://registry.yarnpkg.com/@emotion/cache/-/cache-10.0.29.tgz#87e7e64f412c060102d589fe7c6dc042e6f9d1e0" + 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" + +"@emotion/core@^10.0.14": + version "10.0.35" + resolved "https://registry.yarnpkg.com/@emotion/core/-/core-10.0.35.tgz#513fcf2e22cd4dfe9d3894ed138c9d7a859af9b3" + integrity sha512-sH++vJCdk025fBlRZSAhkRlSUoqSqgCzYf5fMOmqqi3bM6how+sQpg3hkgJonj8GxXM4WbD7dRO+4tegDB9fUw== + dependencies: + "@babel/runtime" "^7.5.5" + "@emotion/cache" "^10.0.27" + "@emotion/css" "^10.0.27" + "@emotion/serialize" "^0.11.15" + "@emotion/sheet" "0.9.4" + "@emotion/utils" "0.11.3" + +"@emotion/css@^10.0.27": + version "10.0.27" + resolved "https://registry.yarnpkg.com/@emotion/css/-/css-10.0.27.tgz#3a7458198fbbebb53b01b2b87f64e5e21241e14c" + integrity sha512-6wZjsvYeBhyZQYNrGoR5yPMYbMBNEnanDrqmsqS1mzDm1cOTu12shvl2j4QHNS36UaTE0USIJawCH9C8oW34Zw== + dependencies: + "@emotion/serialize" "^0.11.15" + "@emotion/utils" "0.11.3" + babel-plugin-emotion "^10.0.27" + +"@emotion/hash@0.8.0": + version "0.8.0" + resolved "https://registry.yarnpkg.com/@emotion/hash/-/hash-0.8.0.tgz#bbbff68978fefdbe68ccb533bc8cbe1d1afb5413" + integrity sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow== + +"@emotion/memoize@0.7.4": + version "0.7.4" + resolved "https://registry.yarnpkg.com/@emotion/memoize/-/memoize-0.7.4.tgz#19bf0f5af19149111c40d98bb0cf82119f5d9eeb" + integrity sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw== + +"@emotion/serialize@^0.11.15", "@emotion/serialize@^0.11.16": + version "0.11.16" + resolved "https://registry.yarnpkg.com/@emotion/serialize/-/serialize-0.11.16.tgz#dee05f9e96ad2fb25a5206b6d759b2d1ed3379ad" + integrity sha512-G3J4o8by0VRrO+PFeSc3js2myYNOXVJ3Ya+RGVxnshRYgsvErfAOglKAiy1Eo1vhzxqtUvjCyS5gtewzkmvSSg== + dependencies: + "@emotion/hash" "0.8.0" + "@emotion/memoize" "0.7.4" + "@emotion/unitless" "0.7.5" + "@emotion/utils" "0.11.3" + csstype "^2.5.7" + +"@emotion/sheet@0.9.4": + version "0.9.4" + resolved "https://registry.yarnpkg.com/@emotion/sheet/-/sheet-0.9.4.tgz#894374bea39ec30f489bbfc3438192b9774d32e5" + integrity sha512-zM9PFmgVSqBw4zL101Q0HrBVTGmpAxFZH/pYx/cjJT5advXguvcgjHFTCaIO3enL/xr89vK2bh0Mfyj9aa0ANA== + +"@emotion/stylis@0.8.5": + version "0.8.5" + resolved "https://registry.yarnpkg.com/@emotion/stylis/-/stylis-0.8.5.tgz#deacb389bd6ee77d1e7fcaccce9e16c5c7e78e04" + integrity sha512-h6KtPihKFn3T9fuIrwvXXUOwlx3rfUvfZIcP5a6rh8Y7zjE3O06hT5Ss4S/YI1AYhuZ1kjaE/5EaOOI2NqSylQ== + +"@emotion/unitless@0.7.5": + version "0.7.5" + resolved "https://registry.yarnpkg.com/@emotion/unitless/-/unitless-0.7.5.tgz#77211291c1900a700b8a78cfafda3160d76949ed" + integrity sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg== + +"@emotion/utils@0.11.3": + version "0.11.3" + resolved "https://registry.yarnpkg.com/@emotion/utils/-/utils-0.11.3.tgz#a759863867befa7e583400d322652a3f44820924" + integrity sha512-0o4l6pZC+hI88+bzuaX/6BgOvQVhbt2PfmxauVaYOGgbsAw14wdKyvMCZXnsnsHys94iadcF+RG/wZyx6+ZZBw== + +"@emotion/weak-memoize@0.2.5": + version "0.2.5" + resolved "https://registry.yarnpkg.com/@emotion/weak-memoize/-/weak-memoize-0.2.5.tgz#8eed982e2ee6f7f4e44c253e12962980791efd46" + integrity sha512-6U71C2Wp7r5XtFtQzYrW5iKFT67OixrSxjI4MptCHzdSVlgabczzqLe0ZSgnub/5Kp4hSbpDB1tMytZY9pwxxA== + +"@istanbuljs/load-nyc-config@^1.0.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz#fd3db1d59ecf7cf121e80650bb86712f9b55eced" + integrity sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ== + dependencies: + camelcase "^5.3.1" + find-up "^4.1.0" + get-package-type "^0.1.0" + js-yaml "^3.13.1" + resolve-from "^5.0.0" + +"@istanbuljs/schema@^0.1.2": + version "0.1.2" + resolved "https://registry.yarnpkg.com/@istanbuljs/schema/-/schema-0.1.2.tgz#26520bf09abe4a5644cd5414e37125a8954241dd" + integrity sha512-tsAQNx32a8CoFhjhijUIhI4kccIAgmGhy8LZMZgGfmXcpMbPRUqn5LWmgRttILi6yeGmBJd2xsPkFMs0PzgPCw== + +"@jest/transform@^26.6.2": + version "26.6.2" + resolved "https://registry.yarnpkg.com/@jest/transform/-/transform-26.6.2.tgz#5ac57c5fa1ad17b2aae83e73e45813894dcf2e4b" + integrity sha512-E9JjhUgNzvuQ+vVAL21vlyfy12gP0GhazGgJC4h6qUt1jSdUXGWJ1wfu/X7Sd8etSgxV4ovT1pb9v5D6QW4XgA== + dependencies: + "@babel/core" "^7.1.0" + "@jest/types" "^26.6.2" + babel-plugin-istanbul "^6.0.0" + chalk "^4.0.0" + convert-source-map "^1.4.0" + fast-json-stable-stringify "^2.0.0" + graceful-fs "^4.2.4" + jest-haste-map "^26.6.2" + jest-regex-util "^26.0.0" + jest-util "^26.6.2" + micromatch "^4.0.2" + pirates "^4.0.1" + slash "^3.0.0" + source-map "^0.6.1" + write-file-atomic "^3.0.0" + +"@jest/types@^25.5.0": + version "25.5.0" + resolved "https://registry.yarnpkg.com/@jest/types/-/types-25.5.0.tgz#4d6a4793f7b9599fc3680877b856a97dbccf2a9d" + integrity sha512-OXD0RgQ86Tu3MazKo8bnrkDRaDXXMGUqd+kTtLtK1Zb7CRzQcaSRPPPV37SvYTdevXEBVxe0HXylEjs8ibkmCw== + dependencies: + "@types/istanbul-lib-coverage" "^2.0.0" + "@types/istanbul-reports" "^1.1.1" + "@types/yargs" "^15.0.0" + chalk "^3.0.0" + +"@jest/types@^26.3.0": + version "26.3.0" + resolved "https://registry.yarnpkg.com/@jest/types/-/types-26.3.0.tgz#97627bf4bdb72c55346eef98e3b3f7ddc4941f71" + integrity sha512-BDPG23U0qDeAvU4f99haztXwdAg3hz4El95LkAM+tHAqqhiVzRpEGHHU8EDxT/AnxOrA65YjLBwDahdJ9pTLJQ== + dependencies: + "@types/istanbul-lib-coverage" "^2.0.0" + "@types/istanbul-reports" "^3.0.0" + "@types/node" "*" + "@types/yargs" "^15.0.0" + chalk "^4.0.0" + +"@jest/types@^26.6.2": + version "26.6.2" + resolved "https://registry.yarnpkg.com/@jest/types/-/types-26.6.2.tgz#bef5a532030e1d88a2f5a6d933f84e97226ed48e" + integrity sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ== + dependencies: + "@types/istanbul-lib-coverage" "^2.0.0" + "@types/istanbul-reports" "^3.0.0" + "@types/node" "*" + "@types/yargs" "^15.0.0" + chalk "^4.0.0" + +"@react-navigation/core@^3.7.7": + version "3.7.7" + resolved "https://registry.yarnpkg.com/@react-navigation/core/-/core-3.7.7.tgz#398b23836928f96d23eb60a10f8be77b160f1284" + integrity sha512-0EYy7Hyip42Fua71w+Hti39u9tKzyNjdHZSWahWoZOZnEIgFwHmW3oT4A18Xv2l/rC2LOyfiddhp/Y1GIrV/3g== + dependencies: + hoist-non-react-statics "^3.3.2" + path-to-regexp "^1.8.0" + query-string "^6.13.1" + react-is "^16.13.0" + +"@react-navigation/native@^3.8.1": + version "3.8.1" + resolved "https://registry.yarnpkg.com/@react-navigation/native/-/native-3.8.1.tgz#c3b13468a4729b0c60d2be9383e21a6860e020c4" + integrity sha512-EUOV7Ac09iMqphKidpLGnzn7pJr+XmDxJc4bGEKtMH/m/EpJYN93llzu9aPJxDJymMQsc/tyPIjJw2vKFcfNFQ== + dependencies: + hoist-non-react-statics "^3.3.2" + react-native-safe-area-view "^0.14.9" + +"@samverschueren/stream-to-observable@^0.3.0": + version "0.3.1" + resolved "https://registry.yarnpkg.com/@samverschueren/stream-to-observable/-/stream-to-observable-0.3.1.tgz#a21117b19ee9be70c379ec1877537ef2e1c63301" + integrity sha512-c/qwwcHyafOQuVQJj0IlBjf5yYgBI7YPJ77k4fOJYesb41jio65eaJODRUmfYKhTOFBrIZ66kgvGPlNbjuoRdQ== + dependencies: + any-observable "^0.3.0" + +"@types/babel__core@^7.0.0", "@types/babel__core@^7.1.7": + version "7.1.12" + resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.1.12.tgz#4d8e9e51eb265552a7e4f1ff2219ab6133bdfb2d" + integrity sha512-wMTHiiTiBAAPebqaPiPDLFA4LYPKr6Ph0Xq/6rq1Ur3v66HXyG+clfR9CNETkD7MQS8ZHvpQOtA53DLws5WAEQ== + dependencies: + "@babel/parser" "^7.1.0" + "@babel/types" "^7.0.0" + "@types/babel__generator" "*" + "@types/babel__template" "*" + "@types/babel__traverse" "*" + +"@types/babel__generator@*": + version "7.6.2" + resolved "https://registry.yarnpkg.com/@types/babel__generator/-/babel__generator-7.6.2.tgz#f3d71178e187858f7c45e30380f8f1b7415a12d8" + integrity sha512-MdSJnBjl+bdwkLskZ3NGFp9YcXGx5ggLpQQPqtgakVhsWK0hTtNYhjpZLlWQTviGTvF8at+Bvli3jV7faPdgeQ== + dependencies: + "@babel/types" "^7.0.0" + +"@types/babel__template@*": + version "7.4.0" + resolved "https://registry.yarnpkg.com/@types/babel__template/-/babel__template-7.4.0.tgz#0c888dd70b3ee9eebb6e4f200e809da0076262be" + integrity sha512-NTPErx4/FiPCGScH7foPyr+/1Dkzkni+rHiYHHoTjvwou7AQzJkNeD60A9CXRy+ZEN2B1bggmkTMCDb+Mv5k+A== + dependencies: + "@babel/parser" "^7.1.0" + "@babel/types" "^7.0.0" + +"@types/babel__traverse@*", "@types/babel__traverse@^7.0.6": + version "7.0.15" + resolved "https://registry.yarnpkg.com/@types/babel__traverse/-/babel__traverse-7.0.15.tgz#db9e4238931eb69ef8aab0ad6523d4d4caa39d03" + integrity sha512-Pzh9O3sTK8V6I1olsXpCfj2k/ygO2q1X0vhhnDrEQyYLHZesWz+zMZMVcwXLCYf0U36EtmyYaFGPfXlTtDHe3A== + dependencies: + "@babel/types" "^7.3.0" + +"@types/cheerio@*": + version "0.22.22" + resolved "https://registry.yarnpkg.com/@types/cheerio/-/cheerio-0.22.22.tgz#ae71cf4ca59b8bbaf34c99af7a5d6c8894988f5f" + integrity sha512-05DYX4zU96IBfZFY+t3Mh88nlwSMtmmzSYaQkKN48T495VV1dkHSah6qYyDTN5ngaS0i0VonH37m+RuzSM0YiA== + dependencies: + "@types/node" "*" + +"@types/color-name@^1.1.1": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@types/color-name/-/color-name-1.1.1.tgz#1c1261bbeaa10a8055bbc5d8ab84b7b2afc846a0" + integrity sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ== + +"@types/dompurify@^2.3.3": + version "2.3.3" + resolved "https://registry.yarnpkg.com/@types/dompurify/-/dompurify-2.3.3.tgz#c24c92f698f77ed9cc9d9fa7888f90cf2bfaa23f" + integrity sha512-nnVQSgRVuZ/843oAfhA25eRSNzUFcBPk/LOiw5gm8mD9/X7CNcbRkQu/OsjCewO8+VIYfPxUnXvPEVGenw14+w== + dependencies: + "@types/trusted-types" "*" + +"@types/enzyme-adapter-react-16@^1.0.6": + version "1.0.6" + resolved "https://registry.yarnpkg.com/@types/enzyme-adapter-react-16/-/enzyme-adapter-react-16-1.0.6.tgz#8aca7ae2fd6c7137d869b6616e696d21bb8b0cec" + integrity sha512-VonDkZ15jzqDWL8mPFIQnnLtjwebuL9YnDkqeCDYnB4IVgwUm0mwKkqhrxLL6mb05xm7qqa3IE95m8CZE9imCg== + dependencies: + "@types/enzyme" "*" + +"@types/enzyme@*": + version "3.10.8" + resolved "https://registry.yarnpkg.com/@types/enzyme/-/enzyme-3.10.8.tgz#ad7ac9d3af3de6fd0673773123fafbc63db50d42" + integrity sha512-vlOuzqsTHxog6PV79+tvOHFb6hq4QZKMq1lLD9MaWD1oec2lHTKndn76XOpSwCA0oFTaIbKVPrgM3k78Jjd16g== + dependencies: + "@types/cheerio" "*" + "@types/react" "*" + +"@types/graceful-fs@^4.1.2": + version "4.1.4" + resolved "https://registry.yarnpkg.com/@types/graceful-fs/-/graceful-fs-4.1.4.tgz#4ff9f641a7c6d1a3508ff88bc3141b152772e753" + integrity sha512-mWA/4zFQhfvOA8zWkXobwJvBD7vzcxgrOQ0J5CH1votGqdq9m7+FwtGaqyCZqC3NyyBkc9z4m+iry4LlqcMWJg== + dependencies: + "@types/node" "*" + +"@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0": + version "2.0.3" + resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.3.tgz#4ba8ddb720221f432e443bd5f9117fd22cfd4762" + integrity sha512-sz7iLqvVUg1gIedBOvlkxPlc8/uVzyS5OwGz1cKjXzkl3FpL3al0crU8YGU1WoHkxn0Wxbw5tyi6hvzJKNzFsw== + +"@types/istanbul-lib-report@*": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz#c14c24f18ea8190c118ee7562b7ff99a36552686" + integrity sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg== + dependencies: + "@types/istanbul-lib-coverage" "*" + +"@types/istanbul-reports@^1.1.1": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@types/istanbul-reports/-/istanbul-reports-1.1.2.tgz#e875cc689e47bce549ec81f3df5e6f6f11cfaeb2" + integrity sha512-P/W9yOX/3oPZSpaYOCQzGqgCQRXn0FFO/V8bWrCQs+wLmvVVxk6CRBXALEvNs9OHIatlnlFokfhuDo2ug01ciw== + dependencies: + "@types/istanbul-lib-coverage" "*" + "@types/istanbul-lib-report" "*" + +"@types/istanbul-reports@^3.0.0": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@types/istanbul-reports/-/istanbul-reports-3.0.0.tgz#508b13aa344fa4976234e75dddcc34925737d821" + integrity sha512-nwKNbvnwJ2/mndE9ItP/zc2TCzw6uuodnF4EHYWD+gCQDVBuRQL5UzbZD0/ezy1iKsFU2ZQiDqg4M9dN4+wZgA== + dependencies: + "@types/istanbul-lib-report" "*" + +"@types/jest@26.x": + version "26.0.13" + resolved "https://registry.yarnpkg.com/@types/jest/-/jest-26.0.13.tgz#5a7b9d5312f5dd521a38329c38ee9d3802a0b85e" + integrity sha512-sCzjKow4z9LILc6DhBvn5AkIfmQzDZkgtVVKmGwVrs5tuid38ws281D4l+7x1kP487+FlKDh5kfMZ8WSPAdmdA== + dependencies: + jest-diff "^25.2.1" + pretty-format "^25.2.1" + +"@types/jsdom@^16.2.3": + version "16.2.5" + resolved "https://registry.yarnpkg.com/@types/jsdom/-/jsdom-16.2.5.tgz#74ebad438741d249ecb416c5486dcde4217eb66c" + integrity sha512-k/ZaTXtReAjwWu0clU0KLS53dyqZnA8mm+jwKFeFrvufXgICp+VNbskETFxKKAguv0pkaEKTax5MaRmvalM+TA== + dependencies: + "@types/node" "*" + "@types/parse5" "*" + "@types/tough-cookie" "*" + +"@types/node@*": + version "14.6.3" + resolved "https://registry.yarnpkg.com/@types/node/-/node-14.6.3.tgz#cc4f979548ca4d8e7b90bc0180052ab99ee64224" + integrity sha512-pC/hkcREG6YfDfui1FBmj8e20jFU5Exjw4NYDm8kEdrW+mOh0T1Zve8DWKnS7ZIZvgncrctcNCXF4Q2I+loyww== + +"@types/parse-json@^4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.0.tgz#2f8bb441434d163b35fb8ffdccd7138927ffb8c0" + integrity sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA== + +"@types/parse5@*": + version "5.0.3" + resolved "https://registry.yarnpkg.com/@types/parse5/-/parse5-5.0.3.tgz#e7b5aebbac150f8b5fdd4a46e7f0bd8e65e19109" + integrity sha512-kUNnecmtkunAoQ3CnjmMkzNU/gtxG8guhi+Fk2U/kOpIKjIMKnXGp4IJCgQJrXSgMsWYimYG4TGjz/UzbGEBTw== + +"@types/prop-types@*": + version "15.7.3" + resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.3.tgz#2ab0d5da2e5815f94b0b9d4b95d1e5f243ab2ca7" + integrity sha512-KfRL3PuHmqQLOG+2tGpRO26Ctg+Cq1E01D2DMriKEATHgWLfeNDmq9e29Q9WIky0dQ3NPkd1mzYH8Lm936Z9qw== + +"@types/raf@^3.4.0": + version "3.4.0" + resolved "https://registry.yarnpkg.com/@types/raf/-/raf-3.4.0.tgz#2b72cbd55405e071f1c4d29992638e022b20acc2" + integrity sha512-taW5/WYqo36N7V39oYyHP9Ipfd5pNFvGTIQsNGj86xV88YQ7GnI30/yMfKDF7Zgin0m3e+ikX88FvImnK4RjGw== + +"@types/react-addons-test-utils@^0.14.25": + version "0.14.25" + resolved "https://registry.yarnpkg.com/@types/react-addons-test-utils/-/react-addons-test-utils-0.14.25.tgz#09cf7f7128d497d23d6e73da5a09406a74438c2b" + integrity sha512-Z3FdgnPHwjqj3DO2OyyXkiEHCTmuwio5ENVafw9MvGQWWs1lQsbasTXO9deZDGKCtqpP8h7oFBil9Ovs08xWnw== + dependencies: + "@types/react" "*" + +"@types/react-dom@^16.9.8": + version "16.9.8" + resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-16.9.8.tgz#fe4c1e11dfc67155733dfa6aa65108b4971cb423" + integrity sha512-ykkPQ+5nFknnlU6lDd947WbQ6TE3NNzbQAkInC2EKY1qeYdTKp7onFusmYZb+ityzx2YviqT6BXSu+LyWWJwcA== + dependencies: + "@types/react" "*" + +"@types/react-test-renderer@^16.9.1": + version "16.9.3" + resolved "https://registry.yarnpkg.com/@types/react-test-renderer/-/react-test-renderer-16.9.3.tgz#96bab1860904366f4e848b739ba0e2f67bcae87e" + integrity sha512-wJ7IlN5NI82XMLOyHSa+cNN4Z0I+8/YaLl04uDgcZ+W+ExWCmCiVTLT/7fRNqzy4OhStZcUwIqLNF7q+AdW43Q== + dependencies: + "@types/react" "*" + +"@types/react@*", "@types/react@^16.9.36": + version "16.9.49" + resolved "https://registry.yarnpkg.com/@types/react/-/react-16.9.49.tgz#09db021cf8089aba0cdb12a49f8021a69cce4872" + integrity sha512-DtLFjSj0OYAdVLBbyjhuV9CdGVHCkHn2R+xr3XkBvK2rS1Y1tkc14XSGjYgm5Fjjr90AxH9tiSzc1pCFMGO06g== + dependencies: + "@types/prop-types" "*" + csstype "^3.0.2" + +"@types/set-interval-async@^1.0.0": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@types/set-interval-async/-/set-interval-async-1.0.0.tgz#7769973e0ded3faee36018795a92b6ba239d668e" + integrity sha512-4twO6B7/dcd+lMyIHwUm/S1RMvVOsgZf0sCevNNCnwyAxn7t9mxLfuZxIGFimYCPhLjJYccsvo4HhXxp4UDoBg== + +"@types/showdown@^1.9.3": + version "1.9.3" + resolved "https://registry.yarnpkg.com/@types/showdown/-/showdown-1.9.3.tgz#eaa881b03a32d3720184731754d3025fc450b970" + integrity sha512-akvzSmrvY4J5d3tHzUUiQr0xpjd4Nb3uzWW6dtwzYJ+qW/KdWw5F8NLatnor5q/1LURHnzDA1ReEwCVqcatRnw== + +"@types/sinonjs__fake-timers@^6.0.1": + version "6.0.2" + resolved "https://registry.yarnpkg.com/@types/sinonjs__fake-timers/-/sinonjs__fake-timers-6.0.2.tgz#3a84cf5ec3249439015e14049bd3161419bf9eae" + integrity sha512-dIPoZ3g5gcx9zZEszaxLSVTvMReD3xxyyDnQUjA6IYDG9Ba2AV0otMPs+77sG9ojB4Qr2N2Vk5RnKeuA0X/0bg== + +"@types/sizzle@^2.3.2": + version "2.3.2" + resolved "https://registry.yarnpkg.com/@types/sizzle/-/sizzle-2.3.2.tgz#a811b8c18e2babab7d542b3365887ae2e4d9de47" + integrity sha512-7EJYyKTL7tFR8+gDbB6Wwz/arpGa0Mywk1TJbNzKzHtzbwVmY4HR9WqS5VV7dsBUKQmPNr192jHr/VpBluj/hg== + +"@types/tough-cookie@*": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@types/tough-cookie/-/tough-cookie-4.0.0.tgz#fef1904e4668b6e5ecee60c52cc6a078ffa6697d" + integrity sha512-I99sngh224D0M7XgW1s120zxCt3VYQ3IQsuw3P3jbq5GG4yc79+ZjyKznyOGIQrflfylLgcfekeZW/vk0yng6A== + +"@types/trusted-types@*": + version "1.0.6" + resolved "https://registry.yarnpkg.com/@types/trusted-types/-/trusted-types-1.0.6.tgz#569b8a08121d3203398290d602d84d73c8dcf5da" + integrity sha512-230RC8sFeHoT6sSUlRO6a8cAnclO06eeiq1QDfiv2FGCLWFvvERWgwIQD4FWqD9A69BN7Lzee4OXwoMVnnsWDw== + +"@types/yargs-parser@*": + version "15.0.0" + resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-15.0.0.tgz#cb3f9f741869e20cce330ffbeb9271590483882d" + integrity sha512-FA/BWv8t8ZWJ+gEOnLLd8ygxH/2UFbAvgEonyfN6yWGLKc7zVjbpl2Y4CTjid9h2RfgPP6SEt6uHwEOply00yw== + +"@types/yargs@^15.0.0": + version "15.0.5" + resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-15.0.5.tgz#947e9a6561483bdee9adffc983e91a6902af8b79" + integrity sha512-Dk/IDOPtOgubt/IaevIUbTgV7doaKkoorvOyYM2CMwuDyP89bekI7H4xLIwunNYiK9jhCkmc6pUrJk3cj2AB9w== + dependencies: + "@types/yargs-parser" "*" + +"@types/yauzl@^2.9.1": + version "2.10.0" + resolved "https://registry.yarnpkg.com/@types/yauzl/-/yauzl-2.10.0.tgz#b3248295276cf8c6f153ebe6a9aba0c988cb2599" + integrity sha512-Cn6WYCm0tXv8p6k+A8PvbDG763EDpBoTzHdA+Q/MF6H3sapGjCm9NzoaJncJS9tUKSuCoDs9XHxYYsQDgxR6kw== + dependencies: + "@types/node" "*" + +"@webassemblyjs/ast@1.9.0": + version "1.9.0" + resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.9.0.tgz#bd850604b4042459a5a41cd7d338cbed695ed964" + integrity sha512-C6wW5L+b7ogSDVqymbkkvuW9kruN//YisMED04xzeBBqjHa2FYnmvOlS6Xj68xWQRgWvI9cIglsjFowH/RJyEA== + dependencies: + "@webassemblyjs/helper-module-context" "1.9.0" + "@webassemblyjs/helper-wasm-bytecode" "1.9.0" + "@webassemblyjs/wast-parser" "1.9.0" + +"@webassemblyjs/floating-point-hex-parser@1.9.0": + version "1.9.0" + resolved "https://registry.yarnpkg.com/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.9.0.tgz#3c3d3b271bddfc84deb00f71344438311d52ffb4" + integrity sha512-TG5qcFsS8QB4g4MhrxK5TqfdNe7Ey/7YL/xN+36rRjl/BlGE/NcBvJcqsRgCP6Z92mRE+7N50pRIi8SmKUbcQA== + +"@webassemblyjs/helper-api-error@1.9.0": + version "1.9.0" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-api-error/-/helper-api-error-1.9.0.tgz#203f676e333b96c9da2eeab3ccef33c45928b6a2" + integrity sha512-NcMLjoFMXpsASZFxJ5h2HZRcEhDkvnNFOAKneP5RbKRzaWJN36NC4jqQHKwStIhGXu5mUWlUUk7ygdtrO8lbmw== + +"@webassemblyjs/helper-buffer@1.9.0": + version "1.9.0" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-buffer/-/helper-buffer-1.9.0.tgz#a1442d269c5feb23fcbc9ef759dac3547f29de00" + integrity sha512-qZol43oqhq6yBPx7YM3m9Bv7WMV9Eevj6kMi6InKOuZxhw+q9hOkvq5e/PpKSiLfyetpaBnogSbNCfBwyB00CA== + +"@webassemblyjs/helper-code-frame@1.9.0": + version "1.9.0" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-code-frame/-/helper-code-frame-1.9.0.tgz#647f8892cd2043a82ac0c8c5e75c36f1d9159f27" + integrity sha512-ERCYdJBkD9Vu4vtjUYe8LZruWuNIToYq/ME22igL+2vj2dQ2OOujIZr3MEFvfEaqKoVqpsFKAGsRdBSBjrIvZA== + dependencies: + "@webassemblyjs/wast-printer" "1.9.0" + +"@webassemblyjs/helper-fsm@1.9.0": + version "1.9.0" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-fsm/-/helper-fsm-1.9.0.tgz#c05256b71244214671f4b08ec108ad63b70eddb8" + integrity sha512-OPRowhGbshCb5PxJ8LocpdX9Kl0uB4XsAjl6jH/dWKlk/mzsANvhwbiULsaiqT5GZGT9qinTICdj6PLuM5gslw== + +"@webassemblyjs/helper-module-context@1.9.0": + version "1.9.0" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-module-context/-/helper-module-context-1.9.0.tgz#25d8884b76839871a08a6c6f806c3979ef712f07" + integrity sha512-MJCW8iGC08tMk2enck1aPW+BE5Cw8/7ph/VGZxwyvGbJwjktKkDK7vy7gAmMDx88D7mhDTCNKAW5tED+gZ0W8g== + dependencies: + "@webassemblyjs/ast" "1.9.0" + +"@webassemblyjs/helper-wasm-bytecode@1.9.0": + version "1.9.0" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.9.0.tgz#4fed8beac9b8c14f8c58b70d124d549dd1fe5790" + integrity sha512-R7FStIzyNcd7xKxCZH5lE0Bqy+hGTwS3LJjuv1ZVxd9O7eHCedSdrId/hMOd20I+v8wDXEn+bjfKDLzTepoaUw== + +"@webassemblyjs/helper-wasm-section@1.9.0": + version "1.9.0" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.9.0.tgz#5a4138d5a6292ba18b04c5ae49717e4167965346" + integrity sha512-XnMB8l3ek4tvrKUUku+IVaXNHz2YsJyOOmz+MMkZvh8h1uSJpSen6vYnw3IoQ7WwEuAhL8Efjms1ZWjqh2agvw== + dependencies: + "@webassemblyjs/ast" "1.9.0" + "@webassemblyjs/helper-buffer" "1.9.0" + "@webassemblyjs/helper-wasm-bytecode" "1.9.0" + "@webassemblyjs/wasm-gen" "1.9.0" + +"@webassemblyjs/ieee754@1.9.0": + version "1.9.0" + resolved "https://registry.yarnpkg.com/@webassemblyjs/ieee754/-/ieee754-1.9.0.tgz#15c7a0fbaae83fb26143bbacf6d6df1702ad39e4" + integrity sha512-dcX8JuYU/gvymzIHc9DgxTzUUTLexWwt8uCTWP3otys596io0L5aW02Gb1RjYpx2+0Jus1h4ZFqjla7umFniTg== + dependencies: + "@xtuc/ieee754" "^1.2.0" + +"@webassemblyjs/leb128@1.9.0": + version "1.9.0" + resolved "https://registry.yarnpkg.com/@webassemblyjs/leb128/-/leb128-1.9.0.tgz#f19ca0b76a6dc55623a09cffa769e838fa1e1c95" + integrity sha512-ENVzM5VwV1ojs9jam6vPys97B/S65YQtv/aanqnU7D8aSoHFX8GyhGg0CMfyKNIHBuAVjy3tlzd5QMMINa7wpw== + dependencies: + "@xtuc/long" "4.2.2" + +"@webassemblyjs/utf8@1.9.0": + version "1.9.0" + resolved "https://registry.yarnpkg.com/@webassemblyjs/utf8/-/utf8-1.9.0.tgz#04d33b636f78e6a6813227e82402f7637b6229ab" + integrity sha512-GZbQlWtopBTP0u7cHrEx+73yZKrQoBMpwkGEIqlacljhXCkVM1kMQge/Mf+csMJAjEdSwhOyLAS0AoR3AG5P8w== + +"@webassemblyjs/wasm-edit@1.9.0": + version "1.9.0" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-edit/-/wasm-edit-1.9.0.tgz#3fe6d79d3f0f922183aa86002c42dd256cfee9cf" + integrity sha512-FgHzBm80uwz5M8WKnMTn6j/sVbqilPdQXTWraSjBwFXSYGirpkSWE2R9Qvz9tNiTKQvoKILpCuTjBKzOIm0nxw== + dependencies: + "@webassemblyjs/ast" "1.9.0" + "@webassemblyjs/helper-buffer" "1.9.0" + "@webassemblyjs/helper-wasm-bytecode" "1.9.0" + "@webassemblyjs/helper-wasm-section" "1.9.0" + "@webassemblyjs/wasm-gen" "1.9.0" + "@webassemblyjs/wasm-opt" "1.9.0" + "@webassemblyjs/wasm-parser" "1.9.0" + "@webassemblyjs/wast-printer" "1.9.0" + +"@webassemblyjs/wasm-gen@1.9.0": + version "1.9.0" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-gen/-/wasm-gen-1.9.0.tgz#50bc70ec68ded8e2763b01a1418bf43491a7a49c" + integrity sha512-cPE3o44YzOOHvlsb4+E9qSqjc9Qf9Na1OO/BHFy4OI91XDE14MjFN4lTMezzaIWdPqHnsTodGGNP+iRSYfGkjA== + dependencies: + "@webassemblyjs/ast" "1.9.0" + "@webassemblyjs/helper-wasm-bytecode" "1.9.0" + "@webassemblyjs/ieee754" "1.9.0" + "@webassemblyjs/leb128" "1.9.0" + "@webassemblyjs/utf8" "1.9.0" + +"@webassemblyjs/wasm-opt@1.9.0": + version "1.9.0" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-opt/-/wasm-opt-1.9.0.tgz#2211181e5b31326443cc8112eb9f0b9028721a61" + integrity sha512-Qkjgm6Anhm+OMbIL0iokO7meajkzQD71ioelnfPEj6r4eOFuqm4YC3VBPqXjFyyNwowzbMD+hizmprP/Fwkl2A== + dependencies: + "@webassemblyjs/ast" "1.9.0" + "@webassemblyjs/helper-buffer" "1.9.0" + "@webassemblyjs/wasm-gen" "1.9.0" + "@webassemblyjs/wasm-parser" "1.9.0" + +"@webassemblyjs/wasm-parser@1.9.0": + version "1.9.0" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-parser/-/wasm-parser-1.9.0.tgz#9d48e44826df4a6598294aa6c87469d642fff65e" + integrity sha512-9+wkMowR2AmdSWQzsPEjFU7njh8HTO5MqO8vjwEHuM+AMHioNqSBONRdr0NQQ3dVQrzp0s8lTcYqzUdb7YgELA== + dependencies: + "@webassemblyjs/ast" "1.9.0" + "@webassemblyjs/helper-api-error" "1.9.0" + "@webassemblyjs/helper-wasm-bytecode" "1.9.0" + "@webassemblyjs/ieee754" "1.9.0" + "@webassemblyjs/leb128" "1.9.0" + "@webassemblyjs/utf8" "1.9.0" + +"@webassemblyjs/wast-parser@1.9.0": + version "1.9.0" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-parser/-/wast-parser-1.9.0.tgz#3031115d79ac5bd261556cecc3fa90a3ef451914" + integrity sha512-qsqSAP3QQ3LyZjNC/0jBJ/ToSxfYJ8kYyuiGvtn/8MK89VrNEfwj7BPQzJVHi0jGTRK2dGdJ5PRqhtjzoww+bw== + dependencies: + "@webassemblyjs/ast" "1.9.0" + "@webassemblyjs/floating-point-hex-parser" "1.9.0" + "@webassemblyjs/helper-api-error" "1.9.0" + "@webassemblyjs/helper-code-frame" "1.9.0" + "@webassemblyjs/helper-fsm" "1.9.0" + "@xtuc/long" "4.2.2" + +"@webassemblyjs/wast-printer@1.9.0": + version "1.9.0" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-printer/-/wast-printer-1.9.0.tgz#4935d54c85fef637b00ce9f52377451d00d47899" + integrity sha512-2J0nE95rHXHyQ24cWjMKJ1tqB/ds8z/cyeOZxJhcb+rW+SQASVjuznUSmdz5GpVJTzU8JkhYut0D3siFDD6wsA== + dependencies: + "@webassemblyjs/ast" "1.9.0" + "@webassemblyjs/wast-parser" "1.9.0" + "@xtuc/long" "4.2.2" + +"@xtuc/ieee754@^1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@xtuc/ieee754/-/ieee754-1.2.0.tgz#eef014a3145ae477a1cbc00cd1e552336dceb790" + integrity sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA== + +"@xtuc/long@4.2.2": + version "4.2.2" + resolved "https://registry.yarnpkg.com/@xtuc/long/-/long-4.2.2.tgz#d291c6a4e97989b5c61d9acf396ae4fe133a718d" + integrity sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ== + +abab@^2.0.0: + version "2.0.5" + resolved "https://registry.yarnpkg.com/abab/-/abab-2.0.5.tgz#c0b678fb32d60fc1219c784d6a826fe385aeb79a" + integrity sha512-9IK9EadsbHo6jLWIpxpR6pL0sazTXV6+SQv25ZB+F7Bj9mJNaOc4nCRabwd5M/JwmUa8idz6Eci6eKfJryPs6Q== + +acorn-globals@^4.3.0: + version "4.3.4" + resolved "https://registry.yarnpkg.com/acorn-globals/-/acorn-globals-4.3.4.tgz#9fa1926addc11c97308c4e66d7add0d40c3272e7" + integrity sha512-clfQEh21R+D0leSbUdWf3OcfqyaCSAQ8Ryq00bofSekfr9W8u1jyYZo6ir0xu9Gtcf7BjcHJpnbZH7JOCpP60A== + dependencies: + acorn "^6.0.1" + acorn-walk "^6.0.1" + +acorn-walk@^6.0.1: + version "6.2.0" + resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-6.2.0.tgz#123cb8f3b84c2171f1f7fb252615b1c78a6b1a8c" + integrity sha512-7evsyfH1cLOCdAzZAd43Cic04yKydNx0cF+7tiA19p1XnLLPU4dpCQOqpjqwokFe//vS0QqfqqjCS2JkiIs0cA== + +acorn@^6.0.1, acorn@^6.0.4, acorn@^6.4.1: + version "6.4.2" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.4.2.tgz#35866fd710528e92de10cf06016498e47e39e1e6" + integrity sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ== + +airbnb-prop-types@^2.16.0: + version "2.16.0" + resolved "https://registry.yarnpkg.com/airbnb-prop-types/-/airbnb-prop-types-2.16.0.tgz#b96274cefa1abb14f623f804173ee97c13971dc2" + integrity sha512-7WHOFolP/6cS96PhKNrslCLMYAI8yB1Pp6u6XmxozQOiZbsI5ycglZr5cHhBFfuRcQQjzCMith5ZPZdYiJCxUg== + dependencies: + array.prototype.find "^2.1.1" + function.prototype.name "^1.1.2" + is-regex "^1.1.0" + object-is "^1.1.2" + object.assign "^4.1.0" + object.entries "^1.1.2" + prop-types "^15.7.2" + prop-types-exact "^1.2.0" + react-is "^16.13.1" + +ajv-errors@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/ajv-errors/-/ajv-errors-1.0.1.tgz#f35986aceb91afadec4102fbd85014950cefa64d" + integrity sha512-DCRfO/4nQ+89p/RK43i8Ezd41EqdGIU4ld7nGF8OQ14oc/we5rEntLCUa7+jrn3nn83BosfwZA0wb4pon2o8iQ== + +ajv-keywords@^3.1.0, ajv-keywords@^3.4.1: + version "3.5.2" + resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.5.2.tgz#31f29da5ab6e00d1c2d329acf7b5929614d5014d" + integrity sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ== + +ajv@^6.1.0, ajv@^6.10.2, ajv@^6.12.3: + version "6.12.6" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" + integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== + dependencies: + fast-deep-equal "^3.1.1" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.4.1" + uri-js "^4.2.2" + +ansi-escapes@^3.0.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-3.2.0.tgz#8780b98ff9dbf5638152d1f1fe5c1d7b4442976b" + integrity sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ== + +ansi-regex@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" + integrity sha1-w7M6te42DYbg5ijwRorn7yfWVN8= + +ansi-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" + integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg= + +ansi-regex@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.0.tgz#388539f55179bf39339c81af30a654d69f87cb75" + integrity sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg== + +ansi-styles@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" + integrity sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4= + +ansi-styles@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" + integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== + dependencies: + color-convert "^1.9.0" + +ansi-styles@^4.0.0, ansi-styles@^4.1.0: + version "4.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.2.1.tgz#90ae75c424d008d2624c5bf29ead3177ebfcf359" + integrity sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA== + dependencies: + "@types/color-name" "^1.1.1" + color-convert "^2.0.1" + +any-observable@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/any-observable/-/any-observable-0.3.0.tgz#af933475e5806a67d0d7df090dd5e8bef65d119b" + integrity sha512-/FQM1EDkTsf63Ub2C6O7GuYFDsSXUwsaZDurV0np41ocwq0jthUAYCmhBX9f+KwlaCgIuWyr/4WlUQUBfKfZog== + +anymatch@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-2.0.0.tgz#bcb24b4f37934d9aa7ac17b4adaf89e7c76ef2eb" + integrity sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw== + dependencies: + micromatch "^3.1.4" + normalize-path "^2.1.1" + +anymatch@^3.0.3, anymatch@~3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.1.tgz#c55ecf02185e2469259399310c173ce31233b142" + integrity sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg== + dependencies: + normalize-path "^3.0.0" + picomatch "^2.0.4" + +aproba@^1.1.1: + version "1.2.0" + resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" + integrity sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw== + +arch@^2.1.2: + version "2.2.0" + resolved "https://registry.yarnpkg.com/arch/-/arch-2.2.0.tgz#1bc47818f305764f23ab3306b0bfc086c5a29d11" + integrity sha512-Of/R0wqp83cgHozfIYLbBMnej79U/SVGOOyuB3VVFv1NRM/PSFMK12x9KVtiYzJqmnU5WR2qp0Z5rHb7sWGnFQ== + +argparse@^1.0.7: + version "1.0.10" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" + integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== + dependencies: + sprintf-js "~1.0.2" + +arr-diff@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520" + integrity sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA= + +arr-flatten@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1" + integrity sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg== + +arr-union@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4" + integrity sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ= + +array-equal@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/array-equal/-/array-equal-1.0.0.tgz#8c2a5ef2472fd9ea742b04c77a75093ba2757c93" + integrity sha1-jCpe8kcv2ep0KwTHenUJO6J1fJM= + +array-find@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/array-find/-/array-find-1.0.0.tgz#6c8e286d11ed768327f8e62ecee87353ca3e78b8" + integrity sha1-bI4obRHtdoMn+OYuzuhzU8o+eLg= + +array-unique@^0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428" + integrity sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg= + +array.prototype.find@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/array.prototype.find/-/array.prototype.find-2.1.1.tgz#3baca26108ca7affb08db06bf0be6cb3115a969c" + integrity sha512-mi+MYNJYLTx2eNYy+Yh6raoQacCsNeeMUaspFPh9Y141lFSsWxxB8V9mM2ye+eqiRs917J6/pJ4M9ZPzenWckA== + dependencies: + define-properties "^1.1.3" + es-abstract "^1.17.4" + +asn1.js@^5.2.0: + version "5.4.1" + resolved "https://registry.yarnpkg.com/asn1.js/-/asn1.js-5.4.1.tgz#11a980b84ebb91781ce35b0fdc2ee294e3783f07" + integrity sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA== + dependencies: + bn.js "^4.0.0" + inherits "^2.0.1" + minimalistic-assert "^1.0.0" + safer-buffer "^2.1.0" + +asn1@~0.2.3: + version "0.2.4" + resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.4.tgz#8d2475dfab553bb33e77b54e59e880bb8ce23136" + integrity sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg== + dependencies: + safer-buffer "~2.1.0" + +assert-plus@1.0.0, assert-plus@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" + integrity sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU= + +assert@^1.1.1: + version "1.5.0" + resolved "https://registry.yarnpkg.com/assert/-/assert-1.5.0.tgz#55c109aaf6e0aefdb3dc4b71240c70bf574b18eb" + integrity sha512-EDsgawzwoun2CZkCgtxJbv392v4nbk9XDD06zI+kQYoBM/3RBWLlEyJARDOmhAAosBjWACEkKL6S+lIZtcAubA== + dependencies: + object-assign "^4.1.1" + util "0.10.3" + +assign-symbols@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367" + integrity sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c= + +async-each@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.3.tgz#b727dbf87d7651602f06f4d4ac387f47d91b0cbf" + integrity sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ== + +async-limiter@~1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.1.tgz#dd379e94f0db8310b08291f9d64c3209766617fd" + integrity sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ== + +async@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/async/-/async-3.2.0.tgz#b3a2685c5ebb641d3de02d161002c60fc9f85720" + integrity sha512-TR2mEZFVOj2pLStYxLht7TyfuRzaydfpxr3k9RpHIzMgw7A64dzsdqCxH1WJyQdoe8T10nDXd9wnEigmiuHIZw== + +asynckit@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" + integrity sha1-x57Zf380y48robyXkLzDZkdLS3k= + +at-least-node@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/at-least-node/-/at-least-node-1.0.0.tgz#602cd4b46e844ad4effc92a8011a3c46e0238dc2" + integrity sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg== + +atob@^2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9" + integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg== + +aws-sign2@~0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8" + integrity sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg= + +aws4@^1.8.0: + version "1.11.0" + resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.11.0.tgz#d61f46d83b2519250e2784daf5b09479a8b41c59" + integrity sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA== + +babel-jest@^26.3.0: + version "26.6.3" + resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-26.6.3.tgz#d87d25cb0037577a0c89f82e5755c5d293c01056" + integrity sha512-pl4Q+GAVOHwvjrck6jKjvmGhnO3jHX/xuB9d27f+EJZ/6k+6nMuPjorrYp7s++bKKdANwzElBWnLWaObvTnaZA== + dependencies: + "@jest/transform" "^26.6.2" + "@jest/types" "^26.6.2" + "@types/babel__core" "^7.1.7" + babel-plugin-istanbul "^6.0.0" + babel-preset-jest "^26.6.2" + chalk "^4.0.0" + graceful-fs "^4.2.4" + slash "^3.0.0" + +babel-plugin-emotion@^10.0.27: + version "10.0.33" + resolved "https://registry.yarnpkg.com/babel-plugin-emotion/-/babel-plugin-emotion-10.0.33.tgz#ce1155dcd1783bbb9286051efee53f4e2be63e03" + integrity sha512-bxZbTTGz0AJQDHm8k6Rf3RQJ8tX2scsfsRyKVgAbiUPUNIRtlK+7JxP+TAd1kRLABFxe0CFm2VdK4ePkoA9FxQ== + dependencies: + "@babel/helper-module-imports" "^7.0.0" + "@emotion/hash" "0.8.0" + "@emotion/memoize" "0.7.4" + "@emotion/serialize" "^0.11.16" + babel-plugin-macros "^2.0.0" + babel-plugin-syntax-jsx "^6.18.0" + convert-source-map "^1.5.0" + escape-string-regexp "^1.0.5" + find-root "^1.1.0" + source-map "^0.5.7" + +babel-plugin-istanbul@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/babel-plugin-istanbul/-/babel-plugin-istanbul-6.0.0.tgz#e159ccdc9af95e0b570c75b4573b7c34d671d765" + integrity sha512-AF55rZXpe7trmEylbaE1Gv54wn6rwU03aptvRoVIGP8YykoSxqdVLV1TfwflBCE/QtHmqtP8SWlTENqbK8GCSQ== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@istanbuljs/load-nyc-config" "^1.0.0" + "@istanbuljs/schema" "^0.1.2" + istanbul-lib-instrument "^4.0.0" + test-exclude "^6.0.0" + +babel-plugin-jest-hoist@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-26.6.2.tgz#8185bd030348d254c6d7dd974355e6a28b21e62d" + integrity sha512-PO9t0697lNTmcEHH69mdtYiOIkkOlj9fySqfO3K1eCcdISevLAE0xY59VLLUj0SoiPiTX/JU2CYFpILydUa5Lw== + dependencies: + "@babel/template" "^7.3.3" + "@babel/types" "^7.3.3" + "@types/babel__core" "^7.0.0" + "@types/babel__traverse" "^7.0.6" + +babel-plugin-macros@^2.0.0: + version "2.8.0" + resolved "https://registry.yarnpkg.com/babel-plugin-macros/-/babel-plugin-macros-2.8.0.tgz#0f958a7cc6556b1e65344465d99111a1e5e10138" + integrity sha512-SEP5kJpfGYqYKpBrj5XU3ahw5p5GOHJ0U5ssOSQ/WBVdwkD2Dzlce95exQTs3jOVWPPKLBN2rlEWkCK7dSmLvg== + dependencies: + "@babel/runtime" "^7.7.2" + cosmiconfig "^6.0.0" + resolve "^1.12.0" + +babel-plugin-syntax-jsx@^6.18.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-jsx/-/babel-plugin-syntax-jsx-6.18.0.tgz#0af32a9a6e13ca7a3fd5069e62d7b0f58d0d8946" + integrity sha1-CvMqmm4Tyno/1QaeYtew9Y0NiUY= + +babel-polyfill@^6.26.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-polyfill/-/babel-polyfill-6.26.0.tgz#379937abc67d7895970adc621f284cd966cf2153" + integrity sha1-N5k3q8Z9eJWXCtxiHyhM2WbPIVM= + dependencies: + babel-runtime "^6.26.0" + core-js "^2.5.0" + regenerator-runtime "^0.10.5" + +babel-preset-current-node-syntax@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.0.tgz#cf5feef29551253471cfa82fc8e0f5063df07a77" + integrity sha512-mGkvkpocWJes1CmMKtgGUwCeeq0pOhALyymozzDWYomHTbDLwueDYG6p4TK1YOeYHCzBzYPsWkgTto10JubI1Q== + dependencies: + "@babel/plugin-syntax-async-generators" "^7.8.4" + "@babel/plugin-syntax-bigint" "^7.8.3" + "@babel/plugin-syntax-class-properties" "^7.8.3" + "@babel/plugin-syntax-import-meta" "^7.8.3" + "@babel/plugin-syntax-json-strings" "^7.8.3" + "@babel/plugin-syntax-logical-assignment-operators" "^7.8.3" + "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" + "@babel/plugin-syntax-numeric-separator" "^7.8.3" + "@babel/plugin-syntax-object-rest-spread" "^7.8.3" + "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" + "@babel/plugin-syntax-optional-chaining" "^7.8.3" + "@babel/plugin-syntax-top-level-await" "^7.8.3" + +babel-preset-jest@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-26.6.2.tgz#747872b1171df032252426586881d62d31798fee" + integrity sha512-YvdtlVm9t3k777c5NPQIv6cxFFFapys25HiUmuSgHwIZhfifweR5c5Sf5nwE3MAbfu327CYSvps8Yx6ANLyleQ== + dependencies: + babel-plugin-jest-hoist "^26.6.2" + babel-preset-current-node-syntax "^1.0.0" + +babel-runtime@^6.26.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe" + integrity sha1-llxwWGaOgrVde/4E/yM3vItWR/4= + dependencies: + core-js "^2.4.0" + regenerator-runtime "^0.11.0" + +bail@^1.0.0: + version "1.0.5" + resolved "https://registry.yarnpkg.com/bail/-/bail-1.0.5.tgz#b6fa133404a392cbc1f8c4bf63f5953351e7a776" + integrity sha512-xFbRxM1tahm08yHBP16MMjVUAvDaBMD38zsM9EMAUN61omwLmKlOpB/Zku5QkjZ8TZ4vn53pj+t518cH0S03RQ== + +balanced-match@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" + integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c= + +base64-arraybuffer@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz#1c37589a7c4b0746e34bd1feb951da2df01c1bdc" + integrity sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ== + +base64-js@^1.0.2: + version "1.3.1" + resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.3.1.tgz#58ece8cb75dd07e71ed08c736abc5fac4dbf8df1" + integrity sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g== + +base64-js@^1.3.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" + integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== + +base@^0.11.1: + version "0.11.2" + resolved "https://registry.yarnpkg.com/base/-/base-0.11.2.tgz#7bde5ced145b6d551a90db87f83c558b4eb48a8f" + integrity sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg== + dependencies: + cache-base "^1.0.1" + class-utils "^0.3.5" + component-emitter "^1.2.1" + define-property "^1.0.0" + isobject "^3.0.1" + mixin-deep "^1.2.0" + pascalcase "^0.1.1" + +bcrypt-pbkdf@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz#a4301d389b6a43f9b67ff3ca11a3f6637e360e9e" + integrity sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4= + dependencies: + tweetnacl "^0.14.3" + +big.js@^5.2.2: + version "5.2.2" + resolved "https://registry.yarnpkg.com/big.js/-/big.js-5.2.2.tgz#65f0af382f578bcdc742bd9c281e9cb2d7768328" + integrity sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ== + +binary-extensions@^1.0.0: + version "1.13.1" + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.13.1.tgz#598afe54755b2868a5330d2aff9d4ebb53209b65" + integrity sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw== + +binary-extensions@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.1.0.tgz#30fa40c9e7fe07dbc895678cd287024dea241dd9" + integrity sha512-1Yj8h9Q+QDF5FzhMs/c9+6UntbD5MkRfRwac8DoEm9ZfUBZ7tZ55YcGVAzEe4bXsdQHEk+s9S5wsOKVdZrw0tQ== + +bindings@^1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.5.0.tgz#10353c9e945334bc0511a6d90b38fbc7c9c504df" + integrity sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ== + dependencies: + file-uri-to-path "1.0.0" + +bl@^4.0.3: + version "4.1.0" + resolved "https://registry.yarnpkg.com/bl/-/bl-4.1.0.tgz#451535264182bec2fbbc83a62ab98cf11d9f7b3a" + integrity sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w== + dependencies: + buffer "^5.5.0" + inherits "^2.0.4" + readable-stream "^3.4.0" + +blob-util@2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/blob-util/-/blob-util-2.0.2.tgz#3b4e3c281111bb7f11128518006cdc60b403a1eb" + integrity sha512-T7JQa+zsXXEa6/8ZhHcQEW1UFfVM49Ts65uBkFL6fz2QmrElqmbajIDJvuA0tEhRe5eIjpV9ZF+0RfZR9voJFQ== + +bluebird@^3.5.5, bluebird@^3.7.2: + version "3.7.2" + resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f" + integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg== + +bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.4.0: + version "4.11.9" + resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.9.tgz#26d556829458f9d1e81fc48952493d0ba3507828" + integrity sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw== + +bn.js@^5.0.0, bn.js@^5.1.1: + version "5.1.3" + resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.1.3.tgz#beca005408f642ebebea80b042b4d18d2ac0ee6b" + integrity sha512-GkTiFpjFtUzU9CbMeJ5iazkCzGL3jrhzerzZIuqLABjbwRaFt33I9tUdSNryIptM+RxDet6OKm2WnLXzW51KsQ== + +boolbase@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e" + integrity sha1-aN/1++YMUes3cl6p4+0xDcwed24= + +brace-expansion@^1.1.7: + version "1.1.11" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +braces@^2.3.1, braces@^2.3.2: + version "2.3.2" + resolved "https://registry.yarnpkg.com/braces/-/braces-2.3.2.tgz#5979fd3f14cd531565e5fa2df1abfff1dfaee729" + integrity sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w== + dependencies: + arr-flatten "^1.1.0" + array-unique "^0.3.2" + extend-shallow "^2.0.1" + fill-range "^4.0.0" + isobject "^3.0.1" + repeat-element "^1.1.2" + snapdragon "^0.8.1" + snapdragon-node "^2.0.1" + split-string "^3.0.2" + to-regex "^3.0.1" + +braces@^3.0.1, braces@~3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" + integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== + dependencies: + fill-range "^7.0.1" + +brorand@^1.0.1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f" + integrity sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8= + +browser-process-hrtime@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz#3c9b4b7d782c8121e56f10106d84c0d0ffc94626" + integrity sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow== + +browserify-aes@^1.0.0, browserify-aes@^1.0.4: + version "1.2.0" + resolved "https://registry.yarnpkg.com/browserify-aes/-/browserify-aes-1.2.0.tgz#326734642f403dabc3003209853bb70ad428ef48" + integrity sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA== + dependencies: + buffer-xor "^1.0.3" + cipher-base "^1.0.0" + create-hash "^1.1.0" + evp_bytestokey "^1.0.3" + inherits "^2.0.1" + safe-buffer "^5.0.1" + +browserify-cipher@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/browserify-cipher/-/browserify-cipher-1.0.1.tgz#8d6474c1b870bfdabcd3bcfcc1934a10e94f15f0" + integrity sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w== + dependencies: + browserify-aes "^1.0.4" + browserify-des "^1.0.0" + evp_bytestokey "^1.0.0" + +browserify-des@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/browserify-des/-/browserify-des-1.0.2.tgz#3af4f1f59839403572f1c66204375f7a7f703e9c" + integrity sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A== + dependencies: + cipher-base "^1.0.1" + des.js "^1.0.0" + inherits "^2.0.1" + safe-buffer "^5.1.2" + +browserify-rsa@^4.0.0, browserify-rsa@^4.0.1: + version "4.1.0" + resolved "https://registry.yarnpkg.com/browserify-rsa/-/browserify-rsa-4.1.0.tgz#b2fd06b5b75ae297f7ce2dc651f918f5be158c8d" + integrity sha512-AdEER0Hkspgno2aR97SAf6vi0y0k8NuOpGnVH3O99rcA5Q6sh8QxcngtHuJ6uXwnfAXNM4Gn1Gb7/MV1+Ymbog== + dependencies: + bn.js "^5.0.0" + randombytes "^2.0.1" + +browserify-sign@^4.0.0: + version "4.2.1" + resolved "https://registry.yarnpkg.com/browserify-sign/-/browserify-sign-4.2.1.tgz#eaf4add46dd54be3bb3b36c0cf15abbeba7956c3" + integrity sha512-/vrA5fguVAKKAVTNJjgSm1tRQDHUU6DbwO9IROu/0WAzC8PKhucDSh18J0RMvVeHAn5puMd+QHC2erPRNf8lmg== + dependencies: + bn.js "^5.1.1" + browserify-rsa "^4.0.1" + create-hash "^1.2.0" + create-hmac "^1.1.7" + elliptic "^6.5.3" + inherits "^2.0.4" + parse-asn1 "^5.1.5" + readable-stream "^3.6.0" + safe-buffer "^5.2.0" + +browserify-zlib@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/browserify-zlib/-/browserify-zlib-0.2.0.tgz#2869459d9aa3be245fe8fe2ca1f46e2e7f54d73f" + integrity sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA== + dependencies: + pako "~1.0.5" + +bs-logger@0.x: + version "0.2.6" + resolved "https://registry.yarnpkg.com/bs-logger/-/bs-logger-0.2.6.tgz#eb7d365307a72cf974cc6cda76b68354ad336bd8" + integrity sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog== + dependencies: + fast-json-stable-stringify "2.x" + +bser@2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/bser/-/bser-2.1.1.tgz#e6787da20ece9d07998533cfd9de6f5c38f4bc05" + integrity sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ== + dependencies: + node-int64 "^0.4.0" + +btoa@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/btoa/-/btoa-1.2.1.tgz#01a9909f8b2c93f6bf680ba26131eb30f7fa3d73" + integrity sha512-SB4/MIGlsiVkMcHmT+pSmIPoNDoHg+7cMzmt3Uxt628MTz2487DKSqK/fuhFBrkuqrYv5UCEnACpF4dTFNKc/g== + +buffer-crc32@~0.2.3: + version "0.2.13" + resolved "https://registry.yarnpkg.com/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242" + integrity sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI= + +buffer-from@1.x, buffer-from@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef" + integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A== + +buffer-xor@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/buffer-xor/-/buffer-xor-1.0.3.tgz#26e61ed1422fb70dd42e6e36729ed51d855fe8d9" + integrity sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk= + +buffer@^4.3.0: + version "4.9.2" + resolved "https://registry.yarnpkg.com/buffer/-/buffer-4.9.2.tgz#230ead344002988644841ab0244af8c44bbe3ef8" + integrity sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg== + dependencies: + base64-js "^1.0.2" + ieee754 "^1.1.4" + isarray "^1.0.0" + +buffer@^5.2.1, buffer@^5.5.0: + version "5.7.1" + resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0" + integrity sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ== + dependencies: + base64-js "^1.3.1" + ieee754 "^1.1.13" + +builtin-status-codes@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz#85982878e21b98e1c66425e03d0174788f569ee8" + integrity sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug= + +cacache@^12.0.2: + version "12.0.4" + resolved "https://registry.yarnpkg.com/cacache/-/cacache-12.0.4.tgz#668bcbd105aeb5f1d92fe25570ec9525c8faa40c" + integrity sha512-a0tMB40oefvuInr4Cwb3GerbL9xTj1D5yg0T5xrjGCGyfvbxseIXX7BAO/u/hIXdafzOI5JC3wDwHyf24buOAQ== + dependencies: + bluebird "^3.5.5" + chownr "^1.1.1" + figgy-pudding "^3.5.1" + glob "^7.1.4" + graceful-fs "^4.1.15" + infer-owner "^1.0.3" + lru-cache "^5.1.1" + mississippi "^3.0.0" + mkdirp "^0.5.1" + move-concurrently "^1.0.1" + promise-inflight "^1.0.1" + rimraf "^2.6.3" + ssri "^6.0.1" + unique-filename "^1.1.1" + y18n "^4.0.0" + +cache-base@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/cache-base/-/cache-base-1.0.1.tgz#0a7f46416831c8b662ee36fe4e7c59d76f666ab2" + integrity sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ== + dependencies: + collection-visit "^1.0.0" + component-emitter "^1.2.1" + get-value "^2.0.6" + has-value "^1.0.0" + isobject "^3.0.1" + set-value "^2.0.0" + to-object-path "^0.3.0" + union-value "^1.0.0" + unset-value "^1.0.0" + +cachedir@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/cachedir/-/cachedir-2.3.0.tgz#0c75892a052198f0b21c7c1804d8331edfcae0e8" + integrity sha512-A+Fezp4zxnit6FanDmv9EqXNAi3vt9DWp51/71UEhXukb7QUuvtv9344h91dyAxuTLoSYJFU299qzR3tzwPAhw== + +call-bind@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.0.tgz#24127054bb3f9bdcb4b1fb82418186072f77b8ce" + integrity sha512-AEXsYIyyDY3MCzbwdhzG3Jx1R0J2wetQyUynn6dYHAO+bg8l1k7jwZtRv4ryryFs7EP+NDlikJlVe59jr0cM2w== + dependencies: + function-bind "^1.1.1" + get-intrinsic "^1.0.0" + +callsites@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" + integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== + +camelcase@^5.0.0, camelcase@^5.3.1: + version "5.3.1" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" + integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== + +canvg@^3.0.6: + version "3.0.10" + resolved "https://registry.yarnpkg.com/canvg/-/canvg-3.0.10.tgz#8e52a2d088b6ffa23ac78970b2a9eebfae0ef4b3" + integrity sha512-qwR2FRNO9NlzTeKIPIKpnTY6fqwuYSequ8Ru8c0YkYU7U0oW+hLUvWadLvAu1Rl72OMNiFhoLu4f8eUjQ7l/+Q== + dependencies: + "@babel/runtime" "^7.12.5" + "@types/raf" "^3.4.0" + core-js "^3.8.3" + raf "^3.4.1" + regenerator-runtime "^0.13.7" + rgbcolor "^1.0.1" + stackblur-canvas "^2.0.0" + svg-pathdata "^6.0.3" + +capture-exit@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/capture-exit/-/capture-exit-2.0.0.tgz#fb953bfaebeb781f62898239dabb426d08a509a4" + integrity sha512-PiT/hQmTonHhl/HFGN+Lx3JJUznrVYJ3+AQsnthneZbvW7x+f08Tk7yLJTLEOUvBTbduLeeBkxEaYXUOUrRq6g== + dependencies: + rsvp "^4.8.4" + +caseless@~0.12.0: + version "0.12.0" + resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" + integrity sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw= + +chalk@^1.0.0, chalk@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" + integrity sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg= + dependencies: + ansi-styles "^2.2.1" + escape-string-regexp "^1.0.2" + has-ansi "^2.0.0" + strip-ansi "^3.0.0" + supports-color "^2.0.0" + +chalk@^2.0.0, chalk@^2.4.1: + version "2.4.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" + 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" + +chalk@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-3.0.0.tgz#3f73c2bf526591f574cc492c51e2456349f844e4" + integrity sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + +chalk@^4.0.0, chalk@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.0.tgz#4e14870a618d9e2edd97dd8345fd9d9dc315646a" + integrity sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + +chalk@^4.1.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" + integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + +character-entities-legacy@^1.0.0: + version "1.1.4" + resolved "https://registry.yarnpkg.com/character-entities-legacy/-/character-entities-legacy-1.1.4.tgz#94bc1845dce70a5bb9d2ecc748725661293d8fc1" + integrity sha512-3Xnr+7ZFS1uxeiUDvV02wQ+QDbc55o97tIV5zHScSPJpcLm/r0DFPcoY3tYRp+VZukxuMeKgXYmsXQHO05zQeA== + +character-entities@^1.0.0: + version "1.2.4" + resolved "https://registry.yarnpkg.com/character-entities/-/character-entities-1.2.4.tgz#e12c3939b7eaf4e5b15e7ad4c5e28e1d48c5b16b" + integrity sha512-iBMyeEHxfVnIakwOuDXpVkc54HijNgCyQB2w0VfGQThle6NXn50zU6V/u+LDhxHcDUPojn6Kpga3PTAD8W1bQw== + +character-reference-invalid@^1.0.0: + version "1.1.4" + resolved "https://registry.yarnpkg.com/character-reference-invalid/-/character-reference-invalid-1.1.4.tgz#083329cda0eae272ab3dbbf37e9a382c13af1560" + integrity sha512-mKKUkUbhPpQlCOfIuZkvSEgktjPFIsZKRRbC6KWVEMvlzblj3i3asQv5ODsrwt0N3pHAEvjP8KTQPHkp0+6jOg== + +check-more-types@^2.24.0: + version "2.24.0" + resolved "https://registry.yarnpkg.com/check-more-types/-/check-more-types-2.24.0.tgz#1420ffb10fd444dcfc79b43891bbfffd32a84600" + integrity sha1-FCD/sQ/URNz8ebQ4kbv//TKoRgA= + +cheerio@0.22.0: + version "0.22.0" + resolved "https://registry.yarnpkg.com/cheerio/-/cheerio-0.22.0.tgz#a9baa860a3f9b595a6b81b1a86873121ed3a269e" + integrity sha1-qbqoYKP5tZWmuBsahocxIe06Jp4= + dependencies: + css-select "~1.2.0" + dom-serializer "~0.1.0" + entities "~1.1.1" + htmlparser2 "^3.9.1" + lodash.assignin "^4.0.9" + lodash.bind "^4.1.4" + lodash.defaults "^4.0.1" + lodash.filter "^4.4.0" + lodash.flatten "^4.2.0" + lodash.foreach "^4.3.0" + lodash.map "^4.4.0" + lodash.merge "^4.4.0" + lodash.pick "^4.2.1" + lodash.reduce "^4.4.0" + lodash.reject "^4.4.0" + lodash.some "^4.4.0" + +chokidar@^2.1.8: + version "2.1.8" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.1.8.tgz#804b3a7b6a99358c3c5c61e71d8728f041cff917" + integrity sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg== + dependencies: + anymatch "^2.0.0" + async-each "^1.0.1" + braces "^2.3.2" + glob-parent "^3.1.0" + inherits "^2.0.3" + is-binary-path "^1.0.0" + is-glob "^4.0.0" + normalize-path "^3.0.0" + path-is-absolute "^1.0.0" + readdirp "^2.2.1" + upath "^1.1.1" + optionalDependencies: + fsevents "^1.2.7" + +chokidar@^3.4.1: + version "3.4.3" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.4.3.tgz#c1df38231448e45ca4ac588e6c79573ba6a57d5b" + integrity sha512-DtM3g7juCXQxFVSNPNByEC2+NImtBuxQQvWlHunpJIS5Ocr0lG306cC7FCi7cEA0fzmybPUIl4txBIobk1gGOQ== + dependencies: + anymatch "~3.1.1" + braces "~3.0.2" + glob-parent "~5.1.0" + is-binary-path "~2.1.0" + is-glob "~4.0.1" + normalize-path "~3.0.0" + readdirp "~3.5.0" + optionalDependencies: + fsevents "~2.1.2" + +chownr@^1.1.1: + version "1.1.4" + resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.4.tgz#6fc9d7b42d32a583596337666e7d08084da2cc6b" + integrity sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg== + +chrome-trace-event@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-1.0.2.tgz#234090ee97c7d4ad1a2c4beae27505deffc608a4" + integrity sha512-9e/zx1jw7B4CO+c/RXoCsfg/x1AfUBioy4owYH0bJprEYAx5hRFLRhWBqHAG57D0ZM4H7vxbP7bPe0VwhQRYDQ== + dependencies: + tslib "^1.9.0" + +ci-info@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-2.0.0.tgz#67a9e964be31a51e15e5010d58e6f12834002f46" + integrity sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ== + +cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.4.tgz#8760e4ecc272f4c363532f926d874aae2c1397de" + integrity sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q== + dependencies: + inherits "^2.0.1" + safe-buffer "^5.0.1" + +class-utils@^0.3.5: + version "0.3.6" + resolved "https://registry.yarnpkg.com/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463" + integrity sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg== + dependencies: + arr-union "^3.1.0" + define-property "^0.2.5" + isobject "^3.0.0" + static-extend "^0.1.1" + +cli-cursor@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-1.0.2.tgz#64da3f7d56a54412e59794bd62dc35295e8f2987" + integrity sha1-ZNo/fValRBLll5S9Ytw1KV6PKYc= + dependencies: + restore-cursor "^1.0.1" + +cli-cursor@^2.0.0, cli-cursor@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-2.1.0.tgz#b35dac376479facc3e94747d41d0d0f5238ffcb5" + integrity sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU= + dependencies: + restore-cursor "^2.0.0" + +cli-table3@~0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/cli-table3/-/cli-table3-0.6.0.tgz#b7b1bc65ca8e7b5cef9124e13dc2b21e2ce4faee" + integrity sha512-gnB85c3MGC7Nm9I/FkiasNBOKjOiO1RNuXXarQms37q4QMpWdlbBgD/VnOStA2faG1dpXMv31RFApjX1/QdgWQ== + dependencies: + object-assign "^4.1.0" + string-width "^4.2.0" + optionalDependencies: + colors "^1.1.2" + +cli-truncate@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/cli-truncate/-/cli-truncate-0.2.1.tgz#9f15cfbb0705005369216c626ac7d05ab90dd574" + integrity sha1-nxXPuwcFAFNpIWxiasfQWrkN1XQ= + dependencies: + slice-ansi "0.0.4" + string-width "^1.0.1" + +cliui@^7.0.2: + version "7.0.4" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-7.0.4.tgz#a0265ee655476fc807aea9df3df8df7783808b4f" + integrity sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ== + dependencies: + string-width "^4.2.0" + strip-ansi "^6.0.0" + wrap-ansi "^7.0.0" + +code-point-at@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" + integrity sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c= + +collapse-white-space@^1.0.2: + version "1.0.6" + resolved "https://registry.yarnpkg.com/collapse-white-space/-/collapse-white-space-1.0.6.tgz#e63629c0016665792060dbbeb79c42239d2c5287" + integrity sha512-jEovNnrhMuqyCcjfEJA56v0Xq8SkIoPKDyaHahwo3POf4qcSXqMYuwNcOTzp74vTsR9Tn08z4MxWqAhcekogkQ== + +collection-visit@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/collection-visit/-/collection-visit-1.0.0.tgz#4bc0373c164bc3291b4d368c829cf1a80a59dca0" + integrity sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA= + dependencies: + map-visit "^1.0.0" + object-visit "^1.0.0" + +color-convert@^1.9.0: + version "1.9.3" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" + integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== + dependencies: + color-name "1.1.3" + +color-convert@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" + integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== + dependencies: + color-name "~1.1.4" + +color-name@1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" + integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= + +color-name@~1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" + integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== + +colors@^1.1.2: + version "1.4.0" + resolved "https://registry.yarnpkg.com/colors/-/colors-1.4.0.tgz#c50491479d4c1bdaed2c9ced32cf7c7dc2360f78" + integrity sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA== + +combined-stream@^1.0.6, combined-stream@~1.0.6: + version "1.0.8" + resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" + integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== + dependencies: + delayed-stream "~1.0.0" + +commander@^2.20.0: + version "2.20.3" + 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: + version "5.1.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-5.1.0.tgz#46abbd1652f8e059bddaef99bbdcb2ad9cf179ae" + integrity sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg== + +common-tags@^1.8.0: + version "1.8.0" + resolved "https://registry.yarnpkg.com/common-tags/-/common-tags-1.8.0.tgz#8e3153e542d4a39e9b10554434afaaf98956a937" + integrity sha512-6P6g0uetGpW/sdyUy/iQQCbFF0kWVMSIVSyYz7Zgjcgh8mgw8PQzDNZeyZ5DQ2gM7LBoZPHmnjz8rUthkBG5tw== + +commondir@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b" + integrity sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs= + +component-emitter@^1.2.1: + version "1.3.0" + resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0" + integrity sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg== + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= + +concat-stream@^1.5.0, concat-stream@^1.6.2: + version "1.6.2" + resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34" + integrity sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw== + dependencies: + buffer-from "^1.0.0" + inherits "^2.0.3" + readable-stream "^2.2.2" + typedarray "^0.0.6" + +console-browserify@^1.1.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/console-browserify/-/console-browserify-1.2.0.tgz#67063cef57ceb6cf4993a2ab3a55840ae8c49336" + integrity sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA== + +constants-browserify@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/constants-browserify/-/constants-browserify-1.0.0.tgz#c20b96d8c617748aaf1c16021760cd27fcb8cb75" + integrity sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U= + +convert-source-map@^1.4.0, convert-source-map@^1.5.0, convert-source-map@^1.7.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.7.0.tgz#17a2cb882d7f77d3490585e2ce6c524424a3a442" + integrity sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA== + dependencies: + safe-buffer "~5.1.1" + +copy-concurrently@^1.0.0: + version "1.0.5" + resolved "https://registry.yarnpkg.com/copy-concurrently/-/copy-concurrently-1.0.5.tgz#92297398cae34937fcafd6ec8139c18051f0b5e0" + integrity sha512-f2domd9fsVDFtaFcbaRZuYXwtdmnzqbADSwhSWYxYB/Q8zsdUUFMXVRwXGDMWmbEzAn1kdRrtI1T/KTFOL4X2A== + dependencies: + aproba "^1.1.1" + fs-write-stream-atomic "^1.0.8" + iferr "^0.1.5" + mkdirp "^0.5.1" + rimraf "^2.5.4" + run-queue "^1.0.0" + +copy-descriptor@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" + integrity sha1-Z29us8OZl8LuGsOpJP1hJHSPV40= + +core-js@^2.4.0, core-js@^2.5.0: + version "2.6.11" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.11.tgz#38831469f9922bded8ee21c9dc46985e0399308c" + integrity sha512-5wjnpaT/3dV+XB4borEsnAYQchn00XSgTAWKDkEqv+K8KevjbzmofK6hfJ9TZIlpj2N0xQpazy7PiRQiWHqzWg== + +core-js@^3.6.0, core-js@^3.8.3: + version "3.26.1" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.26.1.tgz#7a9816dabd9ee846c1c0fe0e8fcad68f3709134e" + integrity sha512-21491RRQVzUn0GGM9Z1Jrpr6PNPxPi+Za8OM9q4tksTSnlbXXGKK1nXNg/QvwFYettXvSX6zWKCtHHfjN4puyA== + +core-util-is@1.0.2, core-util-is@~1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" + integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac= + +cosmiconfig@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-6.0.0.tgz#da4fee853c52f6b1e6935f41c1a2fc50bd4a9982" + integrity sha512-xb3ZL6+L8b9JLLCx3ZdoZy4+2ECphCMo2PwqgP1tlfVq6M6YReyzBJtvWWtbDSpNr9hn96pkCiZqUcFEc+54Qg== + 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" + +create-ecdh@^4.0.0: + version "4.0.4" + resolved "https://registry.yarnpkg.com/create-ecdh/-/create-ecdh-4.0.4.tgz#d6e7f4bffa66736085a0762fd3a632684dabcc4e" + integrity sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A== + dependencies: + bn.js "^4.1.0" + elliptic "^6.5.3" + +create-hash@^1.1.0, create-hash@^1.1.2, create-hash@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/create-hash/-/create-hash-1.2.0.tgz#889078af11a63756bcfb59bd221996be3a9ef196" + integrity sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg== + dependencies: + cipher-base "^1.0.1" + inherits "^2.0.1" + md5.js "^1.3.4" + ripemd160 "^2.0.1" + sha.js "^2.4.0" + +create-hmac@^1.1.0, create-hmac@^1.1.4, create-hmac@^1.1.7: + version "1.1.7" + resolved "https://registry.yarnpkg.com/create-hmac/-/create-hmac-1.1.7.tgz#69170c78b3ab957147b2b8b04572e47ead2243ff" + integrity sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg== + dependencies: + cipher-base "^1.0.3" + create-hash "^1.1.0" + inherits "^2.0.1" + ripemd160 "^2.0.0" + safe-buffer "^5.0.1" + sha.js "^2.4.8" + +cron-validator@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/cron-validator/-/cron-validator-1.1.1.tgz#0a27bb75508c7bc03c8b840d2d9f170eeacb5615" + integrity sha512-vfZb05w/wezuwPZBDvdIBmJp2BvuJExHeyKRa5oBqD2ZDXR61hb3QgPc/3ZhBEQJlAy8Jlnn5XC/JCT3IDqxwg== + +cross-fetch@3.1.5: + version "3.1.5" + resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-3.1.5.tgz#e1389f44d9e7ba767907f7af8454787952ab534f" + integrity sha512-lvb1SBsI0Z7GDwmuid+mU3kWVBwTVUbe7S0H52yaaAdQOXq2YktTCZdlAcNKFzE6QtRz0snpw9bNiPeOIkkQvw== + dependencies: + node-fetch "2.6.7" + +cross-fetch@^3.0.4: + version "3.0.6" + resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-3.0.6.tgz#3a4040bc8941e653e0e9cf17f29ebcd177d3365c" + integrity sha512-KBPUbqgFjzWlVcURG+Svp9TlhA5uliYtiNx/0r8nv0pdypeQCRJ9IaSIc3q/x3q8t3F75cHuwxVql1HFGHCNJQ== + dependencies: + node-fetch "2.6.1" + +cross-spawn@^6.0.0: + version "6.0.5" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" + integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ== + dependencies: + nice-try "^1.0.4" + path-key "^2.0.1" + semver "^5.5.0" + shebang-command "^1.2.0" + which "^1.2.9" + +cross-spawn@^7.0.0: + version "7.0.3" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" + integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== + dependencies: + path-key "^3.1.0" + shebang-command "^2.0.0" + which "^2.0.1" + +crypto-browserify@^3.11.0: + version "3.12.0" + resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.12.0.tgz#396cf9f3137f03e4b8e532c58f698254e00f80ec" + integrity sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg== + dependencies: + browserify-cipher "^1.0.0" + browserify-sign "^4.0.0" + create-ecdh "^4.0.0" + create-hash "^1.1.0" + create-hmac "^1.1.0" + diffie-hellman "^5.0.0" + inherits "^2.0.1" + pbkdf2 "^3.0.3" + public-encrypt "^4.0.0" + randombytes "^2.0.0" + randomfill "^1.0.3" + +css-line-break@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/css-line-break/-/css-line-break-2.1.0.tgz#bfef660dfa6f5397ea54116bb3cb4873edbc4fa0" + integrity sha512-FHcKFCZcAha3LwfVBhCQbW2nCNbkZXn7KVUJcsT5/P8YmfsVja0FMPJr0B903j/E69HUphKiV9iQArX8SDYA4w== + dependencies: + utrie "^1.0.2" + +css-select@~1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/css-select/-/css-select-1.2.0.tgz#2b3a110539c5355f1cd8d314623e870b121ec858" + integrity sha1-KzoRBTnFNV8c2NMUYj6HCxIeyFg= + dependencies: + boolbase "~1.0.0" + css-what "2.1" + domutils "1.5.1" + nth-check "~1.0.1" + +css-what@2.1: + version "2.1.3" + resolved "https://registry.yarnpkg.com/css-what/-/css-what-2.1.3.tgz#a6d7604573365fe74686c3f311c56513d88285f2" + integrity sha512-a+EPoD+uZiNfh+5fxw2nO9QwFa6nJe2Or35fGY6Ipw1R3R4AGz1d1TEZrCegvw2YTmZ0jXirGYlzxxpYSHwpEg== + +cssom@0.3.x, cssom@^0.3.4: + version "0.3.8" + resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.3.8.tgz#9f1276f5b2b463f2114d3f2c75250af8c1a36f4a" + integrity sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg== + +cssstyle@^1.1.1: + version "1.4.0" + resolved "https://registry.yarnpkg.com/cssstyle/-/cssstyle-1.4.0.tgz#9d31328229d3c565c61e586b02041a28fccdccf1" + integrity sha512-GBrLZYZ4X4x6/QEoBnIrqb8B/f5l4+8me2dkom/j1Gtbxy0kBv6OGzKuAsGM75bkGwGAFkt56Iwg28S3XTZgSA== + dependencies: + cssom "0.3.x" + +csstype@^2.5.7: + version "2.6.13" + resolved "https://registry.yarnpkg.com/csstype/-/csstype-2.6.13.tgz#a6893015b90e84dd6e85d0e3b442a1e84f2dbe0f" + integrity sha512-ul26pfSQTZW8dcOnD2iiJssfXw0gdNVX9IJDH/X3K5DGPfj+fUYe3kB+swUY6BF3oZDxaID3AJt+9/ojSAE05A== + +csstype@^3.0.2: + version "3.0.3" + resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.0.3.tgz#2b410bbeba38ba9633353aff34b05d9755d065f8" + integrity sha512-jPl+wbWPOWJ7SXsWyqGRk3lGecbar0Cb0OvZF/r/ZU011R4YqiRehgkQ9p4eQfo9DSDLqLL3wHwfxeJiuIsNag== + +cyclist@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/cyclist/-/cyclist-1.0.1.tgz#596e9698fd0c80e12038c2b82d6eb1b35b6224d9" + integrity sha1-WW6WmP0MgOEgOMK4LW6xs1tiJNk= + +cypress@^5.0.0: + version "5.6.0" + resolved "https://registry.yarnpkg.com/cypress/-/cypress-5.6.0.tgz#6781755c3ddfd644ce3179fcd7389176c0c82280" + integrity sha512-cs5vG3E2JLldAc16+5yQxaVRLLqMVya5RlrfPWkC72S5xrlHFdw7ovxPb61s4wYweROKTyH01WQc2PFzwwVvyQ== + dependencies: + "@cypress/listr-verbose-renderer" "^0.4.1" + "@cypress/request" "^2.88.5" + "@cypress/xvfb" "^1.2.4" + "@types/sinonjs__fake-timers" "^6.0.1" + "@types/sizzle" "^2.3.2" + arch "^2.1.2" + blob-util "2.0.2" + bluebird "^3.7.2" + cachedir "^2.3.0" + chalk "^4.1.0" + check-more-types "^2.24.0" + cli-table3 "~0.6.0" + commander "^5.1.0" + common-tags "^1.8.0" + debug "^4.1.1" + eventemitter2 "^6.4.2" + execa "^4.0.2" + executable "^4.1.1" + extract-zip "^1.7.0" + fs-extra "^9.0.1" + getos "^3.2.1" + is-ci "^2.0.0" + is-installed-globally "^0.3.2" + lazy-ass "^1.6.0" + listr "^0.14.3" + lodash "^4.17.19" + log-symbols "^4.0.0" + minimist "^1.2.5" + moment "^2.27.0" + ospath "^1.2.2" + pretty-bytes "^5.4.1" + ramda "~0.26.1" + request-progress "^3.0.0" + supports-color "^7.2.0" + tmp "~0.2.1" + untildify "^4.0.0" + url "^0.11.0" + yauzl "^2.10.0" + +dashdash@^1.12.0: + version "1.14.1" + resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" + integrity sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA= + dependencies: + assert-plus "^1.0.0" + +data-urls@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/data-urls/-/data-urls-1.1.0.tgz#15ee0582baa5e22bb59c77140da8f9c76963bbfe" + integrity sha512-YTWYI9se1P55u58gL5GkQHW4P6VJBJ5iBT+B5a7i2Tjadhv52paJG0qHX4A0OR6/t52odI64KP2YvFpkDOi3eQ== + dependencies: + abab "^2.0.0" + whatwg-mimetype "^2.2.0" + whatwg-url "^7.0.0" + +date-fns@^1.27.2: + version "1.30.1" + resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-1.30.1.tgz#2e71bf0b119153dbb4cc4e88d9ea5acfb50dc05c" + integrity sha512-hBSVCvSmWC+QypYObzwGOd9wqdDpOt+0wl0KbU+R+uuZBS1jN8VsD1ss3irQDknRj5NvxiTF6oj/nDRnN/UQNw== + +debug@4, debug@4.3.4: + version "4.3.4" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" + integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== + dependencies: + ms "2.1.2" + +debug@^2.2.0, debug@^2.3.3, debug@^2.6.8, debug@^2.6.9: + version "2.6.9" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" + integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== + dependencies: + ms "2.0.0" + +debug@^3.1.0: + version "3.2.7" + resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a" + integrity sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ== + dependencies: + ms "^2.1.1" + +debug@^4.1.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791" + integrity sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw== + dependencies: + ms "^2.1.1" + +debug@^4.1.1: + version "4.3.1" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.1.tgz#f0d229c505e0c6d8c49ac553d1b13dc183f6b2ee" + integrity sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ== + dependencies: + ms "2.1.2" + +decamelize@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" + integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA= + +decode-uri-component@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545" + integrity sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU= + +deeks@2.2.6: + version "2.2.6" + resolved "https://registry.yarnpkg.com/deeks/-/deeks-2.2.6.tgz#7fc4c07c4251e1deb7e919fd14734fea151dc8b2" + integrity sha512-KlfWy96oUxxfAEC8q8QVoik++6yWsTYT9Cm5S6nUddLciZaOy7WDfcFbVCyeHKFO44ptWxtz7sQd9Upm4SGf4g== + +deep-is@~0.1.3: + version "0.1.3" + resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" + integrity sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ= + +define-properties@^1.1.2, define-properties@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1" + integrity sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ== + dependencies: + object-keys "^1.0.12" + +define-property@^0.2.5: + version "0.2.5" + resolved "https://registry.yarnpkg.com/define-property/-/define-property-0.2.5.tgz#c35b1ef918ec3c990f9a5bc57be04aacec5c8116" + integrity sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY= + dependencies: + is-descriptor "^0.1.0" + +define-property@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/define-property/-/define-property-1.0.0.tgz#769ebaaf3f4a63aad3af9e8d304c9bbe79bfb0e6" + integrity sha1-dp66rz9KY6rTr56NMEybvnm/sOY= + dependencies: + is-descriptor "^1.0.0" + +define-property@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/define-property/-/define-property-2.0.2.tgz#d459689e8d654ba77e02a817f8710d702cb16e9d" + integrity sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ== + dependencies: + is-descriptor "^1.0.2" + isobject "^3.0.1" + +delayed-stream@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" + integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk= + +des.js@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/des.js/-/des.js-1.0.1.tgz#5382142e1bdc53f85d86d53e5f4aa7deb91e0843" + integrity sha512-Q0I4pfFrv2VPd34/vfLrFOoRmlYj3OV50i7fskps1jZWK1kApMWWT9G6RRUeYedLcBDIhnSDaUvJMb3AhUlaEA== + dependencies: + inherits "^2.0.1" + minimalistic-assert "^1.0.0" + +devtools-protocol@0.0.981744: + version "0.0.981744" + resolved "https://registry.yarnpkg.com/devtools-protocol/-/devtools-protocol-0.0.981744.tgz#9960da0370284577d46c28979a0b32651022bacf" + integrity sha512-0cuGS8+jhR67Fy7qG3i3Pc7Aw494sb9yG9QgpG97SFVWwolgYjlhJg7n+UaHxOQT30d1TYu/EYe9k01ivLErIg== + +diff-sequences@^25.2.6: + version "25.2.6" + resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-25.2.6.tgz#5f467c00edd35352b7bca46d7927d60e687a76dd" + integrity sha512-Hq8o7+6GaZeoFjtpgvRBUknSXNeJiCx7V9Fr94ZMljNiCr9n9L8H8aJqgWOQiDDGdyn29fRNcDdRVJ5fdyihfg== + +diffie-hellman@^5.0.0: + version "5.0.3" + resolved "https://registry.yarnpkg.com/diffie-hellman/-/diffie-hellman-5.0.3.tgz#40e8ee98f55a2149607146921c63e1ae5f3d2875" + integrity sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg== + dependencies: + bn.js "^4.1.0" + miller-rabin "^4.0.0" + randombytes "^2.0.0" + +doc-path@2.0.4, doc-path@2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/doc-path/-/doc-path-2.1.2.tgz#08344d188619a6ff7c6631e462362dd720e4e81f" + integrity sha512-saM17czrIb4jYLsS5728OKbCa/WQ3xVctkGiMixOHz3X1VYsRn/Q5xPMxE1A5WN+XHHLWak34mMMjmAKRgMLeA== + +dom-helpers@^5.0.1: + version "5.2.0" + resolved "https://registry.yarnpkg.com/dom-helpers/-/dom-helpers-5.2.0.tgz#57fd054c5f8f34c52a3eeffdb7e7e93cd357d95b" + integrity sha512-Ru5o9+V8CpunKnz5LGgWXkmrH/20cGKwcHwS4m73zIvs54CN9epEmT/HLqFJW3kXpakAFkEdzgy1hzlJe3E4OQ== + dependencies: + "@babel/runtime" "^7.8.7" + csstype "^3.0.2" + +dom-serializer@0: + version "0.2.2" + resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-0.2.2.tgz#1afb81f533717175d478655debc5e332d9f9bb51" + integrity sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g== + dependencies: + domelementtype "^2.0.1" + entities "^2.0.0" + +dom-serializer@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-1.0.1.tgz#79695eb49af3cd8abc8d93a73da382deb1ca0795" + integrity sha512-1Aj1Qy3YLbdslkI75QEOfdp9TkQ3o8LRISAzxOibjBs/xWwr1WxZFOQphFkZuepHFGo+kB8e5FVJSS0faAJ4Rw== + dependencies: + domelementtype "^2.0.1" + domhandler "^3.0.0" + entities "^2.0.0" + +dom-serializer@~0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-0.1.1.tgz#1ec4059e284babed36eec2941d4a970a189ce7c0" + integrity sha512-l0IU0pPzLWSHBcieZbpOKgkIn3ts3vAh7ZuFyXNwJxJXk/c4Gwj9xaTJwIDVQCXawWD0qb3IzMGH5rglQaO0XA== + dependencies: + domelementtype "^1.3.0" + entities "^1.1.1" + +domain-browser@^1.1.1: + version "1.2.0" + resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-1.2.0.tgz#3d31f50191a6749dd1375a7f522e823d42e54eda" + integrity sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA== + +domelementtype@1, domelementtype@^1.3.0, domelementtype@^1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-1.3.1.tgz#d048c44b37b0d10a7f2a3d5fee3f4333d790481f" + integrity sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w== + +domelementtype@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-2.0.1.tgz#1f8bdfe91f5a78063274e803b4bdcedf6e94f94d" + integrity sha512-5HOHUDsYZWV8FGWN0Njbr/Rn7f/eWSQi1v7+HsUVwXgn8nWWlL64zKDkS0n8ZmQ3mlWOMuXOnR+7Nx/5tMO5AQ== + +domexception@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/domexception/-/domexception-1.0.1.tgz#937442644ca6a31261ef36e3ec677fe805582c90" + integrity sha512-raigMkn7CJNNo6Ihro1fzG7wr3fHuYVytzquZKX5n0yizGsTcYgzdIUwj1X9pK0VvjeihV+XiclP+DjwbsSKug== + dependencies: + webidl-conversions "^4.0.2" + +domhandler@^2.3.0: + version "2.4.2" + resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-2.4.2.tgz#8805097e933d65e85546f726d60f5eb88b44f803" + integrity sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA== + dependencies: + domelementtype "1" + +domhandler@^3.0, domhandler@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-3.0.0.tgz#51cd13efca31da95bbb0c5bee3a48300e333b3e9" + integrity sha512-eKLdI5v9m67kbXQbJSNn1zjh0SDzvzWVWtX+qEI3eMjZw8daH9k8rlj1FZY9memPwjiskQFbe7vHVVJIAqoEhw== + dependencies: + domelementtype "^2.0.1" + +dompurify@^2.3.8: + version "2.3.8" + resolved "https://registry.yarnpkg.com/dompurify/-/dompurify-2.3.8.tgz#224fe9ae57d7ebd9a1ae1ac18c1c1ca3f532226f" + integrity sha512-eVhaWoVibIzqdGYjwsBWodIQIaXFSB+cKDf4cfxLMsK0xiud6SE+/WCVx/Xw/UwQsa4cS3T2eITcdtmTg2UKcw== + +dompurify@^2.2.0: + version "2.4.1" + resolved "https://registry.yarnpkg.com/dompurify/-/dompurify-2.4.1.tgz#f9cb1a275fde9af6f2d0a2644ef648dd6847b631" + integrity sha512-ewwFzHzrrneRjxzmK6oVz/rZn9VWspGFRDb4/rRtIsM1n36t9AKma/ye8syCpcw+XJ25kOK/hOG7t1j2I2yBqA== + +domutils@1.5.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/domutils/-/domutils-1.5.1.tgz#dcd8488a26f563d61079e48c9f7b7e32373682cf" + integrity sha1-3NhIiib1Y9YQeeSMn3t+Mjc2gs8= + dependencies: + dom-serializer "0" + domelementtype "1" + +domutils@^1.5.1: + version "1.7.0" + resolved "https://registry.yarnpkg.com/domutils/-/domutils-1.7.0.tgz#56ea341e834e06e6748af7a1cb25da67ea9f8c2a" + integrity sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg== + dependencies: + dom-serializer "0" + domelementtype "1" + +domutils@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/domutils/-/domutils-2.2.0.tgz#f3ce1610af5c30280bde1b71f84b018b958f32cf" + integrity sha512-0haAxVr1PR0SqYwCH7mxMpHZUwjih9oPPedqpR/KufsnxPyZ9dyVw1R5093qnJF3WXSbjBkdzRWLw/knJV/fAg== + dependencies: + dom-serializer "^1.0.1" + domelementtype "^2.0.1" + domhandler "^3.0.0" + +duplexify@^3.4.2, duplexify@^3.6.0: + version "3.7.1" + resolved "https://registry.yarnpkg.com/duplexify/-/duplexify-3.7.1.tgz#2a4df5317f6ccfd91f86d6fd25d8d8a103b88309" + integrity sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g== + dependencies: + end-of-stream "^1.0.0" + inherits "^2.0.1" + readable-stream "^2.0.0" + stream-shift "^1.0.0" + +ecc-jsbn@~0.1.1: + version "0.1.2" + resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9" + integrity sha1-OoOpBOVDUyh4dMVkt1SThoSamMk= + dependencies: + jsbn "~0.1.0" + safer-buffer "^2.1.0" + +elastic-builder@^2.7.1: + version "2.7.1" + resolved "https://registry.yarnpkg.com/elastic-builder/-/elastic-builder-2.7.1.tgz#46657831eb93f4c1f42dce1779479a1c98e1bcb7" + integrity sha512-tBhrNDiP5ef+xdKMU5Xp1ssaHONxnIAjs0S7W2BNPJxKcGTxcFLgErRJTZS//Go5RwyQrrvDyGoSrfDqwXLMng== + dependencies: + babel-runtime "^6.26.0" + lodash.has "^4.5.2" + lodash.hasin "^4.5.2" + lodash.head "^4.0.1" + lodash.isempty "^4.4.0" + lodash.isnil "^4.0.0" + lodash.isobject "^3.0.2" + lodash.isstring "^4.0.1" + lodash.omit "^4.5.0" + +elegant-spinner@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/elegant-spinner/-/elegant-spinner-1.0.1.tgz#db043521c95d7e303fd8f345bedc3349cfb0729e" + integrity sha1-2wQ1IcldfjA/2PNFvtwzSc+wcp4= + +elliptic@^6.5.3: + version "6.5.3" + resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.3.tgz#cb59eb2efdaf73a0bd78ccd7015a62ad6e0f93d6" + integrity sha512-IMqzv5wNQf+E6aHeIqATs0tOLeOTwj1QKbRcS3jBbYkl5oLAserA8yJTT7/VyHUYG91PRmPyeQDObKLPpeS4dw== + dependencies: + bn.js "^4.4.0" + brorand "^1.0.1" + hash.js "^1.0.0" + hmac-drbg "^1.0.0" + inherits "^2.0.1" + minimalistic-assert "^1.0.0" + minimalistic-crypto-utils "^1.0.0" + +emoji-regex@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" + integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== + +emojis-list@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-3.0.0.tgz#5570662046ad29e2e916e71aae260abdff4f6a78" + integrity sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q== + +end-of-stream@^1.0.0, end-of-stream@^1.1.0, end-of-stream@^1.4.1: + version "1.4.4" + resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0" + integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q== + dependencies: + once "^1.4.0" + +enhanced-resolve@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-4.3.0.tgz#3b806f3bfafc1ec7de69551ef93cca46c1704126" + integrity sha512-3e87LvavsdxyoCfGusJnrZ5G8SLPOFeHSNpZI/ATL9a5leXo2k0w6MKnbqhdBad9qTobSfB20Ld7UmgoNbAZkQ== + dependencies: + graceful-fs "^4.1.2" + memory-fs "^0.5.0" + tapable "^1.0.0" + +enhanced-resolve@~0.9.0: + version "0.9.1" + resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-0.9.1.tgz#4d6e689b3725f86090927ccc86cd9f1635b89e2e" + integrity sha1-TW5omzcl+GCQknzMhs2fFjW4ni4= + dependencies: + graceful-fs "^4.1.2" + memory-fs "^0.2.0" + tapable "^0.1.8" + +entities@^1.1.1, entities@~1.1.1: + version "1.1.2" + resolved "https://registry.yarnpkg.com/entities/-/entities-1.1.2.tgz#bdfa735299664dfafd34529ed4f8522a275fea56" + integrity sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w== + +entities@^2.0.0: + version "2.0.3" + resolved "https://registry.yarnpkg.com/entities/-/entities-2.0.3.tgz#5c487e5742ab93c15abb5da22759b8590ec03b7f" + integrity sha512-MyoZ0jgnLvB2X3Lg5HqpFmn1kybDiIfEQmKzTb5apr51Rb+T3KdmMiqa70T+bhGnyv7bQ6WMj2QMHpGMmlrUYQ== + +enzyme-adapter-react-16@^1.15.2: + version "1.15.5" + resolved "https://registry.yarnpkg.com/enzyme-adapter-react-16/-/enzyme-adapter-react-16-1.15.5.tgz#7a6f0093d3edd2f7025b36e7fbf290695473ee04" + integrity sha512-33yUJGT1nHFQlbVI5qdo5Pfqvu/h4qPwi1o0a6ZZsjpiqq92a3HjynDhwd1IeED+Su60HDWV8mxJqkTnLYdGkw== + dependencies: + enzyme-adapter-utils "^1.13.1" + enzyme-shallow-equal "^1.0.4" + has "^1.0.3" + object.assign "^4.1.0" + object.values "^1.1.1" + prop-types "^15.7.2" + react-is "^16.13.1" + react-test-renderer "^16.0.0-0" + semver "^5.7.0" + +enzyme-adapter-utils@^1.13.1: + version "1.13.1" + resolved "https://registry.yarnpkg.com/enzyme-adapter-utils/-/enzyme-adapter-utils-1.13.1.tgz#59c1b734b0927543e3d8dc477299ec957feb312d" + integrity sha512-5A9MXXgmh/Tkvee3bL/9RCAAgleHqFnsurTYCbymecO4ohvtNO5zqIhHxV370t7nJAwaCfkgtffarKpC0GPt0g== + dependencies: + airbnb-prop-types "^2.16.0" + function.prototype.name "^1.1.2" + object.assign "^4.1.0" + object.fromentries "^2.0.2" + prop-types "^15.7.2" + semver "^5.7.1" + +enzyme-shallow-equal@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/enzyme-shallow-equal/-/enzyme-shallow-equal-1.0.4.tgz#b9256cb25a5f430f9bfe073a84808c1d74fced2e" + integrity sha512-MttIwB8kKxypwHvRynuC3ahyNc+cFbR8mjVIltnmzQ0uKGqmsfO4bfBuLxb0beLNPhjblUEYvEbsg+VSygvF1Q== + dependencies: + has "^1.0.3" + object-is "^1.1.2" + +errno@^0.1.3, errno@~0.1.7: + version "0.1.7" + resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.7.tgz#4684d71779ad39af177e3f007996f7c67c852618" + integrity sha512-MfrRBDWzIWifgq6tJj60gkAwtLNb6sQPlcFrSOflcP1aFmmruKQ2wRnze/8V6kgyz7H3FF8Npzv78mZ7XLLflg== + dependencies: + prr "~1.0.1" + +error-ex@^1.3.1: + version "1.3.2" + resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" + integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g== + dependencies: + is-arrayish "^0.2.1" + +es-abstract@^1.17.0-next.1, es-abstract@^1.17.5: + version "1.17.6" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.17.6.tgz#9142071707857b2cacc7b89ecb670316c3e2d52a" + integrity sha512-Fr89bON3WFyUi5EvAeI48QTWX0AyekGgLA8H+c+7fbfCkJwRWRMLd8CQedNEyJuoYYhmtEqY92pgte1FAhBlhw== + dependencies: + es-to-primitive "^1.2.1" + function-bind "^1.1.1" + has "^1.0.3" + has-symbols "^1.0.1" + is-callable "^1.2.0" + is-regex "^1.1.0" + object-inspect "^1.7.0" + object-keys "^1.1.1" + object.assign "^4.1.0" + string.prototype.trimend "^1.0.1" + string.prototype.trimstart "^1.0.1" + +es-abstract@^1.17.4: + version "1.17.7" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.17.7.tgz#a4de61b2f66989fc7421676c1cb9787573ace54c" + integrity sha512-VBl/gnfcJ7OercKA9MVaegWsBHFjV492syMudcnQZvt/Dw8ezpcOHYZXa/J96O8vx+g4x65YKhxOwDUh63aS5g== + dependencies: + es-to-primitive "^1.2.1" + function-bind "^1.1.1" + has "^1.0.3" + has-symbols "^1.0.1" + is-callable "^1.2.2" + is-regex "^1.1.1" + object-inspect "^1.8.0" + object-keys "^1.1.1" + object.assign "^4.1.1" + string.prototype.trimend "^1.0.1" + string.prototype.trimstart "^1.0.1" + +es-abstract@^1.18.0-next.1: + version "1.18.0-next.1" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.18.0-next.1.tgz#6e3a0a4bda717e5023ab3b8e90bec36108d22c68" + integrity sha512-I4UGspA0wpZXWENrdA0uHbnhte683t3qT/1VFH9aX2dA5PPSf6QW5HHXf5HImaqPmjXaVeVk4RGWnaylmV7uAA== + dependencies: + es-to-primitive "^1.2.1" + function-bind "^1.1.1" + has "^1.0.3" + has-symbols "^1.0.1" + is-callable "^1.2.2" + is-negative-zero "^2.0.0" + is-regex "^1.1.1" + object-inspect "^1.8.0" + object-keys "^1.1.1" + object.assign "^4.1.1" + string.prototype.trimend "^1.0.1" + string.prototype.trimstart "^1.0.1" + +es-to-primitive@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.1.tgz#e55cd4c9cdc188bcefb03b366c736323fc5c898a" + integrity sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA== + dependencies: + is-callable "^1.1.4" + is-date-object "^1.0.1" + is-symbol "^1.0.2" + +escalade@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" + integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== + +escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= + +escodegen@^1.11.0: + version "1.14.3" + resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-1.14.3.tgz#4e7b81fba61581dc97582ed78cab7f0e8d63f503" + integrity sha512-qFcX0XJkdg+PB3xjZZG/wKSuT1PnQWx57+TVSjIMmILd2yC/6ByYElPwJnslDsuWuSAp4AwJGumarAAmJch5Kw== + dependencies: + esprima "^4.0.1" + estraverse "^4.2.0" + esutils "^2.0.2" + optionator "^0.8.1" + optionalDependencies: + source-map "~0.6.1" + +eslint-import-resolver-node@0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.2.tgz#58f15fb839b8d0576ca980413476aab2472db66a" + integrity sha512-sfmTqJfPSizWu4aymbPr4Iidp5yKm8yDkHp+Ir3YiTHiiDfxh69mOUsmiqW6RZ9zRXFaF64GtYmN7e+8GHBv6Q== + dependencies: + debug "^2.6.9" + resolve "^1.5.0" + +eslint-import-resolver-webpack@0.11.1: + version "0.11.1" + resolved "https://registry.yarnpkg.com/eslint-import-resolver-webpack/-/eslint-import-resolver-webpack-0.11.1.tgz#fcf1fd57a775f51e18f442915f85dd6ba45d2f26" + integrity sha512-eK3zR7xVQR/MaoBWwGuD+CULYVuqe5QFlDukman71aI6IboCGzggDUohHNfu1ZeBnbHcUHJc0ywWoXUBNB6qdg== + dependencies: + array-find "^1.0.0" + debug "^2.6.8" + enhanced-resolve "~0.9.0" + find-root "^1.1.0" + has "^1.0.1" + interpret "^1.0.0" + lodash "^4.17.4" + node-libs-browser "^1.0.0 || ^2.0.0" + resolve "^1.10.0" + semver "^5.3.0" + +eslint-plugin-babel@^5.3.0: + version "5.3.1" + resolved "https://registry.yarnpkg.com/eslint-plugin-babel/-/eslint-plugin-babel-5.3.1.tgz#75a2413ffbf17e7be57458301c60291f2cfbf560" + integrity sha512-VsQEr6NH3dj664+EyxJwO4FCYm/00JhYb3Sk3ft8o+fpKuIfQ9TaW6uVUfvwMXHcf/lsnRIoyFPsLMyiWCSL/g== + dependencies: + eslint-rule-composer "^0.3.0" + +eslint-plugin-no-unsanitized@^3.0.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/eslint-plugin-no-unsanitized/-/eslint-plugin-no-unsanitized-3.1.2.tgz#a54724e0b81d43279bb1f8f5e1d82c97da78c858" + integrity sha512-KPShfliA3Uy9qqwQx35P1fwIOeJjZkb0FbMMUFztRYRposzaynsM8JCEb952fqkidROl1kpqY80uSvn+TcWkQQ== + +eslint-plugin-prefer-object-spread@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/eslint-plugin-prefer-object-spread/-/eslint-plugin-prefer-object-spread-1.2.1.tgz#27fb91853690cceb3ae6101d9c8aecc6a67a402c" + integrity sha1-J/uRhTaQzOs65hAdnIrsxqZ6QCw= + +eslint-rule-composer@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/eslint-rule-composer/-/eslint-rule-composer-0.3.0.tgz#79320c927b0c5c0d3d3d2b76c8b4a488f25bbaf9" + integrity sha512-bt+Sh8CtDmn2OajxvNO+BX7Wn4CIWMpTRm3MaiKPCQcnnlm0CS2mhui6QaoeQugs+3Kj2ESKEEGJUdVafwhiCg== + +eslint-scope@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-4.0.3.tgz#ca03833310f6889a3264781aa82e63eb9cfe7848" + integrity sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg== + dependencies: + esrecurse "^4.1.0" + estraverse "^4.1.1" + +esprima@^4.0.0, esprima@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" + integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== + +esrecurse@^4.1.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921" + integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== + dependencies: + estraverse "^5.2.0" + +estraverse@^4.1.1, estraverse@^4.2.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" + integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== + +estraverse@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.2.0.tgz#307df42547e6cc7324d3cf03c155d5cdb8c53880" + integrity sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ== + +esutils@^2.0.2: + version "2.0.3" + resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" + integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== + +eventemitter2@^6.4.2: + version "6.4.3" + resolved "https://registry.yarnpkg.com/eventemitter2/-/eventemitter2-6.4.3.tgz#35c563619b13f3681e7eb05cbdaf50f56ba58820" + integrity sha512-t0A2msp6BzOf+QAcI6z9XMktLj52OjGQg+8SJH6v5+3uxNpWYRR3wQmfA+6xtMU9kOC59qk9licus5dYcrYkMQ== + +events@^3.0.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/events/-/events-3.2.0.tgz#93b87c18f8efcd4202a461aec4dfc0556b639379" + integrity sha512-/46HWwbfCX2xTawVfkKLGxMifJYQBWMwY1mjywRtb4c9x8l5NP3KoJtnIOiL1hfdRkIuYhETxQlo62IF8tcnlg== + +evp_bytestokey@^1.0.0, evp_bytestokey@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz#7fcbdb198dc71959432efe13842684e0525acb02" + integrity sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA== + dependencies: + md5.js "^1.3.4" + safe-buffer "^5.1.1" + +exec-sh@^0.3.2: + version "0.3.4" + resolved "https://registry.yarnpkg.com/exec-sh/-/exec-sh-0.3.4.tgz#3a018ceb526cc6f6df2bb504b2bfe8e3a4934ec5" + integrity sha512-sEFIkc61v75sWeOe72qyrqg2Qg0OuLESziUDk/O/z2qgS15y2gWVFrI6f2Qn/qw/0/NCfCEsmNA4zOjkwEZT1A== + +execa@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/execa/-/execa-1.0.0.tgz#c6236a5bb4df6d6f15e88e7f017798216749ddd8" + integrity sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA== + dependencies: + cross-spawn "^6.0.0" + get-stream "^4.0.0" + is-stream "^1.1.0" + npm-run-path "^2.0.0" + p-finally "^1.0.0" + signal-exit "^3.0.0" + strip-eof "^1.0.0" + +execa@^4.0.2: + version "4.1.0" + resolved "https://registry.yarnpkg.com/execa/-/execa-4.1.0.tgz#4e5491ad1572f2f17a77d388c6c857135b22847a" + integrity sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA== + 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" + +executable@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/executable/-/executable-4.1.1.tgz#41532bff361d3e57af4d763b70582db18f5d133c" + integrity sha512-8iA79xD3uAch729dUG8xaaBBFGaEa0wdD2VkYLFHwlqosEj/jT66AzcreRDSgV7ehnNLBW2WR5jIXwGKjVdTLg== + dependencies: + pify "^2.2.0" + +exit-hook@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/exit-hook/-/exit-hook-1.1.1.tgz#f05ca233b48c05d54fff07765df8507e95c02ff8" + integrity sha1-8FyiM7SMBdVP/wd2XfhQfpXAL/g= + +expand-brackets@^2.1.4: + version "2.1.4" + resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-2.1.4.tgz#b77735e315ce30f6b6eff0f83b04151a22449622" + integrity sha1-t3c14xXOMPa27/D4OwQVGiJEliI= + dependencies: + debug "^2.3.3" + define-property "^0.2.5" + extend-shallow "^2.0.1" + posix-character-classes "^0.1.0" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" + +extend-shallow@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f" + integrity sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8= + dependencies: + is-extendable "^0.1.0" + +extend-shallow@^3.0.0, extend-shallow@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-3.0.2.tgz#26a71aaf073b39fb2127172746131c2704028db8" + integrity sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg= + dependencies: + assign-symbols "^1.0.0" + is-extendable "^1.0.1" + +extend@^3.0.0, extend@~3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" + integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== + +extglob@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/extglob/-/extglob-2.0.4.tgz#ad00fe4dc612a9232e8718711dc5cb5ab0285543" + integrity sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw== + dependencies: + array-unique "^0.3.2" + define-property "^1.0.0" + expand-brackets "^2.1.4" + extend-shallow "^2.0.1" + fragment-cache "^0.2.1" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" + +extract-zip@^1.7.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/extract-zip/-/extract-zip-1.7.0.tgz#556cc3ae9df7f452c493a0cfb51cc30277940927" + integrity sha512-xoh5G1W/PB0/27lXgMQyIhP5DSY/LhoCsOyZgb+6iMmRtCwVBo55uKaMoEYrDCKQhWvqEip5ZPKAc6eFNyf/MA== + dependencies: + concat-stream "^1.6.2" + debug "^2.6.9" + mkdirp "^0.5.4" + yauzl "^2.10.0" + +extsprintf@1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05" + integrity sha1-lpGEQOMEGnpBT4xS48V06zw+HgU= + +extsprintf@^1.2.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f" + integrity sha1-4mifjzVvrWLMplo6kcXfX5VRaS8= + +fast-deep-equal@^3.1.1: + version "3.1.3" + resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" + integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== + +fast-json-stable-stringify@2.x, fast-json-stable-stringify@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" + integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== + +fast-levenshtein@~2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" + integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc= + +fb-watchman@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/fb-watchman/-/fb-watchman-2.0.1.tgz#fc84fb39d2709cf3ff6d743706157bb5708a8a85" + integrity sha512-DkPJKQeY6kKwmuMretBhr7G6Vodr7bFwDYTXIkfG1gjvNpaxBTQV3PbXg6bR1c1UP4jPOX0jHUbbHANL9vRjVg== + dependencies: + bser "2.1.1" + +fd-slicer@~1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/fd-slicer/-/fd-slicer-1.1.0.tgz#25c7c89cb1f9077f8891bbe61d8f390eae256f1e" + integrity sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4= + dependencies: + pend "~1.2.0" + +fflate@^0.4.8: + version "0.4.8" + resolved "https://registry.yarnpkg.com/fflate/-/fflate-0.4.8.tgz#f90b82aefbd8ac174213abb338bd7ef848f0f5ae" + integrity sha512-FJqqoDBR00Mdj9ppamLa/Y7vxm+PRmNWA67N846RvsoYVMKB4q3y/de5PA7gUmRMYK/8CMz2GDZQmCRN1wBcWA== + +figgy-pudding@^3.5.1: + version "3.5.2" + resolved "https://registry.yarnpkg.com/figgy-pudding/-/figgy-pudding-3.5.2.tgz#b4eee8148abb01dcf1d1ac34367d59e12fa61d6e" + integrity sha512-0btnI/H8f2pavGMN8w40mlSKOfTK2SVJmBfBeVIj3kNw0swwgzyRq0d5TJVOwodFmtvpPeWPN/MCcfuWF0Ezbw== + +figures@^1.7.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/figures/-/figures-1.7.0.tgz#cbe1e3affcf1cd44b80cadfed28dc793a9701d2e" + integrity sha1-y+Hjr/zxzUS4DK3+0o3Hk6lwHS4= + dependencies: + escape-string-regexp "^1.0.5" + object-assign "^4.1.0" + +figures@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/figures/-/figures-2.0.0.tgz#3ab1a2d2a62c8bfb431a0c94cb797a2fce27c962" + integrity sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI= + dependencies: + escape-string-regexp "^1.0.5" + +file-uri-to-path@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz#553a7b8446ff6f684359c445f1e37a05dacc33dd" + integrity sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw== + +fill-range@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-4.0.0.tgz#d544811d428f98eb06a63dc402d2403c328c38f7" + integrity sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc= + dependencies: + extend-shallow "^2.0.1" + is-number "^3.0.0" + repeat-string "^1.6.1" + to-regex-range "^2.1.0" + +fill-range@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" + integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== + dependencies: + to-regex-range "^5.0.1" + +find-cache-dir@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-2.1.0.tgz#8d0f94cd13fe43c6c7c261a0d86115ca918c05f7" + integrity sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ== + dependencies: + commondir "^1.0.1" + make-dir "^2.0.0" + pkg-dir "^3.0.0" + +find-root@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/find-root/-/find-root-1.1.0.tgz#abcfc8ba76f708c42a97b3d685b7e9450bfb9ce4" + integrity sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng== + +find-up@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-3.0.0.tgz#49169f1d7993430646da61ecc5ae355c21c97b73" + integrity sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg== + dependencies: + locate-path "^3.0.0" + +find-up@^4.0.0, find-up@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19" + integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw== + dependencies: + locate-path "^5.0.0" + path-exists "^4.0.0" + +flush-write-stream@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/flush-write-stream/-/flush-write-stream-1.1.1.tgz#8dd7d873a1babc207d94ead0c2e0e44276ebf2e8" + integrity sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w== + dependencies: + inherits "^2.0.3" + readable-stream "^2.3.6" + +for-in@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" + integrity sha1-gQaNKVqBQuwKxybG4iAMMPttXoA= + +forever-agent@~0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" + integrity sha1-+8cfDEGt6zf5bFd60e1C2P2sypE= + +form-data@~2.3.2: + version "2.3.3" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6" + integrity sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ== + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.6" + mime-types "^2.1.12" + +fragment-cache@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/fragment-cache/-/fragment-cache-0.2.1.tgz#4290fad27f13e89be7f33799c6bc5a0abfff0d19" + integrity sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk= + dependencies: + map-cache "^0.2.2" + +from2@^2.1.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/from2/-/from2-2.3.0.tgz#8bfb5502bde4a4d36cfdeea007fcca21d7e382af" + integrity sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8= + dependencies: + inherits "^2.0.1" + readable-stream "^2.0.0" + +fs-constants@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs-constants/-/fs-constants-1.0.0.tgz#6be0de9be998ce16af8afc24497b9ee9b7ccd9ad" + integrity sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow== + +fs-extra@^9.0.1: + version "9.1.0" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-9.1.0.tgz#5954460c764a8da2094ba3554bf839e6b9a7c86d" + integrity sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ== + dependencies: + at-least-node "^1.0.0" + graceful-fs "^4.2.0" + jsonfile "^6.0.1" + universalify "^2.0.0" + +fs-write-stream-atomic@^1.0.8: + version "1.0.10" + resolved "https://registry.yarnpkg.com/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz#b47df53493ef911df75731e70a9ded0189db40c9" + integrity sha1-tH31NJPvkR33VzHnCp3tAYnbQMk= + dependencies: + graceful-fs "^4.1.2" + iferr "^0.1.5" + imurmurhash "^0.1.4" + readable-stream "1 || 2" + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= + +fsevents@^1.2.7: + version "1.2.13" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.2.13.tgz#f325cb0455592428bcf11b383370ef70e3bfcc38" + integrity sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw== + dependencies: + bindings "^1.5.0" + nan "^2.12.1" + +fsevents@^2.1.2: + version "2.2.1" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.2.1.tgz#1fb02ded2036a8ac288d507a65962bd87b97628d" + integrity sha512-bTLYHSeC0UH/EFXS9KqWnXuOl/wHK5Z/d+ghd5AsFMYN7wIGkUCOJyzy88+wJKkZPGON8u4Z9f6U4FdgURE9qA== + +fsevents@~2.1.2: + version "2.1.3" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.1.3.tgz#fb738703ae8d2f9fe900c33836ddebee8b97f23e" + integrity sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ== + +function-bind@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" + integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== + +function.prototype.name@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/function.prototype.name/-/function.prototype.name-1.1.2.tgz#5cdf79d7c05db401591dfde83e3b70c5123e9a45" + integrity sha512-C8A+LlHBJjB2AdcRPorc5JvJ5VUoWlXdEHLOJdCI7kjHEtGTpHQUiqMvCIKUwIsGwZX2jZJy761AXsn356bJQg== + dependencies: + define-properties "^1.1.3" + es-abstract "^1.17.0-next.1" + functions-have-names "^1.2.0" + +functions-have-names@^1.2.0: + version "1.2.1" + resolved "https://registry.yarnpkg.com/functions-have-names/-/functions-have-names-1.2.1.tgz#a981ac397fa0c9964551402cdc5533d7a4d52f91" + integrity sha512-j48B/ZI7VKs3sgeI2cZp7WXWmZXu7Iq5pl5/vptV5N2mq+DGFuS/ulaDjtaoLpYzuD6u8UgrUKHfgo7fDTSiBA== + +gensync@^1.0.0-beta.1: + version "1.0.0-beta.2" + resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" + integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg== + +get-caller-file@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" + integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== + +get-intrinsic@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.0.1.tgz#94a9768fcbdd0595a1c9273aacf4c89d075631be" + integrity sha512-ZnWP+AmS1VUaLgTRy47+zKtjTxz+0xMpx3I52i+aalBK1QP19ggLF3Db89KJX7kjfOfP2eoa01qc++GwPgufPg== + dependencies: + function-bind "^1.1.1" + has "^1.0.3" + has-symbols "^1.0.1" + +get-package-type@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/get-package-type/-/get-package-type-0.1.0.tgz#8de2d803cff44df3bc6c456e6668b36c3926e11a" + integrity sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q== + +get-stream@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5" + integrity sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w== + dependencies: + pump "^3.0.0" + +get-stream@^5.0.0, get-stream@^5.1.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-5.2.0.tgz#4966a1795ee5ace65e706c4b7beb71257d6e22d3" + integrity sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA== + dependencies: + pump "^3.0.0" + +get-value@^2.0.3, get-value@^2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28" + integrity sha1-3BXKHGcjh8p2vTesCjlbogQqLCg= + +getos@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/getos/-/getos-3.2.1.tgz#0134d1f4e00eb46144c5a9c0ac4dc087cbb27dc5" + integrity sha512-U56CfOK17OKgTVqozZjUKNdkfEv6jk5WISBJ8SHoagjE6L69zOwl3Z+O8myjY9MEW3i2HPWQBt/LTbCgcC973Q== + dependencies: + async "^3.2.0" + +getpass@^0.1.1: + version "0.1.7" + resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa" + integrity sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo= + dependencies: + assert-plus "^1.0.0" + +glob-all@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/glob-all/-/glob-all-3.2.1.tgz#082ca81afd2247cbd3ed2149bb2630f4dc877d95" + integrity sha512-x877rVkzB3ipid577QOp+eQCR6M5ZyiwrtaYgrX/z3EThaSPFtLDwBXFHc3sH1cG0R0vFYI5SRYeWMMSEyXkUw== + dependencies: + glob "^7.1.2" + yargs "^15.3.1" + +glob-parent@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-3.1.0.tgz#9e6af6299d8d3bd2bd40430832bd113df906c5ae" + integrity sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4= + dependencies: + is-glob "^3.1.0" + path-dirname "^1.0.0" + +glob-parent@~5.1.0: + version "5.1.1" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.1.tgz#b6c1ef417c4e5663ea498f1c45afac6916bbc229" + integrity sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ== + dependencies: + is-glob "^4.0.1" + +glob@^7.1.2, glob@^7.1.3, glob@^7.1.4: + version "7.1.6" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6" + integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" + +glob@^7.2.0: + version "7.2.3" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" + integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.1.1" + once "^1.3.0" + path-is-absolute "^1.0.0" + +global-dirs@^2.0.1: + version "2.1.0" + resolved "https://registry.yarnpkg.com/global-dirs/-/global-dirs-2.1.0.tgz#e9046a49c806ff04d6c1825e196c8f0091e8df4d" + integrity sha512-MG6kdOUh/xBnyo9cJFeIKkLEc1AyFq42QTU4XiX51i2NEdxLxLWXIjEjmqKeSuKR7pAZjTqUVoT2b2huxVLgYQ== + dependencies: + ini "1.3.7" + +globals@^11.1.0: + version "11.12.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" + integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== + +graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.2.4: + version "4.2.4" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.4.tgz#2256bde14d3632958c465ebc96dc467ca07a29fb" + integrity sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw== + +graceful-fs@^4.1.6, graceful-fs@^4.2.0: + version "4.2.6" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.6.tgz#ff040b2b0853b23c3d31027523706f1885d76bee" + integrity sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ== + +har-schema@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92" + integrity sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI= + +har-validator@~5.1.3: + version "5.1.5" + resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.1.5.tgz#1f0803b9f8cb20c0fa13822df1ecddb36bde1efd" + integrity sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w== + dependencies: + ajv "^6.12.3" + har-schema "^2.0.0" + +harmony-reflect@^1.4.6: + version "1.6.1" + resolved "https://registry.yarnpkg.com/harmony-reflect/-/harmony-reflect-1.6.1.tgz#c108d4f2bb451efef7a37861fdbdae72c9bdefa9" + integrity sha512-WJTeyp0JzGtHcuMsi7rw2VwtkvLa+JyfEKJCFyfcS0+CDkjQ5lHPu7zEhFZP+PDSRrEgXa5Ah0l1MbgbE41XjA== + +has-ansi@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" + integrity sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE= + dependencies: + ansi-regex "^2.0.0" + +has-flag@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" + integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= + +has-flag@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" + integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== + +has-symbols@^1.0.0, has-symbols@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.1.tgz#9f5214758a44196c406d9bd76cebf81ec2dd31e8" + integrity sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg== + +has-value@^0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/has-value/-/has-value-0.3.1.tgz#7b1f58bada62ca827ec0a2078025654845995e1f" + integrity sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8= + dependencies: + get-value "^2.0.3" + has-values "^0.1.4" + isobject "^2.0.0" + +has-value@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-value/-/has-value-1.0.0.tgz#18b281da585b1c5c51def24c930ed29a0be6b177" + integrity sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc= + dependencies: + get-value "^2.0.6" + has-values "^1.0.0" + isobject "^3.0.0" + +has-values@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/has-values/-/has-values-0.1.4.tgz#6d61de95d91dfca9b9a02089ad384bff8f62b771" + integrity sha1-bWHeldkd/Km5oCCJrThL/49it3E= + +has-values@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-values/-/has-values-1.0.0.tgz#95b0b63fec2146619a6fe57fe75628d5a39efe4f" + integrity sha1-lbC2P+whRmGab+V/51Yo1aOe/k8= + dependencies: + is-number "^3.0.0" + kind-of "^4.0.0" + +has@^1.0.1, has@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" + integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== + dependencies: + function-bind "^1.1.1" + +hash-base@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/hash-base/-/hash-base-3.1.0.tgz#55c381d9e06e1d2997a883b4a3fddfe7f0d3af33" + integrity sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA== + dependencies: + inherits "^2.0.4" + readable-stream "^3.6.0" + safe-buffer "^5.2.0" + +hash.js@^1.0.0, hash.js@^1.0.3: + version "1.1.7" + resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.1.7.tgz#0babca538e8d4ee4a0f8988d68866537a003cf42" + integrity sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA== + dependencies: + inherits "^2.0.3" + minimalistic-assert "^1.0.1" + +history@^4.9.0: + version "4.10.1" + resolved "https://registry.yarnpkg.com/history/-/history-4.10.1.tgz#33371a65e3a83b267434e2b3f3b1b4c58aad4cf3" + integrity sha512-36nwAD620w12kuzPAsyINPWJqlNbij+hpK1k9XRloDtym8mxzGYl2c17LnV6IAGB2Dmg4tEa7G7DlawS0+qjew== + dependencies: + "@babel/runtime" "^7.1.2" + loose-envify "^1.2.0" + resolve-pathname "^3.0.0" + tiny-invariant "^1.0.2" + tiny-warning "^1.0.0" + value-equal "^1.0.1" + +hmac-drbg@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1" + integrity sha1-0nRXAQJabHdabFRXk+1QL8DGSaE= + dependencies: + hash.js "^1.0.3" + minimalistic-assert "^1.0.0" + minimalistic-crypto-utils "^1.0.1" + +hoist-non-react-statics@^2.3.1: + version "2.5.5" + resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-2.5.5.tgz#c5903cf409c0dfd908f388e619d86b9c1174cb47" + integrity sha512-rqcy4pJo55FTTLWt+bU8ukscqHeE/e9KWvsOW2b/a3afxQZhwkQdT1rPPCJ0rYXdj4vNcasY8zHTH+jF/qStxw== + +hoist-non-react-statics@^3.1.0, hoist-non-react-statics@^3.3.2: + version "3.3.2" + resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45" + integrity sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw== + dependencies: + react-is "^16.7.0" + +html-encoding-sniffer@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/html-encoding-sniffer/-/html-encoding-sniffer-1.0.2.tgz#e70d84b94da53aa375e11fe3a351be6642ca46f8" + integrity sha512-71lZziiDnsuabfdYiUeWdCVyKuqwWi23L8YeIgV9jSSZHCtb6wB1BKWooH7L3tn4/FuZJMVWyNaIDr4RGmaSYw== + dependencies: + whatwg-encoding "^1.0.1" + +html-to-react@^1.3.4: + version "1.4.3" + resolved "https://registry.yarnpkg.com/html-to-react/-/html-to-react-1.4.3.tgz#1430a1cb581ef29533892ec70a2fdc4554b17ffd" + integrity sha512-txe09A3vxW8yEZGJXJ1is5gGDfBEVACmZDSgwDyH5EsfRdOubBwBCg63ZThZP0xBn0UE4FyvMXZXmohusCxDcg== + dependencies: + domhandler "^3.0" + htmlparser2 "^4.1.0" + lodash.camelcase "^4.3.0" + ramda "^0.27" + +html2canvas@1.4.1, html2canvas@^1.0.0-rc.5: + version "1.4.1" + resolved "https://registry.yarnpkg.com/html2canvas/-/html2canvas-1.4.1.tgz#7cef1888311b5011d507794a066041b14669a543" + integrity sha512-fPU6BHNpsyIhr8yyMpTLLxAbkaK8ArIBcmZIRiBLiDhjeqvXolaEmDGmELFuX9I4xDcaKKcJl+TKZLqruBbmWA== + dependencies: + css-line-break "^2.1.0" + text-segmentation "^1.0.3" + +htmlparser2@^3.9.1: + version "3.10.1" + resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-3.10.1.tgz#bd679dc3f59897b6a34bb10749c855bb53a9392f" + integrity sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ== + dependencies: + domelementtype "^1.3.1" + domhandler "^2.3.0" + domutils "^1.5.1" + entities "^1.1.1" + inherits "^2.0.1" + readable-stream "^3.1.1" + +htmlparser2@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-4.1.0.tgz#9a4ef161f2e4625ebf7dfbe6c0a2f52d18a59e78" + integrity sha512-4zDq1a1zhE4gQso/c5LP1OtrhYTncXNSpvJYtWJBtXAETPlMfi3IFNjGuQbYLuVY4ZR0QMqRVvo4Pdy9KLyP8Q== + dependencies: + domelementtype "^2.0.1" + domhandler "^3.0.0" + domutils "^2.0.0" + entities "^2.0.0" + +http-signature@~1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1" + integrity sha1-muzZJRFHcvPZW2WmCruPfBj7rOE= + dependencies: + assert-plus "^1.0.0" + jsprim "^1.2.2" + sshpk "^1.7.0" + +https-browserify@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-1.0.0.tgz#ec06c10e0a34c0f2faf199f7fd7fc78fffd03c73" + integrity sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM= + +human-signals@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-1.1.1.tgz#c5b1cd14f50aeae09ab6c59fe63ba3395fe4dfa3" + integrity sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw== + +i18n-js@3.0.11: + version "3.0.11" + resolved "https://registry.yarnpkg.com/i18n-js/-/i18n-js-3.0.11.tgz#f9e96bdb641c5b9d6be12759d7c422089987ef02" + integrity sha512-v7dG3kYJTQTyox3NqDabPDE/ZotWntyMI9kh4cYi+XlCSnsIR+KBTS2opPyObL8WndnklcLzbNU92FP/mLge3Q== + +iconv-lite@0.4.24: + version "0.4.24" + 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" + +identity-obj-proxy@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/identity-obj-proxy/-/identity-obj-proxy-3.0.0.tgz#94d2bda96084453ef36fbc5aaec37e0f79f1fc14" + integrity sha1-lNK9qWCERT7zb7xarsN+D3nx/BQ= + dependencies: + harmony-reflect "^1.4.6" + +ieee754@^1.1.13: + version "1.2.1" + resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" + integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== + +ieee754@^1.1.4: + version "1.1.13" + resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.13.tgz#ec168558e95aa181fd87d37f55c32bbcb6708b84" + integrity sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg== + +iferr@^0.1.5: + version "0.1.5" + resolved "https://registry.yarnpkg.com/iferr/-/iferr-0.1.5.tgz#c60eed69e6d8fdb6b3104a1fcbca1c192dc5b501" + integrity sha1-xg7taebY/bazEEofy8ocGS3FtQE= + +import-fresh@^3.1.0: + version "3.2.1" + resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.2.1.tgz#633ff618506e793af5ac91bf48b72677e15cbe66" + integrity sha512-6e1q1cnWP2RXD9/keSkxHScg508CdXqXWgWBaETNhyuBFz+kUZlKboh+ISK+bU++DmbHimVBrOz/zzPe0sZ3sQ== + dependencies: + parent-module "^1.0.0" + resolve-from "^4.0.0" + +imurmurhash@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" + integrity sha1-khi5srkoojixPcT7a21XbyMUU+o= + +indent-string@^3.0.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-3.2.0.tgz#4a5fd6d27cc332f37e5419a504dbb837105c9289" + integrity sha1-Sl/W0nzDMvN+VBmlBNu4NxBckok= + +infer-owner@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/infer-owner/-/infer-owner-1.0.4.tgz#c4cefcaa8e51051c2a40ba2ce8a3d27295af9467" + integrity sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A== + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2, inherits@^2.0.0, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.1, inherits@~2.0.3: + version "2.0.4" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + +inherits@2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.1.tgz#b17d08d326b4423e568eff719f91b0b1cbdf69f1" + integrity sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE= + +inherits@2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" + integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= + +ini@1.3.7: + version "1.3.7" + resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.7.tgz#a09363e1911972ea16d7a8851005d84cf09a9a84" + integrity sha512-iKpRpXP+CrP2jyrxvg1kMUpXDyRUFDWurxbnVT1vQPx+Wz9uCYsMIqYuSBLV+PAaZG/d7kRLKRFc9oDMsH+mFQ== + +interpret@^1.0.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.4.0.tgz#665ab8bc4da27a774a40584e812e3e0fa45b1a1e" + integrity sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA== + +is-accessor-descriptor@^0.1.6: + version "0.1.6" + resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz#a9e12cb3ae8d876727eeef3843f8a0897b5c98d6" + integrity sha1-qeEss66Nh2cn7u84Q/igiXtcmNY= + dependencies: + kind-of "^3.0.2" + +is-accessor-descriptor@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz#169c2f6d3df1f992618072365c9b0ea1f6878656" + integrity sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ== + dependencies: + kind-of "^6.0.0" + +is-alphabetical@^1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-alphabetical/-/is-alphabetical-1.0.4.tgz#9e7d6b94916be22153745d184c298cbf986a686d" + integrity sha512-DwzsA04LQ10FHTZuL0/grVDk4rFoVH1pjAToYwBrHSxcrBIGQuXrQMtD5U1b0U2XVgKZCTLLP8u2Qxqhy3l2Vg== + +is-alphanumerical@^1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-alphanumerical/-/is-alphanumerical-1.0.4.tgz#7eb9a2431f855f6b1ef1a78e326df515696c4dbf" + integrity sha512-UzoZUr+XfVz3t3v4KyGEniVL9BDRoQtY7tOyrRybkVNjDFWyo1yhXNGrrBTQxp3ib9BLAWs7k2YKBQsFRkZG9A== + dependencies: + is-alphabetical "^1.0.0" + is-decimal "^1.0.0" + +is-arrayish@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" + integrity sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0= + +is-binary-path@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-1.0.1.tgz#75f16642b480f187a711c814161fd3a4a7655898" + integrity sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg= + dependencies: + binary-extensions "^1.0.0" + +is-binary-path@~2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" + integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw== + dependencies: + binary-extensions "^2.0.0" + +is-buffer@^1.1.4, is-buffer@^1.1.5: + version "1.1.6" + resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" + integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== + +is-callable@^1.1.4, is-callable@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.0.tgz#83336560b54a38e35e3a2df7afd0454d691468bb" + integrity sha512-pyVD9AaGLxtg6srb2Ng6ynWJqkHU9bEM087AKck0w8QwDarTfNcpIYoU8x8Hv2Icm8u6kFJM18Dag8lyqGkviw== + +is-callable@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.2.tgz#c7c6715cd22d4ddb48d3e19970223aceabb080d9" + integrity sha512-dnMqspv5nU3LoewK2N/y7KLtxtakvTuaCsU9FU50/QDmdbHNy/4/JuRtMHqRU22o3q+W89YQndQEeCVwK+3qrA== + +is-ci@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-2.0.0.tgz#6bc6334181810e04b5c22b3d589fdca55026404c" + integrity sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w== + dependencies: + ci-info "^2.0.0" + +is-core-module@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.1.0.tgz#a4cc031d9b1aca63eecbd18a650e13cb4eeab946" + integrity sha512-YcV7BgVMRFRua2FqQzKtTDMz8iCuLEyGKjr70q8Zm1yy2qKcurbFEd79PAdHV77oL3NrAaOVQIbMmiHQCHB7ZA== + dependencies: + has "^1.0.3" + +is-data-descriptor@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56" + integrity sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y= + dependencies: + kind-of "^3.0.2" + +is-data-descriptor@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz#d84876321d0e7add03990406abbbbd36ba9268c7" + integrity sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ== + dependencies: + kind-of "^6.0.0" + +is-date-object@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.2.tgz#bda736f2cd8fd06d32844e7743bfa7494c3bfd7e" + integrity sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g== + +is-decimal@^1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-decimal/-/is-decimal-1.0.4.tgz#65a3a5958a1c5b63a706e1b333d7cd9f630d3fa5" + integrity sha512-RGdriMmQQvZ2aqaQq3awNA6dCGtKpiDFcOzrTWrDAT2MiWrKQVPmxLGHl7Y2nNu6led0kEyoX0enY0qXYsv9zw== + +is-descriptor@^0.1.0: + version "0.1.6" + resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-0.1.6.tgz#366d8240dde487ca51823b1ab9f07a10a78251ca" + integrity sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg== + dependencies: + is-accessor-descriptor "^0.1.6" + is-data-descriptor "^0.1.4" + kind-of "^5.0.0" + +is-descriptor@^1.0.0, is-descriptor@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-1.0.2.tgz#3b159746a66604b04f8c81524ba365c5f14d86ec" + integrity sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg== + dependencies: + is-accessor-descriptor "^1.0.0" + is-data-descriptor "^1.0.0" + kind-of "^6.0.2" + +is-extendable@^0.1.0, is-extendable@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" + integrity sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik= + +is-extendable@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-1.0.1.tgz#a7470f9e426733d81bd81e1155264e3a3507cab4" + integrity sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA== + dependencies: + is-plain-object "^2.0.4" + +is-extglob@^2.1.0, is-extglob@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" + integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= + +is-fullwidth-code-point@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" + integrity sha1-754xOG8DGn8NZDr4L95QxFfvAMs= + dependencies: + number-is-nan "^1.0.0" + +is-fullwidth-code-point@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" + integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8= + +is-fullwidth-code-point@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" + integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== + +is-glob@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-3.1.0.tgz#7ba5ae24217804ac70707b96922567486cc3e84a" + integrity sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo= + dependencies: + is-extglob "^2.1.0" + +is-glob@^4.0.0, is-glob@^4.0.1, is-glob@~4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.1.tgz#7567dbe9f2f5e2467bc77ab83c4a29482407a5dc" + integrity sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg== + dependencies: + is-extglob "^2.1.1" + +is-hexadecimal@^1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-hexadecimal/-/is-hexadecimal-1.0.4.tgz#cc35c97588da4bd49a8eedd6bc4082d44dcb23a7" + integrity sha512-gyPJuv83bHMpocVYoqof5VDiZveEoGoFL8m3BXNb2VW8Xs+rz9kqO8LOQ5DH6EsuvilT1ApazU0pyl+ytbPtlw== + +is-installed-globally@^0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/is-installed-globally/-/is-installed-globally-0.3.2.tgz#fd3efa79ee670d1187233182d5b0a1dd00313141" + integrity sha512-wZ8x1js7Ia0kecP/CHM/3ABkAmujX7WPvQk6uu3Fly/Mk44pySulQpnHG46OMjHGXApINnV4QhY3SWnECO2z5g== + dependencies: + global-dirs "^2.0.1" + is-path-inside "^3.0.1" + +is-negative-zero@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.0.tgz#9553b121b0fac28869da9ed459e20c7543788461" + integrity sha1-lVOxIbD6wohp2p7UWeIMdUN4hGE= + +is-number@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195" + integrity sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU= + dependencies: + kind-of "^3.0.2" + +is-number@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" + integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== + +is-observable@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-observable/-/is-observable-1.1.0.tgz#b3e986c8f44de950867cab5403f5a3465005975e" + integrity sha512-NqCa4Sa2d+u7BWc6CukaObG3Fh+CU9bvixbpcXYhy2VvYS7vVGIdAgnIS5Ks3A/cqk4rebLJ9s8zBstT2aKnIA== + dependencies: + symbol-observable "^1.1.0" + +is-path-inside@^3.0.1: + version "3.0.2" + resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.2.tgz#f5220fc82a3e233757291dddc9c5877f2a1f3017" + integrity sha512-/2UGPSgmtqwo1ktx8NDHjuPwZWmHhO+gj0f93EkhLB5RgW9RZevWYYlIkS6zePc6U2WpOdQYIwHe9YC4DWEBVg== + +is-plain-obj@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e" + integrity sha1-caUMhCnfync8kqOQpKA7OfzVHT4= + +is-plain-object@^2.0.3, is-plain-object@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677" + integrity sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og== + dependencies: + isobject "^3.0.1" + +is-promise@^2.1.0: + version "2.2.2" + resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-2.2.2.tgz#39ab959ccbf9a774cf079f7b40c7a26f763135f1" + integrity sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ== + +is-regex@^1.1.0, is-regex@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.1.tgz#c6f98aacc546f6cec5468a07b7b153ab564a57b9" + integrity sha512-1+QkEcxiLlB7VEyFtyBg94e08OAsvq7FUBgApTq/w2ymCLyKJgDPsybBENVtA7XCQEgEXxKPonG+mvYRxh/LIg== + dependencies: + has-symbols "^1.0.1" + +is-stream@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" + integrity sha1-EtSj3U5o4Lec6428hBc66A2RykQ= + +is-stream@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.0.tgz#bde9c32680d6fae04129d6ac9d921ce7815f78e3" + integrity sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw== + +is-symbol@^1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.3.tgz#38e1014b9e6329be0de9d24a414fd7441ec61937" + integrity sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ== + dependencies: + has-symbols "^1.0.1" + +is-typedarray@^1.0.0, is-typedarray@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" + integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo= + +is-whitespace-character@^1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-whitespace-character/-/is-whitespace-character-1.0.4.tgz#0858edd94a95594c7c9dd0b5c174ec6e45ee4aa7" + integrity sha512-SDweEzfIZM0SJV0EUga669UTKlmL0Pq8Lno0QDQsPnvECB3IM2aP0gdx5TrU0A01MAPfViaZiI2V1QMZLaKK5w== + +is-windows@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" + integrity sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA== + +is-word-character@^1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-word-character/-/is-word-character-1.0.4.tgz#ce0e73216f98599060592f62ff31354ddbeb0230" + integrity sha512-5SMO8RVennx3nZrqtKwCGyyetPE9VDba5ugvKLaD4KopPG5kR4mQ7tNt/r7feL5yt5h3lpuBbIUmCOG2eSzXHA== + +is-wsl@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-1.1.0.tgz#1f16e4aa22b04d1336b66188a66af3c600c3a66d" + integrity sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0= + +isarray@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" + integrity sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8= + +isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" + integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= + +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= + +isobject@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" + integrity sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk= + dependencies: + isarray "1.0.0" + +isobject@^3.0.0, isobject@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" + integrity sha1-TkMekrEalzFjaqH5yNHMvP2reN8= + +isstream@~0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" + integrity sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo= + +istanbul-lib-coverage@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-3.0.0.tgz#f5944a37c70b550b02a78a5c3b2055b280cec8ec" + integrity sha512-UiUIqxMgRDET6eR+o5HbfRYP1l0hqkWOs7vNxC/mggutCMUIhWMm8gAHb8tHlyfD3/l6rlgNA5cKdDzEAf6hEg== + +istanbul-lib-instrument@^4.0.0: + version "4.0.3" + resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.3.tgz#873c6fff897450118222774696a3f28902d77c1d" + integrity sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ== + dependencies: + "@babel/core" "^7.7.5" + "@istanbuljs/schema" "^0.1.2" + istanbul-lib-coverage "^3.0.0" + semver "^6.3.0" + +jest-diff@^25.2.1: + version "25.5.0" + resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-25.5.0.tgz#1dd26ed64f96667c068cef026b677dfa01afcfa9" + integrity sha512-z1kygetuPiREYdNIumRpAHY6RXiGmp70YHptjdaxTWGmA085W3iCnXNx0DhflK3vwrKmrRWyY1wUpkPMVxMK7A== + dependencies: + chalk "^3.0.0" + diff-sequences "^25.2.6" + jest-get-type "^25.2.6" + pretty-format "^25.5.0" + +jest-dom@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/jest-dom/-/jest-dom-4.0.0.tgz#94eba3cbc6576e7bd6821867c92d176de28920eb" + integrity sha512-gBxYZlZB1Jgvf2gP2pRfjjUWF8woGBHj/g5rAQgFPB/0K2atGuhVcPO+BItyjWeKg9zM+dokgcMOH01vrWVMFA== + +jest-fetch-mock@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/jest-fetch-mock/-/jest-fetch-mock-3.0.3.tgz#31749c456ae27b8919d69824f1c2bd85fe0a1f3b" + integrity sha512-Ux1nWprtLrdrH4XwE7O7InRY6psIi3GOsqNESJgMJ+M5cv4A8Lh7SN9d2V2kKRZ8ebAfcd1LNyZguAOb6JiDqw== + dependencies: + cross-fetch "^3.0.4" + promise-polyfill "^8.1.3" + +jest-get-type@^25.2.6: + version "25.2.6" + resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-25.2.6.tgz#0b0a32fab8908b44d508be81681487dbabb8d877" + integrity sha512-DxjtyzOHjObRM+sM1knti6or+eOgcGU4xVSb2HNP1TqO4ahsT+rqZg+nyqHWJSvWgKC5cG3QjGFBqxLghiF/Ig== + +jest-haste-map@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-26.6.2.tgz#dd7e60fe7dc0e9f911a23d79c5ff7fb5c2cafeaa" + integrity sha512-easWIJXIw71B2RdR8kgqpjQrbMRWQBgiBwXYEhtGUTaX+doCjBheluShdDMeR8IMfJiTqH4+zfhtg29apJf/8w== + dependencies: + "@jest/types" "^26.6.2" + "@types/graceful-fs" "^4.1.2" + "@types/node" "*" + anymatch "^3.0.3" + fb-watchman "^2.0.0" + graceful-fs "^4.2.4" + jest-regex-util "^26.0.0" + jest-serializer "^26.6.2" + jest-util "^26.6.2" + jest-worker "^26.6.2" + micromatch "^4.0.2" + sane "^4.0.3" + walker "^1.0.7" + optionalDependencies: + fsevents "^2.1.2" + +jest-regex-util@^26.0.0: + version "26.0.0" + resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-26.0.0.tgz#d25e7184b36e39fd466c3bc41be0971e821fee28" + integrity sha512-Gv3ZIs/nA48/Zvjrl34bf+oD76JHiGDUxNOVgUjh3j890sblXryjY4rss71fPtD/njchl6PSE2hIhvyWa1eT0A== + +jest-serializer@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/jest-serializer/-/jest-serializer-26.6.2.tgz#d139aafd46957d3a448f3a6cdabe2919ba0742d1" + integrity sha512-S5wqyz0DXnNJPd/xfIzZ5Xnp1HrJWBczg8mMfMpN78OJ5eDxXyf+Ygld9wX1DnUWbIbhM1YDY95NjR4CBXkb2g== + dependencies: + "@types/node" "*" + graceful-fs "^4.2.4" + +jest-util@26.x: + version "26.3.0" + resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-26.3.0.tgz#a8974b191df30e2bf523ebbfdbaeb8efca535b3e" + integrity sha512-4zpn6bwV0+AMFN0IYhH/wnzIQzRaYVrz1A8sYnRnj4UXDXbOVtWmlaZkO9mipFqZ13okIfN87aDoJWB7VH6hcw== + dependencies: + "@jest/types" "^26.3.0" + "@types/node" "*" + chalk "^4.0.0" + graceful-fs "^4.2.4" + is-ci "^2.0.0" + micromatch "^4.0.2" + +jest-util@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-26.6.2.tgz#907535dbe4d5a6cb4c47ac9b926f6af29576cbc1" + integrity sha512-MDW0fKfsn0OI7MS7Euz6h8HNDXVQ0gaM9uW6RjfDmd1DAFcaxX9OqIakHIqhbnmF08Cf2DLDG+ulq8YQQ0Lp0Q== + dependencies: + "@jest/types" "^26.6.2" + "@types/node" "*" + chalk "^4.0.0" + graceful-fs "^4.2.4" + is-ci "^2.0.0" + micromatch "^4.0.2" + +jest-worker@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-26.6.2.tgz#7f72cbc4d643c365e27b9fd775f9d0eaa9c7a8ed" + integrity sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ== + dependencies: + "@types/node" "*" + merge-stream "^2.0.0" + supports-color "^7.0.0" + +jquery@^3.5.0: + version "3.5.1" + resolved "https://registry.yarnpkg.com/jquery/-/jquery-3.5.1.tgz#d7b4d08e1bfdb86ad2f1a3d039ea17304717abb5" + integrity sha512-XwIBPqcMn57FxfT+Go5pzySnm4KWkT1Tv7gjrpT1srtf8Weynl6R273VJ5GjkRb51IzMp5nbaPjJXMWeju2MKg== + +"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" + integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== + +js-yaml@^3.13.1: + version "3.14.0" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.0.tgz#a7a34170f26a21bb162424d8adacb4113a69e482" + integrity sha512-/4IbIeHcD9VMHFqDR/gQ7EdZdLimOvW2DdcxFjdyyZ9NsbS+ccrXqVWDtab/lRl5AlUqmpBx8EhPaWR+OtY17A== + dependencies: + argparse "^1.0.7" + esprima "^4.0.0" + +jsbn@~0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" + integrity sha1-peZUwuWi3rXyAdls77yoDA7y9RM= + +jsdom@13.1.0: + version "13.1.0" + resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-13.1.0.tgz#fa7356f0cc8111d0f1077cb7800d06f22f1d66c7" + integrity sha512-C2Kp0qNuopw0smXFaHeayvharqF3kkcNqlcIlSX71+3XrsOFwkEPLt/9f5JksMmaul2JZYIQuY+WTpqHpQQcLg== + dependencies: + abab "^2.0.0" + acorn "^6.0.4" + acorn-globals "^4.3.0" + array-equal "^1.0.0" + cssom "^0.3.4" + cssstyle "^1.1.1" + data-urls "^1.1.0" + domexception "^1.0.1" + escodegen "^1.11.0" + html-encoding-sniffer "^1.0.2" + nwsapi "^2.0.9" + parse5 "5.1.0" + pn "^1.1.0" + request "^2.88.0" + request-promise-native "^1.0.5" + saxes "^3.1.4" + symbol-tree "^3.2.2" + tough-cookie "^2.5.0" + w3c-hr-time "^1.0.1" + w3c-xmlserializer "^1.0.1" + webidl-conversions "^4.0.2" + whatwg-encoding "^1.0.5" + whatwg-mimetype "^2.3.0" + whatwg-url "^7.0.0" + ws "^6.1.2" + xml-name-validator "^3.0.0" + +jsesc@^2.5.1: + version "2.5.2" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" + integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== + +json-2-csv@^3.7.6: + version "3.7.6" + resolved "https://registry.yarnpkg.com/json-2-csv/-/json-2-csv-3.7.6.tgz#2a88b323b8986f31dcd4ef785b3bfb3521d42899" + integrity sha512-um9bT7CgI77f/m5G/V5uRKz9UruFQFijD5Fh+EAnr5QowOJpdIk1ya37KSq1MxjBnJgvmpqCnI7ZjsvyTYiW0w== + dependencies: + deeks "2.2.6" + doc-path "2.0.4" + +json-parse-better-errors@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9" + integrity sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw== + +json-parse-even-better-errors@^2.3.0: + version "2.3.1" + resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d" + integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w== + +json-schema-traverse@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" + integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== + +json-schema@0.2.3: + version "0.2.3" + resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" + integrity sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM= + +json-stringify-safe@~5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" + integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus= + +json5@2.x, json5@^2.1.2: + version "2.1.3" + resolved "https://registry.yarnpkg.com/json5/-/json5-2.1.3.tgz#c9b0f7fa9233bfe5807fe66fcf3a5617ed597d43" + integrity sha512-KXPvOm8K9IJKFM0bmdn8QXh7udDh1g/giieX0NLCaMnb4hEiVFqnop2ImTXCc5e0/oHz3LTqmHGtExn5hfMkOA== + dependencies: + minimist "^1.2.5" + +json5@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.1.tgz#779fb0018604fa854eacbf6252180d83543e3dbe" + integrity sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow== + dependencies: + minimist "^1.2.0" + +jsonfile@^6.0.1: + version "6.1.0" + resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-6.1.0.tgz#bc55b2634793c679ec6403094eb13698a6ec0aae" + integrity sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ== + dependencies: + universalify "^2.0.0" + optionalDependencies: + graceful-fs "^4.1.6" + +jspdf@^2.5.1: + version "2.5.1" + resolved "https://registry.yarnpkg.com/jspdf/-/jspdf-2.5.1.tgz#00c85250abf5447a05f3b32ab9935ab4a56592cc" + integrity sha512-hXObxz7ZqoyhxET78+XR34Xu2qFGrJJ2I2bE5w4SM8eFaFEkW2xcGRVUss360fYelwRSid/jT078kbNvmoW0QA== + dependencies: + "@babel/runtime" "^7.14.0" + atob "^2.1.2" + btoa "^1.2.1" + fflate "^0.4.8" + optionalDependencies: + canvg "^3.0.6" + core-js "^3.6.0" + dompurify "^2.2.0" + html2canvas "^1.0.0-rc.5" + +jsprim@^1.2.2: + version "1.4.1" + resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2" + integrity sha1-MT5mvB5cwG5Di8G3SZwuXFastqI= + dependencies: + assert-plus "1.0.0" + extsprintf "1.3.0" + json-schema "0.2.3" + verror "1.10.0" + +kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0: + version "3.2.2" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" + integrity sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ= + dependencies: + is-buffer "^1.1.5" + +kind-of@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-4.0.0.tgz#20813df3d712928b207378691a45066fae72dd57" + integrity sha1-IIE989cSkosgc3hpGkUGb65y3Vc= + dependencies: + is-buffer "^1.1.5" + +kind-of@^5.0.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-5.1.0.tgz#729c91e2d857b7a419a1f9aa65685c4c33f5845d" + integrity sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw== + +kind-of@^6.0.0, kind-of@^6.0.2: + version "6.0.3" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd" + integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw== + +lazy-ass@^1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/lazy-ass/-/lazy-ass-1.6.0.tgz#7999655e8646c17f089fdd187d150d3324d54513" + integrity sha1-eZllXoZGwX8In90YfRUNMyTVRRM= + +levn@~0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" + integrity sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4= + dependencies: + prelude-ls "~1.1.2" + type-check "~0.3.2" + +lines-and-columns@^1.1.6: + version "1.1.6" + resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.1.6.tgz#1c00c743b433cd0a4e80758f7b64a57440d9ff00" + integrity sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA= + +listr-silent-renderer@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/listr-silent-renderer/-/listr-silent-renderer-1.1.1.tgz#924b5a3757153770bf1a8e3fbf74b8bbf3f9242e" + integrity sha1-kktaN1cVN3C/Go4/v3S4u/P5JC4= + +listr-update-renderer@^0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/listr-update-renderer/-/listr-update-renderer-0.5.0.tgz#4ea8368548a7b8aecb7e06d8c95cb45ae2ede6a2" + integrity sha512-tKRsZpKz8GSGqoI/+caPmfrypiaq+OQCbd+CovEC24uk1h952lVj5sC7SqyFUm+OaJ5HN/a1YLt5cit2FMNsFA== + dependencies: + chalk "^1.1.3" + cli-truncate "^0.2.1" + elegant-spinner "^1.0.1" + figures "^1.7.0" + indent-string "^3.0.0" + log-symbols "^1.0.2" + log-update "^2.3.0" + strip-ansi "^3.0.1" + +listr-verbose-renderer@^0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/listr-verbose-renderer/-/listr-verbose-renderer-0.5.0.tgz#f1132167535ea4c1261102b9f28dac7cba1e03db" + integrity sha512-04PDPqSlsqIOaaaGZ+41vq5FejI9auqTInicFRndCBgE3bXG8D6W1I+mWhk+1nqbHmyhla/6BUrd5OSiHwKRXw== + dependencies: + chalk "^2.4.1" + cli-cursor "^2.1.0" + date-fns "^1.27.2" + figures "^2.0.0" + +listr@^0.14.3: + version "0.14.3" + resolved "https://registry.yarnpkg.com/listr/-/listr-0.14.3.tgz#2fea909604e434be464c50bddba0d496928fa586" + integrity sha512-RmAl7su35BFd/xoMamRjpIE4j3v+L28o8CT5YhAXQJm1fD+1l9ngXY8JAQRJ+tFK2i5njvi0iRUKV09vPwA0iA== + dependencies: + "@samverschueren/stream-to-observable" "^0.3.0" + is-observable "^1.1.0" + is-promise "^2.1.0" + is-stream "^1.1.0" + listr-silent-renderer "^1.1.1" + listr-update-renderer "^0.5.0" + listr-verbose-renderer "^0.5.0" + p-map "^2.0.0" + rxjs "^6.3.3" + +loader-runner@^2.4.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-2.4.0.tgz#ed47066bfe534d7e84c4c7b9998c2a75607d9357" + integrity sha512-Jsmr89RcXGIwivFY21FcRrisYZfvLMTWx5kOLc+JTxtpBOG6xML0vzbc6SEQG2FO9/4Fc3wW4LVcB5DmGflaRw== + +loader-utils@^1.2.3: + version "1.4.0" + resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-1.4.0.tgz#c579b5e34cb34b1a74edc6c1fb36bfa371d5a613" + integrity sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA== + dependencies: + big.js "^5.2.2" + emojis-list "^3.0.0" + json5 "^1.0.1" + +locate-path@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e" + integrity sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A== + dependencies: + p-locate "^3.0.0" + path-exists "^3.0.0" + +locate-path@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0" + integrity sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g== + dependencies: + p-locate "^4.1.0" + +lodash.assignin@^4.0.9: + version "4.2.0" + resolved "https://registry.yarnpkg.com/lodash.assignin/-/lodash.assignin-4.2.0.tgz#ba8df5fb841eb0a3e8044232b0e263a8dc6a28a2" + integrity sha1-uo31+4QesKPoBEIysOJjqNxqKKI= + +lodash.bind@^4.1.4: + version "4.2.1" + resolved "https://registry.yarnpkg.com/lodash.bind/-/lodash.bind-4.2.1.tgz#7ae3017e939622ac31b7d7d7dcb1b34db1690d35" + integrity sha1-euMBfpOWIqwxt9fX3LGzTbFpDTU= + +lodash.camelcase@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6" + integrity sha1-soqmKIorn8ZRA1x3EfZathkDMaY= + +lodash.defaults@^4.0.1: + version "4.2.0" + resolved "https://registry.yarnpkg.com/lodash.defaults/-/lodash.defaults-4.2.0.tgz#d09178716ffea4dde9e5fb7b37f6f0802274580c" + integrity sha1-0JF4cW/+pN3p5ft7N/bwgCJ0WAw= + +lodash.filter@^4.4.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/lodash.filter/-/lodash.filter-4.6.0.tgz#668b1d4981603ae1cc5a6fa760143e480b4c4ace" + integrity sha1-ZosdSYFgOuHMWm+nYBQ+SAtMSs4= + +lodash.flatten@^4.2.0: + version "4.4.0" + resolved "https://registry.yarnpkg.com/lodash.flatten/-/lodash.flatten-4.4.0.tgz#f31c22225a9632d2bbf8e4addbef240aa765a61f" + integrity sha1-8xwiIlqWMtK7+OSt2+8kCqdlph8= + +lodash.foreach@^4.3.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/lodash.foreach/-/lodash.foreach-4.5.0.tgz#1a6a35eace401280c7f06dddec35165ab27e3e53" + integrity sha1-Gmo16s5AEoDH8G3d7DUWWrJ+PlM= + +lodash.has@^4.5.2: + version "4.5.2" + resolved "https://registry.yarnpkg.com/lodash.has/-/lodash.has-4.5.2.tgz#d19f4dc1095058cccbe2b0cdf4ee0fe4aa37c862" + integrity sha1-0Z9NwQlQWMzL4rDN9O4P5Ko3yGI= + +lodash.hasin@^4.5.2: + version "4.5.2" + resolved "https://registry.yarnpkg.com/lodash.hasin/-/lodash.hasin-4.5.2.tgz#f91e352378d21ef7090b9e7687c2ca35c5b4d52a" + integrity sha1-+R41I3jSHvcJC552h8LKNcW01So= + +lodash.head@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/lodash.head/-/lodash.head-4.0.1.tgz#e2aa322d3ec40cd6aae186082977d993b354ed9c" + integrity sha1-4qoyLT7EDNaq4YYIKXfZk7NU7Zw= + +lodash.isempty@^4.4.0: + version "4.4.0" + resolved "https://registry.yarnpkg.com/lodash.isempty/-/lodash.isempty-4.4.0.tgz#6f86cbedd8be4ec987be9aaf33c9684db1b31e7e" + integrity sha1-b4bL7di+TsmHvpqvM8loTbGzHn4= + +lodash.isnil@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/lodash.isnil/-/lodash.isnil-4.0.0.tgz#49e28cd559013458c814c5479d3c663a21bfaa6c" + integrity sha1-SeKM1VkBNFjIFMVHnTxmOiG/qmw= + +lodash.isobject@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/lodash.isobject/-/lodash.isobject-3.0.2.tgz#3c8fb8d5b5bf4bf90ae06e14f2a530a4ed935e1d" + integrity sha1-PI+41bW/S/kK4G4U8qUwpO2TXh0= + +lodash.isstring@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/lodash.isstring/-/lodash.isstring-4.0.1.tgz#d527dfb5456eca7cc9bb95d5daeaf88ba54a5451" + integrity sha1-1SfftUVuynzJu5XV2ur4i6VKVFE= + +lodash.map@^4.4.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/lodash.map/-/lodash.map-4.6.0.tgz#771ec7839e3473d9c4cde28b19394c3562f4f6d3" + integrity sha1-dx7Hg540c9nEzeKLGTlMNWL09tM= + +lodash.memoize@4.x: + version "4.1.2" + resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe" + integrity sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4= + +lodash.merge@^4.4.0: + version "4.6.2" + resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" + integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== + +lodash.omit@^4.5.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/lodash.omit/-/lodash.omit-4.5.0.tgz#6eb19ae5a1ee1dd9df0b969e66ce0b7fa30b5e60" + integrity sha1-brGa5aHuHdnfC5aeZs4Lf6MLXmA= + +lodash.once@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/lodash.once/-/lodash.once-4.1.1.tgz#0dd3971213c7c56df880977d504c88fb471a97ac" + integrity sha1-DdOXEhPHxW34gJd9UEyI+0cal6w= + +lodash.pick@^4.2.1: + version "4.4.0" + resolved "https://registry.yarnpkg.com/lodash.pick/-/lodash.pick-4.4.0.tgz#52f05610fff9ded422611441ed1fc123a03001b3" + integrity sha1-UvBWEP/53tQiYRRB7R/BI6AwAbM= + +lodash.reduce@^4.4.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/lodash.reduce/-/lodash.reduce-4.6.0.tgz#f1ab6b839299ad48f784abbf476596f03b914d3b" + integrity sha1-8atrg5KZrUj3hKu/R2WW8DuRTTs= + +lodash.reject@^4.4.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/lodash.reject/-/lodash.reject-4.6.0.tgz#80d6492dc1470864bbf583533b651f42a9f52415" + integrity sha1-gNZJLcFHCGS79YNTO2UfQqn1JBU= + +lodash.some@^4.4.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/lodash.some/-/lodash.some-4.6.0.tgz#1bb9f314ef6b8baded13b549169b2a945eb68e4d" + integrity sha1-G7nzFO9ri63tE7VJFpsqlF62jk0= + +lodash.sortby@^4.7.0: + version "4.7.0" + resolved "https://registry.yarnpkg.com/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438" + integrity sha1-7dFMgk4sycHgsKG0K7UhBRakJDg= + +lodash@^4.17.19, lodash@^4.17.4: + version "4.17.20" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.20.tgz#b44a9b6297bcb698f1c51a3545a2b3b368d59c52" + integrity sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA== + +log-symbols@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-1.0.2.tgz#376ff7b58ea3086a0f09facc74617eca501e1a18" + integrity sha1-N2/3tY6jCGoPCfrMdGF+ylAeGhg= + dependencies: + chalk "^1.0.0" + +log-symbols@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-4.0.0.tgz#69b3cc46d20f448eccdb75ea1fa733d9e821c920" + integrity sha512-FN8JBzLx6CzeMrB0tg6pqlGU1wCrXW+ZXGH481kfsBqer0hToTIiHdjH4Mq8xJUbvATujKCvaREGWpGUionraA== + dependencies: + chalk "^4.0.0" + +log-update@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/log-update/-/log-update-2.3.0.tgz#88328fd7d1ce7938b29283746f0b1bc126b24708" + integrity sha1-iDKP19HOeTiykoN0bwsbwSayRwg= + dependencies: + ansi-escapes "^3.0.0" + cli-cursor "^2.0.0" + wrap-ansi "^3.0.1" + +loose-envify@^1.1.0, loose-envify@^1.2.0, loose-envify@^1.3.1, loose-envify@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" + integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== + dependencies: + js-tokens "^3.0.0 || ^4.0.0" + +lru-cache@^4.1.5: + version "4.1.5" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.5.tgz#8bbe50ea85bed59bc9e33dcab8235ee9bcf443cd" + integrity sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g== + dependencies: + pseudomap "^1.0.2" + yallist "^2.1.2" + +lru-cache@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" + integrity sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w== + dependencies: + yallist "^3.0.2" + +make-dir@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-2.1.0.tgz#5f0310e18b8be898cc07009295a30ae41e91e6f5" + integrity sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA== + dependencies: + pify "^4.0.1" + semver "^5.6.0" + +make-error@1.x: + version "1.3.6" + resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" + integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== + +makeerror@1.0.x: + version "1.0.11" + resolved "https://registry.yarnpkg.com/makeerror/-/makeerror-1.0.11.tgz#e01a5c9109f2af79660e4e8b9587790184f5a96c" + integrity sha1-4BpckQnyr3lmDk6LlYd5AYT1qWw= + dependencies: + tmpl "1.0.x" + +map-cache@^0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf" + integrity sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8= + +map-visit@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/map-visit/-/map-visit-1.0.0.tgz#ecdca8f13144e660f1b5bd41f12f3479d98dfb8f" + integrity sha1-7Nyo8TFE5mDxtb1B8S80edmN+48= + dependencies: + object-visit "^1.0.0" + +markdown-escapes@^1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/markdown-escapes/-/markdown-escapes-1.0.4.tgz#c95415ef451499d7602b91095f3c8e8975f78535" + integrity sha512-8z4efJYk43E0upd0NbVXwgSTQs6cT3T06etieCMEg7dRbzCbxUCK/GHlX8mhHRDcp+OLlHkPKsvqQTCvsRl2cg== + +md5.js@^1.3.4: + version "1.3.5" + resolved "https://registry.yarnpkg.com/md5.js/-/md5.js-1.3.5.tgz#b5d07b8e3216e3e27cd728d72f70d1e6a342005f" + integrity sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg== + dependencies: + hash-base "^3.0.0" + inherits "^2.0.1" + safe-buffer "^5.1.2" + +mdast-add-list-metadata@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/mdast-add-list-metadata/-/mdast-add-list-metadata-1.0.1.tgz#95e73640ce2fc1fa2dcb7ec443d09e2bfe7db4cf" + integrity sha512-fB/VP4MJ0LaRsog7hGPxgOrSL3gE/2uEdZyDuSEnKCv/8IkYHiDkIQSbChiJoHyxZZXZ9bzckyRk+vNxFzh8rA== + dependencies: + unist-util-visit-parents "1.1.2" + +memory-fs@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.2.0.tgz#f2bb25368bc121e391c2520de92969caee0a0290" + integrity sha1-8rslNovBIeORwlIN6Slpyu4KApA= + +memory-fs@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.4.1.tgz#3a9a20b8462523e447cfbc7e8bb80ed667bfc552" + integrity sha1-OpoguEYlI+RHz7x+i7gO1me/xVI= + dependencies: + errno "^0.1.3" + readable-stream "^2.0.1" + +memory-fs@^0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.5.0.tgz#324c01288b88652966d161db77838720845a8e3c" + integrity sha512-jA0rdU5KoQMC0e6ppoNRtpp6vjFq6+NY7r8hywnC7V+1Xj/MtHwGIbB1QaK/dunyjWteJzmkpd7ooeWg10T7GA== + dependencies: + errno "^0.1.3" + readable-stream "^2.0.1" + +merge-stream@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" + integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== + +micromatch@^3.1.10, micromatch@^3.1.4: + version "3.1.10" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23" + integrity sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg== + dependencies: + arr-diff "^4.0.0" + array-unique "^0.3.2" + braces "^2.3.1" + define-property "^2.0.2" + extend-shallow "^3.0.2" + extglob "^2.0.4" + fragment-cache "^0.2.1" + kind-of "^6.0.2" + nanomatch "^1.2.9" + object.pick "^1.3.0" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.2" + +micromatch@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.2.tgz#4fcb0999bf9fbc2fcbdd212f6d629b9a56c39259" + integrity sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q== + dependencies: + braces "^3.0.1" + picomatch "^2.0.5" + +miller-rabin@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/miller-rabin/-/miller-rabin-4.0.1.tgz#f080351c865b0dc562a8462966daa53543c78a4d" + integrity sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA== + dependencies: + bn.js "^4.0.0" + brorand "^1.0.1" + +mime-db@1.44.0: + version "1.44.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.44.0.tgz#fa11c5eb0aca1334b4233cb4d52f10c5a6272f92" + integrity sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg== + +mime-types@^2.1.12, mime-types@~2.1.19: + version "2.1.27" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.27.tgz#47949f98e279ea53119f5722e0f34e529bec009f" + integrity sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w== + dependencies: + mime-db "1.44.0" + +mimic-fn@^1.0.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.2.0.tgz#820c86a39334640e99516928bd03fca88057d022" + integrity sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ== + +mimic-fn@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" + integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== + +mini-create-react-context@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/mini-create-react-context/-/mini-create-react-context-0.4.0.tgz#df60501c83151db69e28eac0ef08b4002efab040" + integrity sha512-b0TytUgFSbgFJGzJqXPKCFCBWigAjpjo+Fl7Vf7ZbKRDptszpppKxXH6DRXEABZ/gcEQczeb0iZ7JvL8e8jjCA== + dependencies: + "@babel/runtime" "^7.5.5" + tiny-warning "^1.0.3" + +minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7" + integrity sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A== + +minimalistic-crypto-utils@^1.0.0, minimalistic-crypto-utils@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a" + integrity sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo= + +minimatch@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" + integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== + dependencies: + brace-expansion "^1.1.7" + +minimatch@^3.1.1: + version "3.1.2" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" + integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== + dependencies: + brace-expansion "^1.1.7" + +minimist@^1.1.1, minimist@^1.2.0, minimist@^1.2.5: + version "1.2.5" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" + integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== + +mississippi@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/mississippi/-/mississippi-3.0.0.tgz#ea0a3291f97e0b5e8776b363d5f0a12d94c67022" + integrity sha512-x471SsVjUtBRtcvd4BzKE9kFC+/2TeWgKCgw0bZcw1b9l2X3QX5vCWgF+KaZaYm87Ss//rHnWryupDrgLvmSkA== + dependencies: + concat-stream "^1.5.0" + duplexify "^3.4.2" + end-of-stream "^1.1.0" + flush-write-stream "^1.0.0" + from2 "^2.1.0" + parallel-transform "^1.1.0" + pump "^3.0.0" + pumpify "^1.3.3" + stream-each "^1.1.0" + through2 "^2.0.0" + +mixin-deep@^1.2.0: + version "1.3.2" + resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.2.tgz#1120b43dc359a785dce65b55b82e257ccf479566" + integrity sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA== + dependencies: + for-in "^1.0.2" + is-extendable "^1.0.1" + +mkdirp-classic@^0.5.2: + version "0.5.3" + resolved "https://registry.yarnpkg.com/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz#fa10c9115cc6d8865be221ba47ee9bed78601113" + integrity sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A== + +mkdirp@1.x: + version "1.0.4" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" + integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== + +mkdirp@^0.5.1, mkdirp@^0.5.3, mkdirp@^0.5.4: + version "0.5.5" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.5.tgz#d91cefd62d1436ca0f41620e251288d420099def" + integrity sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ== + dependencies: + minimist "^1.2.5" + +moment@^2.27.0: + version "2.29.1" + resolved "https://registry.yarnpkg.com/moment/-/moment-2.29.1.tgz#b2be769fa31940be9eeea6469c075e35006fa3d3" + integrity sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ== + +move-concurrently@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/move-concurrently/-/move-concurrently-1.0.1.tgz#be2c005fda32e0b29af1f05d7c4b33214c701f92" + integrity sha1-viwAX9oy4LKa8fBdfEszIUxwH5I= + dependencies: + aproba "^1.1.1" + copy-concurrently "^1.0.0" + fs-write-stream-atomic "^1.0.8" + mkdirp "^0.5.1" + rimraf "^2.5.4" + run-queue "^1.0.3" + +ms@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" + integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= + +ms@2.1.2, ms@^2.1.1: + version "2.1.2" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" + integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== + +nan@^2.12.1: + version "2.14.2" + resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.2.tgz#f5376400695168f4cc694ac9393d0c9585eeea19" + integrity sha512-M2ufzIiINKCuDfBSAUr1vWQ+vuVcA9kqx8JJUsbQi6yf1uGRyb7HfpdfUr5qLXf3B/t8dPvcjhKMmlfnP47EzQ== + +nanomatch@^1.2.9: + version "1.2.13" + resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119" + integrity sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA== + dependencies: + arr-diff "^4.0.0" + array-unique "^0.3.2" + define-property "^2.0.2" + extend-shallow "^3.0.2" + fragment-cache "^0.2.1" + is-windows "^1.0.2" + kind-of "^6.0.2" + object.pick "^1.3.0" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" + +neo-async@^2.5.0, neo-async@^2.6.1: + version "2.6.2" + resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f" + integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw== + +nice-try@^1.0.4: + version "1.0.5" + resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" + integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ== + +node-fetch@2.6.1: + version "2.6.1" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.1.tgz#045bd323631f76ed2e2b55573394416b639a0052" + integrity sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw== + +node-fetch@2.6.7: + version "2.6.7" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.7.tgz#24de9fba827e3b4ae44dc8b20256a379160052ad" + integrity sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ== + dependencies: + whatwg-url "^5.0.0" + +node-int64@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" + integrity sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs= + +"node-libs-browser@^1.0.0 || ^2.0.0", node-libs-browser@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/node-libs-browser/-/node-libs-browser-2.2.1.tgz#b64f513d18338625f90346d27b0d235e631f6425" + integrity sha512-h/zcD8H9kaDZ9ALUWwlBUDo6TKF8a7qBSCSEGfjTVIYeqsioSKaAX+BN7NgiMGp6iSIXZ3PxgCu8KS3b71YK5Q== + dependencies: + assert "^1.1.1" + browserify-zlib "^0.2.0" + buffer "^4.3.0" + console-browserify "^1.1.0" + constants-browserify "^1.0.0" + crypto-browserify "^3.11.0" + domain-browser "^1.1.1" + events "^3.0.0" + https-browserify "^1.0.0" + os-browserify "^0.3.0" + path-browserify "0.0.1" + process "^0.11.10" + punycode "^1.2.4" + querystring-es3 "^0.2.0" + readable-stream "^2.3.3" + stream-browserify "^2.0.1" + stream-http "^2.7.2" + string_decoder "^1.0.0" + timers-browserify "^2.0.4" + tty-browserify "0.0.0" + url "^0.11.0" + util "^0.11.0" + vm-browserify "^1.0.1" + +node-modules-regexp@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/node-modules-regexp/-/node-modules-regexp-1.0.0.tgz#8d9dbe28964a4ac5712e9131642107c71e90ec40" + integrity sha1-jZ2+KJZKSsVxLpExZCEHxx6Q7EA= + +normalize-path@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9" + integrity sha1-GrKLVW4Zg2Oowab35vogE3/mrtk= + dependencies: + remove-trailing-separator "^1.0.1" + +normalize-path@^3.0.0, normalize-path@~3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" + integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== + +npm-run-path@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f" + integrity sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8= + dependencies: + path-key "^2.0.0" + +npm-run-path@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea" + integrity sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw== + dependencies: + path-key "^3.0.0" + +nth-check@~1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/nth-check/-/nth-check-1.0.2.tgz#b2bd295c37e3dd58a3bf0700376663ba4d9cf05c" + integrity sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg== + dependencies: + boolbase "~1.0.0" + +number-is-nan@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" + integrity sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0= + +nwsapi@^2.0.9: + version "2.2.0" + resolved "https://registry.yarnpkg.com/nwsapi/-/nwsapi-2.2.0.tgz#204879a9e3d068ff2a55139c2c772780681a38b7" + integrity sha512-h2AatdwYH+JHiZpv7pt/gSX1XoRGb7L/qSIeuqA6GwYoF9w1vP1cw42TO0aI2pNyshRK5893hNSl+1//vHK7hQ== + +oauth-sign@~0.9.0: + version "0.9.0" + resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455" + integrity sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ== + +object-assign@^4.1.0, object-assign@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" + integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= + +object-copy@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/object-copy/-/object-copy-0.1.0.tgz#7e7d858b781bd7c991a41ba975ed3812754e998c" + integrity sha1-fn2Fi3gb18mRpBupde04EnVOmYw= + dependencies: + copy-descriptor "^0.1.0" + define-property "^0.2.5" + kind-of "^3.0.3" + +object-inspect@^1.7.0, object-inspect@^1.8.0: + version "1.8.0" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.8.0.tgz#df807e5ecf53a609cc6bfe93eac3cc7be5b3a9d0" + integrity sha512-jLdtEOB112fORuypAyl/50VRVIBIdVQOSUUGQHzJ4xBSbit81zRarz7GThkEFZy1RceYrWYcPcBFPQwHyAc1gA== + +object-is@^1.1.2: + version "1.1.3" + resolved "https://registry.yarnpkg.com/object-is/-/object-is-1.1.3.tgz#2e3b9e65560137455ee3bd62aec4d90a2ea1cc81" + integrity sha512-teyqLvFWzLkq5B9ki8FVWA902UER2qkxmdA4nLf+wjOLAWgxzCWZNCxpDq9MvE8MmhWNr+I8w3BN49Vx36Y6Xg== + dependencies: + define-properties "^1.1.3" + es-abstract "^1.18.0-next.1" + +object-keys@^1.0.11, object-keys@^1.0.12, object-keys@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" + integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== + +object-visit@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/object-visit/-/object-visit-1.0.1.tgz#f79c4493af0c5377b59fe39d395e41042dd045bb" + integrity sha1-95xEk68MU3e1n+OdOV5BBC3QRbs= + dependencies: + isobject "^3.0.0" + +object.assign@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.0.tgz#968bf1100d7956bb3ca086f006f846b3bc4008da" + integrity sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w== + dependencies: + define-properties "^1.1.2" + function-bind "^1.1.1" + has-symbols "^1.0.0" + object-keys "^1.0.11" + +object.assign@^4.1.1: + version "4.1.2" + resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.2.tgz#0ed54a342eceb37b38ff76eb831a0e788cb63940" + integrity sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ== + dependencies: + call-bind "^1.0.0" + define-properties "^1.1.3" + has-symbols "^1.0.1" + object-keys "^1.1.1" + +object.entries@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/object.entries/-/object.entries-1.1.2.tgz#bc73f00acb6b6bb16c203434b10f9a7e797d3add" + integrity sha512-BQdB9qKmb/HyNdMNWVr7O3+z5MUIx3aiegEIJqjMBbBf0YT9RRxTJSim4mzFqtyr7PDAHigq0N9dO0m0tRakQA== + dependencies: + define-properties "^1.1.3" + es-abstract "^1.17.5" + has "^1.0.3" + +object.fromentries@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/object.fromentries/-/object.fromentries-2.0.2.tgz#4a09c9b9bb3843dd0f89acdb517a794d4f355ac9" + integrity sha512-r3ZiBH7MQppDJVLx6fhD618GKNG40CZYH9wgwdhKxBDDbQgjeWGGd4AtkZad84d291YxvWe7bJGuE65Anh0dxQ== + dependencies: + define-properties "^1.1.3" + es-abstract "^1.17.0-next.1" + function-bind "^1.1.1" + has "^1.0.3" + +object.pick@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/object.pick/-/object.pick-1.3.0.tgz#87a10ac4c1694bd2e1cbf53591a66141fb5dd747" + integrity sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c= + dependencies: + isobject "^3.0.1" + +object.values@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.1.1.tgz#68a99ecde356b7e9295a3c5e0ce31dc8c953de5e" + integrity sha512-WTa54g2K8iu0kmS/us18jEmdv1a4Wi//BZ/DTVYEcH0XhLM5NYdpDHja3gt57VrZLcNAO2WGA+KpWsDBaHt6eA== + dependencies: + define-properties "^1.1.3" + es-abstract "^1.17.0-next.1" + function-bind "^1.1.1" + has "^1.0.3" + +once@^1.3.0, once@^1.3.1, once@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= + dependencies: + wrappy "1" + +onetime@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/onetime/-/onetime-1.1.0.tgz#a1f7838f8314c516f05ecefcbc4ccfe04b4ed789" + integrity sha1-ofeDj4MUxRbwXs78vEzP4EtO14k= + +onetime@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/onetime/-/onetime-2.0.1.tgz#067428230fd67443b2794b22bba528b6867962d4" + integrity sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ= + dependencies: + mimic-fn "^1.0.0" + +onetime@^5.1.0: + version "5.1.2" + resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e" + integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg== + dependencies: + mimic-fn "^2.1.0" + +optionator@^0.8.1: + version "0.8.3" + resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.3.tgz#84fa1d036fe9d3c7e21d99884b601167ec8fb495" + integrity sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA== + dependencies: + deep-is "~0.1.3" + fast-levenshtein "~2.0.6" + levn "~0.3.0" + prelude-ls "~1.1.2" + type-check "~0.3.2" + word-wrap "~1.2.3" + +os-browserify@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/os-browserify/-/os-browserify-0.3.0.tgz#854373c7f5c2315914fc9bfc6bd8238fdda1ec27" + integrity sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc= + +ospath@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/ospath/-/ospath-1.2.2.tgz#1276639774a3f8ef2572f7fe4280e0ea4550c07b" + integrity sha1-EnZjl3Sj+O8lcvf+QoDg6kVQwHs= + +p-finally@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" + integrity sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4= + +p-limit@^2.0.0, p-limit@^2.2.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" + integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w== + dependencies: + p-try "^2.0.0" + +p-locate@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-3.0.0.tgz#322d69a05c0264b25997d9f40cd8a891ab0064a4" + integrity sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ== + dependencies: + p-limit "^2.0.0" + +p-locate@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07" + integrity sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A== + dependencies: + p-limit "^2.2.0" + +p-map@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/p-map/-/p-map-2.1.0.tgz#310928feef9c9ecc65b68b17693018a665cea175" + integrity sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw== + +p-try@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" + integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== + +pako@~1.0.5: + version "1.0.11" + resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.11.tgz#6c9599d340d54dfd3946380252a35705a6b992bf" + integrity sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw== + +parallel-transform@^1.1.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/parallel-transform/-/parallel-transform-1.2.0.tgz#9049ca37d6cb2182c3b1d2c720be94d14a5814fc" + integrity sha512-P2vSmIu38uIlvdcU7fDkyrxj33gTUy/ABO5ZUbGowxNCopBq/OoD42bP4UmMrJoPyk4Uqf0mu3mtWBhHCZD8yg== + dependencies: + cyclist "^1.0.1" + inherits "^2.0.3" + readable-stream "^2.1.5" + +parent-module@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" + integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== + dependencies: + callsites "^3.0.0" + +parse-asn1@^5.0.0, parse-asn1@^5.1.5: + version "5.1.6" + resolved "https://registry.yarnpkg.com/parse-asn1/-/parse-asn1-5.1.6.tgz#385080a3ec13cb62a62d39409cb3e88844cdaed4" + integrity sha512-RnZRo1EPU6JBnra2vGHj0yhp6ebyjBZpmUCLHWiFhxlzvBCCpAuZ7elsBp1PVAbQN0/04VD/19rfzlBSwLstMw== + dependencies: + asn1.js "^5.2.0" + browserify-aes "^1.0.0" + evp_bytestokey "^1.0.0" + pbkdf2 "^3.0.3" + safe-buffer "^5.1.1" + +parse-entities@^1.1.0: + version "1.2.2" + resolved "https://registry.yarnpkg.com/parse-entities/-/parse-entities-1.2.2.tgz#c31bf0f653b6661354f8973559cb86dd1d5edf50" + integrity sha512-NzfpbxW/NPrzZ/yYSoQxyqUZMZXIdCfE0OIN4ESsnptHJECoUk3FZktxNuzQf4tjt5UEopnxpYJbvYuxIFDdsg== + 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" + +parse-json@^5.0.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.1.0.tgz#f96088cdf24a8faa9aea9a009f2d9d942c999646" + integrity sha512-+mi/lmVVNKFNVyLXV31ERiy2CY5E1/F6QtJFEzoChPRwwngMNXRDQ9GJ5WdE2Z2P4AujsOi0/+2qHID68KwfIQ== + 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" + +parse5@5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/parse5/-/parse5-5.1.0.tgz#c59341c9723f414c452975564c7c00a68d58acd2" + integrity sha512-fxNG2sQjHvlVAYmzBZS9YlDp6PTSSDwa98vkD4QgVDDCAo84z5X1t5XyJQ62ImdLXx5NdIIfihey6xpum9/gRQ== + +pascalcase@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14" + integrity sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ= + +path-browserify@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-0.0.1.tgz#e6c4ddd7ed3aa27c68a20cc4e50e1a4ee83bbc4a" + integrity sha512-BapA40NHICOS+USX9SN4tyhq+A2RrN/Ws5F0Z5aMHDp98Fl86lX8Oti8B7uN93L4Ifv4fHOEA+pQw87gmMO/lQ== + +path-dirname@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/path-dirname/-/path-dirname-1.0.2.tgz#cc33d24d525e099a5388c0336c6e32b9160609e0" + integrity sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA= + +path-exists@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" + integrity sha1-zg6+ql94yxiSXqfYENe1mwEP1RU= + +path-exists@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" + integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== + +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= + +path-key@^2.0.0, path-key@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" + integrity sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A= + +path-key@^3.0.0, path-key@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" + integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== + +path-parse@^1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c" + integrity sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw== + +path-to-regexp@^1.7.0, path-to-regexp@^1.8.0: + version "1.8.0" + resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-1.8.0.tgz#887b3ba9d84393e87a0a0b9f4cb756198b53548a" + integrity sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA== + dependencies: + isarray "0.0.1" + +path-type@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" + integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== + +pbkdf2@^3.0.3: + version "3.1.1" + resolved "https://registry.yarnpkg.com/pbkdf2/-/pbkdf2-3.1.1.tgz#cb8724b0fada984596856d1a6ebafd3584654b94" + integrity sha512-4Ejy1OPxi9f2tt1rRV7Go7zmfDQ+ZectEQz3VGUQhgq62HtIRPDyG/JtnwIxs6x3uNMwo2V7q1fMvKjb+Tnpqg== + dependencies: + create-hash "^1.1.2" + create-hmac "^1.1.4" + ripemd160 "^2.0.1" + safe-buffer "^5.0.1" + sha.js "^2.4.8" + +pend@~1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50" + integrity sha1-elfrVQpng/kRUzH89GY9XI4AelA= + +performance-now@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" + integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns= + +picomatch@^2.0.4, picomatch@^2.0.5, picomatch@^2.2.1: + version "2.2.2" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.2.2.tgz#21f333e9b6b8eaff02468f5146ea406d345f4dad" + integrity sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg== + +pify@^2.2.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" + integrity sha1-7RQaasBDqEnqWISY59yosVMw6Qw= + +pify@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/pify/-/pify-4.0.1.tgz#4b2cd25c50d598735c50292224fd8c6df41e3231" + integrity sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g== + +pirates@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.1.tgz#643a92caf894566f91b2b986d2c66950a8e2fb87" + integrity sha512-WuNqLTbMI3tmfef2TKxlQmAiLHKtFhlsCZnPIpuv2Ow0RDVO8lfy1Opf4NUzlMXLjPl+Men7AuVdX6TA+s+uGA== + dependencies: + node-modules-regexp "^1.0.0" + +pkg-dir@4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3" + integrity sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ== + dependencies: + find-up "^4.0.0" + +pkg-dir@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-3.0.0.tgz#2749020f239ed990881b1f71210d51eb6523bea3" + integrity sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw== + dependencies: + find-up "^3.0.0" + +pn@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/pn/-/pn-1.1.0.tgz#e2f4cef0e219f463c179ab37463e4e1ecdccbafb" + integrity sha512-2qHaIQr2VLRFoxe2nASzsV6ef4yOOH+Fi9FBOVH6cqeSgUnoyySPZkxzLuzd+RYOQTRpROA0ztTMqxROKSb/nA== + +posix-character-classes@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" + integrity sha1-AerA/jta9xoqbAL+q7jB/vfgDqs= + +prelude-ls@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" + integrity sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ= + +pretty-bytes@^5.4.1: + version "5.5.0" + resolved "https://registry.yarnpkg.com/pretty-bytes/-/pretty-bytes-5.5.0.tgz#0cecda50a74a941589498011cf23275aa82b339e" + integrity sha512-p+T744ZyjjiaFlMUZZv6YPC5JrkNj8maRmPaQCWFJFplUAzpIUTRaTcS+7wmZtUoFXHtESJb23ISliaWyz3SHA== + +pretty-format@^25.2.1, pretty-format@^25.5.0: + version "25.5.0" + resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-25.5.0.tgz#7873c1d774f682c34b8d48b6743a2bf2ac55791a" + integrity sha512-kbo/kq2LQ/A/is0PQwsEHM7Ca6//bGPPvU6UnsdDRSKTWxT/ru/xb88v4BJf6a69H+uTytOEsTusT9ksd/1iWQ== + dependencies: + "@jest/types" "^25.5.0" + ansi-regex "^5.0.0" + ansi-styles "^4.0.0" + react-is "^16.12.0" + +process-nextick-args@~2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" + integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== + +process@^0.11.10: + version "0.11.10" + resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" + integrity sha1-czIwDoQBYb2j5podHZGn1LwW8YI= + +promise-inflight@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/promise-inflight/-/promise-inflight-1.0.1.tgz#98472870bf228132fcbdd868129bad12c3c029e3" + integrity sha1-mEcocL8igTL8vdhoEputEsPAKeM= + +promise-polyfill@^8.1.3: + version "8.1.3" + resolved "https://registry.yarnpkg.com/promise-polyfill/-/promise-polyfill-8.1.3.tgz#8c99b3cf53f3a91c68226ffde7bde81d7f904116" + integrity sha512-MG5r82wBzh7pSKDRa9y+vllNHz3e3d4CNj1PQE4BQYxLme0gKYYBm9YENq+UkEikyZ0XbiGWxYlVw3Rl9O/U8g== + +prop-types-exact@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/prop-types-exact/-/prop-types-exact-1.2.0.tgz#825d6be46094663848237e3925a98c6e944e9869" + integrity sha512-K+Tk3Kd9V0odiXFP9fwDHUYRyvK3Nun3GVyPapSIs5OBkITAm15W0CPFD/YKTkMUAbc0b9CUwRQp2ybiBIq+eA== + dependencies: + has "^1.0.3" + object.assign "^4.1.0" + reflect.ownkeys "^0.2.0" + +prop-types@^15.6.2, prop-types@^15.7.2: + version "15.7.2" + resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5" + integrity sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ== + dependencies: + loose-envify "^1.4.0" + object-assign "^4.1.1" + react-is "^16.8.1" + +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= + +pseudomap@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3" + integrity sha1-8FKijacOYYkX7wqKw0wa5aaChrM= + +psl@^1.1.28: + version "1.8.0" + resolved "https://registry.yarnpkg.com/psl/-/psl-1.8.0.tgz#9326f8bcfb013adcc005fdff056acce020e51c24" + integrity sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ== + +public-encrypt@^4.0.0: + version "4.0.3" + resolved "https://registry.yarnpkg.com/public-encrypt/-/public-encrypt-4.0.3.tgz#4fcc9d77a07e48ba7527e7cbe0de33d0701331e0" + integrity sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q== + dependencies: + bn.js "^4.1.0" + browserify-rsa "^4.0.0" + create-hash "^1.1.0" + parse-asn1 "^5.0.0" + randombytes "^2.0.1" + safe-buffer "^5.1.2" + +pump@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/pump/-/pump-2.0.1.tgz#12399add6e4cf7526d973cbc8b5ce2e2908b3909" + integrity sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA== + dependencies: + end-of-stream "^1.1.0" + once "^1.3.1" + +pump@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64" + integrity sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww== + dependencies: + end-of-stream "^1.1.0" + once "^1.3.1" + +pumpify@^1.3.3: + version "1.5.1" + resolved "https://registry.yarnpkg.com/pumpify/-/pumpify-1.5.1.tgz#36513be246ab27570b1a374a5ce278bfd74370ce" + integrity sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ== + dependencies: + duplexify "^3.6.0" + inherits "^2.0.3" + pump "^2.0.0" + +punycode@1.3.2: + version "1.3.2" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d" + integrity sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0= + +punycode@^1.2.4: + version "1.4.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" + integrity sha1-wNWmOycYgArY4esPpSachN1BhF4= + +punycode@^2.1.0, punycode@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" + integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== + +qs@~6.5.2: + version "6.5.2" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36" + integrity sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA== + +query-string@^6.13.1: + version "6.13.2" + resolved "https://registry.yarnpkg.com/query-string/-/query-string-6.13.2.tgz#3585aa9412c957cbd358fd5eaca7466f05586dda" + integrity sha512-BMmDaUiLDFU1hlM38jTFcRt7HYiGP/zt1sRzrIWm5zpeEuO1rkbPS0ELI3uehoLuuhHDCS8u8lhFN3fEN4JzPQ== + dependencies: + decode-uri-component "^0.2.0" + split-on-first "^1.0.0" + strict-uri-encode "^2.0.0" + +querystring-es3@^0.2.0: + version "0.2.1" + resolved "https://registry.yarnpkg.com/querystring-es3/-/querystring-es3-0.2.1.tgz#9ec61f79049875707d69414596fd907a4d711e73" + integrity sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM= + +querystring@0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620" + integrity sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA= + +raf@^3.4.1: + version "3.4.1" + resolved "https://registry.yarnpkg.com/raf/-/raf-3.4.1.tgz#0742e99a4a6552f445d73e3ee0328af0ff1ede39" + integrity sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA== + dependencies: + performance-now "^2.1.0" + +ramda@^0.27: + version "0.27.1" + resolved "https://registry.yarnpkg.com/ramda/-/ramda-0.27.1.tgz#66fc2df3ef873874ffc2da6aa8984658abacf5c9" + integrity sha512-PgIdVpn5y5Yns8vqb8FzBUEYn98V3xcPgawAkkgj0YJ0qDsnHCiNmZYfOGMgOvoB0eWFLpYbhxUR3mxfDIMvpw== + +ramda@~0.26.1: + version "0.26.1" + resolved "https://registry.yarnpkg.com/ramda/-/ramda-0.26.1.tgz#8d41351eb8111c55353617fc3bbffad8e4d35d06" + integrity sha512-hLWjpy7EnsDBb0p+Z3B7rPi3GDeRG5ZtiI33kJhTt+ORCd38AbAIjB/9zRIUoeTbE/AVX5ZkU7m6bznsvrf8eQ== + +randombytes@^2.0.0, randombytes@^2.0.1, randombytes@^2.0.5, randombytes@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" + integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ== + dependencies: + safe-buffer "^5.1.0" + +randomfill@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/randomfill/-/randomfill-1.0.4.tgz#c92196fc86ab42be983f1bf31778224931d61458" + integrity sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw== + dependencies: + randombytes "^2.0.5" + safe-buffer "^5.1.0" + +react-addons-test-utils@^15.6.2: + version "15.6.2" + resolved "https://registry.yarnpkg.com/react-addons-test-utils/-/react-addons-test-utils-15.6.2.tgz#c12b6efdc2247c10da7b8770d185080a7b047156" + integrity sha1-wStu/cIkfBDae4dw0YUICnsEcVY= + +react-id-generator@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/react-id-generator/-/react-id-generator-3.0.1.tgz#30ec683954b3c0a5aa0732c4b98ed0f88fd85d00" + integrity sha512-YxorMaYxB8ItXA3Cuadcl/8ZaquU9Tzrrr5ogFL8tNqevF96cmCtx3LZLXYqBEj3BxoV9aBIK5yJjIuX/XHQ1A== + +react-is@^16.12.0, react-is@^16.13.0, react-is@^16.13.1, react-is@^16.6.0, react-is@^16.7.0, react-is@^16.8.1, react-is@^16.8.6: + version "16.13.1" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" + integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== + +react-markdown@^4.3.1: + version "4.3.1" + resolved "https://registry.yarnpkg.com/react-markdown/-/react-markdown-4.3.1.tgz#39f0633b94a027445b86c9811142d05381300f2f" + integrity sha512-HQlWFTbDxTtNY6bjgp3C3uv1h2xcjCSi1zAEzfBW9OwJJvENSYiLXWNXN5hHLsoqai7RnZiiHzcnWdXk2Splzw== + dependencies: + html-to-react "^1.3.4" + mdast-add-list-metadata "1.0.1" + prop-types "^15.7.2" + react-is "^16.8.6" + remark-parse "^5.0.0" + unified "^6.1.5" + unist-util-visit "^1.3.0" + xtend "^4.0.1" + +react-mde@^10.2.1: + version "10.2.1" + resolved "https://registry.yarnpkg.com/react-mde/-/react-mde-10.2.1.tgz#6debedbbed224155f5f4c025ae0c1655a41d385c" + integrity sha512-rq99Y6xQknZRQSzUpkY5KJRl3cE7GpiC+bSG2L10T2m1p6Y90zQxC060TWk1yoeXtGtveao1NXEV1UcpvOhRsQ== + +react-native-base64@^0.0.2: + version "0.0.2" + resolved "https://registry.yarnpkg.com/react-native-base64/-/react-native-base64-0.0.2.tgz#c28463c2c6779ac3ec5fdd12979ebc8c5f9b410a" + integrity sha512-Fu/J1a2y0X22EJDWqJR2oEa1fpP4gTFjYxk8ElJdt1Yak3HOXmFJ7EohLVHU2DaQkgmKfw8qb7u/48gpzveRbg== + +react-native-i18n@^2.0.15: + version "2.0.15" + resolved "https://registry.yarnpkg.com/react-native-i18n/-/react-native-i18n-2.0.15.tgz#09b5a9836116fa7dbd0054c46e2d1014c1ef3c65" + integrity sha512-V8VwUP0TLda3oJvgt5tdnFaOV7WXPhTjCTLO7sXI3C2SHggSbD4bCUryMzNJhesimJidH21V2Owvj4zAylHoQQ== + dependencies: + i18n-js "3.0.11" + +react-native-safe-area-view@^0.14.9: + version "0.14.9" + resolved "https://registry.yarnpkg.com/react-native-safe-area-view/-/react-native-safe-area-view-0.14.9.tgz#90ee8383037010d9a5055a97cf97e4c1da1f0c3d" + integrity sha512-WII/ulhpVyL/qbYb7vydq7dJAfZRBcEhg4/UWt6F6nAKpLa3gAceMOxBxI914ppwSP/TdUsandFy6lkJQE0z4A== + dependencies: + hoist-non-react-statics "^2.3.1" + +react-navigation@^4.3.9: + version "4.4.1" + resolved "https://registry.yarnpkg.com/react-navigation/-/react-navigation-4.4.1.tgz#7511b5d46bba8e52fc2f426144127a012454c84f" + integrity sha512-E0TJHLS8mcdliubPjbIfyplZG1oQhHYzH3cHKMSVXWE4dhSSf1x//r+92kW9LbS62v51Nj3Bxw2cJMHw0xP9Kw== + dependencies: + "@react-navigation/core" "^3.7.7" + "@react-navigation/native" "^3.8.1" + +react-router-dom@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/react-router-dom/-/react-router-dom-5.2.0.tgz#9e65a4d0c45e13289e66c7b17c7e175d0ea15662" + integrity sha512-gxAmfylo2QUjcwxI63RhQ5G85Qqt4voZpUXSEqCwykV0baaOTQDR1f0PmY8AELqIyVc0NEZUj0Gov5lNGcXgsA== + dependencies: + "@babel/runtime" "^7.1.2" + history "^4.9.0" + loose-envify "^1.3.1" + prop-types "^15.6.2" + react-router "5.2.0" + tiny-invariant "^1.0.2" + tiny-warning "^1.0.0" + +react-router@5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/react-router/-/react-router-5.2.0.tgz#424e75641ca8747fbf76e5ecca69781aa37ea293" + integrity sha512-smz1DUuFHRKdcJC0jobGo8cVbhO3x50tCL4icacOlcwDOEQPq4TMqwx3sY1TP+DvtTgz4nm3thuo7A+BK2U0Dw== + dependencies: + "@babel/runtime" "^7.1.2" + history "^4.9.0" + hoist-non-react-statics "^3.1.0" + loose-envify "^1.3.1" + mini-create-react-context "^0.4.0" + path-to-regexp "^1.7.0" + prop-types "^15.6.2" + react-is "^16.6.0" + tiny-invariant "^1.0.2" + tiny-warning "^1.0.0" + +react-test-renderer@^16.0.0-0, react-test-renderer@^16.12.0: + version "16.14.0" + resolved "https://registry.yarnpkg.com/react-test-renderer/-/react-test-renderer-16.14.0.tgz#e98360087348e260c56d4fe2315e970480c228ae" + integrity sha512-L8yPjqPE5CZO6rKsKXRO/rVPiaCOy0tQQJbC+UjPNlobl5mad59lvPjwFsQHTvL03caVDIVr9x9/OSgDe6I5Eg== + dependencies: + object-assign "^4.1.1" + prop-types "^15.6.2" + react-is "^16.8.6" + scheduler "^0.19.1" + +react-toast-notifications@^2.4.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/react-toast-notifications/-/react-toast-notifications-2.4.0.tgz#6213730bd1fe158fc01aeef200687ea94c5c5b24" + integrity sha512-8tkrbNh7LxkiFmtqAL/AiI55efIeI+fBk3c6ImsiZ0VObb4yvOq0cqYuJHyUiv9fuD2aBxvXGVH+n4Snt8qoWA== + dependencies: + "@emotion/core" "^10.0.14" + react-transition-group "^4.3.0" + +react-transition-group@^4.3.0: + version "4.4.1" + resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-4.4.1.tgz#63868f9325a38ea5ee9535d828327f85773345c9" + integrity sha512-Djqr7OQ2aPUiYurhPalTrVy9ddmFCCzwhqQmtN+J3+3DzLO209Fdr70QrN8Z3DsglWql6iY1lDWAfpFiBtuKGw== + dependencies: + "@babel/runtime" "^7.5.5" + dom-helpers "^5.0.1" + loose-envify "^1.4.0" + prop-types "^15.6.2" + +"readable-stream@1 || 2", readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.3.3, readable-stream@^2.3.6, readable-stream@~2.3.6: + version "2.3.7" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57" + 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" + +readable-stream@^3.1.1, readable-stream@^3.4.0, readable-stream@^3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198" + integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA== + dependencies: + inherits "^2.0.3" + string_decoder "^1.1.1" + util-deprecate "^1.0.1" + +readdirp@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.2.1.tgz#0e87622a3325aa33e892285caf8b4e846529a525" + integrity sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ== + dependencies: + graceful-fs "^4.1.11" + micromatch "^3.1.10" + readable-stream "^2.0.2" + +readdirp@~3.5.0: + version "3.5.0" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.5.0.tgz#9ba74c019b15d365278d2e91bb8c48d7b4d42c9e" + integrity sha512-cMhu7c/8rdhkHXWsY+osBhfSy0JikwpHK/5+imo+LpeasTF8ouErHrlYkwT0++njiyuDvc7OFY5T3ukvZ8qmFQ== + dependencies: + picomatch "^2.2.1" + +reflect.ownkeys@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/reflect.ownkeys/-/reflect.ownkeys-0.2.0.tgz#749aceec7f3fdf8b63f927a04809e90c5c0b3460" + integrity sha1-dJrO7H8/34tj+SegSAnpDFwLNGA= + +regenerator-runtime@^0.10.5: + version "0.10.5" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.10.5.tgz#336c3efc1220adcedda2c9fab67b5a7955a33658" + integrity sha1-M2w+/BIgrc7dosn6tntaeVWjNlg= + +regenerator-runtime@^0.11.0: + version "0.11.1" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9" + integrity sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg== + +regenerator-runtime@^0.13.11, regenerator-runtime@^0.13.7: + version "0.13.11" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz#f6dca3e7ceec20590d07ada785636a90cdca17f9" + integrity sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg== + +regenerator-runtime@^0.13.2, regenerator-runtime@^0.13.4: + version "0.13.7" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz#cac2dacc8a1ea675feaabaeb8ae833898ae46f55" + integrity sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew== + +regex-not@^1.0.0, regex-not@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/regex-not/-/regex-not-1.0.2.tgz#1f4ece27e00b0b65e0247a6810e6a85d83a5752c" + integrity sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A== + dependencies: + extend-shallow "^3.0.2" + safe-regex "^1.1.0" + +remark-parse@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/remark-parse/-/remark-parse-5.0.0.tgz#4c077f9e499044d1d5c13f80d7a98cf7b9285d95" + integrity sha512-b3iXszZLH1TLoyUzrATcTQUZrwNl1rE70rVdSruJFlDaJ9z5aMkhrG43Pp68OgfHndL/ADz6V69Zow8cTQu+JA== + dependencies: + 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 "^1.1.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 "^1.0.0" + vfile-location "^2.0.0" + xtend "^4.0.1" + +remove-trailing-separator@^1.0.1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef" + integrity sha1-wkvOKig62tW8P1jg1IJJuSN52O8= + +repeat-element@^1.1.2: + version "1.1.3" + resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.3.tgz#782e0d825c0c5a3bb39731f84efee6b742e6b1ce" + integrity sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g== + +repeat-string@^1.5.4, repeat-string@^1.6.1: + version "1.6.1" + resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" + integrity sha1-jcrkcOHIirwtYA//Sndihtp15jc= + +replace-ext@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/replace-ext/-/replace-ext-1.0.0.tgz#de63128373fcbf7c3ccfa4de5a480c45a67958eb" + integrity sha1-3mMSg3P8v3w8z6TeWkgMRaZ5WOs= + +replace-in-file@^6.3.5: + version "6.3.5" + resolved "https://registry.yarnpkg.com/replace-in-file/-/replace-in-file-6.3.5.tgz#ff956b0ab5bc96613207d603d197cd209400a654" + integrity sha512-arB9d3ENdKva2fxRnSjwBEXfK1npgyci7ZZuwysgAp7ORjHSyxz6oqIjTEv8R0Ydl4Ll7uOAZXL4vbkhGIizCg== + dependencies: + chalk "^4.1.2" + glob "^7.2.0" + yargs "^17.2.1" + +request-progress@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/request-progress/-/request-progress-3.0.0.tgz#4ca754081c7fec63f505e4faa825aa06cd669dbe" + integrity sha1-TKdUCBx/7GP1BeT6qCWqBs1mnb4= + dependencies: + throttleit "^1.0.0" + +request-promise-core@1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/request-promise-core/-/request-promise-core-1.1.4.tgz#3eedd4223208d419867b78ce815167d10593a22f" + integrity sha512-TTbAfBBRdWD7aNNOoVOBH4pN/KigV6LyapYNNlAPA8JwbovRti1E88m3sYAwsLi5ryhPKsE9APwnjFTgdUjTpw== + dependencies: + lodash "^4.17.19" + +request-promise-native@^1.0.5: + version "1.0.9" + resolved "https://registry.yarnpkg.com/request-promise-native/-/request-promise-native-1.0.9.tgz#e407120526a5efdc9a39b28a5679bf47b9d9dc28" + integrity sha512-wcW+sIUiWnKgNY0dqCpOZkUbF/I+YPi+f09JZIDa39Ec+q82CpSYniDp+ISgTTbKmnpJWASeJBPZmoxH84wt3g== + dependencies: + request-promise-core "1.1.4" + stealthy-require "^1.1.1" + tough-cookie "^2.3.3" + +request@^2.88.0: + version "2.88.2" + resolved "https://registry.yarnpkg.com/request/-/request-2.88.2.tgz#d73c918731cb5a87da047e207234146f664d12b3" + integrity sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw== + dependencies: + aws-sign2 "~0.7.0" + aws4 "^1.8.0" + caseless "~0.12.0" + combined-stream "~1.0.6" + extend "~3.0.2" + forever-agent "~0.6.1" + form-data "~2.3.2" + har-validator "~5.1.3" + http-signature "~1.2.0" + is-typedarray "~1.0.0" + isstream "~0.1.2" + json-stringify-safe "~5.0.1" + mime-types "~2.1.19" + oauth-sign "~0.9.0" + performance-now "^2.1.0" + qs "~6.5.2" + safe-buffer "^5.1.2" + tough-cookie "~2.5.0" + tunnel-agent "^0.6.0" + uuid "^3.3.2" + +require-directory@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" + integrity sha1-jGStX9MNqxyXbiNE/+f3kqam30I= + +resolve-from@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" + integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== + +resolve-from@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69" + integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw== + +resolve-pathname@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/resolve-pathname/-/resolve-pathname-3.0.0.tgz#99d02224d3cf263689becbb393bc560313025dcd" + integrity sha512-C7rARubxI8bXFNB/hqcp/4iUeIXJhJZvFPFPiSPRnhU5UPxzMFIl+2E6yY6c4k9giDJAhtV+enfA+G89N6Csng== + +resolve-url@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" + integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo= + +resolve@^1.10.0, resolve@^1.3.2, resolve@^1.5.0, resolve@^1.7.1: + version "1.19.0" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.19.0.tgz#1af5bf630409734a067cae29318aac7fa29a267c" + integrity sha512-rArEXAgsBG4UgRGcynxWIWKFvh/XZCcS8UJdHhwy91zwAvCZIbcs+vAbflgBnNjYMs/i/i+/Ux6IZhML1yPvxg== + dependencies: + is-core-module "^2.1.0" + path-parse "^1.0.6" + +resolve@^1.12.0: + version "1.17.0" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.17.0.tgz#b25941b54968231cc2d1bb76a79cb7f2c0bf8444" + integrity sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w== + dependencies: + path-parse "^1.0.6" + +restore-cursor@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-1.0.1.tgz#34661f46886327fed2991479152252df92daa541" + integrity sha1-NGYfRohjJ/7SmRR5FSJS35LapUE= + dependencies: + exit-hook "^1.0.0" + onetime "^1.0.0" + +restore-cursor@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-2.0.0.tgz#9f7ee287f82fd326d4fd162923d62129eee0dfaf" + integrity sha1-n37ih/gv0ybU/RYpI9YhKe7g368= + dependencies: + onetime "^2.0.0" + signal-exit "^3.0.2" + +ret@~0.1.10: + version "0.1.15" + resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc" + integrity sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg== + +rgbcolor@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/rgbcolor/-/rgbcolor-1.0.1.tgz#d6505ecdb304a6595da26fa4b43307306775945d" + integrity sha512-9aZLIrhRaD97sgVhtJOW6ckOEh6/GnvQtdVNfdZ6s67+3/XwLS9lBcQYzEEhYVeUowN7pRzMLsyGhK2i/xvWbw== + +rimraf@^2.5.4, rimraf@^2.6.3: + version "2.7.1" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec" + integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w== + dependencies: + glob "^7.1.3" + +rimraf@^3.0.0: + version "3.0.2" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" + integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== + dependencies: + glob "^7.1.3" + +rimraf@^2.5.4, rimraf@^2.6.3: + version "2.7.1" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec" + integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w== + dependencies: + glob "^7.1.3" + +ripemd160@^2.0.0, ripemd160@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-2.0.2.tgz#a1c1a6f624751577ba5d07914cbc92850585890c" + integrity sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA== + dependencies: + hash-base "^3.0.0" + inherits "^2.0.1" + +rsvp@^4.8.4: + version "4.8.5" + resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-4.8.5.tgz#c8f155311d167f68f21e168df71ec5b083113734" + integrity sha512-nfMOlASu9OnRJo1mbEk2cz0D56a1MBNrJ7orjRZQG10XDyuvwksKbuXNp6qa+kbn839HwjwhBzhFmdsaEAfauA== + +run-queue@^1.0.0, run-queue@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/run-queue/-/run-queue-1.0.3.tgz#e848396f057d223f24386924618e25694161ec47" + integrity sha1-6Eg5bwV9Ij8kOGkkYY4laUFh7Ec= + dependencies: + aproba "^1.1.1" + +rxjs@^6.3.3: + version "6.6.3" + resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.6.3.tgz#8ca84635c4daa900c0d3967a6ee7ac60271ee552" + integrity sha512-trsQc+xYYXZ3urjOiJOuCOa5N3jAZ3eiSpQB5hIT8zGlL2QfnHLJ2r7GMkBGuIausdJN1OneaI6gQlsqNHHmZQ== + dependencies: + tslib "^1.9.0" + +safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@^5.2.0, safe-buffer@~5.2.0: + version "5.2.1" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" + integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== + +safe-buffer@~5.1.0, safe-buffer@~5.1.1: + version "5.1.2" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" + integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== + +safe-regex@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/safe-regex/-/safe-regex-1.1.0.tgz#40a3669f3b077d1e943d44629e157dd48023bf2e" + integrity sha1-QKNmnzsHfR6UPURinhV91IAjvy4= + dependencies: + ret "~0.1.10" + +"safer-buffer@>= 2.1.2 < 3", safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0: + version "2.1.2" + resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" + integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== + +sane@^4.0.3: + version "4.1.0" + resolved "https://registry.yarnpkg.com/sane/-/sane-4.1.0.tgz#ed881fd922733a6c461bc189dc2b6c006f3ffded" + integrity sha512-hhbzAgTIX8O7SHfp2c8/kREfEn4qO/9q8C9beyY6+tvZ87EpoZ3i1RIEvp27YBswnNbY9mWd6paKVmKbAgLfZA== + dependencies: + "@cnakazawa/watch" "^1.0.3" + anymatch "^2.0.0" + capture-exit "^2.0.0" + exec-sh "^0.3.2" + execa "^1.0.0" + fb-watchman "^2.0.0" + micromatch "^3.1.4" + minimist "^1.1.1" + walker "~1.0.5" + +saxes@^3.1.4: + version "3.1.11" + resolved "https://registry.yarnpkg.com/saxes/-/saxes-3.1.11.tgz#d59d1fd332ec92ad98a2e0b2ee644702384b1c5b" + integrity sha512-Ydydq3zC+WYDJK1+gRxRapLIED9PWeSuuS41wqyoRmzvhhh9nc+QQrVMKJYzJFULazeGhzSV0QleN2wD3boh2g== + dependencies: + xmlchars "^2.1.1" + +scheduler@^0.19.1: + version "0.19.1" + resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.19.1.tgz#4f3e2ed2c1a7d65681f4c854fa8c5a1ccb40f196" + integrity sha512-n/zwRWRYSUj0/3g/otKDRPMh6qv2SYMWNq85IEa8iZyAv8od9zDYpGSnpBEjNgcMNq6Scbu5KfIPxNF72R/2EA== + dependencies: + loose-envify "^1.1.0" + object-assign "^4.1.1" + +schema-utils@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-1.0.0.tgz#0b79a93204d7b600d4b2850d1f66c2a34951c770" + integrity sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g== + dependencies: + ajv "^6.1.0" + ajv-errors "^1.0.0" + ajv-keywords "^3.1.0" + +semver@7.x: + version "7.3.2" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.2.tgz#604962b052b81ed0786aae84389ffba70ffd3938" + integrity sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ== + +semver@^5.3.0, semver@^5.4.1, semver@^5.5.0, semver@^5.6.0, semver@^5.7.0, semver@^5.7.1: + version "5.7.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" + integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== + +semver@^6.3.0: + version "6.3.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" + integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== + +serialize-javascript@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-4.0.0.tgz#b525e1238489a5ecfc42afacc3fe99e666f4b1aa" + integrity sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw== + dependencies: + randombytes "^2.1.0" + +set-interval-async@1.0.33: + version "1.0.33" + resolved "https://registry.yarnpkg.com/set-interval-async/-/set-interval-async-1.0.33.tgz#f9a0a2ad7d8fb62cd6eac0ce088a6d631602089c" + integrity sha512-cKV9rLl707sWirvrZEL8XxyOxaPowueFRYKruRRj2cKHRd+M0JGg6IPqoUZVXkvaOZxvM3ulqDdNJuG5MmngxA== + dependencies: + "@babel/runtime" "7.5.0" + +set-value@^2.0.0, set-value@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/set-value/-/set-value-2.0.1.tgz#a18d40530e6f07de4228c7defe4227af8cad005b" + integrity sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw== + dependencies: + extend-shallow "^2.0.1" + is-extendable "^0.1.1" + is-plain-object "^2.0.3" + split-string "^3.0.1" + +setimmediate@^1.0.4: + version "1.0.5" + resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" + integrity sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU= + +sha.js@^2.4.0, sha.js@^2.4.8: + version "2.4.11" + resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.4.11.tgz#37a5cf0b81ecbc6943de109ba2960d1b26584ae7" + integrity sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ== + dependencies: + inherits "^2.0.1" + safe-buffer "^5.0.1" + +shebang-command@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" + integrity sha1-RKrGW2lbAzmJaMOfNj/uXer98eo= + dependencies: + shebang-regex "^1.0.0" + +shebang-command@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" + integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== + dependencies: + shebang-regex "^3.0.0" + +shebang-regex@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" + integrity sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM= + +shebang-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" + integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== + +showdown@^1.9.1: + version "1.9.1" + resolved "https://registry.yarnpkg.com/showdown/-/showdown-1.9.1.tgz#134e148e75cd4623e09c21b0511977d79b5ad0ef" + integrity sha512-9cGuS382HcvExtf5AHk7Cb4pAeQQ+h0eTr33V1mu+crYWV4KvWAw6el92bDrqGEk5d46Ai/fhbEUwqJ/mTCNEA== + dependencies: + yargs "^14.2" + +signal-exit@^3.0.0, signal-exit@^3.0.2: + version "3.0.3" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.3.tgz#a1410c2edd8f077b08b4e253c8eacfcaf057461c" + integrity sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA== + +slash@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" + integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== + +slice-ansi@0.0.4: + version "0.0.4" + resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-0.0.4.tgz#edbf8903f66f7ce2f8eafd6ceed65e264c831b35" + integrity sha1-7b+JA/ZvfOL46v1s7tZeJkyDGzU= + +snapdragon-node@^2.0.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b" + integrity sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw== + dependencies: + define-property "^1.0.0" + isobject "^3.0.0" + snapdragon-util "^3.0.1" + +snapdragon-util@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/snapdragon-util/-/snapdragon-util-3.0.1.tgz#f956479486f2acd79700693f6f7b805e45ab56e2" + integrity sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ== + dependencies: + kind-of "^3.2.0" + +snapdragon@^0.8.1: + version "0.8.2" + resolved "https://registry.yarnpkg.com/snapdragon/-/snapdragon-0.8.2.tgz#64922e7c565b0e14204ba1aa7d6964278d25182d" + integrity sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg== + dependencies: + base "^0.11.1" + debug "^2.2.0" + define-property "^0.2.5" + extend-shallow "^2.0.1" + map-cache "^0.2.2" + source-map "^0.5.6" + source-map-resolve "^0.5.0" + use "^3.1.0" + +source-list-map@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-2.0.1.tgz#3993bd873bfc48479cca9ea3a547835c7c154b34" + integrity sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw== + +source-map-resolve@^0.5.0: + version "0.5.3" + resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.3.tgz#190866bece7553e1f8f267a2ee82c606b5509a1a" + integrity sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw== + dependencies: + atob "^2.1.2" + decode-uri-component "^0.2.0" + resolve-url "^0.2.1" + source-map-url "^0.4.0" + urix "^0.1.0" + +source-map-support@~0.5.12: + version "0.5.19" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.19.tgz#a98b62f86dcaf4f67399648c085291ab9e8fed61" + integrity sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw== + dependencies: + buffer-from "^1.0.0" + source-map "^0.6.0" + +source-map-url@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3" + integrity sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM= + +source-map@^0.5.0, source-map@^0.5.6, source-map@^0.5.7: + version "0.5.7" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" + integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= + +source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" + integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== + +split-on-first@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/split-on-first/-/split-on-first-1.1.0.tgz#f610afeee3b12bce1d0c30425e76398b78249a5f" + integrity sha512-43ZssAJaMusuKWL8sKUBQXHWOpq8d6CfN/u1p4gUzfJkM05C8rxTmYrkIPTXapZpORA6LkkzcUulJ8FqA7Uudw== + +split-string@^3.0.1, split-string@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2" + integrity sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw== + dependencies: + extend-shallow "^3.0.0" + +sprintf-js@~1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" + integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= + +sshpk@^1.7.0: + version "1.16.1" + resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.16.1.tgz#fb661c0bef29b39db40769ee39fa70093d6f6877" + integrity sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg== + dependencies: + asn1 "~0.2.3" + assert-plus "^1.0.0" + bcrypt-pbkdf "^1.0.0" + dashdash "^1.12.0" + ecc-jsbn "~0.1.1" + getpass "^0.1.1" + jsbn "~0.1.0" + safer-buffer "^2.0.2" + tweetnacl "~0.14.0" + +ssri@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/ssri/-/ssri-6.0.1.tgz#2a3c41b28dd45b62b63676ecb74001265ae9edd8" + integrity sha512-3Wge10hNcT1Kur4PDFwEieXSCMCJs/7WvSACcrMYrNp+b8kDL1/0wJch5Ni2WrtwEa2IO8OsVfeKIciKCDx/QA== + dependencies: + figgy-pudding "^3.5.1" + +stackblur-canvas@^2.0.0: + version "2.5.0" + resolved "https://registry.yarnpkg.com/stackblur-canvas/-/stackblur-canvas-2.5.0.tgz#aa87bbed1560fdcd3138fff344fc6a1c413ebac4" + integrity sha512-EeNzTVfj+1In7aSLPKDD03F/ly4RxEuF/EX0YcOG0cKoPXs+SLZxDawQbexQDBzwROs4VKLWTOaZQlZkGBFEIQ== + +state-toggle@^1.0.0: + version "1.0.3" + resolved "https://registry.yarnpkg.com/state-toggle/-/state-toggle-1.0.3.tgz#e123b16a88e143139b09c6852221bc9815917dfe" + integrity sha512-d/5Z4/2iiCnHw6Xzghyhb+GcmF89bxwgXG60wjIiZaxnymbyOmI8Hk4VqHXiVVp6u2ysaskFfXg3ekCj4WNftQ== + +static-extend@^0.1.1: + version "0.1.2" + resolved "https://registry.yarnpkg.com/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6" + integrity sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY= + dependencies: + define-property "^0.2.5" + object-copy "^0.1.0" + +stealthy-require@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/stealthy-require/-/stealthy-require-1.1.1.tgz#35b09875b4ff49f26a777e509b3090a3226bf24b" + integrity sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks= + +stream-browserify@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/stream-browserify/-/stream-browserify-2.0.2.tgz#87521d38a44aa7ee91ce1cd2a47df0cb49dd660b" + integrity sha512-nX6hmklHs/gr2FuxYDltq8fJA1GDlxKQCz8O/IM4atRqBH8OORmBNgfvW5gG10GT/qQ9u0CzIvr2X5Pkt6ntqg== + dependencies: + inherits "~2.0.1" + readable-stream "^2.0.2" + +stream-each@^1.1.0: + version "1.2.3" + resolved "https://registry.yarnpkg.com/stream-each/-/stream-each-1.2.3.tgz#ebe27a0c389b04fbcc233642952e10731afa9bae" + integrity sha512-vlMC2f8I2u/bZGqkdfLQW/13Zihpej/7PmSiMQsbYddxuTsJp8vRe2x2FvVExZg7FaOds43ROAuFJwPR4MTZLw== + dependencies: + end-of-stream "^1.1.0" + stream-shift "^1.0.0" + +stream-http@^2.7.2: + version "2.8.3" + resolved "https://registry.yarnpkg.com/stream-http/-/stream-http-2.8.3.tgz#b2d242469288a5a27ec4fe8933acf623de6514fc" + integrity sha512-+TSkfINHDo4J+ZobQLWiMouQYB+UVYFttRA94FpEzzJ7ZdqcL4uUUQ7WkdkI4DSozGmgBUE/a47L+38PenXhUw== + dependencies: + builtin-status-codes "^3.0.0" + inherits "^2.0.1" + readable-stream "^2.3.6" + to-arraybuffer "^1.0.0" + xtend "^4.0.0" + +stream-shift@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/stream-shift/-/stream-shift-1.0.1.tgz#d7088281559ab2778424279b0877da3c392d5a3d" + integrity sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ== + +strict-uri-encode@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz#b9c7330c7042862f6b142dc274bbcc5866ce3546" + integrity sha1-ucczDHBChi9rFC3CdLvMWGbONUY= + +string-width@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" + integrity sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M= + dependencies: + code-point-at "^1.0.0" + is-fullwidth-code-point "^1.0.0" + strip-ansi "^3.0.0" + +string-width@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" + integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw== + dependencies: + is-fullwidth-code-point "^2.0.0" + strip-ansi "^4.0.0" + +string-width@^4.1.0, string-width@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.0.tgz#952182c46cc7b2c313d1596e623992bd163b72b5" + integrity sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.0" + +string.prototype.trimend@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.1.tgz#85812a6b847ac002270f5808146064c995fb6913" + integrity sha512-LRPxFUaTtpqYsTeNKaFOw3R4bxIzWOnbQ837QfBylo8jIxtcbK/A/sMV7Q+OAV/vWo+7s25pOE10KYSjaSO06g== + dependencies: + define-properties "^1.1.3" + es-abstract "^1.17.5" + +string.prototype.trimstart@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.1.tgz#14af6d9f34b053f7cfc89b72f8f2ee14b9039a54" + integrity sha512-XxZn+QpvrBI1FOcg6dIpxUPgWCPuNXvMD72aaRaUQv1eD4e/Qy8i/hFTe0BUmD60p/QA6bh1avmuPTfNjqVWRw== + dependencies: + define-properties "^1.1.3" + es-abstract "^1.17.5" + +string_decoder@^1.0.0, string_decoder@^1.1.1: + version "1.3.0" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" + integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== + dependencies: + safe-buffer "~5.2.0" + +string_decoder@~1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" + integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== + dependencies: + safe-buffer "~5.1.0" + +strip-ansi@^3.0.0, strip-ansi@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" + integrity sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8= + dependencies: + ansi-regex "^2.0.0" + +strip-ansi@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" + integrity sha1-qEeQIusaw2iocTibY1JixQXuNo8= + dependencies: + ansi-regex "^3.0.0" + +strip-ansi@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.0.tgz#0b1571dd7669ccd4f3e06e14ef1eed26225ae532" + integrity sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w== + dependencies: + ansi-regex "^5.0.0" + +strip-eof@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" + integrity sha1-u0P/VZim6wXYm1n80SnJgzE2Br8= + +strip-final-newline@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad" + integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA== + +supports-color@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" + integrity sha1-U10EXOa2Nj+kARcIRimZXp3zJMc= + +supports-color@^5.3.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" + integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== + dependencies: + has-flag "^3.0.0" + +supports-color@^7.0.0, supports-color@^7.1.0, supports-color@^7.2.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" + integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== + dependencies: + has-flag "^4.0.0" + +svg-pathdata@5.0.5: + version "5.0.5" + resolved "https://registry.yarnpkg.com/svg-pathdata/-/svg-pathdata-5.0.5.tgz#65e8d765642ba15fe15434444087d082bc526b29" + integrity sha512-TAAvLNSE3fEhyl/Da19JWfMAdhSXTYeviXsLSoDT1UM76ADj5ndwAPX1FKQEgB/gFMPavOy6tOqfalXKUiXrow== + +svg-pathdata@^6.0.3: + version "6.0.3" + resolved "https://registry.yarnpkg.com/svg-pathdata/-/svg-pathdata-6.0.3.tgz#80b0e0283b652ccbafb69ad4f8f73e8d3fbf2cac" + integrity sha512-qsjeeq5YjBZ5eMdFuUa4ZosMLxgr5RZ+F+Y1OrDhuOCEInRMA3x74XdBtggJcj9kOeInz0WE+LgCPDkZFlBYJw== + +symbol-observable@^1.1.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.2.0.tgz#c22688aed4eab3cdc2dfeacbb561660560a00804" + integrity sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ== + +symbol-tree@^3.2.2: + version "3.2.4" + resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.4.tgz#430637d248ba77e078883951fb9aa0eed7c63fa2" + integrity sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw== + +tapable@^0.1.8: + version "0.1.10" + resolved "https://registry.yarnpkg.com/tapable/-/tapable-0.1.10.tgz#29c35707c2b70e50d07482b5d202e8ed446dafd4" + integrity sha1-KcNXB8K3DlDQdIK10gLo7URtr9Q= + +tapable@^1.0.0, tapable@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/tapable/-/tapable-1.1.3.tgz#a1fccc06b58db61fd7a45da2da44f5f3a3e67ba2" + integrity sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA== + +tar-fs@2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/tar-fs/-/tar-fs-2.1.1.tgz#489a15ab85f1f0befabb370b7de4f9eb5cbe8784" + integrity sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng== + dependencies: + chownr "^1.1.1" + mkdirp-classic "^0.5.2" + pump "^3.0.0" + tar-stream "^2.1.4" + +tar-stream@^2.1.4: + version "2.2.0" + resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-2.2.0.tgz#acad84c284136b060dc3faa64474aa9aebd77287" + integrity sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ== + dependencies: + bl "^4.0.3" + end-of-stream "^1.4.1" + fs-constants "^1.0.0" + inherits "^2.0.3" + readable-stream "^3.1.1" + +terser-webpack-plugin@^1.4.3: + version "1.4.5" + resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-1.4.5.tgz#a217aefaea330e734ffacb6120ec1fa312d6040b" + integrity sha512-04Rfe496lN8EYruwi6oPQkG0vo8C+HT49X687FZnpPF0qMAIHONI6HEXYPKDOE8e5HjXTyKfqRd/agHtH0kOtw== + 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" + +terser@^4.1.2: + version "4.8.0" + resolved "https://registry.yarnpkg.com/terser/-/terser-4.8.0.tgz#63056343d7c70bb29f3af665865a46fe03a0df17" + integrity sha512-EAPipTNeWsb/3wLPeup1tVPaXfIaU68xMnVdPafIL1TV05OhASArYyIfFvnvJCNrR2NIOvDVNNTFRa+Re2MWyw== + dependencies: + commander "^2.20.0" + source-map "~0.6.1" + source-map-support "~0.5.12" + +test-exclude@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-6.0.0.tgz#04a8698661d805ea6fa293b6cb9e63ac044ef15e" + integrity sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w== + dependencies: + "@istanbuljs/schema" "^0.1.2" + glob "^7.1.4" + minimatch "^3.0.4" + +text-segmentation@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/text-segmentation/-/text-segmentation-1.0.3.tgz#52a388159efffe746b24a63ba311b6ac9f2d7943" + integrity sha512-iOiPUo/BGnZ6+54OsWxZidGCsdU8YbE4PSpdPinp7DeMtUJNJBoJ/ouUSTJjHkh1KntHaltHl/gDs2FC4i5+Nw== + dependencies: + utrie "^1.0.2" + +throttleit@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/throttleit/-/throttleit-1.0.0.tgz#9e785836daf46743145a5984b6268d828528ac6c" + integrity sha1-nnhYNtr0Z0MUWlmEtiaNgoUorGw= + +through2@^2.0.0: + version "2.0.5" + resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.5.tgz#01c1e39eb31d07cb7d03a96a70823260b23132cd" + integrity sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ== + dependencies: + readable-stream "~2.3.6" + xtend "~4.0.1" + +through@^2.3.8: + version "2.3.8" + resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" + integrity sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg== + +timers-browserify@^2.0.4: + version "2.0.12" + resolved "https://registry.yarnpkg.com/timers-browserify/-/timers-browserify-2.0.12.tgz#44a45c11fbf407f34f97bccd1577c652361b00ee" + integrity sha512-9phl76Cqm6FhSX9Xe1ZUAMLtm1BLkKj2Qd5ApyWkXzsMRaA7dgr81kf4wJmQf/hAvg8EEyJxDo3du/0KlhPiKQ== + dependencies: + setimmediate "^1.0.4" + +tiny-invariant@^1.0.2: + version "1.1.0" + resolved "https://registry.yarnpkg.com/tiny-invariant/-/tiny-invariant-1.1.0.tgz#634c5f8efdc27714b7f386c35e6760991d230875" + integrity sha512-ytxQvrb1cPc9WBEI/HSeYYoGD0kWnGEOR8RY6KomWLBVhqz0RgTwVO9dLrGz7dC+nN9llyI7OKAgRq8Vq4ZBSw== + +tiny-warning@^1.0.0, tiny-warning@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/tiny-warning/-/tiny-warning-1.0.3.tgz#94a30db453df4c643d0fd566060d60a875d84754" + integrity sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA== + +tmp@~0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.2.1.tgz#8457fc3037dcf4719c251367a1af6500ee1ccf14" + integrity sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ== + dependencies: + rimraf "^3.0.0" + +tmpl@1.0.x: + version "1.0.4" + resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.4.tgz#23640dd7b42d00433911140820e5cf440e521dd1" + integrity sha1-I2QN17QtAEM5ERQIIOXPRA5SHdE= + +to-arraybuffer@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz#7d229b1fcc637e466ca081180836a7aabff83f43" + integrity sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M= + +to-fast-properties@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" + integrity sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4= + +to-object-path@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/to-object-path/-/to-object-path-0.3.0.tgz#297588b7b0e7e0ac08e04e672f85c1f4999e17af" + integrity sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68= + dependencies: + kind-of "^3.0.2" + +to-regex-range@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-2.1.1.tgz#7c80c17b9dfebe599e27367e0d4dd5590141db38" + integrity sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg= + dependencies: + is-number "^3.0.0" + repeat-string "^1.6.1" + +to-regex-range@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" + integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== + dependencies: + is-number "^7.0.0" + +to-regex@^3.0.1, to-regex@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/to-regex/-/to-regex-3.0.2.tgz#13cfdd9b336552f30b51f33a8ae1b42a7a7599ce" + integrity sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw== + dependencies: + define-property "^2.0.2" + extend-shallow "^3.0.2" + regex-not "^1.0.2" + safe-regex "^1.1.0" + +tough-cookie@^2.3.3, tough-cookie@^2.5.0, tough-cookie@~2.5.0: + version "2.5.0" + resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.5.0.tgz#cd9fb2a0aa1d5a12b473bd9fb96fa3dcff65ade2" + integrity sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g== + dependencies: + psl "^1.1.28" + punycode "^2.1.1" + +tr46@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/tr46/-/tr46-1.0.1.tgz#a8b13fd6bfd2489519674ccde55ba3693b706d09" + integrity sha1-qLE/1r/SSJUZZ0zN5VujaTtwbQk= + dependencies: + punycode "^2.1.0" + +tr46@~0.0.3: + version "0.0.3" + resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" + integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw== + +trim-trailing-lines@^1.0.0: + version "1.1.3" + resolved "https://registry.yarnpkg.com/trim-trailing-lines/-/trim-trailing-lines-1.1.3.tgz#7f0739881ff76657b7776e10874128004b625a94" + integrity sha512-4ku0mmjXifQcTVfYDfR5lpgV7zVqPg6zV9rdZmwOPqq0+Zq19xDqEgagqVbc4pOOShbncuAOIs59R3+3gcF3ZA== + +trim@0.0.1, trim@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/trim/-/trim-1.0.0.tgz#fd1f30b878bdd2d8435fa0f2cc9cbb55f518be7d" + integrity sha512-UgtES1lYpE+f4WiGY5lyJlHchuGhTa/xMPH96g/B7gc+pEQPiL41s6ECm7Ky3hkhARG/u1SHGFcleJodAvQOKQ== + +trough@^1.0.0: + version "1.0.5" + resolved "https://registry.yarnpkg.com/trough/-/trough-1.0.5.tgz#b8b639cefad7d0bb2abd37d433ff8293efa5f406" + integrity sha512-rvuRbTarPXmMb79SmzEp8aqXNKcK+y0XaB298IXueQ8I2PsrATcPBCSPyK/dDNa2iWOhKlfNnOjdAOTBU/nkFA== + +ts-jest@^26.1.0: + version "26.3.0" + resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-26.3.0.tgz#6b2845045347dce394f069bb59358253bc1338a9" + integrity sha512-Jq2uKfx6bPd9+JDpZNMBJMdMQUC3sJ08acISj8NXlVgR2d5OqslEHOR2KHMgwymu8h50+lKIm0m0xj/ioYdW2Q== + dependencies: + "@types/jest" "26.x" + bs-logger "0.x" + buffer-from "1.x" + fast-json-stable-stringify "2.x" + jest-util "26.x" + json5 "2.x" + lodash.memoize "4.x" + make-error "1.x" + mkdirp "1.x" + semver "7.x" + yargs-parser "18.x" + +tsc@^1.20150623.0: + version "1.20150623.0" + resolved "https://registry.yarnpkg.com/tsc/-/tsc-1.20150623.0.tgz#4ebc3c774e169148cbc768a7342533f082c7a6e5" + integrity sha1-Trw8d04WkUjLx2inNCUz8ILHpuU= + +tslib@^1.9.0: + version "1.14.1" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" + integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== + +tty-browserify@0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.0.tgz#a157ba402da24e9bf957f9aa69d524eed42901a6" + integrity sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY= + +tunnel-agent@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" + integrity sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0= + dependencies: + safe-buffer "^5.0.1" + +tweetnacl@^0.14.3, tweetnacl@~0.14.0: + version "0.14.5" + resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" + integrity sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q= + +type-check@~0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" + integrity sha1-WITKtRLPHTVeP7eE8wgEsrUg23I= + dependencies: + prelude-ls "~1.1.2" + +typedarray-to-buffer@^3.1.5: + version "3.1.5" + resolved "https://registry.yarnpkg.com/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz#a97ee7a9ff42691b9f783ff1bc5112fe3fca9080" + integrity sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q== + dependencies: + is-typedarray "^1.0.0" + +typedarray@^0.0.6: + version "0.0.6" + resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" + integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= + +unbzip2-stream@1.4.3: + version "1.4.3" + resolved "https://registry.yarnpkg.com/unbzip2-stream/-/unbzip2-stream-1.4.3.tgz#b0da04c4371311df771cdc215e87f2130991ace7" + integrity sha512-mlExGW4w71ebDJviH16lQLtZS32VKqsSfk80GCfUlwT/4/hNRFsoscrF/c++9xinkMzECL1uL9DDwXqFWkruPg== + dependencies: + buffer "^5.2.1" + through "^2.3.8" + +unherit@^1.0.4: + version "1.1.3" + resolved "https://registry.yarnpkg.com/unherit/-/unherit-1.1.3.tgz#6c9b503f2b41b262330c80e91c8614abdaa69c22" + integrity sha512-Ft16BJcnapDKp0+J/rqFC3Rrk6Y/Ng4nzsC028k2jdDII/rdZ7Wd3pPT/6+vIIxRagwRc9K0IUX0Ra4fKvw+WQ== + dependencies: + inherits "^2.0.0" + xtend "^4.0.0" + +unified@^6.1.5: + version "6.2.0" + resolved "https://registry.yarnpkg.com/unified/-/unified-6.2.0.tgz#7fbd630f719126d67d40c644b7e3f617035f6dba" + integrity sha512-1k+KPhlVtqmG99RaTbAv/usu85fcSRu3wY8X+vnsEhIxNP5VbVIDiXnLqyKIG+UMdyTg0ZX9EI6k2AfjJkHPtA== + dependencies: + bail "^1.0.0" + extend "^3.0.0" + is-plain-obj "^1.1.0" + trough "^1.0.0" + vfile "^2.0.0" + x-is-string "^0.1.0" + +union-value@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.1.tgz#0b6fe7b835aecda61c6ea4d4f02c14221e109847" + integrity sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg== + dependencies: + arr-union "^3.1.0" + get-value "^2.0.6" + is-extendable "^0.1.1" + set-value "^2.0.1" + +unique-filename@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/unique-filename/-/unique-filename-1.1.1.tgz#1d69769369ada0583103a1e6ae87681b56573230" + integrity sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ== + dependencies: + unique-slug "^2.0.0" + +unique-slug@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/unique-slug/-/unique-slug-2.0.2.tgz#baabce91083fc64e945b0f3ad613e264f7cd4e6c" + integrity sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w== + dependencies: + imurmurhash "^0.1.4" + +unist-util-is@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/unist-util-is/-/unist-util-is-3.0.0.tgz#d9e84381c2468e82629e4a5be9d7d05a2dd324cd" + integrity sha512-sVZZX3+kspVNmLWBPAB6r+7D9ZgAFPNWm66f7YNb420RlQSbn+n8rG8dGZSkrER7ZIXGQYNm5pqC3v3HopH24A== + +unist-util-remove-position@^1.0.0: + version "1.1.4" + resolved "https://registry.yarnpkg.com/unist-util-remove-position/-/unist-util-remove-position-1.1.4.tgz#ec037348b6102c897703eee6d0294ca4755a2020" + integrity sha512-tLqd653ArxJIPnKII6LMZwH+mb5q+n/GtXQZo6S6csPRs5zB0u79Yw8ouR3wTw8wxvdJFhpP6Y7jorWdCgLO0A== + dependencies: + unist-util-visit "^1.1.0" + +unist-util-stringify-position@^1.0.0, unist-util-stringify-position@^1.1.1: + version "1.1.2" + resolved "https://registry.yarnpkg.com/unist-util-stringify-position/-/unist-util-stringify-position-1.1.2.tgz#3f37fcf351279dcbca7480ab5889bb8a832ee1c6" + integrity sha512-pNCVrk64LZv1kElr0N1wPiHEUoXNVFERp+mlTg/s9R5Lwg87f9bM/3sQB99w+N9D/qnM9ar3+AKDBwo/gm/iQQ== + +unist-util-visit-parents@1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/unist-util-visit-parents/-/unist-util-visit-parents-1.1.2.tgz#f6e3afee8bdbf961c0e6f028ea3c0480028c3d06" + integrity sha512-yvo+MMLjEwdc3RhhPYSximset7rwjMrdt9E41Smmvg25UQIenzrN83cRnF1JMzoMi9zZOQeYXHSDf7p+IQkW3Q== + +unist-util-visit-parents@^2.0.0: + version "2.1.2" + resolved "https://registry.yarnpkg.com/unist-util-visit-parents/-/unist-util-visit-parents-2.1.2.tgz#25e43e55312166f3348cae6743588781d112c1e9" + integrity sha512-DyN5vD4NE3aSeB+PXYNKxzGsfocxp6asDc2XXE3b0ekO2BaRUpBicbbUygfSvYfUz1IkmjFR1YF7dPklraMZ2g== + dependencies: + unist-util-is "^3.0.0" + +unist-util-visit@^1.1.0, unist-util-visit@^1.3.0: + version "1.4.1" + resolved "https://registry.yarnpkg.com/unist-util-visit/-/unist-util-visit-1.4.1.tgz#4724aaa8486e6ee6e26d7ff3c8685960d560b1e3" + integrity sha512-AvGNk7Bb//EmJZyhtRUnNMEpId/AZ5Ph/KUpTI09WHQuDZHKovQ1oEv3mfmKpWKtoMzyMC4GLBm1Zy5k12fjIw== + dependencies: + unist-util-visit-parents "^2.0.0" + +universalify@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.0.tgz#75a4984efedc4b08975c5aeb73f530d02df25717" + integrity sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ== + +unset-value@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/unset-value/-/unset-value-1.0.0.tgz#8376873f7d2335179ffb1e6fc3a8ed0dfc8ab559" + integrity sha1-g3aHP30jNRef+x5vw6jtDfyKtVk= + dependencies: + has-value "^0.3.1" + isobject "^3.0.0" + +untildify@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/untildify/-/untildify-4.0.0.tgz#2bc947b953652487e4600949fb091e3ae8cd919b" + integrity sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw== + +upath@^1.1.1: + version "1.2.0" + resolved "https://registry.yarnpkg.com/upath/-/upath-1.2.0.tgz#8f66dbcd55a883acdae4408af8b035a5044c1894" + integrity sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg== + +uri-js@^4.2.2: + version "4.4.0" + resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.0.tgz#aa714261de793e8a82347a7bcc9ce74e86f28602" + integrity sha512-B0yRTzYdUCCn9n+F4+Gh4yIDtMQcaJsmYBDsTSG8g/OejKBodLQ2IHfN3bM7jUsRXndopT7OIXWdYqc1fjmV6g== + dependencies: + punycode "^2.1.0" + +urix@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72" + integrity sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI= + +url@^0.11.0: + version "0.11.0" + resolved "https://registry.yarnpkg.com/url/-/url-0.11.0.tgz#3838e97cfc60521eb73c525a8e55bfdd9e2e28f1" + integrity sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE= + dependencies: + punycode "1.3.2" + querystring "0.2.0" + +use@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f" + integrity sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ== + +util-deprecate@^1.0.1, util-deprecate@~1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= + +util@0.10.3: + version "0.10.3" + resolved "https://registry.yarnpkg.com/util/-/util-0.10.3.tgz#7afb1afe50805246489e3db7fe0ed379336ac0f9" + integrity sha1-evsa/lCAUkZInj23/g7TeTNqwPk= + dependencies: + inherits "2.0.1" + +util@^0.11.0: + version "0.11.1" + resolved "https://registry.yarnpkg.com/util/-/util-0.11.1.tgz#3236733720ec64bb27f6e26f421aaa2e1b588d61" + integrity sha512-HShAsny+zS2TZfaXxD9tYj4HQGlBezXZMZuM/S5PKLLoZkShZiGk9o5CzukI1LVHZvjdvZ2Sj1aW/Ndn2NB/HQ== + dependencies: + inherits "2.0.3" + +utrie@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/utrie/-/utrie-1.0.2.tgz#d42fe44de9bc0119c25de7f564a6ed1b2c87a645" + integrity sha512-1MLa5ouZiOmQzUbjbu9VmjLzn1QLXBhwpUa7kdLUQK+KQ5KA9I1vk5U4YHe/X2Ch7PYnJfWuWT+VbuxbGwljhw== + dependencies: + base64-arraybuffer "^1.0.2" + +uuid@^3.3.2: + version "3.4.0" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee" + integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A== + +value-equal@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/value-equal/-/value-equal-1.0.1.tgz#1e0b794c734c5c0cade179c437d356d931a34d6c" + integrity sha512-NOJ6JZCAWr0zlxZt+xqCHNTEKOsrks2HQd4MqhP1qy4z1SkbEP467eNx6TgDKXMvUOb+OENfJCZwM+16n7fRfw== + +verror@1.10.0: + version "1.10.0" + resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400" + integrity sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA= + dependencies: + assert-plus "^1.0.0" + core-util-is "1.0.2" + extsprintf "^1.2.0" + +vfile-location@^2.0.0: + version "2.0.6" + resolved "https://registry.yarnpkg.com/vfile-location/-/vfile-location-2.0.6.tgz#8a274f39411b8719ea5728802e10d9e0dff1519e" + integrity sha512-sSFdyCP3G6Ka0CEmN83A2YCMKIieHx0EDaj5IDP4g1pa5ZJ4FJDvpO0WODLxo4LUX4oe52gmSCK7Jw4SBghqxA== + +vfile-message@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/vfile-message/-/vfile-message-1.1.1.tgz#5833ae078a1dfa2d96e9647886cd32993ab313e1" + integrity sha512-1WmsopSGhWt5laNir+633LszXvZ+Z/lxveBf6yhGsqnQIhlhzooZae7zV6YVM1Sdkw68dtAW3ow0pOdPANugvA== + dependencies: + unist-util-stringify-position "^1.1.1" + +vfile@^2.0.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/vfile/-/vfile-2.3.0.tgz#e62d8e72b20e83c324bc6c67278ee272488bf84a" + integrity sha512-ASt4mBUHcTpMKD/l5Q+WJXNtshlWxOogYyGYYrg4lt/vuRjC1EFQtlAofL5VmtVNIZJzWYFJjzGWZ0Gw8pzW1w== + dependencies: + is-buffer "^1.1.4" + replace-ext "1.0.0" + unist-util-stringify-position "^1.0.0" + vfile-message "^1.0.0" + +vm-browserify@^1.0.1: + version "1.1.2" + resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-1.1.2.tgz#78641c488b8e6ca91a75f511e7a3b32a86e5dda0" + integrity sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ== + +w3c-hr-time@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz#0a89cdf5cc15822df9c360543676963e0cc308cd" + integrity sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ== + dependencies: + browser-process-hrtime "^1.0.0" + +w3c-xmlserializer@^1.0.1: + version "1.1.2" + resolved "https://registry.yarnpkg.com/w3c-xmlserializer/-/w3c-xmlserializer-1.1.2.tgz#30485ca7d70a6fd052420a3d12fd90e6339ce794" + integrity sha512-p10l/ayESzrBMYWRID6xbuCKh2Fp77+sA0doRuGn4tTIMrrZVeqfpKjXHY+oDh3K4nLdPgNwMTVP6Vp4pvqbNg== + dependencies: + domexception "^1.0.1" + webidl-conversions "^4.0.2" + xml-name-validator "^3.0.0" + +walker@^1.0.7, walker@~1.0.5: + version "1.0.7" + resolved "https://registry.yarnpkg.com/walker/-/walker-1.0.7.tgz#2f7f9b8fd10d677262b18a884e28d19618e028fb" + integrity sha1-L3+bj9ENZ3JisYqITijRlhjgKPs= + dependencies: + makeerror "1.0.x" + +watchpack-chokidar2@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/watchpack-chokidar2/-/watchpack-chokidar2-2.0.1.tgz#38500072ee6ece66f3769936950ea1771be1c957" + integrity sha512-nCFfBIPKr5Sh61s4LPpy1Wtfi0HE8isJ3d2Yb5/Ppw2P2B/3eVSEBjKfN0fmHJSK14+31KwMKmcrzs2GM4P0Ww== + dependencies: + chokidar "^2.1.8" + +watchpack@^1.7.4: + version "1.7.5" + resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-1.7.5.tgz#1267e6c55e0b9b5be44c2023aed5437a2c26c453" + integrity sha512-9P3MWk6SrKjHsGkLT2KHXdQ/9SNkyoJbabxnKOoJepsvJjJG8uYTR3yTPxPQvNDI3w4Nz1xnE0TLHK4RIVe/MQ== + dependencies: + graceful-fs "^4.1.2" + neo-async "^2.5.0" + optionalDependencies: + chokidar "^3.4.1" + watchpack-chokidar2 "^2.0.1" + +webidl-conversions@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" + integrity sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ== + +webidl-conversions@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-4.0.2.tgz#a855980b1f0b6b359ba1d5d9fb39ae941faa63ad" + integrity sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg== + +webpack-sources@^1.4.0, webpack-sources@^1.4.1: + version "1.4.3" + resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-1.4.3.tgz#eedd8ec0b928fbf1cbfe994e22d2d890f330a933" + integrity sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ== + dependencies: + source-list-map "^2.0.0" + source-map "~0.6.1" + +webpack@^4.41.5: + version "4.44.2" + resolved "https://registry.yarnpkg.com/webpack/-/webpack-4.44.2.tgz#6bfe2b0af055c8b2d1e90ed2cd9363f841266b72" + integrity sha512-6KJVGlCxYdISyurpQ0IPTklv+DULv05rs2hseIXer6D7KrUicRDLFb4IUM1S6LUAKypPM/nSiVSuv8jHu1m3/Q== + 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.3.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" + +whatwg-encoding@^1.0.1, whatwg-encoding@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz#5abacf777c32166a51d085d6b4f3e7d27113ddb0" + integrity sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw== + dependencies: + iconv-lite "0.4.24" + +whatwg-mimetype@^2.2.0, whatwg-mimetype@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz#3d4b1e0312d2079879f826aff18dbeeca5960fbf" + integrity sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g== + +whatwg-url@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d" + integrity sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw== + dependencies: + tr46 "~0.0.3" + webidl-conversions "^3.0.0" + +whatwg-url@^7.0.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-7.1.0.tgz#c2c492f1eca612988efd3d2266be1b9fc6170d06" + integrity sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg== + dependencies: + lodash.sortby "^4.7.0" + tr46 "^1.0.1" + webidl-conversions "^4.0.2" + +which@^1.2.9: + version "1.3.1" + resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" + integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== + dependencies: + isexe "^2.0.0" + +which@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" + integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== + dependencies: + isexe "^2.0.0" + +word-wrap@~1.2.3: + version "1.2.3" + resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c" + integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ== + +worker-farm@^1.7.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/worker-farm/-/worker-farm-1.7.0.tgz#26a94c5391bbca926152002f69b84a4bf772e5a8" + integrity sha512-rvw3QTZc8lAxyVrqcSGVm5yP/IJ2UcB3U0graE3LCFoZ0Yn2x4EoVSqJKdB/T5M+FLcRPjz4TDacRf3OCfNUzw== + dependencies: + errno "~0.1.7" + +wrap-ansi@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-3.0.1.tgz#288a04d87eda5c286e060dfe8f135ce8d007f8ba" + integrity sha1-KIoE2H7aXChuBg3+jxNc6NAH+Lo= + dependencies: + string-width "^2.1.1" + strip-ansi "^4.0.0" + +wrap-ansi@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= + +write-file-atomic@^3.0.0: + version "3.0.3" + resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-3.0.3.tgz#56bd5c5a5c70481cd19c571bd39ab965a5de56e8" + integrity sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q== + dependencies: + imurmurhash "^0.1.4" + is-typedarray "^1.0.0" + signal-exit "^3.0.2" + typedarray-to-buffer "^3.1.5" + +ws@^6.1.2: + version "6.2.1" + resolved "https://registry.yarnpkg.com/ws/-/ws-6.2.1.tgz#442fdf0a47ed64f59b6a5d8ff130f4748ed524fb" + integrity sha512-GIyAXC2cB7LjvpgMt9EKS2ldqr0MTrORaleiOno6TweZ6r3TKtoFQWay/2PceJ3RuBasOHzXNn5Lrw1X0bEjqA== + dependencies: + async-limiter "~1.0.0" + +ws@^7.2.3: + version "7.3.1" + resolved "https://registry.yarnpkg.com/ws/-/ws-7.3.1.tgz#d0547bf67f7ce4f12a72dfe31262c68d7dc551c8" + integrity sha512-D3RuNkynyHmEJIpD2qrgVkc9DQ23OrN/moAwZX4L8DfvszsJxpjQuUq3LMx6HoYji9fbIOBY18XWBsAux1ZZUA== + +x-is-string@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/x-is-string/-/x-is-string-0.1.0.tgz#474b50865af3a49a9c4657f05acd145458f77d82" + integrity sha1-R0tQhlrzpJqcRlfwWs0UVFj3fYI= + +xml-name-validator@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-3.0.0.tgz#6ae73e06de4d8c6e47f9fb181f78d648ad457c6a" + integrity sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw== + +xmlchars@^2.1.1: + version "2.2.0" + resolved "https://registry.yarnpkg.com/xmlchars/-/xmlchars-2.2.0.tgz#060fe1bcb7f9c76fe2a17db86a9bc3ab894210cb" + integrity sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw== + +xtend@^4.0.0, xtend@^4.0.1, xtend@~4.0.1: + version "4.0.2" + resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" + integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== + +y18n@^4.0.0, y18n@^5.0.5: + version "5.0.5" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.5.tgz#8769ec08d03b1ea2df2500acef561743bbb9ab18" + integrity sha512-hsRUr4FFrvhhRH12wOdfs38Gy7k2FFzB9qgN9v3aLykRq0dRcdcpz5C9FxdS2NuhOrI/628b/KSTJ3rwHysYSg== + +yallist@^2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52" + integrity sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI= + +yallist@^3.0.2: + version "3.1.1" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" + integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== + +yaml@^1.7.2: + version "1.10.0" + resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.0.tgz#3b593add944876077d4d683fee01081bd9fff31e" + integrity sha512-yr2icI4glYaNG+KWONODapy2/jDdMSDnrONSjblABjD9B4Z5LgiircSt8m8sRZFNi08kG9Sm0uSHtEmP3zaEGg== + +yargs-parser@18.x: + version "18.1.3" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-18.1.3.tgz#be68c4975c6b2abf469236b0c870362fab09a7b0" + integrity sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ== + dependencies: + camelcase "^5.0.0" + decamelize "^1.2.0" + +yargs-parser@^20.2.2: + version "20.2.9" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee" + integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w== + +yargs@16.2.0, yargs@^14.2, yargs@^15.3.1, yargs@^17.2.1: + version "16.2.0" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-16.2.0.tgz#1c82bf0f6b6a66eafce7ef30e376f49a12477f66" + integrity sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw== + 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" + +yauzl@^2.10.0: + version "2.10.0" + resolved "https://registry.yarnpkg.com/yauzl/-/yauzl-2.10.0.tgz#c7eb17c93e112cb1086fa6d8e51fb0667b79a5f9" + integrity sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk= + dependencies: + buffer-crc32 "~0.2.3" + fd-slicer "~1.1.0"