From e7808cfb0322c1adcf61e7955b8b4a8c2badd0d2 Mon Sep 17 00:00:00 2001 From: Andrey Zhavoronkov <41117609+azhavoro@users.noreply.github.com> Date: Sat, 28 Mar 2020 06:57:56 +0300 Subject: [PATCH] Data streaming using chunks (#1007) Huge feature (200+ commits from different developers). It completely changes layout of data (please expect very long DB migration process if you have a lot of tasks). The primary idea is to send data as zip chunks (e.g. 36 images in one chunk) or encoded video chunks and decode them on the client side. It helps to solve the problem with latency when you try to view a separate frame in the UI quickly (play mode). Another important feature of the patch is to provide access to the original images. Thus for annotations the client uses compressed chunks but if you want to export a dataset Datumaro will use original chunks (but video will be decoded with original quality and encoded with maximum/optimal quality in any case). --- .codacy.yml | 1 + .travis.yml | 2 +- CONTRIBUTING.md | 90 +- Dockerfile | 13 +- Dockerfile.ui | 7 + cvat-canvas/package-lock.json | 401 +- cvat-canvas/package.json | 7 +- cvat-canvas/src/typescript/canvasModel.ts | 14 +- cvat-canvas/src/typescript/canvasView.ts | 23 +- cvat-canvas/webpack.config.js | 18 +- cvat-core/src/download.worker.js | 33 + cvat-core/src/frames.js | 554 +- cvat-core/src/server-proxy.js | 95 +- cvat-core/src/session.js | 144 +- cvat-core/tests/mocks/dummy-data.mock.js | 193 +- cvat-core/webpack.config.js | 24 +- cvat-data/.eslintignore | 1 + cvat-data/.eslintrc.js | 56 + cvat-data/.gitignore | 1 + cvat-data/README.md | 7 + cvat-data/package-lock.json | 8109 +++++++++++++++++ cvat-data/package.json | 34 + cvat-data/src/js/3rdparty/Decoder.js | 888 ++ cvat-data/src/js/3rdparty/Decoder.worker.js | 888 ++ cvat-data/src/js/3rdparty/README.md | 88 + cvat-data/src/js/3rdparty/avc.wasm | Bin 0 -> 126815 bytes cvat-data/src/js/3rdparty/mp4.js | 977 ++ cvat-data/src/js/3rdparty_patch.diff | 162 + cvat-data/src/js/cvat-data.js | 350 + cvat-data/src/js/unzip_imgs.worker.js | 35 + cvat-data/webpack.config.js | 64 + cvat-ui/package-lock.json | 162 +- cvat-ui/package.json | 4 +- cvat-ui/src/actions/annotation-actions.ts | 33 +- cvat-ui/src/actions/tasks-actions.ts | 4 + .../standard-workspace/canvas-wrapper.tsx | 11 + .../components/annotation-page/styles.scss | 1 + .../top-bar/player-navigation.tsx | 6 +- .../annotation-page/top-bar/top-bar.tsx | 3 + .../advanced-configuration-form.tsx | 160 +- .../create-task-page/create-task-content.tsx | 5 +- cvat-ui/src/components/task-page/details.tsx | 30 +- cvat-ui/src/components/task-page/styles.scss | 13 +- .../standard-workspace/canvas-wrapper.tsx | 3 + .../annotation-page/top-bar/top-bar.tsx | 16 +- cvat-ui/src/reducers/annotation-reducer.ts | 8 +- cvat-ui/src/reducers/interfaces.ts | 1 + cvat-ui/webpack.config.js | 28 +- cvat/apps/annotation/annotation.py | 55 +- cvat/apps/annotation/format.py | 2 - cvat/apps/auto_annotation/image_loader.py | 18 +- cvat/apps/auto_annotation/model_manager.py | 17 +- cvat/apps/auto_segmentation/views.py | 36 +- cvat/apps/dataset_manager/bindings.py | 52 +- .../plugins/cvat_rest_api_task_images.py | 3 +- cvat/apps/dataset_manager/task.py | 22 +- cvat/apps/engine/admin.py | 2 +- cvat/apps/engine/annotation.py | 2 +- cvat/apps/engine/data_manager.py | 4 + cvat/apps/engine/frame_provider.py | 149 + cvat/apps/engine/media_extractors.py | 499 +- .../migrations/0020_remove_task_flipped.py | 45 +- .../migrations/0024_auto_20191023_1025.py | 461 + .../migrations/0025_auto_20200324_1222.py | 18 + cvat/apps/engine/mime_types.py | 13 + cvat/apps/engine/models.py | 180 +- cvat/apps/engine/serializers.py | 165 +- .../engine/js/3rdparty/Decoder.worker.js | 2 + .../engine/static/engine/js/3rdparty/avc.wasm | Bin 0 -> 126815 bytes .../static/engine/js/annotationSaver.js | 10 +- .../engine/static/engine/js/annotationUI.js | 19 +- .../engine/static/engine/js/cvat-core.min.js | 6 +- .../static/engine/js/download.worker.js | 9 + cvat/apps/engine/static/engine/js/logger.js | 3 + cvat/apps/engine/static/engine/js/player.js | 474 +- .../engine/static/engine/js/shapeBuffer.js | 8 +- .../static/engine/js/unzip_imgs.worker.js | 9 + cvat/apps/engine/static/engine/stylesheet.css | 7 + cvat/apps/engine/task.py | 208 +- .../engine/templates/engine/annotation.html | 2 + cvat/apps/engine/tests/test_model.py | 25 - cvat/apps/engine/tests/test_rest_api.py | 453 +- cvat/apps/engine/views.py | 148 +- cvat/apps/reid/reid.py | 24 +- cvat/apps/tf_annotation/views.py | 28 +- cvat/requirements/base.txt | 2 +- cvat/settings/base.py | 46 +- cvat/settings/testing.py | 11 + datumaro/datumaro/util/tf_util.py | 2 +- utils/cli/core/core.py | 26 +- utils/cli/core/definition.py | 9 +- utils/cli/tests/test_cli.py | 10 +- 92 files changed, 15719 insertions(+), 1332 deletions(-) create mode 100644 cvat-core/src/download.worker.js create mode 100644 cvat-data/.eslintignore create mode 100644 cvat-data/.eslintrc.js create mode 100644 cvat-data/.gitignore create mode 100644 cvat-data/README.md create mode 100644 cvat-data/package-lock.json create mode 100644 cvat-data/package.json create mode 100644 cvat-data/src/js/3rdparty/Decoder.js create mode 100644 cvat-data/src/js/3rdparty/Decoder.worker.js create mode 100644 cvat-data/src/js/3rdparty/README.md create mode 100644 cvat-data/src/js/3rdparty/avc.wasm create mode 100644 cvat-data/src/js/3rdparty/mp4.js create mode 100644 cvat-data/src/js/3rdparty_patch.diff create mode 100644 cvat-data/src/js/cvat-data.js create mode 100644 cvat-data/src/js/unzip_imgs.worker.js create mode 100644 cvat-data/webpack.config.js create mode 100644 cvat/apps/engine/frame_provider.py create mode 100644 cvat/apps/engine/migrations/0024_auto_20191023_1025.py create mode 100644 cvat/apps/engine/migrations/0025_auto_20200324_1222.py create mode 100644 cvat/apps/engine/mime_types.py create mode 100644 cvat/apps/engine/static/engine/js/3rdparty/Decoder.worker.js create mode 100644 cvat/apps/engine/static/engine/js/3rdparty/avc.wasm create mode 100644 cvat/apps/engine/static/engine/js/download.worker.js create mode 100644 cvat/apps/engine/static/engine/js/unzip_imgs.worker.js delete mode 100644 cvat/apps/engine/tests/test_model.py diff --git a/.codacy.yml b/.codacy.yml index 55fc0679..7e85c730 100644 --- a/.codacy.yml +++ b/.codacy.yml @@ -1,4 +1,5 @@ exclude_paths: - '**/3rdparty/**' - '**/engine/js/cvat-core.min.js' + - '**/engine/js/unzip_imgs.js' - CHANGELOG.md diff --git a/.travis.yml b/.travis.yml index 8cbae296..fd76331d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,4 +14,4 @@ before_script: script: - docker-compose -f docker-compose.yml -f docker-compose.ci.yml run cvat_ci /bin/bash -c 'python3 manage.py test cvat/apps utils/cli' - docker-compose -f docker-compose.yml -f docker-compose.ci.yml run cvat_ci /bin/bash -c 'python3 manage.py test datumaro/' - - docker-compose -f docker-compose.yml -f docker-compose.ci.yml run cvat_ci /bin/bash -c 'cd cvat-core && npm install && npm run test && npm run coveralls' + - docker-compose -f docker-compose.yml -f docker-compose.ci.yml run cvat_ci /bin/bash -c 'cd cvat-data && npm install && cd ../cvat-core && npm install && npm run test && npm run coveralls' diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 40faceb7..01a2539c 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -12,52 +12,60 @@ patches and features. Next steps should work on clear Ubuntu 18.04. -- Install necessary dependencies: - -```sh -$ sudo apt-get update && sudo apt-get --no-install-recommends install -y ffmpeg build-essential nodejs npm curl redis-server python3-dev python3-pip python3-venv libldap2-dev libsasl2-dev -``` +- Install necessary dependencies: + ```sh + $ sudo apt-get update && sudo apt-get --no-install-recommends install -y ffmpeg build-essential nodejs npm curl redis-server python3-dev python3-pip python3-venv libldap2-dev libsasl2-dev + ``` + Also please make sure that you have installed ffmpeg with all necessary libav* libraries and pkg-config package. + ```sh + # General dependencies + sudo apt-get install -y pkg-config + + # Library components + sudo apt-get install -y \ + libavformat-dev libavcodec-dev libavdevice-dev \ + libavutil-dev libswscale-dev libswresample-dev libavfilter-dev + ``` + See [PyAV Dependencies installation guide](http://docs.mikeboers.com/pyav/develop/overview/installation.html#dependencies) + for details. - Install [Visual Studio Code](https://code.visualstudio.com/docs/setup/linux#_debian-and-ubuntu-based-distributions) for development - Install CVAT on your local host: - -```sh -git clone https://github.com/opencv/cvat -cd cvat && mkdir logs keys -python3 -m venv .env -. .env/bin/activate -pip install -U pip wheel setuptools -pip install -r cvat/requirements/development.txt -pip install -r datumaro/requirements.txt -python manage.py migrate -python manage.py collectstatic -``` - -- Create a super user for CVAT: - -```sh -$ python manage.py createsuperuser -Username (leave blank to use 'django'): *** -Email address: *** -Password: *** -Password (again): *** -``` - -- Install npm packages for UI and start UI debug server (run the following command from CVAT root directory): -```sh -npm install && \ -cd cvat-core && npm install && \ -cd ../cvat-canvas && npm install && \ -cd ../cvat-ui && npm install && npm start -``` - -- Open new terminal (Ctrl + Shift + T), run Visual Studio Code from the virtual environment - -```sh - cd .. && source .env/bin/activate && code -``` + ```sh + git clone https://github.com/opencv/cvat + cd cvat && mkdir logs keys + python3 -m venv .env + . .env/bin/activate + pip install -U pip wheel setuptools + pip install -r cvat/requirements/development.txt + pip install -r datumaro/requirements.txt + python manage.py migrate + python manage.py collectstatic + ``` + +- Create a super user for CVAT: + ```sh + $ python manage.py createsuperuser + Username (leave blank to use 'django'): *** + Email address: *** + Password: *** + Password (again): *** + ``` + +- Install npm packages for UI and start UI debug server (run the following command from CVAT root directory): + ```sh + cd cvat-core && npm install && \ + cd ../cvat-canvas && npm install && \ + cd ../cvat-data && npm install && \ + cd ../cvat-ui && npm install && npm start + ``` + +- Open new terminal (Ctrl + Shift + T), run Visual Studio Code from the virtual environment + ```sh + cd .. && source .env/bin/activate && code + ``` - Install followig vscode extensions: - [Debugger for Chrome](https://marketplace.visualstudio.com/items?itemName=msjsdiag.debugger-for-chrome) diff --git a/Dockerfile b/Dockerfile index 54c8bed1..54a08c4d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -35,8 +35,17 @@ RUN apt-get update && \ supervisor \ ffmpeg \ gstreamer0.10-ffmpeg \ + libavcodec-dev \ + libavdevice-dev \ + libavfilter-dev \ + libavformat-dev \ + libavutil-dev \ + libldap2-dev \ + libswresample-dev \ + libswscale-dev \ libldap2-dev \ libsasl2-dev \ + pkg-config \ python3-dev \ python3-pip \ tzdata \ @@ -57,7 +66,8 @@ RUN apt-get update && \ dpkg-reconfigure -f noninteractive tzdata && \ add-apt-repository --remove ppa:mc3man/gstffmpeg-keep -y && \ add-apt-repository --remove ppa:mc3man/xerus-media -y && \ - rm -rf /var/lib/apt/lists/* + rm -rf /var/lib/apt/lists/* && \ + echo 'application/wasm wasm' >> /etc/mime.types # Add a non-root user ENV USER=${USER} @@ -123,6 +133,7 @@ COPY ssh ${HOME}/.ssh COPY utils ${HOME}/utils COPY cvat/ ${HOME}/cvat COPY cvat-core/ ${HOME}/cvat-core +COPY cvat-data/ ${HOME}/cvat-data COPY tests ${HOME}/tests COPY datumaro/ ${HOME}/datumaro diff --git a/Dockerfile.ui b/Dockerfile.ui index 8586f2b2..80fe3c7f 100644 --- a/Dockerfile.ui +++ b/Dockerfile.ui @@ -17,6 +17,11 @@ ENV TERM=xterm \ COPY cvat-core/package*.json /tmp/cvat-core/ COPY cvat-canvas/package*.json /tmp/cvat-canvas/ COPY cvat-ui/package*.json /tmp/cvat-ui/ +COPY cvat-data/package*.json /tmp/cvat-data/ + +# Install cvat-data dependencies +WORKDIR /tmp/cvat-data/ +RUN npm install # Install cvat-core dependencies WORKDIR /tmp/cvat-core/ @@ -31,6 +36,7 @@ WORKDIR /tmp/cvat-ui/ RUN npm install # Build source code +COPY cvat-data/ /tmp/cvat-data/ COPY cvat-core/ /tmp/cvat-core/ COPY cvat-canvas/ /tmp/cvat-canvas/ COPY cvat-ui/ /tmp/cvat-ui/ @@ -38,5 +44,6 @@ RUN npm run build FROM nginx:stable-alpine # Replace default.conf configuration to remove unnecessary rules +RUN sed -i "s/}/application\/wasm wasm;\n}/g" /etc/nginx/mime.types COPY cvat-ui/react_nginx.conf /etc/nginx/conf.d/default.conf COPY --from=cvat-ui /tmp/cvat-ui/dist /usr/share/nginx/html/ diff --git a/cvat-canvas/package-lock.json b/cvat-canvas/package-lock.json index 022e4582..221e18b0 100644 --- a/cvat-canvas/package-lock.json +++ b/cvat-canvas/package-lock.json @@ -337,6 +337,189 @@ "@babel/plugin-syntax-async-generators": "^7.2.0" } }, + "@babel/plugin-proposal-class-properties": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.8.3.tgz", + "integrity": "sha512-EqFhbo7IosdgPgZggHaNObkmO1kNUe3slaKu54d5OWvy+p9QIKOzK1GAEpAIsZtWVtPXUHSMcT4smvDrCfY4AA==", + "dev": true, + "requires": { + "@babel/helper-create-class-features-plugin": "^7.8.3", + "@babel/helper-plugin-utils": "^7.8.3" + }, + "dependencies": { + "@babel/code-frame": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.8.3.tgz", + "integrity": "sha512-a9gxpmdXtZEInkCSHUJDLHZVBgb1QS0jhss4cPP93EW7s+uC5bikET2twEF3KV+7rDblJcmNvTR7VJejqd2C2g==", + "dev": true, + "requires": { + "@babel/highlight": "^7.8.3" + } + }, + "@babel/generator": { + "version": "7.8.7", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.8.7.tgz", + "integrity": "sha512-DQwjiKJqH4C3qGiyQCAExJHoZssn49JTMJgZ8SANGgVFdkupcUhLOdkAeoC6kmHZCPfoDG5M0b6cFlSN5wW7Ew==", + "dev": true, + "requires": { + "@babel/types": "^7.8.7", + "jsesc": "^2.5.1", + "lodash": "^4.17.13", + "source-map": "^0.5.0" + } + }, + "@babel/helper-create-class-features-plugin": { + "version": "7.8.6", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.8.6.tgz", + "integrity": "sha512-klTBDdsr+VFFqaDHm5rR69OpEQtO2Qv8ECxHS1mNhJJvaHArR6a1xTf5K/eZW7eZpJbhCx3NW1Yt/sKsLXLblg==", + "dev": true, + "requires": { + "@babel/helper-function-name": "^7.8.3", + "@babel/helper-member-expression-to-functions": "^7.8.3", + "@babel/helper-optimise-call-expression": "^7.8.3", + "@babel/helper-plugin-utils": "^7.8.3", + "@babel/helper-replace-supers": "^7.8.6", + "@babel/helper-split-export-declaration": "^7.8.3" + } + }, + "@babel/helper-function-name": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.8.3.tgz", + "integrity": "sha512-BCxgX1BC2hD/oBlIFUgOCQDOPV8nSINxCwM3o93xP4P9Fq6aV5sgv2cOOITDMtCfQ+3PvHp3l689XZvAM9QyOA==", + "dev": true, + "requires": { + "@babel/helper-get-function-arity": "^7.8.3", + "@babel/template": "^7.8.3", + "@babel/types": "^7.8.3" + } + }, + "@babel/helper-get-function-arity": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.8.3.tgz", + "integrity": "sha512-FVDR+Gd9iLjUMY1fzE2SR0IuaJToR4RkCDARVfsBBPSP53GEqSFjD8gNyxg246VUyc/ALRxFaAK8rVG7UT7xRA==", + "dev": true, + "requires": { + "@babel/types": "^7.8.3" + } + }, + "@babel/helper-member-expression-to-functions": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.8.3.tgz", + "integrity": "sha512-fO4Egq88utkQFjbPrSHGmGLFqmrshs11d46WI+WZDESt7Wu7wN2G2Iu+NMMZJFDOVRHAMIkB5SNh30NtwCA7RA==", + "dev": true, + "requires": { + "@babel/types": "^7.8.3" + } + }, + "@babel/helper-optimise-call-expression": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.8.3.tgz", + "integrity": "sha512-Kag20n86cbO2AvHca6EJsvqAd82gc6VMGule4HwebwMlwkpXuVqrNRj6CkCV2sKxgi9MyAUnZVnZ6lJ1/vKhHQ==", + "dev": true, + "requires": { + "@babel/types": "^7.8.3" + } + }, + "@babel/helper-plugin-utils": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.8.3.tgz", + "integrity": "sha512-j+fq49Xds2smCUNYmEHF9kGNkhbet6yVIBp4e6oeQpH1RUs/Ir06xUKzDjDkGcaaokPiTNs2JBWHjaE4csUkZQ==", + "dev": true + }, + "@babel/helper-replace-supers": { + "version": "7.8.6", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.8.6.tgz", + "integrity": "sha512-PeMArdA4Sv/Wf4zXwBKPqVj7n9UF/xg6slNRtZW84FM7JpE1CbG8B612FyM4cxrf4fMAMGO0kR7voy1ForHHFA==", + "dev": true, + "requires": { + "@babel/helper-member-expression-to-functions": "^7.8.3", + "@babel/helper-optimise-call-expression": "^7.8.3", + "@babel/traverse": "^7.8.6", + "@babel/types": "^7.8.6" + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.8.3.tgz", + "integrity": "sha512-3x3yOeyBhW851hroze7ElzdkeRXQYQbFIb7gLK1WQYsw2GWDay5gAJNw1sWJ0VFP6z5J1whqeXH/WCdCjZv6dA==", + "dev": true, + "requires": { + "@babel/types": "^7.8.3" + } + }, + "@babel/highlight": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.8.3.tgz", + "integrity": "sha512-PX4y5xQUvy0fnEVHrYOarRPXVWafSjTW9T0Hab8gVIawpl2Sj0ORyrygANq+KjcNlSSTw0YCLSNA8OyZ1I4yEg==", + "dev": true, + "requires": { + "chalk": "^2.0.0", + "esutils": "^2.0.2", + "js-tokens": "^4.0.0" + } + }, + "@babel/parser": { + "version": "7.8.7", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.8.7.tgz", + "integrity": "sha512-9JWls8WilDXFGxs0phaXAZgpxTZhSk/yOYH2hTHC0X1yC7Z78IJfvR1vJ+rmJKq3I35td2XzXzN6ZLYlna+r/A==", + "dev": true + }, + "@babel/template": { + "version": "7.8.6", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.8.6.tgz", + "integrity": "sha512-zbMsPMy/v0PWFZEhQJ66bqjhH+z0JgMoBWuikXybgG3Gkd/3t5oQ1Rw2WQhnSrsOmsKXnZOx15tkC4qON/+JPg==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.8.3", + "@babel/parser": "^7.8.6", + "@babel/types": "^7.8.6" + } + }, + "@babel/traverse": { + "version": "7.8.6", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.8.6.tgz", + "integrity": "sha512-2B8l0db/DPi8iinITKuo7cbPznLCEk0kCxDoB9/N6gGNg/gxOXiR/IcymAFPiBwk5w6TtQ27w4wpElgp9btR9A==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.8.3", + "@babel/generator": "^7.8.6", + "@babel/helper-function-name": "^7.8.3", + "@babel/helper-split-export-declaration": "^7.8.3", + "@babel/parser": "^7.8.6", + "@babel/types": "^7.8.6", + "debug": "^4.1.0", + "globals": "^11.1.0", + "lodash": "^4.17.13" + } + }, + "@babel/types": { + "version": "7.8.7", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.8.7.tgz", + "integrity": "sha512-k2TreEHxFA4CjGkL+GYjRyx35W0Mr7DP5+9q6WMkyKXB+904bYmG40syjMFV0oLlhhFCwWl0vA0DyzTDkwAiJw==", + "dev": true, + "requires": { + "esutils": "^2.0.2", + "lodash": "^4.17.13", + "to-fast-properties": "^2.0.0" + } + }, + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + } + } + }, "@babel/plugin-proposal-dynamic-import": { "version": "7.5.0", "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.5.0.tgz", @@ -1567,9 +1750,9 @@ "dev": true }, "aws4": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.9.0.tgz", - "integrity": "sha512-Uvq6hVe90D0B2WEnUqtdgY1bATGz3mw33nH9Y+dmA+w5DHvUmBgkr5rM/KCHpCsiFNRUfokW/szpPPgMK2hm4A==", + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.9.1.tgz", + "integrity": "sha512-wMHVg2EOHaMRxbzgFJ9gtjOOCrI80OHLG14rxi28XwOW8ux6IiEbRCGGGqCtdAIg4FQCbW20k9RsT4y3gJlFug==", "dev": true }, "babel-loader": { @@ -1939,28 +2122,6 @@ "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=", "dev": true }, - "cacache": { - "version": "11.3.3", - "resolved": "https://registry.npmjs.org/cacache/-/cacache-11.3.3.tgz", - "integrity": "sha512-p8WcneCytvzPxhDvYp31PD039vi77I12W+/KfR9S8AZbaiARFBCpsPJS+9uhWfeBfeAtW7o/4vt3MUqLkbY6nA==", - "dev": true, - "requires": { - "bluebird": "^3.5.5", - "chownr": "^1.1.1", - "figgy-pudding": "^3.5.1", - "glob": "^7.1.4", - "graceful-fs": "^4.1.15", - "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": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", @@ -2628,9 +2789,9 @@ } }, "css-loader": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-3.2.0.tgz", - "integrity": "sha512-QTF3Ud5H7DaZotgdcJjGMvyDj5F3Pn1j/sC6VBEOVp94cbwqyIBdcs/quzj4MC1BKQSrTpQznegH/5giYbhnCQ==", + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-3.4.2.tgz", + "integrity": "sha512-jYq4zdZT0oS0Iykt+fqnzVLRIeiPWhka+7BqPn+oSIpWJAHak5tmB/WZrJ2a21JhCeFyNnnlroSl8c+MtVndzA==", "dev": true, "requires": { "camelcase": "^5.3.1", @@ -2638,24 +2799,41 @@ "icss-utils": "^4.1.1", "loader-utils": "^1.2.3", "normalize-path": "^3.0.0", - "postcss": "^7.0.17", + "postcss": "^7.0.23", "postcss-modules-extract-imports": "^2.0.0", "postcss-modules-local-by-default": "^3.0.2", - "postcss-modules-scope": "^2.1.0", + "postcss-modules-scope": "^2.1.1", "postcss-modules-values": "^3.0.0", - "postcss-value-parser": "^4.0.0", - "schema-utils": "^2.0.0" + "postcss-value-parser": "^4.0.2", + "schema-utils": "^2.6.0" }, "dependencies": { + "postcss": { + "version": "7.0.27", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.27.tgz", + "integrity": "sha512-WuQETPMcW9Uf1/22HWUWP9lgsIC+KEHg2kozMflKjbeUtw9ujvFX6QmIfozaErDkmLWS9WEnEdEe6Uo9/BNTdQ==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + } + }, "schema-utils": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.2.0.tgz", - "integrity": "sha512-5EwsCNhfFTZvUreQhx/4vVQpJ/lnCAkgoIHLhSpp4ZirE+4hzFvdJi0FMub6hxbFVBJYSpeVVmon+2e7uEGRrA==", + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.6.4.tgz", + "integrity": "sha512-VNjcaUxVnEeun6B2fiiUDjXXBtD4ZSH7pdbfIu1pOFwgptDPLMo/z9jr4sUfsjFVPqDCEin/F7IYlq7/E6yDbQ==", "dev": true, "requires": { "ajv": "^6.10.2", "ajv-keywords": "^3.4.1" } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true } } }, @@ -4755,13 +4933,13 @@ } }, "globule": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/globule/-/globule-1.3.0.tgz", - "integrity": "sha512-YlD4kdMqRCQHrhVdonet4TdRtv1/sZKepvoxNT4Nrhrp5HI8XFfc8kFlGlBn2myBo80aGp8Eft259mbcUJhgSg==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/globule/-/globule-1.3.1.tgz", + "integrity": "sha512-OVyWOHgw29yosRHCHo7NncwR1hW5ew0W/UrvtwvjefVJeQ26q4/8r8FmPsSF1hJ93IgWkyv16pCTz6WblMzm/g==", "dev": true, "requires": { "glob": "~7.1.1", - "lodash": "~4.17.10", + "lodash": "~4.17.12", "minimatch": "~3.0.2" } }, @@ -5149,6 +5327,12 @@ "integrity": "sha1-8w9xbI4r00bHtn0985FVZqfAVgc=", "dev": true }, + "infer-owner": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz", + "integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==", + "dev": true + }, "inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", @@ -5378,13 +5562,10 @@ "dev": true }, "is-finite": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.0.2.tgz", - "integrity": "sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko=", - "dev": true, - "requires": { - "number-is-nan": "^1.0.0" - } + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.1.0.tgz", + "integrity": "sha512-cdyMtqX/BOqqNBBiKlIVkytNHm49MtMlYyn1zxzvJKWmFMlGzm+ry5BBfYyeY9YmNKbRSo/o7OX9w9ale0wg3w==", + "dev": true }, "is-fullwidth-code-point": { "version": "2.0.0", @@ -5584,9 +5765,9 @@ "dev": true }, "js-base64": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.5.1.tgz", - "integrity": "sha512-M7kLczedRMYX4L8Mdh4MzyAMM9O5osx+4FcOQuTvr3A9F2D9S5JXheN0ewNbrvK2UatkTRhL5ejGmGSjNMiZuw==", + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.5.2.tgz", + "integrity": "sha512-Vg8czh0Q7sFBSUMWWArX/miJeBWYBPpdU/3M/DKSaekLMqrqVPaedp+5mZhie/r0lgrcaYBfwXatEew6gwgiQQ==", "dev": true }, "js-levenshtein": { @@ -6363,9 +6544,9 @@ } }, "node-sass": { - "version": "4.13.0", - "resolved": "https://registry.npmjs.org/node-sass/-/node-sass-4.13.0.tgz", - "integrity": "sha512-W1XBrvoJ1dy7VsvTAS5q1V45lREbTlZQqFbiHb3R3OTTCma0XBtuG6xZ6Z4506nR4lmHPTqVRwxT6KgtWC97CA==", + "version": "4.13.1", + "resolved": "https://registry.npmjs.org/node-sass/-/node-sass-4.13.1.tgz", + "integrity": "sha512-TTWFx+ZhyDx1Biiez2nB0L3YrCZ/8oHagaDalbuBSlqXgUPsdkUSzJsVxeDO9LtPB49+Fh3WQl3slABo6AotNw==", "dev": true, "requires": { "async-foreach": "^0.1.3", @@ -7381,9 +7562,9 @@ } }, "postcss-modules-scope": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-2.1.0.tgz", - "integrity": "sha512-91Rjps0JnmtUB0cujlc8KIKCsJXWjzuxGeT/+Q2i2HXKZ7nBUeF9YQTZZTNvHVoNYj1AthsjnGLtqDUE0Op79A==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-2.1.1.tgz", + "integrity": "sha512-OXRUPecnHCg8b9xWvldG/jUpRIGPNRka0r4D4j0ESUU2/5IOnpsjfPPmDprM3Ih8CgZ8FXjWqaniK5v4rWt3oQ==", "dev": true, "requires": { "postcss": "^7.0.6", @@ -7633,9 +7814,9 @@ "dev": true }, "psl": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.6.0.tgz", - "integrity": "sha512-SYKKmVel98NCOYXpkwUqZqh0ahZeeKfmisiLIcEZdsb+WbLv02g/dI5BUmZnIyOe7RzZtLax81nnb2HbvC2tzA==", + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.7.0.tgz", + "integrity": "sha512-5NsSEDv8zY70ScRnOTn7bK7eanl2MvFrOrS/R6x+dBt5g1ghnj9Zv90kO8GwT8gxcu2ANyFprnFYB85IogIJOQ==", "dev": true }, "pstree.remy": { @@ -8010,9 +8191,9 @@ } }, "request": { - "version": "2.88.0", - "resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz", - "integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==", + "version": "2.88.2", + "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", + "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", "dev": true, "requires": { "aws-sign2": "~0.7.0", @@ -8022,7 +8203,7 @@ "extend": "~3.0.2", "forever-agent": "~0.6.1", "form-data": "~2.3.2", - "har-validator": "~5.1.0", + "har-validator": "~5.1.3", "http-signature": "~1.2.0", "is-typedarray": "~1.0.0", "isstream": "~0.1.2", @@ -8032,7 +8213,7 @@ "performance-now": "^2.1.0", "qs": "~6.5.2", "safe-buffer": "^5.1.2", - "tough-cookie": "~2.4.3", + "tough-cookie": "~2.5.0", "tunnel-agent": "^0.6.0", "uuid": "^3.3.2" }, @@ -8402,22 +8583,22 @@ } }, "sass-loader": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-8.0.0.tgz", - "integrity": "sha512-+qeMu563PN7rPdit2+n5uuYVR0SSVwm0JsOUsaJXzgYcClWSlmX0iHDnmeOobPkf5kUglVot3QS6SyLyaQoJ4w==", + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-8.0.2.tgz", + "integrity": "sha512-7o4dbSK8/Ol2KflEmSco4jTjQoV988bM82P9CZdmo9hR3RLnvNc0ufMNdMrB0caq38JQ/FgF4/7RcbcfKzxoFQ==", "dev": true, "requires": { "clone-deep": "^4.0.1", "loader-utils": "^1.2.3", "neo-async": "^2.6.1", - "schema-utils": "^2.1.0", + "schema-utils": "^2.6.1", "semver": "^6.3.0" }, "dependencies": { "schema-utils": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.6.1.tgz", - "integrity": "sha512-0WXHDs1VDJyo+Zqs9TKLKyD/h7yDpHUhEFsM2CzkICFdoX1av+GBq/J2xRTFfsQO5kBfhZzANf2VcIm84jqDbg==", + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.6.4.tgz", + "integrity": "sha512-VNjcaUxVnEeun6B2fiiUDjXXBtD4ZSH7pdbfIu1pOFwgptDPLMo/z9jr4sUfsjFVPqDCEin/F7IYlq7/E6yDbQ==", "dev": true, "requires": { "ajv": "^6.10.2", @@ -8523,12 +8704,6 @@ } } }, - "serialize-javascript": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-1.7.0.tgz", - "integrity": "sha512-ke8UG8ulpFOxO8f8gRYabHQe/ZntKlcig2Mp+8+URDP1D8vJZ0KUt7LYo07q25Z/+JVSgpr/cui9PIp5H6/+nA==", - "dev": true - }, "serve-index": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", @@ -9401,28 +9576,66 @@ } }, "terser-webpack-plugin": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-1.3.0.tgz", - "integrity": "sha512-W2YWmxPjjkUcOWa4pBEv4OP4er1aeQJlSo2UhtCFQCuRXEHjOFscO8VyWHj9JLlA0RzQb8Y2/Ta78XZvT54uGg==", + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-1.4.3.tgz", + "integrity": "sha512-QMxecFz/gHQwteWwSo5nTc6UaICqN1bMedC5sMtUc7y3Ha3Q8y6ZO0iCR8pq4RJC8Hjf0FEPEHZqcMB/+DFCrA==", "dev": true, "requires": { - "cacache": "^11.3.2", - "find-cache-dir": "^2.0.0", + "cacache": "^12.0.2", + "find-cache-dir": "^2.1.0", "is-wsl": "^1.1.0", - "loader-utils": "^1.2.3", "schema-utils": "^1.0.0", - "serialize-javascript": "^1.7.0", + "serialize-javascript": "^2.1.2", "source-map": "^0.6.1", - "terser": "^4.0.0", - "webpack-sources": "^1.3.0", + "terser": "^4.1.2", + "webpack-sources": "^1.4.0", "worker-farm": "^1.7.0" }, "dependencies": { + "cacache": { + "version": "12.0.3", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-12.0.3.tgz", + "integrity": "sha512-kqdmfXEGFepesTuROHMs3MpFLWrPkSSpRqOw80RCflZXy/khxaArvFrQ7uJxSUduzAufc6G0g1VUCOZXxWavPw==", + "dev": true, + "requires": { + "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" + } + }, + "serialize-javascript": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-2.1.2.tgz", + "integrity": "sha512-rs9OggEUF0V4jUSecXazOYsLfu7OGK2qIn3c7IPBiffz32XniEp/TX9Xmc9LQfK2nQ2QKHvZ2oygKUGU0lG4jQ==", + "dev": true + }, "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true + }, + "webpack-sources": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.4.3.tgz", + "integrity": "sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ==", + "dev": true, + "requires": { + "source-list-map": "^2.0.0", + "source-map": "~0.6.1" + } } } }, @@ -9548,21 +9761,13 @@ } }, "tough-cookie": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz", - "integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==", + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", + "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", "dev": true, "requires": { - "psl": "^1.1.24", - "punycode": "^1.4.1" - }, - "dependencies": { - "punycode": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", - "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", - "dev": true - } + "psl": "^1.1.28", + "punycode": "^2.1.1" } }, "trim-newlines": { diff --git a/cvat-canvas/package.json b/cvat-canvas/package.json index 06ea6c5c..a9d97182 100644 --- a/cvat-canvas/package.json +++ b/cvat-canvas/package.json @@ -19,23 +19,24 @@ "devDependencies": { "@babel/cli": "^7.5.5", "@babel/core": "^7.5.5", + "@babel/plugin-proposal-class-properties": "^7.8.3", "@babel/preset-env": "^7.5.5", "@babel/preset-typescript": "^7.3.3", "@types/node": "^12.6.8", "@typescript-eslint/eslint-plugin": "^1.13.0", "@typescript-eslint/parser": "^1.13.0", "babel-loader": "^8.0.6", - "css-loader": "^3.2.0", + "css-loader": "^3.4.2", "dts-bundle-webpack": "^1.0.2", "eslint": "^6.1.0", "eslint-config-airbnb-typescript": "^4.0.1", "eslint-config-typescript-recommended": "^1.4.17", "eslint-plugin-import": "^2.18.2", - "node-sass": "^4.13.0", + "node-sass": "^4.13.1", "nodemon": "^1.19.1", "postcss-loader": "^3.0.0", "postcss-preset-env": "^6.7.0", - "sass-loader": "^8.0.0", + "sass-loader": "^8.0.2", "style-loader": "^1.0.0", "typescript": "^3.5.3", "webpack": "^4.36.1", diff --git a/cvat-canvas/src/typescript/canvasModel.ts b/cvat-canvas/src/typescript/canvasModel.ts index f72bc632..66a2717b 100644 --- a/cvat-canvas/src/typescript/canvasModel.ts +++ b/cvat-canvas/src/typescript/canvasModel.ts @@ -9,6 +9,12 @@ export interface Size { height: number; } +export interface Image { + renderWidth: number; + renderHeight: number; + imageData: ImageData | CanvasImageSource; +} + export interface Position { x: number; y: number; @@ -110,7 +116,7 @@ export enum Mode { } export interface CanvasModel { - readonly image: HTMLImageElement | null; + readonly image: Image | null; readonly objects: any[]; readonly zLayer: number | null; readonly gridSize: Size; @@ -153,7 +159,7 @@ export class CanvasModelImpl extends MasterImpl implements CanvasModel { activeElement: ActiveElement; angle: number; canvasSize: Size; - image: HTMLImageElement | null; + image: Image | null; imageID: number | null; imageOffset: number; imageSize: Size; @@ -310,7 +316,7 @@ export class CanvasModelImpl extends MasterImpl implements CanvasModel { this.data.image = null; this.notify(UpdateReasons.IMAGE_CHANGED); }, - ).then((data: HTMLImageElement): void => { + ).then((data: Image): void => { if (frameData.number !== this.data.imageID) { // already another image return; @@ -516,7 +522,7 @@ export class CanvasModelImpl extends MasterImpl implements CanvasModel { return this.data.zLayer; } - public get image(): HTMLImageElement | null { + public get image(): Image | null { return this.data.image; } diff --git a/cvat-canvas/src/typescript/canvasView.ts b/cvat-canvas/src/typescript/canvasView.ts index 3290a382..5d614948 100644 --- a/cvat-canvas/src/typescript/canvasView.ts +++ b/cvat-canvas/src/typescript/canvasView.ts @@ -285,7 +285,7 @@ export class CanvasViewImpl implements CanvasView, Listener { } private moveCanvas(): void { - for (const obj of [this.background, this.grid, this.loadingAnimation]) { + for (const obj of [this.background, this.grid]) { obj.style.top = `${this.geometry.top}px`; obj.style.left = `${this.geometry.left}px`; } @@ -303,7 +303,7 @@ export class CanvasViewImpl implements CanvasView, Listener { private transformCanvas(): void { // Transform canvas - for (const obj of [this.background, this.grid, this.loadingAnimation, this.content]) { + for (const obj of [this.background, this.grid, this.content]) { obj.style.transform = `scale(${this.geometry.scale}) rotate(${this.geometry.angle}deg)`; } @@ -358,7 +358,7 @@ export class CanvasViewImpl implements CanvasView, Listener { } private resizeCanvas(): void { - for (const obj of [this.background, this.grid, this.loadingAnimation]) { + for (const obj of [this.background, this.grid]) { obj.style.width = `${this.geometry.image.width}px`; obj.style.height = `${this.geometry.image.height}px`; } @@ -709,10 +709,21 @@ export class CanvasViewImpl implements CanvasView, Listener { } else { this.loadingAnimation.classList.add('cvat_canvas_hidden'); const ctx = this.background.getContext('2d'); - this.background.setAttribute('width', `${image.width}px`); - this.background.setAttribute('height', `${image.height}px`); + this.background.setAttribute('width', `${image.renderWidth}px`); + this.background.setAttribute('height', `${image.renderHeight}px`); + if (ctx) { - ctx.drawImage(image, 0, 0); + if (image.imageData instanceof ImageData) { + ctx.scale(image.renderWidth / image.imageData.width, + image.renderHeight / image.imageData.height); + ctx.putImageData(image.imageData, 0, 0); + // Transformation matrix must not affect the putImageData() method. + // By this reason need to redraw the image to apply scale. + // https://www.w3.org/TR/2dcontext/#dom-context-2d-putimagedata + ctx.drawImage(this.background, 0, 0); + } else { + ctx.drawImage(image.imageData, 0, 0); + } } this.moveCanvas(); this.resizeCanvas(); diff --git a/cvat-canvas/webpack.config.js b/cvat-canvas/webpack.config.js index 69d97b12..2420c5e4 100644 --- a/cvat-canvas/webpack.config.js +++ b/cvat-canvas/webpack.config.js @@ -23,10 +23,12 @@ const nodeConfig = { }, module: { rules: [{ + test: /\.ts$/, exclude: /node_modules/, use: { loader: 'babel-loader', options: { + plugins: ['@babel/plugin-proposal-class-properties'], presets: [ ['@babel/preset-env'], ['@babel/typescript'], @@ -35,14 +37,20 @@ const nodeConfig = { }, }, }, { - test: /\.css$/, - use: ['style-loader', 'css-loader'] + test: /\.(css|scss)$/, + exclude: /node_modules/, + use: ['style-loader', { + loader: 'css-loader', + options: { + importLoaders: 2, + }, + }, 'postcss-loader', 'sass-loader'] }], }, plugins: [ new DtsBundleWebpack({ name: 'cvat-canvas.node', - main: 'dist/declaration/canvas.d.ts', + main: 'dist/declaration/src/typescript/canvas.d.ts', out: '../cvat-canvas.node.d.ts', }), ] @@ -70,10 +78,12 @@ const webConfig = { }, module: { rules: [{ + test: /\.ts$/, exclude: /node_modules/, use: { loader: 'babel-loader', options: { + plugins: ['@babel/plugin-proposal-class-properties'], presets: [ ['@babel/preset-env', { targets: '> 2.5%', // https://github.com/browserslist/browserslist @@ -97,7 +107,7 @@ const webConfig = { plugins: [ new DtsBundleWebpack({ name: 'cvat-canvas', - main: 'dist/declaration/canvas.d.ts', + main: 'dist/declaration/src/typescript/canvas.d.ts', out: '../cvat-canvas.d.ts', }), ] diff --git a/cvat-core/src/download.worker.js b/cvat-core/src/download.worker.js new file mode 100644 index 00000000..0999361a --- /dev/null +++ b/cvat-core/src/download.worker.js @@ -0,0 +1,33 @@ +/* +* Copyright (C) 2019 Intel Corporation +* SPDX-License-Identifier: MIT +*/ + +/* global + require:false +*/ + +const Axios = require('axios'); + +Axios.defaults.withCredentials = true; +Axios.defaults.xsrfHeaderName = 'X-CSRFTOKEN'; +Axios.defaults.xsrfCookieName = 'csrftoken'; + + +onmessage = (e) => { + Axios.get(e.data.url, e.data.config) + .then((response) => { + postMessage({ + responseData: response.data, + id: e.data.id, + isSuccess: true, + }); + }) + .catch((error) => { + postMessage({ + id: e.data.id, + error, + isSuccess: false, + }); + }); +}; diff --git a/cvat-core/src/frames.js b/cvat-core/src/frames.js index 4141de07..7f92e926 100644 --- a/cvat-core/src/frames.js +++ b/cvat-core/src/frames.js @@ -9,14 +9,14 @@ */ (() => { + const cvatData = require('../../cvat-data'); const PluginRegistry = require('./plugins'); const serverProxy = require('./server-proxy'); - const { ArgumentError } = require('./exceptions'); const { isBrowser, isNode } = require('browser-or-node'); + const { Exception, ArgumentError, DataError } = require('./exceptions'); // This is the frames storage const frameDataCache = {}; - const frameCache = {}; /** * Class provides meta information about specific frame and frame itself @@ -24,8 +24,28 @@ * @hideconstructor */ class FrameData { - constructor(width, height, tid, number) { + constructor({ + width, + height, + name, + taskID, + frameNumber, + startFrame, + stopFrame, + decodeForward, + }) { Object.defineProperties(this, Object.freeze({ + /** + * @name filename + * @type {string} + * @memberof module:API.cvat.classes.FrameData + * @readonly + * @instance + */ + filename: { + value: name, + writable: false, + }, /** * @name width * @type {integer} @@ -49,7 +69,7 @@ writable: false, }, tid: { - value: tid, + value: taskID, writable: false, }, /** @@ -60,7 +80,19 @@ * @instance */ number: { - value: number, + value: frameNumber, + writable: false, + }, + startFrame: { + value: startFrame, + writable: false, + }, + stopFrame: { + value: stopFrame, + writable: false, + }, + decodeForward: { + value: decodeForward, writable: false, }, })); @@ -86,42 +118,419 @@ } FrameData.prototype.data.implementation = async function (onServerRequest) { - return new Promise(async (resolve, reject) => { - try { - if (this.number in frameCache[this.tid]) { - resolve(frameCache[this.tid][this.number]); - } else { - onServerRequest(); - const frame = await serverProxy.frames.getData(this.tid, this.number); - - if (isNode) { - frameCache[this.tid][this.number] = global.Buffer.from(frame, 'binary').toString('base64'); - resolve(frameCache[this.tid][this.number]); - } else if (isBrowser) { - const reader = new FileReader(); - reader.onload = () => { - const image = new Image(frame.width, frame.height); - image.onload = () => { - frameCache[this.tid][this.number] = image; - resolve(frameCache[this.tid][this.number]); - }; - image.src = reader.result; - }; - - reader.readAsDataURL(frame); + return new Promise((resolve, reject) => { + const resolveWrapper = (data) => { + this._data = { + imageData: data, + renderWidth: this.width, + renderHeight: this.height, + }; + return resolve(this._data); + }; + + if (this._data) { + resolve(this._data); + return; + } + + const { provider } = frameDataCache[this.tid]; + const { chunkSize } = frameDataCache[this.tid]; + const start = parseInt(this.number / chunkSize, 10) * chunkSize; + const stop = Math.min( + this.stopFrame, + (parseInt(this.number / chunkSize, 10) + 1) * chunkSize - 1, + ); + const chunkNumber = Math.floor(this.number / chunkSize); + + const onDecodeAll = async (frameNumber) => { + if (frameDataCache[this.tid].activeChunkRequest + && chunkNumber === frameDataCache[this.tid].activeChunkRequest.chunkNumber) { + const callbackArray = frameDataCache[this.tid].activeChunkRequest.callbacks; + for (let i = callbackArray.length - 1; i >= 0; --i) { + if (callbackArray[i].frameNumber === frameNumber) { + const callback = callbackArray[i]; + callbackArray.splice(i, 1); + callback.resolve(await provider.frame(callback.frameNumber)); + } } + if (callbackArray.length === 0) { + frameDataCache[this.tid].activeChunkRequest = null; + } + } + }; + + const rejectRequestAll = () => { + if (frameDataCache[this.tid].activeChunkRequest + && chunkNumber === frameDataCache[this.tid].activeChunkRequest.chunkNumber) { + for (const r of frameDataCache[this.tid].activeChunkRequest.callbacks) { + r.reject(r.frameNumber); + } + frameDataCache[this.tid].activeChunkRequest = null; } - } catch (exception) { - reject(exception); + }; + + const makeActiveRequest = () => { + const taskDataCache = frameDataCache[this.tid]; + const activeChunk = taskDataCache.activeChunkRequest; + activeChunk.request = serverProxy.frames.getData(this.tid, + activeChunk.chunkNumber).then((chunk) => { + frameDataCache[this.tid].activeChunkRequest.completed = true; + if (!taskDataCache.nextChunkRequest) { + provider.requestDecodeBlock(chunk, + taskDataCache.activeChunkRequest.start, + taskDataCache.activeChunkRequest.stop, + taskDataCache.activeChunkRequest.onDecodeAll, + taskDataCache.activeChunkRequest.rejectRequestAll); + } + }).catch((exception) => { + if (exception instanceof Exception) { + reject(exception); + } else { + reject(new Exception(exception.message)); + } + }).finally(() => { + if (taskDataCache.nextChunkRequest) { + if (taskDataCache.activeChunkRequest) { + for (const r of taskDataCache.activeChunkRequest.callbacks) { + r.reject(r.frameNumber); + } + } + taskDataCache.activeChunkRequest = taskDataCache.nextChunkRequest; + taskDataCache.nextChunkRequest = null; + makeActiveRequest(); + } + }); + }; + + if (isNode) { + resolve('Dummy data'); + } else if (isBrowser) { + provider.frame(this.number).then((frame) => { + if (frame === null) { + onServerRequest(); + const activeRequest = frameDataCache[this.tid].activeChunkRequest; + if (!provider.isChunkCached(start, stop)) { + if (!activeRequest + || (activeRequest + && activeRequest.completed + && activeRequest.chunkNumber !== chunkNumber)) { + if (activeRequest && activeRequest.rejectRequestAll) { + activeRequest.rejectRequestAll(); + } + frameDataCache[this.tid].activeChunkRequest = { + request: null, + chunkNumber, + start, + stop, + onDecodeAll, + rejectRequestAll, + completed: false, + callbacks: [{ + resolve: resolveWrapper, + reject, + frameNumber: this.number, + }], + }; + makeActiveRequest(); + } else if (activeRequest.chunkNumber === chunkNumber) { + if (!activeRequest.onDecodeAll + && !activeRequest.rejectRequestAll) { + activeRequest.onDecodeAll = onDecodeAll; + activeRequest.rejectRequestAll = rejectRequestAll; + } + activeRequest.callbacks.push({ + resolve: resolveWrapper, + reject, + frameNumber: this.number, + }); + } else { + if (frameDataCache[this.tid].nextChunkRequest) { + const { callbacks } = frameDataCache[this.tid].nextChunkRequest; + for (const r of callbacks) { + r.reject(r.frameNumber); + } + } + frameDataCache[this.tid].nextChunkRequest = { + request: null, + chunkNumber, + start, + stop, + onDecodeAll, + rejectRequestAll, + completed: false, + callbacks: [{ + resolve: resolveWrapper, + reject, + frameNumber: this.number, + }], + }; + } + } else { + activeRequest.callbacks.push({ + resolve: resolveWrapper, + reject, + frameNumber: this.number, + }); + provider.requestDecodeBlock(null, start, stop, + onDecodeAll, rejectRequestAll); + } + } else { + if (this.number % chunkSize > chunkSize / 4 + && provider.decodedBlocksCacheSize > 1 + && this.decodeForward + && !provider.isNextChunkExists(this.number)) { + const nextChunkNumber = Math.floor(this.number / chunkSize) + 1; + if (nextChunkNumber * chunkSize < this.stopFrame) { + provider.setReadyToLoading(nextChunkNumber); + const nextStart = nextChunkNumber * chunkSize; + const nextStop = (nextChunkNumber + 1) * chunkSize - 1; + if (!provider.isChunkCached(nextStart, nextStop)) { + if (!frameDataCache[this.tid].activeChunkRequest) { + frameDataCache[this.tid].activeChunkRequest = { + request: null, + chunkNumber: nextChunkNumber, + start: nextStart, + stop: nextStop, + onDecodeAll: null, + rejectRequestAll: null, + completed: false, + callbacks: [], + }; + makeActiveRequest(); + } + } else { + provider.requestDecodeBlock(null, nextStart, nextStop, + null, null); + } + } + } + resolveWrapper(frame); + } + }).catch((exception) => { + if (exception instanceof Exception) { + reject(exception); + } else { + reject(new Exception(exception.message)); + } + }); } }); }; + function getFrameMeta(taskID, frame) { + const { meta, mode } = frameDataCache[taskID]; + let size = null; + if (mode === 'interpolation') { + [size] = meta.frames; + } else if (mode === 'annotation') { + if (frame >= meta.size) { + throw new ArgumentError( + `Meta information about frame ${frame} can't be received from the server`, + ); + } else { + size = meta.frames[frame]; + } + } else { + throw new DataError( + `Invalid mode is specified ${mode}`, + ); + } + return size; + } + + class FrameBuffer { + constructor(size, chunkSize, stopFrame, taskID) { + this._size = size; + this._buffer = {}; + this._requestedChunks = {}; + this._chunkSize = chunkSize; + this._stopFrame = stopFrame; + this._activeFillBufferRequest = false; + this._taskID = taskID; + } + + getFreeBufferSize() { + let requestedFrameCount = 0; + for (const chunk of Object.values(this._requestedChunks)) { + requestedFrameCount += chunk.requestedFrames.size; + } + + return this._size - Object.keys(this._buffer).length - requestedFrameCount; + } + + requestOneChunkFrames(chunkIdx) { + return new Promise((resolve, reject) => { + this._requestedChunks[chunkIdx] = { + ...this._requestedChunks[chunkIdx], + resolve, + reject, + }; + for (const frame of this._requestedChunks[chunkIdx].requestedFrames.entries()) { + const requestedFrame = frame[1]; + const frameMeta = getFrameMeta(this._taskID, requestedFrame); + const frameData = new FrameData({ + ...frameMeta, + taskID: this._taskID, + frameNumber: requestedFrame, + startFrame: frameDataCache[this._taskID].startFrame, + stopFrame: frameDataCache[this._taskID].stopFrame, + decodeForward: false, + }); + + frameData.data().then(() => { + if (!(chunkIdx in this._requestedChunks) + || !this._requestedChunks[chunkIdx].requestedFrames.has(requestedFrame)) { + reject(chunkIdx); + } else { + this._requestedChunks[chunkIdx].requestedFrames.delete(requestedFrame); + this._requestedChunks[chunkIdx].buffer[requestedFrame] = frameData; + if (this._requestedChunks[chunkIdx].requestedFrames.size === 0) { + const bufferedframes = Object.keys( + this._requestedChunks[chunkIdx].buffer, + ).map((f) => +f); + this._requestedChunks[chunkIdx].resolve(new Set(bufferedframes)); + } + } + }).catch(() => { + reject(chunkIdx); + }); + } + }); + } + + fillBuffer(startFrame, frameStep = 1, count = null) { + const freeSize = this.getFreeBufferSize(); + const requestedFrameCount = count ? count * frameStep : freeSize * frameStep; + const stopFrame = Math.min(startFrame + requestedFrameCount, this._stopFrame + 1); + + for (let i = startFrame; i < stopFrame; i += frameStep) { + const chunkIdx = Math.floor(i / this._chunkSize); + if (!(chunkIdx in this._requestedChunks)) { + this._requestedChunks[chunkIdx] = { + requestedFrames: new Set(), + resolve: null, + reject: null, + buffer: {}, + }; + } + this._requestedChunks[chunkIdx].requestedFrames.add(i); + } + + let bufferedFrames = new Set(); + + // Need to decode chunks in sequence + // eslint-disable-next-line no-async-promise-executor + return new Promise(async (resolve, reject) => { + for (const chunkIdx in this._requestedChunks) { + if (Object.prototype.hasOwnProperty.call(this._requestedChunks, chunkIdx)) { + try { + const chunkFrames = await this.requestOneChunkFrames(chunkIdx); + if (chunkIdx in this._requestedChunks) { + bufferedFrames = new Set([...bufferedFrames, ...chunkFrames]); + this._buffer = { + ...this._buffer, + ...this._requestedChunks[chunkIdx].buffer, + }; + delete this._requestedChunks[chunkIdx]; + if (Object.keys(this._requestedChunks).length === 0) { + resolve(bufferedFrames); + } + } else { + reject(chunkIdx); + break; + } + } catch (error) { + reject(error); + break; + } + } + } + }); + } + + async makeFillRequest(start, step, count = null) { + if (!this._activeFillBufferRequest) { + this._activeFillBufferRequest = true; + try { + await this.fillBuffer(start, step, count); + this._activeFillBufferRequest = false; + } catch (error) { + if (typeof (error) === 'number' && error in this._requestedChunks) { + this._activeFillBufferRequest = false; + } + throw error; + } + } + } + + async require(frameNumber, taskID, fillBuffer, frameStep) { + for (const frame in this._buffer) { + if (frame < frameNumber + || frame >= frameNumber + this._size * frameStep) { + delete this._buffer[frame]; + } + } + + this._required = frameNumber; + const frameMeta = getFrameMeta(taskID, frameNumber); + let frame = new FrameData({ + ...frameMeta, + taskID, + frameNumber, + startFrame: frameDataCache[taskID].startFrame, + stopFrame: frameDataCache[taskID].stopFrame, + decodeForward: !fillBuffer, + }); + + if (frameNumber in this._buffer) { + frame = this._buffer[frameNumber]; + delete this._buffer[frameNumber]; + const cachedFrames = this.cachedFrames(); + if (fillBuffer && !this._activeFillBufferRequest + && this._size > this._chunkSize + && cachedFrames.length < (this._size * 3) / 4) { + const maxFrame = cachedFrames ? Math.max(...cachedFrames) : frameNumber; + if (maxFrame < this._stopFrame) { + this.makeFillRequest(maxFrame + 1, frameStep).catch((e) => { + if (e !== 'not needed') { + throw e; + } + }); + } + } + } else if (fillBuffer) { + this.clear(); + await this.makeFillRequest(frameNumber, frameStep, fillBuffer ? null : 1); + + frame = this._buffer[frameNumber]; + } else { + this.clear(); + } + + return frame; + } + + clear() { + for (const chunkIdx in this._requestedChunks) { + if (Object.prototype.hasOwnProperty.call(this._requestedChunks, chunkIdx) + && this._requestedChunks[chunkIdx].reject) { + this._requestedChunks[chunkIdx].reject('not needed'); + } + } + this._activeFillBufferRequest = false; + this._requestedChunks = {}; + this._buffer = {}; + } + + cachedFrames() { + return Object.keys(this._buffer).map((f) => +f); + } + } + async function getPreview(taskID) { - return new Promise(async (resolve, reject) => { - try { - // Just go to server and get preview (no any cache) - const result = await serverProxy.frames.getPreview(taskID); + return new Promise((resolve, reject) => { + // Just go to server and get preview (no any cache) + serverProxy.frames.getPreview(taskID).then((result) => { if (isNode) { resolve(global.Buffer.from(result, 'binary').toString('base64')); } else if (isBrowser) { @@ -131,48 +540,75 @@ }; reader.readAsDataURL(result); } - } catch (error) { + }).catch((error) => { reject(error); - } + }); }); } - async function getFrame(taskID, mode, frame) { + async function getFrame(taskID, chunkSize, chunkType, mode, frame, + startFrame, stopFrame, isPlaying, step) { if (!(taskID in frameDataCache)) { + const blockType = chunkType === 'video' ? cvatData.BlockType.MP4VIDEO + : cvatData.BlockType.ARCHIVE; + + const meta = await serverProxy.frames.getMeta(taskID); + const mean = meta.frames.reduce((a, b) => a + b.width * b.height, 0) + / meta.frames.length; + const stdDev = Math.sqrt(meta.frames.map( + (x) => Math.pow(x.width * x.height - mean, 2), + ).reduce((a, b) => a + b) / meta.frames.length); + + // limit of decoded frames cache by 2GB + const decodedBlocksCacheSize = Math.floor(2147483648 / (mean + stdDev) / 4 / chunkSize) + || 1; + frameDataCache[taskID] = { - meta: await serverProxy.frames.getMeta(taskID), + meta, + chunkSize, + mode, + startFrame, + stopFrame, + provider: new cvatData.FrameProvider( + blockType, chunkSize, Math.max(decodedBlocksCacheSize, 9), + decodedBlocksCacheSize, 1, + ), + frameBuffer: new FrameBuffer( + Math.min(180, decodedBlocksCacheSize * chunkSize), + chunkSize, + stopFrame, + taskID, + ), + decodedBlocksCacheSize, + activeChunkRequest: null, + nextChunkRequest: null, }; - - frameCache[taskID] = {}; + const frameMeta = getFrameMeta(taskID, frame); + // actual only for video chunks + frameDataCache[taskID].provider.setRenderSize(frameMeta.width, frameMeta.height); } - if (!(frame in frameDataCache[taskID])) { - let size = null; - if (mode === 'interpolation') { - [size] = frameDataCache[taskID].meta; - } else if (mode === 'annotation') { - if (frame >= frameDataCache[taskID].meta.length) { - throw new ArgumentError( - `Meta information about frame ${frame} can't be received from the server`, - ); - } else { - size = frameDataCache[taskID].meta[frame]; - } - } else { - throw new ArgumentError( - `Invalid mode is specified ${mode}`, - ); - } + return frameDataCache[taskID].frameBuffer.require(frame, taskID, isPlaying, step); + } - frameDataCache[taskID][frame] = new FrameData(size.width, size.height, taskID, frame); + function getRanges(taskID) { + if (!(taskID in frameDataCache)) { + return { + decoded: [], + buffered: [], + }; } - return frameDataCache[taskID][frame]; + return { + decoded: frameDataCache[taskID].provider.cachedFrames, + buffered: frameDataCache[taskID].frameBuffer.cachedFrames(), + }; } module.exports = { FrameData, getFrame, + getRanges, getPreview, }; })(); diff --git a/cvat-core/src/server-proxy.js b/cvat-core/src/server-proxy.js index 7a833fb1..82513282 100644 --- a/cvat-core/src/server-proxy.js +++ b/cvat-core/src/server-proxy.js @@ -14,6 +14,7 @@ } = require('./exceptions'); const store = require('store'); const config = require('./config'); + const DownloadWorker = require('./download.worker'); function generateError(errorData) { if (errorData.response) { @@ -26,12 +27,66 @@ return new ServerError(message, 0); } + class WorkerWrappedAxios { + constructor() { + const worker = new DownloadWorker(); + const requests = {}; + let requestId = 0; + + worker.onmessage = (e) => { + if (e.data.id in requests) { + if (e.data.isSuccess) { + requests[e.data.id].resolve(e.data.responseData); + } else { + requests[e.data.id].reject(e.data.error); + } + + delete requests[e.data.id]; + } + }; + + worker.onerror = (e) => { + if (e.data.id in requests) { + requests[e.data.id].reject(e); + delete requests[e.data.id]; + } + }; + + function getRequestId() { + return requestId++; + } + + async function get(url, requestConfig) { + return new Promise((resolve, reject) => { + const newRequestId = getRequestId(); + requests[newRequestId] = { + resolve, + reject, + }; + worker.postMessage({ + url, + config: requestConfig, + id: newRequestId, + }); + }); + } + + Object.defineProperties(this, Object.freeze({ + get: { + value: get, + writable: false, + }, + })); + } + } + class ServerProxy { constructor() { const Axios = require('axios'); Axios.defaults.withCredentials = true; Axios.defaults.xsrfHeaderName = 'X-CSRFTOKEN'; Axios.defaults.xsrfCookieName = 'csrftoken'; + const workerAxios = new WorkerWrappedAxios(); let token = store.get('token'); if (token) { @@ -275,7 +330,7 @@ }); } - async function createTask(taskData, files, onUpdate) { + async function createTask(taskSpec, taskDataSpec, onUpdate) { const { backendAPI } = config; async function wait(id) { @@ -315,12 +370,14 @@ }); } - const batchOfFiles = new FormData(); - for (const key in files) { - if (Object.prototype.hasOwnProperty.call(files, key)) { - for (let i = 0; i < files[key].length; i++) { - batchOfFiles.append(`${key}[${i}]`, files[key][i]); - } + const taskData = new FormData(); + for (const [key, value] of Object.entries(taskDataSpec)) { + if (Array.isArray(value)) { + value.forEach((element, idx) => { + taskData.append(`${key}[${idx}]`, element); + }); + } else { + taskData.set(key, value); } } @@ -328,7 +385,7 @@ onUpdate('The task is being created on the server..'); try { - response = await Axios.post(`${backendAPI}/tasks`, JSON.stringify(taskData), { + response = await Axios.post(`${backendAPI}/tasks`, JSON.stringify(taskSpec), { proxy: config.proxy, headers: { 'Content-Type': 'application/json', @@ -340,7 +397,7 @@ onUpdate('The data is being uploaded to the server..'); try { - await Axios.post(`${backendAPI}/tasks/${response.data.id}/data`, batchOfFiles, { + await Axios.post(`${backendAPI}/tasks/${response.data.id}/data`, taskData, { proxy: config.proxy, }); } catch (errorData) { @@ -435,8 +492,7 @@ let response = null; try { - // TODO: change 0 frame to preview - response = await Axios.get(`${backendAPI}/tasks/${tid}/frames/0`, { + response = await Axios.get(`${backendAPI}/tasks/${tid}/data?type=preview`, { proxy: config.proxy, responseType: 'blob', }); @@ -451,20 +507,23 @@ return response.data; } - async function getData(tid, frame) { + async function getData(tid, chunk) { const { backendAPI } = config; let response = null; try { - response = await Axios.get(`${backendAPI}/tasks/${tid}/frames/${frame}`, { - proxy: config.proxy, - responseType: 'blob', - }); + response = await workerAxios.get( + `${backendAPI}/tasks/${tid}/data?type=chunk&number=${chunk}&quality=compressed`, + { + proxy: config.proxy, + responseType: 'arraybuffer', + }, + ); } catch (errorData) { throw generateError(errorData); } - return response.data; + return response; } async function getMeta(tid) { @@ -472,7 +531,7 @@ let response = null; try { - response = await Axios.get(`${backendAPI}/tasks/${tid}/frames/meta`, { + response = await Axios.get(`${backendAPI}/tasks/${tid}/data/meta`, { proxy: config.proxy, }); } catch (errorData) { diff --git a/cvat-core/src/session.js b/cvat-core/src/session.js index 5ad15fe7..987b3fae 100644 --- a/cvat-core/src/session.js +++ b/cvat-core/src/session.js @@ -11,7 +11,7 @@ const PluginRegistry = require('./plugins'); const loggerStorage = require('./logger-storage'); const serverProxy = require('./server-proxy'); - const { getFrame, getPreview } = require('./frames'); + const { getFrame, getRanges, getPreview } = require('./frames'); const { ArgumentError } = require('./exceptions'); const { TaskStatus } = require('./enums'); const { Label } = require('./labels'); @@ -113,9 +113,14 @@ }), frames: Object.freeze({ value: { - async get(frame) { + async get(frame, isPlaying = false, step = 1) { const result = await PluginRegistry - .apiWrapper.call(this, prototype.frames.get, frame); + .apiWrapper.call(this, prototype.frames.get, frame, isPlaying, step); + return result; + }, + async ranges() { + const result = await PluginRegistry + .apiWrapper.call(this, prototype.frames.ranges); return result; }, async preview() { @@ -416,8 +421,10 @@ * @async * @throws {module:API.cvat.exceptions.PluginError} * @throws {module:API.cvat.exceptions.ServerError} + * @throws {module:API.cvat.exceptions.DataError} * @throws {module:API.cvat.exceptions.ArgumentError} */ + /** * Get the first frame of a task for preview * @method preview @@ -430,6 +437,15 @@ * @throws {module:API.cvat.exceptions.ArgumentError} */ + /** + * Returns the ranges of cached frames + * @method ranges + * @memberof Session.frames + * @returns {Array{string}} + * @instance + * @async + */ + /** * Namespace is used for an interaction with logs * @namespace logger @@ -692,6 +708,7 @@ this.frames = { get: Object.getPrototypeOf(this).frames.get.bind(this), + ranges: Object.getPrototypeOf(this).frames.ranges.bind(this), preview: Object.getPrototypeOf(this).frames.preview.bind(this), }; @@ -755,6 +772,10 @@ start_frame: undefined, stop_frame: undefined, frame_filter: undefined, + data_chunk_size: undefined, + data_compressed_chunk_type: undefined, + data_original_chunk_type: undefined, + use_zip_chunks: undefined, }; for (const property in data) { @@ -992,6 +1013,24 @@ data.image_quality = quality; }, }, + /** + * @name useZipChunks + * @type {boolean} + * @memberof module:API.cvat.classes.Task + * @instance + * @throws {module:API.cvat.exceptions.ArgumentError} + */ + useZipChunks: { + get: () => data.use_zip_chunks, + set: (useZipChunks) => { + if (typeof (useZipChunks) !== 'boolean') { + throw new ArgumentError( + 'Value must be a boolean', + ); + } + data.use_zip_chunks = useZipChunks; + }, + }, /** * After task has been created value can be appended only. * @name labels @@ -1173,6 +1212,21 @@ data.frame_filter = filter; }, }, + dataChunkSize: { + get: () => data.data_chunk_size, + set: (chunkSize) => { + if (typeof (chunkSize) !== 'number' || chunkSize < 1) { + throw new ArgumentError( + `Chunk size value must be a positive number. But value ${chunkSize} has been got.`, + ); + } + + data.data_chunk_size = chunkSize; + }, + }, + dataChunkType: { + get: () => data.data_compressed_chunk_type, + }, })); // When we call a function, for example: task.annotations.get() @@ -1206,6 +1260,7 @@ this.frames = { get: Object.getPrototypeOf(this).frames.get.bind(this), + ranges: Object.getPrototypeOf(this).frames.ranges.bind(this), preview: Object.getPrototypeOf(this).frames.preview.bind(this), }; @@ -1297,7 +1352,7 @@ ); }; - Job.prototype.frames.get.implementation = async function (frame) { + Job.prototype.frames.get.implementation = async function (frame, isPlaying, step) { if (!Number.isInteger(frame) || frame < 0) { throw new ArgumentError( `Frame must be a positive integer. Got: "${frame}"`, @@ -1310,13 +1365,25 @@ ); } - const frameData = await getFrame(this.task.id, this.task.mode, frame); + const frameData = await getFrame( + this.task.id, + this.task.dataChunkSize, + this.task.dataChunkType, + this.task.mode, + frame, + this.startFrame, + this.stopFrame, + isPlaying, + step, + ); return frameData; }; - Job.prototype.frames.preview.implementation = async function () { - const frameData = await getPreview(this.task.id); - return frameData; + Job.prototype.frames.ranges.implementation = async function () { + const rangesData = await getRanges( + this.task.id, + ); + return rangesData; }; // TODO: Check filter for annotations @@ -1473,39 +1540,44 @@ return this; } - const taskData = { + const taskSpec = { name: this.name, labels: this.labels.map((el) => el.toJSON()), - image_quality: this.imageQuality, z_order: Boolean(this.zOrder), }; if (typeof (this.bugTracker) !== 'undefined') { - taskData.bug_tracker = this.bugTracker; + taskSpec.bug_tracker = this.bugTracker; } if (typeof (this.segmentSize) !== 'undefined') { - taskData.segment_size = this.segmentSize; + taskSpec.segment_size = this.segmentSize; } if (typeof (this.overlap) !== 'undefined') { - taskData.overlap = this.overlap; + taskSpec.overlap = this.overlap; } + + const taskDataSpec = { + client_files: this.clientFiles, + server_files: this.serverFiles, + remote_files: this.remoteFiles, + image_quality: this.imageQuality, + use_zip_chunks: this.useZipChunks, + }; + if (typeof (this.startFrame) !== 'undefined') { - taskData.start_frame = this.startFrame; + taskDataSpec.start_frame = this.startFrame; } if (typeof (this.stopFrame) !== 'undefined') { - taskData.stop_frame = this.stopFrame; + taskDataSpec.stop_frame = this.stopFrame; } if (typeof (this.frameFilter) !== 'undefined') { - taskData.frame_filter = this.frameFilter; + taskDataSpec.frame_filter = this.frameFilter; + } + if (typeof (this.dataChunkSize) !== 'undefined') { + taskDataSpec.chunk_size = this.dataChunkSize; } - const taskFiles = { - client_files: this.clientFiles, - server_files: this.serverFiles, - remote_files: this.remoteFiles, - }; - - const task = await serverProxy.tasks.createTask(taskData, taskFiles, onUpdate); + const task = await serverProxy.tasks.createTask(taskSpec, taskDataSpec, onUpdate); return new Task(task); }; @@ -1514,7 +1586,7 @@ return result; }; - Task.prototype.frames.get.implementation = async function (frame) { + Task.prototype.frames.get.implementation = async function (frame, isPlaying, step) { if (!Number.isInteger(frame) || frame < 0) { throw new ArgumentError( `Frame must be a positive integer. Got: "${frame}"`, @@ -1527,10 +1599,32 @@ ); } - const result = await getFrame(this.id, this.mode, frame); + const result = await getFrame( + this.id, + this.dataChunkSize, + this.dataChunkType, + this.mode, + frame, + 0, + this.size - 1, + isPlaying, + step, + ); return result; }; + Job.prototype.frames.preview.implementation = async function () { + const frameData = await getPreview(this.task.id); + return frameData; + }; + + Task.prototype.frames.ranges.implementation = async function () { + const rangesData = await getRanges( + this.id, + ); + return rangesData; + }; + Task.prototype.frames.preview.implementation = async function () { const frameData = await getPreview(this.id); return frameData; diff --git a/cvat-core/tests/mocks/dummy-data.mock.js b/cvat-core/tests/mocks/dummy-data.mock.js index e8449c06..b4a6ea22 100644 --- a/cvat-core/tests/mocks/dummy-data.mock.js +++ b/cvat-core/tests/mocks/dummy-data.mock.js @@ -2522,78 +2522,126 @@ const taskAnnotationsDummyData = { const jobAnnotationsDummyData = JSON.parse(JSON.stringify(taskAnnotationsDummyData)); const frameMetaDummyData = { - 1: [{ - "width": 1920, - "height": 1080 - }, { - "width": 1600, - "height": 1143 - }, { - "width": 1600, - "height": 859 - }, { - "width": 3840, - "height": 2160 - }, { - "width": 2560, - "height": 1920 - }, { - "width": 1920, - "height": 1080 - }, { - "width": 1920, - "height": 1080 - }, { - "width": 700, - "height": 453 - }, { - "width": 1920, - "height": 1200 - }], - 2: [{ - "width": 1920, - "height": 1080 - }], - 3: [{ - "width": 1888, - "height": 1408 - }], - 100: [{ - "width": 1920, - "height": 1080 - }, { - "width": 1600, - "height": 1143 - }, { - "width": 1600, - "height": 859 - }, { - "width": 3840, - "height": 2160 - }, { - "width": 2560, - "height": 1920 - }, { - "width": 1920, - "height": 1080 - }, { - "width": 1920, - "height": 1080 - }, { - "width": 700, - "height": 453 - }, { - "width": 1920, - "height": 1200 - }], - 101: [{ - "width": 1888, - "height": 1408 - }], - 102: [{ - "width":1920, - "height":1080 - }], + 1: { + "chunk_size": 36, + "size": 9, + "image_quality": 95, + "start_frame": 0, + "stop_frame": 8, + "frame_filter": "", + "frames":[{ + "width": 1920, + "height": 1080 + }, { + "width": 1600, + "height": 1143 + }, { + "width": 1600, + "height": 859 + }, { + "width": 3840, + "height": 2160 + }, { + "width": 2560, + "height": 1920 + }, { + "width": 1920, + "height": 1080 + }, { + "width": 1920, + "height": 1080 + }, { + "width": 700, + "height": 453 + }, { + "width": 1920, + "height": 1200 + }], + }, + 2: { + "chunk_size": 36, + "size": 75, + "image_quality": 50, + "start_frame": 0, + "stop_frame": 74, + "frame_filter": "", + "frames": [{ + "width": 1920, + "height": 1080 + }], + }, + 3: { + "chunk_size": 36, + "size": 5002, + "image_quality": 50, + "start_frame": 0, + "stop_frame": 5001, + "frame_filter": "", + "frames": [{ + "width": 1888, + "height": 1408 + }], + }, + 100: { + "chunk_size": 36, + "size": 9, + "image_quality": 50, + "start_frame": 0, + "stop_frame": 8, + "frame_filter": "", + "frames": [{ + "width": 1920, + "height": 1080 + }, { + "width": 1600, + "height": 1143 + }, { + "width": 1600, + "height": 859 + }, { + "width": 3840, + "height": 2160 + }, { + "width": 2560, + "height": 1920 + }, { + "width": 1920, + "height": 1080 + }, { + "width": 1920, + "height": 1080 + }, { + "width": 700, + "height": 453 + }, { + "width": 1920, + "height": 1200 + }], + }, + 101: { + "chunk_size": 36, + "size": 5002, + "image_quality": 50, + "start_frame": 0, + "stop_frame": 5001, + "frame_filter": "", + "frames": [{ + "width": 1888, + "height": 1408 + }], + }, + 102: { + "chunk_size": 36, + "size": 1, + "image_quality": 50, + "start_frame": 0, + "stop_frame": 0, + "frame_filter": "", + "frames": [{ + "width":1920, + "height":1080 + }], + }, } module.exports = { @@ -2606,3 +2654,4 @@ module.exports = { frameMetaDummyData, formatsDummyData, } + diff --git a/cvat-core/webpack.config.js b/cvat-core/webpack.config.js index be9464f5..6e16f46a 100644 --- a/cvat-core/webpack.config.js +++ b/cvat-core/webpack.config.js @@ -46,13 +46,33 @@ const webConfig = { options: { presets: [ ['@babel/preset-env', { - targets: '> 2.5%', // https://github.com/browserslist/browserslist + targets: '> 2.5%', }], ], sourceType: 'unambiguous', }, }, - }], + }, { + test: /3rdparty\/.*\.worker\.js$/, + use: { + loader: 'worker-loader', + options: { + publicPath: '/static/engine/js/3rdparty/', + name: '[name].js', + }, + }, + }, { + test: /\.worker\.js$/, + exclude: /3rdparty/, + use: { + loader: 'worker-loader', + options: { + publicPath: '/static/engine/js/', + name: '[name].js', + }, + }, + }, + ], }, }; diff --git a/cvat-data/.eslintignore b/cvat-data/.eslintignore new file mode 100644 index 00000000..dbec6390 --- /dev/null +++ b/cvat-data/.eslintignore @@ -0,0 +1 @@ +**/3rdparty/*.js diff --git a/cvat-data/.eslintrc.js b/cvat-data/.eslintrc.js new file mode 100644 index 00000000..3dca50a3 --- /dev/null +++ b/cvat-data/.eslintrc.js @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2018-2020 Intel Corporation + * + * SPDX-License-Identifier: MIT + */ + +module.exports = { + "env": { + "node": false, + "browser": true, + "es6": true, + "jquery": true, + "qunit": true, + }, + "parserOptions": { + "parser": "babel-eslint", + "sourceType": "module", + "ecmaVersion": 2018, + }, + "plugins": [ + "security", + "no-unsanitized", + "no-unsafe-innerhtml", + ], + "extends": [ + "eslint:recommended", + "plugin:security/recommended", + "plugin:no-unsanitized/DOM", + "airbnb-base", + ], + "rules": { + "no-await-in-loop": [0], + "global-require": [0], + "no-new": [0], + "class-methods-use-this": [0], + "no-restricted-properties": [0, { + "object": "Math", + "property": "pow", + }], + "no-plusplus": [0], + "no-param-reassign": [0], + "no-underscore-dangle": ["error", { "allowAfterThis": true }], + "no-restricted-syntax": [0, {"selector": "ForOfStatement"}], + "no-continue": [0], + "no-unsafe-innerhtml/no-unsafe-innerhtml": 1, + // This rule actual for user input data on the node.js environment mainly. + "security/detect-object-injection": 0, + "indent": ["warn", 4], + "no-useless-constructor": 0, + "func-names": [0], + "valid-typeof": [0], + "no-console": [0], // this rule deprecates console.log, console.warn etc. because "it is not good in production code" + "max-classes-per-file": [0], + "quotes": ["warn", "single"], + }, +}; diff --git a/cvat-data/.gitignore b/cvat-data/.gitignore new file mode 100644 index 00000000..1521c8b7 --- /dev/null +++ b/cvat-data/.gitignore @@ -0,0 +1 @@ +dist diff --git a/cvat-data/README.md b/cvat-data/README.md new file mode 100644 index 00000000..ef803264 --- /dev/null +++ b/cvat-data/README.md @@ -0,0 +1,7 @@ +# cvat-data module + +```bash +npm run build # build with minification +npm run build -- --mode=development # build without minification +npm run server # run debug server +``` diff --git a/cvat-data/package-lock.json b/cvat-data/package-lock.json new file mode 100644 index 00000000..e5335a5d --- /dev/null +++ b/cvat-data/package-lock.json @@ -0,0 +1,8109 @@ +{ + "name": "cvat-data", + "version": "0.1.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@babel/cli": { + "version": "7.6.4", + "resolved": "https://registry.npmjs.org/@babel/cli/-/cli-7.6.4.tgz", + "integrity": "sha512-tqrDyvPryBM6xjIyKKUwr3s8CzmmYidwgdswd7Uc/Cv0ogZcuS1TYQTLx/eWKP3UbJ6JxZAiYlBZabXm/rtRsQ==", + "dev": true, + "requires": { + "chokidar": "^2.1.8", + "commander": "^2.8.1", + "convert-source-map": "^1.1.0", + "fs-readdir-recursive": "^1.1.0", + "glob": "^7.0.0", + "lodash": "^4.17.13", + "mkdirp": "^0.5.1", + "output-file-sync": "^2.0.0", + "slash": "^2.0.0", + "source-map": "^0.5.0" + } + }, + "@babel/code-frame": { + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.5.5.tgz", + "integrity": "sha512-27d4lZoomVyo51VegxI20xZPuSHusqbQag/ztrBC7wegWoQ1nLREPVSKSW8byhTlzTKyNE4ifaTA6lCp7JjpFw==", + "dev": true, + "requires": { + "@babel/highlight": "^7.0.0" + } + }, + "@babel/core": { + "version": "7.6.4", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.6.4.tgz", + "integrity": "sha512-Rm0HGw101GY8FTzpWSyRbki/jzq+/PkNQJ+nSulrdY6gFGOsNseCqD6KHRYe2E+EdzuBdr2pxCp6s4Uk6eJ+XQ==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.5.5", + "@babel/generator": "^7.6.4", + "@babel/helpers": "^7.6.2", + "@babel/parser": "^7.6.4", + "@babel/template": "^7.6.0", + "@babel/traverse": "^7.6.3", + "@babel/types": "^7.6.3", + "convert-source-map": "^1.1.0", + "debug": "^4.1.0", + "json5": "^2.1.0", + "lodash": "^4.17.13", + "resolve": "^1.3.2", + "semver": "^5.4.1", + "source-map": "^0.5.0" + }, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + } + } + }, + "@babel/generator": { + "version": "7.6.4", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.6.4.tgz", + "integrity": "sha512-jsBuXkFoZxk0yWLyGI9llT9oiQ2FeTASmRFE32U+aaDTfoE92t78eroO7PTpU/OrYq38hlcDM6vbfLDaOLy+7w==", + "dev": true, + "requires": { + "@babel/types": "^7.6.3", + "jsesc": "^2.5.1", + "lodash": "^4.17.13", + "source-map": "^0.5.0" + } + }, + "@babel/helper-annotate-as-pure": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.0.0.tgz", + "integrity": "sha512-3UYcJUj9kvSLbLbUIfQTqzcy5VX7GRZ/CCDrnOaZorFFM01aXp1+GJwuFGV4NDDoAS+mOUyHcO6UD/RfqOks3Q==", + "dev": true, + "requires": { + "@babel/types": "^7.0.0" + } + }, + "@babel/helper-builder-binary-assignment-operator-visitor": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.1.0.tgz", + "integrity": "sha512-qNSR4jrmJ8M1VMM9tibvyRAHXQs2PmaksQF7c1CGJNipfe3D8p+wgNwgso/P2A2r2mdgBWAXljNWR0QRZAMW8w==", + "dev": true, + "requires": { + "@babel/helper-explode-assignable-expression": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "@babel/helper-call-delegate": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/helper-call-delegate/-/helper-call-delegate-7.4.4.tgz", + "integrity": "sha512-l79boDFJ8S1c5hvQvG+rc+wHw6IuH7YldmRKsYtpbawsxURu/paVy57FZMomGK22/JckepaikOkY0MoAmdyOlQ==", + "dev": true, + "requires": { + "@babel/helper-hoist-variables": "^7.4.4", + "@babel/traverse": "^7.4.4", + "@babel/types": "^7.4.4" + } + }, + "@babel/helper-define-map": { + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/@babel/helper-define-map/-/helper-define-map-7.5.5.tgz", + "integrity": "sha512-fTfxx7i0B5NJqvUOBBGREnrqbTxRh7zinBANpZXAVDlsZxYdclDp467G1sQ8VZYMnAURY3RpBUAgOYT9GfzHBg==", + "dev": true, + "requires": { + "@babel/helper-function-name": "^7.1.0", + "@babel/types": "^7.5.5", + "lodash": "^4.17.13" + } + }, + "@babel/helper-explode-assignable-expression": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.1.0.tgz", + "integrity": "sha512-NRQpfHrJ1msCHtKjbzs9YcMmJZOg6mQMmGRB+hbamEdG5PNpaSm95275VD92DvJKuyl0s2sFiDmMZ+EnnvufqA==", + "dev": true, + "requires": { + "@babel/traverse": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "@babel/helper-function-name": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.1.0.tgz", + "integrity": "sha512-A95XEoCpb3TO+KZzJ4S/5uW5fNe26DjBGqf1o9ucyLyCmi1dXq/B3c8iaWTfBk3VvetUxl16e8tIrd5teOCfGw==", + "dev": true, + "requires": { + "@babel/helper-get-function-arity": "^7.0.0", + "@babel/template": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "@babel/helper-get-function-arity": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.0.0.tgz", + "integrity": "sha512-r2DbJeg4svYvt3HOS74U4eWKsUAMRH01Z1ds1zx8KNTPtpTL5JAsdFv8BNyOpVqdFhHkkRDIg5B4AsxmkjAlmQ==", + "dev": true, + "requires": { + "@babel/types": "^7.0.0" + } + }, + "@babel/helper-hoist-variables": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.4.4.tgz", + "integrity": "sha512-VYk2/H/BnYbZDDg39hr3t2kKyifAm1W6zHRfhx8jGjIHpQEBv9dry7oQ2f3+J703TLu69nYdxsovl0XYfcnK4w==", + "dev": true, + "requires": { + "@babel/types": "^7.4.4" + } + }, + "@babel/helper-member-expression-to-functions": { + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.5.5.tgz", + "integrity": "sha512-5qZ3D1uMclSNqYcXqiHoA0meVdv+xUEex9em2fqMnrk/scphGlGgg66zjMrPJESPwrFJ6sbfFQYUSa0Mz7FabA==", + "dev": true, + "requires": { + "@babel/types": "^7.5.5" + } + }, + "@babel/helper-module-imports": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.0.0.tgz", + "integrity": "sha512-aP/hlLq01DWNEiDg4Jn23i+CXxW/owM4WpDLFUbpjxe4NS3BhLVZQ5i7E0ZrxuQ/vwekIeciyamgB1UIYxxM6A==", + "dev": true, + "requires": { + "@babel/types": "^7.0.0" + } + }, + "@babel/helper-module-transforms": { + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.5.5.tgz", + "integrity": "sha512-jBeCvETKuJqeiaCdyaheF40aXnnU1+wkSiUs/IQg3tB85up1LyL8x77ClY8qJpuRJUcXQo+ZtdNESmZl4j56Pw==", + "dev": true, + "requires": { + "@babel/helper-module-imports": "^7.0.0", + "@babel/helper-simple-access": "^7.1.0", + "@babel/helper-split-export-declaration": "^7.4.4", + "@babel/template": "^7.4.4", + "@babel/types": "^7.5.5", + "lodash": "^4.17.13" + } + }, + "@babel/helper-optimise-call-expression": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.0.0.tgz", + "integrity": "sha512-u8nd9NQePYNQV8iPWu/pLLYBqZBa4ZaY1YWRFMuxrid94wKI1QNt67NEZ7GAe5Kc/0LLScbim05xZFWkAdrj9g==", + "dev": true, + "requires": { + "@babel/types": "^7.0.0" + } + }, + "@babel/helper-plugin-utils": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.0.0.tgz", + "integrity": "sha512-CYAOUCARwExnEixLdB6sDm2dIJ/YgEAKDM1MOeMeZu9Ld/bDgVo8aiWrXwcY7OBh+1Ea2uUcVRcxKk0GJvW7QA==", + "dev": true + }, + "@babel/helper-regex": { + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/@babel/helper-regex/-/helper-regex-7.5.5.tgz", + "integrity": "sha512-CkCYQLkfkiugbRDO8eZn6lRuR8kzZoGXCg3149iTk5se7g6qykSpy3+hELSwquhu+TgHn8nkLiBwHvNX8Hofcw==", + "dev": true, + "requires": { + "lodash": "^4.17.13" + } + }, + "@babel/helper-remap-async-to-generator": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.1.0.tgz", + "integrity": "sha512-3fOK0L+Fdlg8S5al8u/hWE6vhufGSn0bN09xm2LXMy//REAF8kDCrYoOBKYmA8m5Nom+sV9LyLCwrFynA8/slg==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.0.0", + "@babel/helper-wrap-function": "^7.1.0", + "@babel/template": "^7.1.0", + "@babel/traverse": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "@babel/helper-replace-supers": { + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.5.5.tgz", + "integrity": "sha512-XvRFWrNnlsow2u7jXDuH4jDDctkxbS7gXssrP4q2nUD606ukXHRvydj346wmNg+zAgpFx4MWf4+usfC93bElJg==", + "dev": true, + "requires": { + "@babel/helper-member-expression-to-functions": "^7.5.5", + "@babel/helper-optimise-call-expression": "^7.0.0", + "@babel/traverse": "^7.5.5", + "@babel/types": "^7.5.5" + } + }, + "@babel/helper-simple-access": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.1.0.tgz", + "integrity": "sha512-Vk+78hNjRbsiu49zAPALxTb+JUQCz1aolpd8osOF16BGnLtseD21nbHgLPGUwrXEurZgiCOUmvs3ExTu4F5x6w==", + "dev": true, + "requires": { + "@babel/template": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.4.4.tgz", + "integrity": "sha512-Ro/XkzLf3JFITkW6b+hNxzZ1n5OQ80NvIUdmHspih1XAhtN3vPTuUFT4eQnela+2MaZ5ulH+iyP513KJrxbN7Q==", + "dev": true, + "requires": { + "@babel/types": "^7.4.4" + } + }, + "@babel/helper-wrap-function": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.2.0.tgz", + "integrity": "sha512-o9fP1BZLLSrYlxYEYyl2aS+Flun5gtjTIG8iln+XuEzQTs0PLagAGSXUcqruJwD5fM48jzIEggCKpIfWTcR7pQ==", + "dev": true, + "requires": { + "@babel/helper-function-name": "^7.1.0", + "@babel/template": "^7.1.0", + "@babel/traverse": "^7.1.0", + "@babel/types": "^7.2.0" + } + }, + "@babel/helpers": { + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.6.2.tgz", + "integrity": "sha512-3/bAUL8zZxYs1cdX2ilEE0WobqbCmKWr/889lf2SS0PpDcpEIY8pb1CCyz0pEcX3pEb+MCbks1jIokz2xLtGTA==", + "dev": true, + "requires": { + "@babel/template": "^7.6.0", + "@babel/traverse": "^7.6.2", + "@babel/types": "^7.6.0" + } + }, + "@babel/highlight": { + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.5.0.tgz", + "integrity": "sha512-7dV4eu9gBxoM0dAnj/BCFDW9LFU0zvTrkq0ugM7pnHEgguOEeOz1so2ZghEdzviYzQEED0r4EAgpsBChKy1TRQ==", + "dev": true, + "requires": { + "chalk": "^2.0.0", + "esutils": "^2.0.2", + "js-tokens": "^4.0.0" + } + }, + "@babel/parser": { + "version": "7.6.4", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.6.4.tgz", + "integrity": "sha512-D8RHPW5qd0Vbyo3qb+YjO5nvUVRTXFLQ/FsDxJU2Nqz4uB5EnUN0ZQSEYpvTIbRuttig1XbHWU5oMeQwQSAA+A==", + "dev": true + }, + "@babel/plugin-proposal-async-generator-functions": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.2.0.tgz", + "integrity": "sha512-+Dfo/SCQqrwx48ptLVGLdE39YtWRuKc/Y9I5Fy0P1DDBB9lsAHpjcEJQt+4IifuSOSTLBKJObJqMvaO1pIE8LQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-remap-async-to-generator": "^7.1.0", + "@babel/plugin-syntax-async-generators": "^7.2.0" + } + }, + "@babel/plugin-proposal-dynamic-import": { + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.5.0.tgz", + "integrity": "sha512-x/iMjggsKTFHYC6g11PL7Qy58IK8H5zqfm9e6hu4z1iH2IRyAp9u9dL80zA6R76yFovETFLKz2VJIC2iIPBuFw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-syntax-dynamic-import": "^7.2.0" + } + }, + "@babel/plugin-proposal-json-strings": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.2.0.tgz", + "integrity": "sha512-MAFV1CA/YVmYwZG0fBQyXhmj0BHCB5egZHCKWIFVv/XCxAeVGIHfos3SwDck4LvCllENIAg7xMKOG5kH0dzyUg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-syntax-json-strings": "^7.2.0" + } + }, + "@babel/plugin-proposal-object-rest-spread": { + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.6.2.tgz", + "integrity": "sha512-LDBXlmADCsMZV1Y9OQwMc0MyGZ8Ta/zlD9N67BfQT8uYwkRswiu2hU6nJKrjrt/58aH/vqfQlR/9yId/7A2gWw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-syntax-object-rest-spread": "^7.2.0" + } + }, + "@babel/plugin-proposal-optional-catch-binding": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.2.0.tgz", + "integrity": "sha512-mgYj3jCcxug6KUcX4OBoOJz3CMrwRfQELPQ5560F70YQUBZB7uac9fqaWamKR1iWUzGiK2t0ygzjTScZnVz75g==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-syntax-optional-catch-binding": "^7.2.0" + } + }, + "@babel/plugin-proposal-unicode-property-regex": { + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.6.2.tgz", + "integrity": "sha512-NxHETdmpeSCtiatMRYWVJo7266rrvAC3DTeG5exQBIH/fMIUK7ejDNznBbn3HQl/o9peymRRg7Yqkx6PdUXmMw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-regex": "^7.4.4", + "regexpu-core": "^4.6.0" + } + }, + "@babel/plugin-syntax-async-generators": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.2.0.tgz", + "integrity": "sha512-1ZrIRBv2t0GSlcwVoQ6VgSLpLgiN/FVQUzt9znxo7v2Ov4jJrs8RY8tv0wvDmFN3qIdMKWrmMMW6yZ0G19MfGg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-syntax-dynamic-import": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.2.0.tgz", + "integrity": "sha512-mVxuJ0YroI/h/tbFTPGZR8cv6ai+STMKNBq0f8hFxsxWjl94qqhsb+wXbpNMDPU3cfR1TIsVFzU3nXyZMqyK4w==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-syntax-json-strings": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.2.0.tgz", + "integrity": "sha512-5UGYnMSLRE1dqqZwug+1LISpA403HzlSfsg6P9VXU6TBjcSHeNlw4DxDx7LgpF+iKZoOG/+uzqoRHTdcUpiZNg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-syntax-object-rest-spread": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.2.0.tgz", + "integrity": "sha512-t0JKGgqk2We+9may3t0xDdmneaXmyxq0xieYcKHxIsrJO64n1OiMWNUtc5gQK1PA0NpdCRrtZp4z+IUaKugrSA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-syntax-optional-catch-binding": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.2.0.tgz", + "integrity": "sha512-bDe4xKNhb0LI7IvZHiA13kff0KEfaGX/Hv4lMA9+7TEc63hMNvfKo6ZFpXhKuEp+II/q35Gc4NoMeDZyaUbj9w==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-arrow-functions": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.2.0.tgz", + "integrity": "sha512-ER77Cax1+8/8jCB9fo4Ud161OZzWN5qawi4GusDuRLcDbDG+bIGYY20zb2dfAFdTRGzrfq2xZPvF0R64EHnimg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-async-to-generator": { + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.5.0.tgz", + "integrity": "sha512-mqvkzwIGkq0bEF1zLRRiTdjfomZJDV33AH3oQzHVGkI2VzEmXLpKKOBvEVaFZBJdN0XTyH38s9j/Kiqr68dggg==", + "dev": true, + "requires": { + "@babel/helper-module-imports": "^7.0.0", + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-remap-async-to-generator": "^7.1.0" + } + }, + "@babel/plugin-transform-block-scoped-functions": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.2.0.tgz", + "integrity": "sha512-ntQPR6q1/NKuphly49+QiQiTN0O63uOwjdD6dhIjSWBI5xlrbUFh720TIpzBhpnrLfv2tNH/BXvLIab1+BAI0w==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-block-scoping": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.6.3.tgz", + "integrity": "sha512-7hvrg75dubcO3ZI2rjYTzUrEuh1E9IyDEhhB6qfcooxhDA33xx2MasuLVgdxzcP6R/lipAC6n9ub9maNW6RKdw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "lodash": "^4.17.13" + } + }, + "@babel/plugin-transform-classes": { + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.5.5.tgz", + "integrity": "sha512-U2htCNK/6e9K7jGyJ++1p5XRU+LJjrwtoiVn9SzRlDT2KubcZ11OOwy3s24TjHxPgxNwonCYP7U2K51uVYCMDg==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.0.0", + "@babel/helper-define-map": "^7.5.5", + "@babel/helper-function-name": "^7.1.0", + "@babel/helper-optimise-call-expression": "^7.0.0", + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-replace-supers": "^7.5.5", + "@babel/helper-split-export-declaration": "^7.4.4", + "globals": "^11.1.0" + } + }, + "@babel/plugin-transform-computed-properties": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.2.0.tgz", + "integrity": "sha512-kP/drqTxY6Xt3NNpKiMomfgkNn4o7+vKxK2DDKcBG9sHj51vHqMBGy8wbDS/J4lMxnqs153/T3+DmCEAkC5cpA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-destructuring": { + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.6.0.tgz", + "integrity": "sha512-2bGIS5P1v4+sWTCnKNDZDxbGvEqi0ijeqM/YqHtVGrvG2y0ySgnEEhXErvE9dA0bnIzY9bIzdFK0jFA46ASIIQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-dotall-regex": { + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.6.2.tgz", + "integrity": "sha512-KGKT9aqKV+9YMZSkowzYoYEiHqgaDhGmPNZlZxX6UeHC4z30nC1J9IrZuGqbYFB1jaIGdv91ujpze0exiVK8bA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-regex": "^7.4.4", + "regexpu-core": "^4.6.0" + } + }, + "@babel/plugin-transform-duplicate-keys": { + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.5.0.tgz", + "integrity": "sha512-igcziksHizyQPlX9gfSjHkE2wmoCH3evvD2qR5w29/Dk0SMKE/eOI7f1HhBdNhR/zxJDqrgpoDTq5YSLH/XMsQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-exponentiation-operator": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.2.0.tgz", + "integrity": "sha512-umh4hR6N7mu4Elq9GG8TOu9M0bakvlsREEC+ialrQN6ABS4oDQ69qJv1VtR3uxlKMCQMCvzk7vr17RHKcjx68A==", + "dev": true, + "requires": { + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.1.0", + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-for-of": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.4.4.tgz", + "integrity": "sha512-9T/5Dlr14Z9TIEXLXkt8T1DU7F24cbhwhMNUziN3hB1AXoZcdzPcTiKGRn/6iOymDqtTKWnr/BtRKN9JwbKtdQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-function-name": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.4.4.tgz", + "integrity": "sha512-iU9pv7U+2jC9ANQkKeNF6DrPy4GBa4NWQtl6dHB4Pb3izX2JOEvDTFarlNsBj/63ZEzNNIAMs3Qw4fNCcSOXJA==", + "dev": true, + "requires": { + "@babel/helper-function-name": "^7.1.0", + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-literals": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.2.0.tgz", + "integrity": "sha512-2ThDhm4lI4oV7fVQ6pNNK+sx+c/GM5/SaML0w/r4ZB7sAneD/piDJtwdKlNckXeyGK7wlwg2E2w33C/Hh+VFCg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-member-expression-literals": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.2.0.tgz", + "integrity": "sha512-HiU3zKkSU6scTidmnFJ0bMX8hz5ixC93b4MHMiYebmk2lUVNGOboPsqQvx5LzooihijUoLR/v7Nc1rbBtnc7FA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-modules-amd": { + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.5.0.tgz", + "integrity": "sha512-n20UsQMKnWrltocZZm24cRURxQnWIvsABPJlw/fvoy9c6AgHZzoelAIzajDHAQrDpuKFFPPcFGd7ChsYuIUMpg==", + "dev": true, + "requires": { + "@babel/helper-module-transforms": "^7.1.0", + "@babel/helper-plugin-utils": "^7.0.0", + "babel-plugin-dynamic-import-node": "^2.3.0" + } + }, + "@babel/plugin-transform-modules-commonjs": { + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.6.0.tgz", + "integrity": "sha512-Ma93Ix95PNSEngqomy5LSBMAQvYKVe3dy+JlVJSHEXZR5ASL9lQBedMiCyVtmTLraIDVRE3ZjTZvmXXD2Ozw3g==", + "dev": true, + "requires": { + "@babel/helper-module-transforms": "^7.4.4", + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-simple-access": "^7.1.0", + "babel-plugin-dynamic-import-node": "^2.3.0" + } + }, + "@babel/plugin-transform-modules-systemjs": { + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.5.0.tgz", + "integrity": "sha512-Q2m56tyoQWmuNGxEtUyeEkm6qJYFqs4c+XyXH5RAuYxObRNz9Zgj/1g2GMnjYp2EUyEy7YTrxliGCXzecl/vJg==", + "dev": true, + "requires": { + "@babel/helper-hoist-variables": "^7.4.4", + "@babel/helper-plugin-utils": "^7.0.0", + "babel-plugin-dynamic-import-node": "^2.3.0" + } + }, + "@babel/plugin-transform-modules-umd": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.2.0.tgz", + "integrity": "sha512-BV3bw6MyUH1iIsGhXlOK6sXhmSarZjtJ/vMiD9dNmpY8QXFFQTj+6v92pcfy1iqa8DeAfJFwoxcrS/TUZda6sw==", + "dev": true, + "requires": { + "@babel/helper-module-transforms": "^7.1.0", + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-named-capturing-groups-regex": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.6.3.tgz", + "integrity": "sha512-jTkk7/uE6H2s5w6VlMHeWuH+Pcy2lmdwFoeWCVnvIrDUnB5gQqTVI8WfmEAhF2CDEarGrknZcmSFg1+bkfCoSw==", + "dev": true, + "requires": { + "regexpu-core": "^4.6.0" + } + }, + "@babel/plugin-transform-new-target": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.4.4.tgz", + "integrity": "sha512-r1z3T2DNGQwwe2vPGZMBNjioT2scgWzK9BCnDEh+46z8EEwXBq24uRzd65I7pjtugzPSj921aM15RpESgzsSuA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-object-super": { + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.5.5.tgz", + "integrity": "sha512-un1zJQAhSosGFBduPgN/YFNvWVpRuHKU7IHBglLoLZsGmruJPOo6pbInneflUdmq7YvSVqhpPs5zdBvLnteltQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-replace-supers": "^7.5.5" + } + }, + "@babel/plugin-transform-parameters": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.4.4.tgz", + "integrity": "sha512-oMh5DUO1V63nZcu/ZVLQFqiihBGo4OpxJxR1otF50GMeCLiRx5nUdtokd+u9SuVJrvvuIh9OosRFPP4pIPnwmw==", + "dev": true, + "requires": { + "@babel/helper-call-delegate": "^7.4.4", + "@babel/helper-get-function-arity": "^7.0.0", + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-property-literals": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.2.0.tgz", + "integrity": "sha512-9q7Dbk4RhgcLp8ebduOpCbtjh7C0itoLYHXd9ueASKAG/is5PQtMR5VJGka9NKqGhYEGn5ITahd4h9QeBMylWQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-regenerator": { + "version": "7.4.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.4.5.tgz", + "integrity": "sha512-gBKRh5qAaCWntnd09S8QC7r3auLCqq5DI6O0DlfoyDjslSBVqBibrMdsqO+Uhmx3+BlOmE/Kw1HFxmGbv0N9dA==", + "dev": true, + "requires": { + "regenerator-transform": "^0.14.0" + } + }, + "@babel/plugin-transform-reserved-words": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.2.0.tgz", + "integrity": "sha512-fz43fqW8E1tAB3DKF19/vxbpib1fuyCwSPE418ge5ZxILnBhWyhtPgz8eh1RCGGJlwvksHkyxMxh0eenFi+kFw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-shorthand-properties": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.2.0.tgz", + "integrity": "sha512-QP4eUM83ha9zmYtpbnyjTLAGKQritA5XW/iG9cjtuOI8s1RuL/3V6a3DeSHfKutJQ+ayUfeZJPcnCYEQzaPQqg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-spread": { + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.6.2.tgz", + "integrity": "sha512-DpSvPFryKdK1x+EDJYCy28nmAaIMdxmhot62jAXF/o99iA33Zj2Lmcp3vDmz+MUh0LNYVPvfj5iC3feb3/+PFg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-sticky-regex": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.2.0.tgz", + "integrity": "sha512-KKYCoGaRAf+ckH8gEL3JHUaFVyNHKe3ASNsZ+AlktgHevvxGigoIttrEJb8iKN03Q7Eazlv1s6cx2B2cQ3Jabw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-regex": "^7.0.0" + } + }, + "@babel/plugin-transform-template-literals": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.4.4.tgz", + "integrity": "sha512-mQrEC4TWkhLN0z8ygIvEL9ZEToPhG5K7KDW3pzGqOfIGZ28Jb0POUkeWcoz8HnHvhFy6dwAT1j8OzqN8s804+g==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.0.0", + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-typeof-symbol": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.2.0.tgz", + "integrity": "sha512-2LNhETWYxiYysBtrBTqL8+La0jIoQQnIScUJc74OYvUGRmkskNY4EzLCnjHBzdmb38wqtTaixpo1NctEcvMDZw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-unicode-regex": { + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.6.2.tgz", + "integrity": "sha512-orZI6cWlR3nk2YmYdb0gImrgCUwb5cBUwjf6Ks6dvNVvXERkwtJWOQaEOjPiu0Gu1Tq6Yq/hruCZZOOi9F34Dw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-regex": "^7.4.4", + "regexpu-core": "^4.6.0" + } + }, + "@babel/preset-env": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.6.3.tgz", + "integrity": "sha512-CWQkn7EVnwzlOdR5NOm2+pfgSNEZmvGjOhlCHBDq0J8/EStr+G+FvPEiz9B56dR6MoiUFjXhfE4hjLoAKKJtIQ==", + "dev": true, + "requires": { + "@babel/helper-module-imports": "^7.0.0", + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-proposal-async-generator-functions": "^7.2.0", + "@babel/plugin-proposal-dynamic-import": "^7.5.0", + "@babel/plugin-proposal-json-strings": "^7.2.0", + "@babel/plugin-proposal-object-rest-spread": "^7.6.2", + "@babel/plugin-proposal-optional-catch-binding": "^7.2.0", + "@babel/plugin-proposal-unicode-property-regex": "^7.6.2", + "@babel/plugin-syntax-async-generators": "^7.2.0", + "@babel/plugin-syntax-dynamic-import": "^7.2.0", + "@babel/plugin-syntax-json-strings": "^7.2.0", + "@babel/plugin-syntax-object-rest-spread": "^7.2.0", + "@babel/plugin-syntax-optional-catch-binding": "^7.2.0", + "@babel/plugin-transform-arrow-functions": "^7.2.0", + "@babel/plugin-transform-async-to-generator": "^7.5.0", + "@babel/plugin-transform-block-scoped-functions": "^7.2.0", + "@babel/plugin-transform-block-scoping": "^7.6.3", + "@babel/plugin-transform-classes": "^7.5.5", + "@babel/plugin-transform-computed-properties": "^7.2.0", + "@babel/plugin-transform-destructuring": "^7.6.0", + "@babel/plugin-transform-dotall-regex": "^7.6.2", + "@babel/plugin-transform-duplicate-keys": "^7.5.0", + "@babel/plugin-transform-exponentiation-operator": "^7.2.0", + "@babel/plugin-transform-for-of": "^7.4.4", + "@babel/plugin-transform-function-name": "^7.4.4", + "@babel/plugin-transform-literals": "^7.2.0", + "@babel/plugin-transform-member-expression-literals": "^7.2.0", + "@babel/plugin-transform-modules-amd": "^7.5.0", + "@babel/plugin-transform-modules-commonjs": "^7.6.0", + "@babel/plugin-transform-modules-systemjs": "^7.5.0", + "@babel/plugin-transform-modules-umd": "^7.2.0", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.6.3", + "@babel/plugin-transform-new-target": "^7.4.4", + "@babel/plugin-transform-object-super": "^7.5.5", + "@babel/plugin-transform-parameters": "^7.4.4", + "@babel/plugin-transform-property-literals": "^7.2.0", + "@babel/plugin-transform-regenerator": "^7.4.5", + "@babel/plugin-transform-reserved-words": "^7.2.0", + "@babel/plugin-transform-shorthand-properties": "^7.2.0", + "@babel/plugin-transform-spread": "^7.6.2", + "@babel/plugin-transform-sticky-regex": "^7.2.0", + "@babel/plugin-transform-template-literals": "^7.4.4", + "@babel/plugin-transform-typeof-symbol": "^7.2.0", + "@babel/plugin-transform-unicode-regex": "^7.6.2", + "@babel/types": "^7.6.3", + "browserslist": "^4.6.0", + "core-js-compat": "^3.1.1", + "invariant": "^2.2.2", + "js-levenshtein": "^1.1.3", + "semver": "^5.5.0" + } + }, + "@babel/template": { + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.6.0.tgz", + "integrity": "sha512-5AEH2EXD8euCk446b7edmgFdub/qfH1SN6Nii3+fyXP807QRx9Q73A2N5hNwRRslC2H9sNzaFhsPubkS4L8oNQ==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "@babel/parser": "^7.6.0", + "@babel/types": "^7.6.0" + } + }, + "@babel/traverse": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.6.3.tgz", + "integrity": "sha512-unn7P4LGsijIxaAJo/wpoU11zN+2IaClkQAxcJWBNCMS6cmVh802IyLHNkAjQ0iYnRS3nnxk5O3fuXW28IMxTw==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.5.5", + "@babel/generator": "^7.6.3", + "@babel/helper-function-name": "^7.1.0", + "@babel/helper-split-export-declaration": "^7.4.4", + "@babel/parser": "^7.6.3", + "@babel/types": "^7.6.3", + "debug": "^4.1.0", + "globals": "^11.1.0", + "lodash": "^4.17.13" + }, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + } + } + }, + "@babel/types": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.6.3.tgz", + "integrity": "sha512-CqbcpTxMcpuQTMhjI37ZHVgjBkysg5icREQIEZ0eG1yCNwg3oy+5AaLiOKmjsCj6nqOsa6Hf0ObjRVwokb7srA==", + "dev": true, + "requires": { + "esutils": "^2.0.2", + "lodash": "^4.17.13", + "to-fast-properties": "^2.0.0" + } + }, + "@webassemblyjs/ast": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.8.5.tgz", + "integrity": "sha512-aJMfngIZ65+t71C3y2nBBg5FFG0Okt9m0XEgWZ7Ywgn1oMAT8cNwx00Uv1cQyHtidq0Xn94R4TAywO+LCQ+ZAQ==", + "dev": true, + "requires": { + "@webassemblyjs/helper-module-context": "1.8.5", + "@webassemblyjs/helper-wasm-bytecode": "1.8.5", + "@webassemblyjs/wast-parser": "1.8.5" + } + }, + "@webassemblyjs/floating-point-hex-parser": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.8.5.tgz", + "integrity": "sha512-9p+79WHru1oqBh9ewP9zW95E3XAo+90oth7S5Re3eQnECGq59ly1Ri5tsIipKGpiStHsUYmY3zMLqtk3gTcOtQ==", + "dev": true + }, + "@webassemblyjs/helper-api-error": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.8.5.tgz", + "integrity": "sha512-Za/tnzsvnqdaSPOUXHyKJ2XI7PDX64kWtURyGiJJZKVEdFOsdKUCPTNEVFZq3zJ2R0G5wc2PZ5gvdTRFgm81zA==", + "dev": true + }, + "@webassemblyjs/helper-buffer": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.8.5.tgz", + "integrity": "sha512-Ri2R8nOS0U6G49Q86goFIPNgjyl6+oE1abW1pS84BuhP1Qcr5JqMwRFT3Ah3ADDDYGEgGs1iyb1DGX+kAi/c/Q==", + "dev": true + }, + "@webassemblyjs/helper-code-frame": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-code-frame/-/helper-code-frame-1.8.5.tgz", + "integrity": "sha512-VQAadSubZIhNpH46IR3yWO4kZZjMxN1opDrzePLdVKAZ+DFjkGD/rf4v1jap744uPVU6yjL/smZbRIIJTOUnKQ==", + "dev": true, + "requires": { + "@webassemblyjs/wast-printer": "1.8.5" + } + }, + "@webassemblyjs/helper-fsm": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-fsm/-/helper-fsm-1.8.5.tgz", + "integrity": "sha512-kRuX/saORcg8se/ft6Q2UbRpZwP4y7YrWsLXPbbmtepKr22i8Z4O3V5QE9DbZK908dh5Xya4Un57SDIKwB9eow==", + "dev": true + }, + "@webassemblyjs/helper-module-context": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-module-context/-/helper-module-context-1.8.5.tgz", + "integrity": "sha512-/O1B236mN7UNEU4t9X7Pj38i4VoU8CcMHyy3l2cV/kIF4U5KoHXDVqcDuOs1ltkac90IM4vZdHc52t1x8Yfs3g==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.8.5", + "mamacro": "^0.0.3" + } + }, + "@webassemblyjs/helper-wasm-bytecode": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.8.5.tgz", + "integrity": "sha512-Cu4YMYG3Ddl72CbmpjU/wbP6SACcOPVbHN1dI4VJNJVgFwaKf1ppeFJrwydOG3NDHxVGuCfPlLZNyEdIYlQ6QQ==", + "dev": true + }, + "@webassemblyjs/helper-wasm-section": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.8.5.tgz", + "integrity": "sha512-VV083zwR+VTrIWWtgIUpqfvVdK4ff38loRmrdDBgBT8ADXYsEZ5mPQ4Nde90N3UYatHdYoDIFb7oHzMncI02tA==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.8.5", + "@webassemblyjs/helper-buffer": "1.8.5", + "@webassemblyjs/helper-wasm-bytecode": "1.8.5", + "@webassemblyjs/wasm-gen": "1.8.5" + } + }, + "@webassemblyjs/ieee754": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.8.5.tgz", + "integrity": "sha512-aaCvQYrvKbY/n6wKHb/ylAJr27GglahUO89CcGXMItrOBqRarUMxWLJgxm9PJNuKULwN5n1csT9bYoMeZOGF3g==", + "dev": true, + "requires": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "@webassemblyjs/leb128": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.8.5.tgz", + "integrity": "sha512-plYUuUwleLIziknvlP8VpTgO4kqNaH57Y3JnNa6DLpu/sGcP6hbVdfdX5aHAV716pQBKrfuU26BJK29qY37J7A==", + "dev": true, + "requires": { + "@xtuc/long": "4.2.2" + } + }, + "@webassemblyjs/utf8": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.8.5.tgz", + "integrity": "sha512-U7zgftmQriw37tfD934UNInokz6yTmn29inT2cAetAsaU9YeVCveWEwhKL1Mg4yS7q//NGdzy79nlXh3bT8Kjw==", + "dev": true + }, + "@webassemblyjs/wasm-edit": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.8.5.tgz", + "integrity": "sha512-A41EMy8MWw5yvqj7MQzkDjU29K7UJq1VrX2vWLzfpRHt3ISftOXqrtojn7nlPsZ9Ijhp5NwuODuycSvfAO/26Q==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.8.5", + "@webassemblyjs/helper-buffer": "1.8.5", + "@webassemblyjs/helper-wasm-bytecode": "1.8.5", + "@webassemblyjs/helper-wasm-section": "1.8.5", + "@webassemblyjs/wasm-gen": "1.8.5", + "@webassemblyjs/wasm-opt": "1.8.5", + "@webassemblyjs/wasm-parser": "1.8.5", + "@webassemblyjs/wast-printer": "1.8.5" + } + }, + "@webassemblyjs/wasm-gen": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.8.5.tgz", + "integrity": "sha512-BCZBT0LURC0CXDzj5FXSc2FPTsxwp3nWcqXQdOZE4U7h7i8FqtFK5Egia6f9raQLpEKT1VL7zr4r3+QX6zArWg==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.8.5", + "@webassemblyjs/helper-wasm-bytecode": "1.8.5", + "@webassemblyjs/ieee754": "1.8.5", + "@webassemblyjs/leb128": "1.8.5", + "@webassemblyjs/utf8": "1.8.5" + } + }, + "@webassemblyjs/wasm-opt": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.8.5.tgz", + "integrity": "sha512-HKo2mO/Uh9A6ojzu7cjslGaHaUU14LdLbGEKqTR7PBKwT6LdPtLLh9fPY33rmr5wcOMrsWDbbdCHq4hQUdd37Q==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.8.5", + "@webassemblyjs/helper-buffer": "1.8.5", + "@webassemblyjs/wasm-gen": "1.8.5", + "@webassemblyjs/wasm-parser": "1.8.5" + } + }, + "@webassemblyjs/wasm-parser": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.8.5.tgz", + "integrity": "sha512-pi0SYE9T6tfcMkthwcgCpL0cM9nRYr6/6fjgDtL6q/ZqKHdMWvxitRi5JcZ7RI4SNJJYnYNaWy5UUrHQy998lw==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.8.5", + "@webassemblyjs/helper-api-error": "1.8.5", + "@webassemblyjs/helper-wasm-bytecode": "1.8.5", + "@webassemblyjs/ieee754": "1.8.5", + "@webassemblyjs/leb128": "1.8.5", + "@webassemblyjs/utf8": "1.8.5" + } + }, + "@webassemblyjs/wast-parser": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-parser/-/wast-parser-1.8.5.tgz", + "integrity": "sha512-daXC1FyKWHF1i11obK086QRlsMsY4+tIOKgBqI1lxAnkp9xe9YMcgOxm9kLe+ttjs5aWV2KKE1TWJCN57/Btsg==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.8.5", + "@webassemblyjs/floating-point-hex-parser": "1.8.5", + "@webassemblyjs/helper-api-error": "1.8.5", + "@webassemblyjs/helper-code-frame": "1.8.5", + "@webassemblyjs/helper-fsm": "1.8.5", + "@xtuc/long": "4.2.2" + } + }, + "@webassemblyjs/wast-printer": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.8.5.tgz", + "integrity": "sha512-w0U0pD4EhlnvRyeJzBqaVSJAo9w/ce7/WPogeXLzGkO6hzhr4GnQIZ4W4uUt5b9ooAaXPtnXlj0gzsXEOUNYMg==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.8.5", + "@webassemblyjs/wast-parser": "1.8.5", + "@xtuc/long": "4.2.2" + } + }, + "@xtuc/ieee754": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", + "dev": true + }, + "@xtuc/long": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", + "dev": true + }, + "abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", + "dev": true + }, + "acorn": { + "version": "5.7.3", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.3.tgz", + "integrity": "sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw==", + "dev": true + }, + "acorn-jsx": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.1.0.tgz", + "integrity": "sha512-tMUqwBWfLFbJbizRmEcWSLw6HnFzfdJs2sOJEOwwtVPMoH/0Ay+E703oZz78VSXZiiDcZrQ5XKjPIUQixhmgVw==", + "dev": true + }, + "ajv": { + "version": "6.10.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.2.tgz", + "integrity": "sha512-TXtUUEYHuaTEbLZWIKUr5pmBuhDLy+8KYtPYdcV8qC+pOZL+NKqYwvWSRrVXHn+ZmRRAu8vJTAznH7Oag6RVRw==", + "dev": true, + "requires": { + "fast-deep-equal": "^2.0.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "ajv-errors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ajv-errors/-/ajv-errors-1.0.1.tgz", + "integrity": "sha512-DCRfO/4nQ+89p/RK43i8Ezd41EqdGIU4ld7nGF8OQ14oc/we5rEntLCUa7+jrn3nn83BosfwZA0wb4pon2o8iQ==", + "dev": true + }, + "ajv-keywords": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-1.5.1.tgz", + "integrity": "sha1-MU3QpLM2j609/NxU7eYXG4htrzw=", + "dev": true + }, + "ansi-align": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-2.0.0.tgz", + "integrity": "sha1-w2rsy6VjuJzrVW82kPCx2eNUf38=", + "dev": true, + "requires": { + "string-width": "^2.0.0" + } + }, + "ansi-colors": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.4.tgz", + "integrity": "sha512-hHUXGagefjN2iRrID63xckIvotOXOojhQKWIPUZ4mNUZ9nLZW+7FMNoE1lOkEhNWYsx/7ysGIuJYCiMAA9FnrA==", + "dev": true + }, + "ansi-escapes": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz", + "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==", + "dev": true + }, + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "anymatch": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", + "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", + "dev": true, + "requires": { + "micromatch": "^3.1.4", + "normalize-path": "^2.1.1" + }, + "dependencies": { + "normalize-path": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", + "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "dev": true, + "requires": { + "remove-trailing-separator": "^1.0.1" + } + } + } + }, + "aproba": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", + "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", + "dev": true + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "arr-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", + "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", + "dev": true + }, + "arr-flatten": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", + "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", + "dev": true + }, + "arr-union": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", + "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=", + "dev": true + }, + "array-includes": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.0.3.tgz", + "integrity": "sha1-GEtI9i2S10UrsxsyMWXH+L0CJm0=", + "dev": true, + "requires": { + "define-properties": "^1.1.2", + "es-abstract": "^1.7.0" + } + }, + "array-union": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", + "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", + "dev": true, + "requires": { + "array-uniq": "^1.0.1" + } + }, + "array-uniq": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", + "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=", + "dev": true + }, + "array-unique": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", + "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", + "dev": true + }, + "asn1.js": { + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-4.10.1.tgz", + "integrity": "sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw==", + "dev": true, + "requires": { + "bn.js": "^4.0.0", + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0" + } + }, + "assert": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/assert/-/assert-1.5.0.tgz", + "integrity": "sha512-EDsgawzwoun2CZkCgtxJbv392v4nbk9XDD06zI+kQYoBM/3RBWLlEyJARDOmhAAosBjWACEkKL6S+lIZtcAubA==", + "dev": true, + "requires": { + "object-assign": "^4.1.1", + "util": "0.10.3" + }, + "dependencies": { + "inherits": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz", + "integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE=", + "dev": true + }, + "util": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz", + "integrity": "sha1-evsa/lCAUkZInj23/g7TeTNqwPk=", + "dev": true, + "requires": { + "inherits": "2.0.1" + } + } + } + }, + "assign-symbols": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", + "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=", + "dev": true + }, + "astral-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", + "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==", + "dev": true + }, + "async-each": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.3.tgz", + "integrity": "sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==", + "dev": true + }, + "async-mutex": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/async-mutex/-/async-mutex-0.1.4.tgz", + "integrity": "sha512-zVWTmAnxxHaeB2B1te84oecI8zTDJ/8G49aVBblRX6be0oq6pAybNcUSxwfgVOmOjSCvN4aYZAqwtyNI8e1YGw==" + }, + "atob": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", + "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", + "dev": true + }, + "babel-code-frame": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", + "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", + "dev": true, + "requires": { + "chalk": "^1.1.3", + "esutils": "^2.0.2", + "js-tokens": "^3.0.2" + }, + "dependencies": { + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true + }, + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, + "requires": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + } + }, + "js-tokens": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", + "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=", + "dev": true + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true + } + } + }, + "babel-loader": { + "version": "8.0.6", + "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-8.0.6.tgz", + "integrity": "sha512-4BmWKtBOBm13uoUwd08UwjZlaw3O9GWf456R9j+5YykFZ6LUIjIKLc0zEZf+hauxPOJs96C8k6FvYD09vWzhYw==", + "dev": true, + "requires": { + "find-cache-dir": "^2.0.0", + "loader-utils": "^1.0.2", + "mkdirp": "^0.5.1", + "pify": "^4.0.1" + } + }, + "babel-plugin-dynamic-import-node": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.0.tgz", + "integrity": "sha512-o6qFkpeQEBxcqt0XYlWzAVxNCSCZdUgcR8IRlhD/8DylxjjO4foPcvTW0GGKa/cVt3rvxZ7o5ippJ+/0nvLhlQ==", + "dev": true, + "requires": { + "object.assign": "^4.1.0" + } + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "dev": true + }, + "base": { + "version": "0.11.2", + "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", + "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", + "dev": true, + "requires": { + "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" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "base64-js": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.1.tgz", + "integrity": "sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g==", + "dev": true + }, + "big.js": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", + "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", + "dev": true + }, + "binary-extensions": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", + "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==", + "dev": true + }, + "bn.js": { + "version": "4.11.8", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz", + "integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==", + "dev": true + }, + "boxen": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/boxen/-/boxen-1.3.0.tgz", + "integrity": "sha512-TNPjfTr432qx7yOjQyaXm3dSR0MH9vXp7eT1BFSl/C51g+EFnOR9hTg1IreahGBmDNCehscshe45f+C1TBZbLw==", + "dev": true, + "requires": { + "ansi-align": "^2.0.0", + "camelcase": "^4.0.0", + "chalk": "^2.0.1", + "cli-boxes": "^1.0.0", + "string-width": "^2.0.0", + "term-size": "^1.2.0", + "widest-line": "^2.0.0" + }, + "dependencies": { + "camelcase": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", + "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=", + "dev": true + } + } + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "dev": true, + "requires": { + "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" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "brorand": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", + "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=", + "dev": true + }, + "browserify-aes": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", + "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", + "dev": true, + "requires": { + "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": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.1.tgz", + "integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==", + "dev": true, + "requires": { + "browserify-aes": "^1.0.4", + "browserify-des": "^1.0.0", + "evp_bytestokey": "^1.0.0" + } + }, + "browserify-des": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.2.tgz", + "integrity": "sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==", + "dev": true, + "requires": { + "cipher-base": "^1.0.1", + "des.js": "^1.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "browserify-rsa": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.0.1.tgz", + "integrity": "sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ=", + "dev": true, + "requires": { + "bn.js": "^4.1.0", + "randombytes": "^2.0.1" + } + }, + "browserify-sign": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.0.4.tgz", + "integrity": "sha1-qk62jl17ZYuqa/alfmMMvXqT0pg=", + "dev": true, + "requires": { + "bn.js": "^4.1.1", + "browserify-rsa": "^4.0.0", + "create-hash": "^1.1.0", + "create-hmac": "^1.1.2", + "elliptic": "^6.0.0", + "inherits": "^2.0.1", + "parse-asn1": "^5.0.0" + } + }, + "browserify-zlib": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.2.0.tgz", + "integrity": "sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==", + "dev": true, + "requires": { + "pako": "~1.0.5" + } + }, + "browserslist": { + "version": "4.7.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.7.1.tgz", + "integrity": "sha512-QtULFqKIAtiyNx7NhZ/p4rB8m3xDozVo/pi5VgTlADLF2tNigz/QH+v0m5qhn7XfHT7u+607NcCNOnC0HZAlMg==", + "dev": true, + "requires": { + "caniuse-lite": "^1.0.30000999", + "electron-to-chromium": "^1.3.284", + "node-releases": "^1.1.36" + } + }, + "buffer": { + "version": "4.9.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz", + "integrity": "sha1-bRu2AbB6TvztlwlBMgkwJ8lbwpg=", + "dev": true, + "requires": { + "base64-js": "^1.0.2", + "ieee754": "^1.1.4", + "isarray": "^1.0.0" + } + }, + "buffer-from": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", + "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", + "dev": true + }, + "buffer-xor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", + "integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=", + "dev": true + }, + "builtin-status-codes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz", + "integrity": "sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug=", + "dev": true + }, + "cacache": { + "version": "12.0.3", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-12.0.3.tgz", + "integrity": "sha512-kqdmfXEGFepesTuROHMs3MpFLWrPkSSpRqOw80RCflZXy/khxaArvFrQ7uJxSUduzAufc6G0g1VUCOZXxWavPw==", + "dev": true, + "requires": { + "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" + }, + "dependencies": { + "bluebird": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.1.tgz", + "integrity": "sha512-DdmyoGCleJnkbp3nkbxTLJ18rjDsE4yCggEwKNXkeV123sPNfOCYeDoeuOY+F2FrSjO1YXcTU+dsy96KMy+gcg==", + "dev": true + }, + "lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "requires": { + "yallist": "^3.0.2" + } + }, + "y18n": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", + "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==", + "dev": true + }, + "yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true + } + } + }, + "cache-base": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", + "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", + "dev": true, + "requires": { + "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" + } + }, + "caller-path": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-0.1.0.tgz", + "integrity": "sha1-lAhe9jWB7NPaqSREqP6U6CV3dR8=", + "dev": true, + "requires": { + "callsites": "^0.2.0" + }, + "dependencies": { + "callsites": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-0.2.0.tgz", + "integrity": "sha1-r6uWJikQp/M8GaV3WCXGnzTjUMo=", + "dev": true + } + } + }, + "callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true + }, + "caniuse-lite": { + "version": "1.0.30001002", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001002.tgz", + "integrity": "sha512-pRuxPE8wdrWmVPKcDmJJiGBxr6lFJq4ivdSeo9FTmGj5Rb8NX3Mby2pARG57MXF15hYAhZ0nHV5XxT2ig4bz3g==", + "dev": true + }, + "capture-stack-trace": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/capture-stack-trace/-/capture-stack-trace-1.0.1.tgz", + "integrity": "sha512-mYQLZnx5Qt1JgB1WEiMCf2647plpGeQ2NMR/5L0HNZzGQo4fuSPnK+wjfPnKZV0aiJDgzmWqqkV/g7JD+DW0qw==", + "dev": true + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "chardet": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", + "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", + "dev": true + }, + "chokidar": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz", + "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==", + "dev": true, + "requires": { + "anymatch": "^2.0.0", + "async-each": "^1.0.1", + "braces": "^2.3.2", + "fsevents": "^1.2.7", + "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" + } + }, + "chownr": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.3.tgz", + "integrity": "sha512-i70fVHhmV3DtTl6nqvZOnIjbY0Pe4kAUjwHj8z0zAdgBtYrJyYwLKCCuRBQ5ppkyL0AkN7HKRnETdmdp1zqNXw==", + "dev": true + }, + "chrome-trace-event": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.2.tgz", + "integrity": "sha512-9e/zx1jw7B4CO+c/RXoCsfg/x1AfUBioy4owYH0bJprEYAx5hRFLRhWBqHAG57D0ZM4H7vxbP7bPe0VwhQRYDQ==", + "dev": true, + "requires": { + "tslib": "^1.9.0" + } + }, + "ci-info": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-1.6.0.tgz", + "integrity": "sha512-vsGdkwSCDpWmP80ncATX7iea5DWQemg1UgCW5J8tqjU3lYw4FBYuj89J0CTVomA7BEfvSZd84GmHko+MxFQU2A==", + "dev": true + }, + "cipher-base": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", + "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "circular-json": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/circular-json/-/circular-json-0.3.3.tgz", + "integrity": "sha512-UZK3NBx2Mca+b5LsG7bY183pHWt5Y1xts4P3Pz7ENTwGVnJOUWbRb3ocjvX7hx9tq/yTAdclXm9sZ38gNuem4A==", + "dev": true + }, + "class-utils": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", + "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", + "dev": true, + "requires": { + "arr-union": "^3.1.0", + "define-property": "^0.2.5", + "isobject": "^3.0.0", + "static-extend": "^0.1.1" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + } + } + }, + "cli-boxes": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-1.0.0.tgz", + "integrity": "sha1-T6kXw+WclKAEzWH47lCdplFocUM=", + "dev": true + }, + "cli-cursor": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", + "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=", + "dev": true, + "requires": { + "restore-cursor": "^2.0.0" + } + }, + "cli-width": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz", + "integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=", + "dev": true + }, + "co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", + "dev": true + }, + "code-point-at": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", + "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", + "dev": true + }, + "collection-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", + "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", + "dev": true, + "requires": { + "map-visit": "^1.0.0", + "object-visit": "^1.0.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true + }, + "commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", + "dev": true + }, + "component-emitter": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", + "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==", + "dev": true + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + }, + "dependencies": { + "process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "dev": true + }, + "readable-stream": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "configstore": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/configstore/-/configstore-3.1.2.tgz", + "integrity": "sha512-vtv5HtGjcYUgFrXc6Kx747B83MRRVS5R1VTEQoXvuP+kMI+if6uywV0nDGoiydJRy4yk7h9od5Og0kxx4zUXmw==", + "dev": true, + "requires": { + "dot-prop": "^4.1.0", + "graceful-fs": "^4.1.2", + "make-dir": "^1.0.0", + "unique-string": "^1.0.0", + "write-file-atomic": "^2.0.0", + "xdg-basedir": "^3.0.0" + }, + "dependencies": { + "make-dir": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz", + "integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==", + "dev": true, + "requires": { + "pify": "^3.0.0" + } + }, + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + } + } + }, + "confusing-browser-globals": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/confusing-browser-globals/-/confusing-browser-globals-1.0.9.tgz", + "integrity": "sha512-KbS1Y0jMtyPgIxjO7ZzMAuUpAKMt1SzCL9fsrKsX6b0zJPTaT0SiSPmewwVZg9UAO83HVIlEhZF84LIjZ0lmAw==", + "dev": true + }, + "console-browserify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.1.0.tgz", + "integrity": "sha1-8CQcRXMKn8YyOyBtvzjtx0HQuxA=", + "dev": true, + "requires": { + "date-now": "^0.1.4" + } + }, + "constants-browserify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz", + "integrity": "sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U=", + "dev": true + }, + "contains-path": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/contains-path/-/contains-path-0.1.0.tgz", + "integrity": "sha1-/ozxhP9mcLa67wGp1IYaXL7EEgo=", + "dev": true + }, + "convert-source-map": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.6.0.tgz", + "integrity": "sha512-eFu7XigvxdZ1ETfbgPBohgyQ/Z++C0eEhTor0qRwBw9unw+L0/6V8wkSuGgzdThkiS5lSpdptOQPD8Ak40a+7A==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.1" + } + }, + "copy-concurrently": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/copy-concurrently/-/copy-concurrently-1.0.5.tgz", + "integrity": "sha512-f2domd9fsVDFtaFcbaRZuYXwtdmnzqbADSwhSWYxYB/Q8zsdUUFMXVRwXGDMWmbEzAn1kdRrtI1T/KTFOL4X2A==", + "dev": true, + "requires": { + "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": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", + "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=", + "dev": true + }, + "copy-webpack-plugin": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-5.0.5.tgz", + "integrity": "sha512-7N68eIoQTyudAuxkfPT7HzGoQ+TsmArN/I3HFwG+lVE3FNzqvZKIiaxtYh4o3BIznioxUvx9j26+Rtsc9htQUQ==", + "dev": true, + "requires": { + "cacache": "^12.0.3", + "find-cache-dir": "^2.1.0", + "glob-parent": "^3.1.0", + "globby": "^7.1.1", + "is-glob": "^4.0.1", + "loader-utils": "^1.2.3", + "minimatch": "^3.0.4", + "normalize-path": "^3.0.0", + "p-limit": "^2.2.1", + "schema-utils": "^1.0.0", + "serialize-javascript": "^2.1.0", + "webpack-log": "^2.0.0" + }, + "dependencies": { + "globby": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/globby/-/globby-7.1.1.tgz", + "integrity": "sha1-+yzP+UAfhgCUXfral0QMypcrhoA=", + "dev": true, + "requires": { + "array-union": "^1.0.1", + "dir-glob": "^2.0.0", + "glob": "^7.1.2", + "ignore": "^3.3.5", + "pify": "^3.0.0", + "slash": "^1.0.0" + } + }, + "ignore": { + "version": "3.3.10", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.10.tgz", + "integrity": "sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug==", + "dev": true + }, + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + }, + "serialize-javascript": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-2.1.2.tgz", + "integrity": "sha512-rs9OggEUF0V4jUSecXazOYsLfu7OGK2qIn3c7IPBiffz32XniEp/TX9Xmc9LQfK2nQ2QKHvZ2oygKUGU0lG4jQ==", + "dev": true + }, + "slash": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz", + "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=", + "dev": true + } + } + }, + "core-js-compat": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.3.2.tgz", + "integrity": "sha512-gfiK4QnNXhnnHVOIZst2XHdFfdMTPxtR0EGs0TdILMlGIft+087oH6/Sw2xTTIjpWXC9vEwsJA8VG3XTGcmO5g==", + "dev": true, + "requires": { + "browserslist": "^4.7.0", + "semver": "^6.3.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" + }, + "create-ecdh": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.3.tgz", + "integrity": "sha512-GbEHQPMOswGpKXM9kCWVrremUcBmjteUaQ01T9rkKCPDXfUHX0IoP9LpHYo2NPFampa4e+/pFDc3jQdxrxQLaw==", + "dev": true, + "requires": { + "bn.js": "^4.1.0", + "elliptic": "^6.0.0" + } + }, + "create-error-class": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/create-error-class/-/create-error-class-3.0.2.tgz", + "integrity": "sha1-Br56vvlHo/FKMP1hBnHUAbyot7Y=", + "dev": true, + "requires": { + "capture-stack-trace": "^1.0.0" + } + }, + "create-hash": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", + "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", + "dev": true, + "requires": { + "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": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", + "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", + "dev": true, + "requires": { + "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" + } + }, + "cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "dev": true, + "requires": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + }, + "crypto-browserify": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz", + "integrity": "sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==", + "dev": true, + "requires": { + "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" + } + }, + "crypto-random-string": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-1.0.0.tgz", + "integrity": "sha1-ojD2T1aDEOFJgAmUB5DsmVRbyn4=", + "dev": true + }, + "cyclist": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cyclist/-/cyclist-1.0.1.tgz", + "integrity": "sha1-WW6WmP0MgOEgOMK4LW6xs1tiJNk=", + "dev": true + }, + "d": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz", + "integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==", + "dev": true, + "requires": { + "es5-ext": "^0.10.50", + "type": "^1.0.1" + } + }, + "date-now": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/date-now/-/date-now-0.1.4.tgz", + "integrity": "sha1-6vQ5/U1ISK105cx9vvIAZyueNFs=", + "dev": true + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", + "dev": true + }, + "decode-uri-component": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", + "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=", + "dev": true + }, + "deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "dev": true + }, + "deep-is": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", + "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", + "dev": true + }, + "define-properties": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", + "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "dev": true, + "requires": { + "object-keys": "^1.0.12" + } + }, + "define-property": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "dev": true, + "requires": { + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" + }, + "dependencies": { + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "des.js": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.0.0.tgz", + "integrity": "sha1-wHTS4qpqipoH29YfmhXCzYPsjsw=", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0" + } + }, + "detect-file": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/detect-file/-/detect-file-1.0.0.tgz", + "integrity": "sha1-8NZtA2cqglyxtzvbP+YjEMjlUrc=", + "dev": true + }, + "diffie-hellman": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", + "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==", + "dev": true, + "requires": { + "bn.js": "^4.1.0", + "miller-rabin": "^4.0.0", + "randombytes": "^2.0.0" + } + }, + "dir-glob": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-2.2.2.tgz", + "integrity": "sha512-f9LBi5QWzIW3I6e//uxZoLBlUt9kcp66qo0sSCxL6YZKc75R1c4MFCoe/LaZiBGmgujvQdxc5Bn3QhfyvK5Hsw==", + "dev": true, + "requires": { + "path-type": "^3.0.0" + }, + "dependencies": { + "path-type": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", + "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", + "dev": true, + "requires": { + "pify": "^3.0.0" + } + }, + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + } + } + }, + "doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, + "domain-browser": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.2.0.tgz", + "integrity": "sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA==", + "dev": true + }, + "dot-prop": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-4.2.0.tgz", + "integrity": "sha512-tUMXrxlExSW6U2EXiiKGSBVdYgtV8qlHL+C10TsW4PURY/ic+eaysnSkwB4kA/mBlCyy/IKDJ+Lc3wbWeaXtuQ==", + "dev": true, + "requires": { + "is-obj": "^1.0.0" + } + }, + "duplexer3": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", + "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=", + "dev": true + }, + "duplexify": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz", + "integrity": "sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==", + "dev": true, + "requires": { + "end-of-stream": "^1.0.0", + "inherits": "^2.0.1", + "readable-stream": "^2.0.0", + "stream-shift": "^1.0.0" + } + }, + "electron-to-chromium": { + "version": "1.3.289", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.289.tgz", + "integrity": "sha512-39GEOWgTxtMDk/WjIQLg4W/l1s4FZdiMCqUBLjd92tAXsBPDFLwuwCba5OGhuTdVYm6E128TZIqSnMpeocUlCQ==", + "dev": true + }, + "elliptic": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.1.tgz", + "integrity": "sha512-xvJINNLbTeWQjrl6X+7eQCrIy/YPv5XCpKW6kB5mKvtnGILoLDcySuwomfdzt0BMdLNVnuRNTuzKNHj0bva1Cg==", + "dev": true, + "requires": { + "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": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true + }, + "emojis-list": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-2.1.0.tgz", + "integrity": "sha1-TapNnbAPmBmIDHn6RXrlsJof04k=", + "dev": true + }, + "end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "dev": true, + "requires": { + "once": "^1.4.0" + } + }, + "enhanced-resolve": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-4.1.1.tgz", + "integrity": "sha512-98p2zE+rL7/g/DzMHMTF4zZlCgeVdJ7yr6xzEpJRYwFYrGi9ANdn5DnJURg6RpBkyk60XYDnWIv51VfIhfNGuA==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "memory-fs": "^0.5.0", + "tapable": "^1.0.0" + }, + "dependencies": { + "memory-fs": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.5.0.tgz", + "integrity": "sha512-jA0rdU5KoQMC0e6ppoNRtpp6vjFq6+NY7r8hywnC7V+1Xj/MtHwGIbB1QaK/dunyjWteJzmkpd7ooeWg10T7GA==", + "dev": true, + "requires": { + "errno": "^0.1.3", + "readable-stream": "^2.0.1" + } + } + } + }, + "errno": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.7.tgz", + "integrity": "sha512-MfrRBDWzIWifgq6tJj60gkAwtLNb6sQPlcFrSOflcP1aFmmruKQ2wRnze/8V6kgyz7H3FF8Npzv78mZ7XLLflg==", + "dev": true, + "requires": { + "prr": "~1.0.1" + } + }, + "error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "requires": { + "is-arrayish": "^0.2.1" + } + }, + "es-abstract": { + "version": "1.16.0", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.16.0.tgz", + "integrity": "sha512-xdQnfykZ9JMEiasTAJZJdMWCQ1Vm00NBw79/AWi7ELfZuuPCSOMDZbT9mkOfSctVtfhb+sAAzrm+j//GjjLHLg==", + "dev": true, + "requires": { + "es-to-primitive": "^1.2.0", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.0", + "is-callable": "^1.1.4", + "is-regex": "^1.0.4", + "object-inspect": "^1.6.0", + "object-keys": "^1.1.1", + "string.prototype.trimleft": "^2.1.0", + "string.prototype.trimright": "^2.1.0" + } + }, + "es-to-primitive": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.0.tgz", + "integrity": "sha512-qZryBOJjV//LaxLTV6UC//WewneB3LcXOL9NP++ozKVXsIIIpm/2c13UDiD9Jp2eThsecw9m3jPqDwTyobcdbg==", + "dev": true, + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, + "es5-ext": { + "version": "0.10.51", + "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.51.tgz", + "integrity": "sha512-oRpWzM2WcLHVKpnrcyB7OW8j/s67Ba04JCm0WnNv3RiABSvs7mrQlutB8DBv793gKcp0XENR8Il8WxGTlZ73gQ==", + "dev": true, + "requires": { + "es6-iterator": "~2.0.3", + "es6-symbol": "~3.1.1", + "next-tick": "^1.0.0" + } + }, + "es6-iterator": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", + "integrity": "sha1-p96IkUGgWpSwhUQDstCg+/qY87c=", + "dev": true, + "requires": { + "d": "1", + "es5-ext": "^0.10.35", + "es6-symbol": "^3.1.1" + } + }, + "es6-map": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/es6-map/-/es6-map-0.1.5.tgz", + "integrity": "sha1-kTbgUD3MBqMBaQ8LsU/042TpSfA=", + "dev": true, + "requires": { + "d": "1", + "es5-ext": "~0.10.14", + "es6-iterator": "~2.0.1", + "es6-set": "~0.1.5", + "es6-symbol": "~3.1.1", + "event-emitter": "~0.3.5" + } + }, + "es6-promise": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-3.0.2.tgz", + "integrity": "sha1-AQ1YWEI6XxGJeWZfRkhqlcbuK7Y=" + }, + "es6-set": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/es6-set/-/es6-set-0.1.5.tgz", + "integrity": "sha1-0rPsXU2ADO2BjbU40ol02wpzzLE=", + "dev": true, + "requires": { + "d": "1", + "es5-ext": "~0.10.14", + "es6-iterator": "~2.0.1", + "es6-symbol": "3.1.1", + "event-emitter": "~0.3.5" + }, + "dependencies": { + "es6-symbol": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.1.tgz", + "integrity": "sha1-vwDvT9q2uhtG7Le2KbTH7VcVzHc=", + "dev": true, + "requires": { + "d": "1", + "es5-ext": "~0.10.14" + } + } + } + }, + "es6-symbol": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.2.tgz", + "integrity": "sha512-/ZypxQsArlv+KHpGvng52/Iz8by3EQPxhmbuz8yFG89N/caTFBSbcXONDw0aMjy827gQg26XAjP4uXFvnfINmQ==", + "dev": true, + "requires": { + "d": "^1.0.1", + "es5-ext": "^0.10.51" + } + }, + "es6-weak-map": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.3.tgz", + "integrity": "sha512-p5um32HOTO1kP+w7PRnB+5lQ43Z6muuMuIMffvDN8ZB4GcnjLBV6zGStpbASIMk4DCAvEaamhe2zhyCb/QXXsA==", + "dev": true, + "requires": { + "d": "1", + "es5-ext": "^0.10.46", + "es6-iterator": "^2.0.3", + "es6-symbol": "^3.1.1" + } + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true + }, + "escope": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/escope/-/escope-3.6.0.tgz", + "integrity": "sha1-4Bl16BJ4GhY6ba392AOY3GTIicM=", + "dev": true, + "requires": { + "es6-map": "^0.1.3", + "es6-weak-map": "^2.0.1", + "esrecurse": "^4.1.0", + "estraverse": "^4.1.1" + } + }, + "eslint": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-6.5.1.tgz", + "integrity": "sha512-32h99BoLYStT1iq1v2P9uwpyznQ4M2jRiFB6acitKz52Gqn+vPaMDUTB1bYi1WN4Nquj2w+t+bimYUG83DC55A==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "ajv": "^6.10.0", + "chalk": "^2.1.0", + "cross-spawn": "^6.0.5", + "debug": "^4.0.1", + "doctrine": "^3.0.0", + "eslint-scope": "^5.0.0", + "eslint-utils": "^1.4.2", + "eslint-visitor-keys": "^1.1.0", + "espree": "^6.1.1", + "esquery": "^1.0.1", + "esutils": "^2.0.2", + "file-entry-cache": "^5.0.1", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^5.0.0", + "globals": "^11.7.0", + "ignore": "^4.0.6", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "inquirer": "^6.4.1", + "is-glob": "^4.0.0", + "js-yaml": "^3.13.1", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.3.0", + "lodash": "^4.17.14", + "minimatch": "^3.0.4", + "mkdirp": "^0.5.1", + "natural-compare": "^1.4.0", + "optionator": "^0.8.2", + "progress": "^2.0.0", + "regexpp": "^2.0.1", + "semver": "^6.1.2", + "strip-ansi": "^5.2.0", + "strip-json-comments": "^3.0.1", + "table": "^5.2.3", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "glob-parent": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.0.tgz", + "integrity": "sha512-qjtRgnIVmOfnKUE3NJAQEdk+lKrxfw8t5ke7SXtfMTHcjsBfOfWXCQfdb30zfDoZQ2IRSIiidmjtbHZPZ++Ihw==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + } + } + }, + "eslint-config-airbnb-base": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/eslint-config-airbnb-base/-/eslint-config-airbnb-base-14.0.0.tgz", + "integrity": "sha512-2IDHobw97upExLmsebhtfoD3NAKhV4H0CJWP3Uprd/uk+cHuWYOczPVxQ8PxLFUAw7o3Th1RAU8u1DoUpr+cMA==", + "dev": true, + "requires": { + "confusing-browser-globals": "^1.0.7", + "object.assign": "^4.1.0", + "object.entries": "^1.1.0" + } + }, + "eslint-import-resolver-node": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.2.tgz", + "integrity": "sha512-sfmTqJfPSizWu4aymbPr4Iidp5yKm8yDkHp+Ir3YiTHiiDfxh69mOUsmiqW6RZ9zRXFaF64GtYmN7e+8GHBv6Q==", + "dev": true, + "requires": { + "debug": "^2.6.9", + "resolve": "^1.5.0" + } + }, + "eslint-module-utils": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.4.1.tgz", + "integrity": "sha512-H6DOj+ejw7Tesdgbfs4jeS4YMFrT8uI8xwd1gtQqXssaR0EQ26L+2O/w6wkYFy2MymON0fTwHmXBvvfLNZVZEw==", + "dev": true, + "requires": { + "debug": "^2.6.8", + "pkg-dir": "^2.0.0" + }, + "dependencies": { + "find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dev": true, + "requires": { + "locate-path": "^2.0.0" + } + }, + "locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "dev": true, + "requires": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + } + }, + "p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dev": true, + "requires": { + "p-try": "^1.0.0" + } + }, + "p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "dev": true, + "requires": { + "p-limit": "^1.1.0" + } + }, + "p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", + "dev": true + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true + }, + "pkg-dir": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz", + "integrity": "sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s=", + "dev": true, + "requires": { + "find-up": "^2.1.0" + } + } + } + }, + "eslint-plugin-import": { + "version": "2.18.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.18.2.tgz", + "integrity": "sha512-5ohpsHAiUBRNaBWAF08izwUGlbrJoJJ+W9/TBwsGoR1MnlgfwMIKrFeSjWbt6moabiXW9xNvtFz+97KHRfI4HQ==", + "dev": true, + "requires": { + "array-includes": "^3.0.3", + "contains-path": "^0.1.0", + "debug": "^2.6.9", + "doctrine": "1.5.0", + "eslint-import-resolver-node": "^0.3.2", + "eslint-module-utils": "^2.4.0", + "has": "^1.0.3", + "minimatch": "^3.0.4", + "object.values": "^1.1.0", + "read-pkg-up": "^2.0.0", + "resolve": "^1.11.0" + }, + "dependencies": { + "doctrine": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz", + "integrity": "sha1-N53Ocw9hZvds76TmcHoVmwLFpvo=", + "dev": true, + "requires": { + "esutils": "^2.0.2", + "isarray": "^1.0.0" + } + } + } + }, + "eslint-plugin-no-unsafe-innerhtml": { + "version": "1.0.16", + "resolved": "https://registry.npmjs.org/eslint-plugin-no-unsafe-innerhtml/-/eslint-plugin-no-unsafe-innerhtml-1.0.16.tgz", + "integrity": "sha1-fQKHjI6b95FriINtWsEitC8VGTI=", + "dev": true, + "requires": { + "eslint": "^3.7.1" + }, + "dependencies": { + "acorn-jsx": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-3.0.1.tgz", + "integrity": "sha1-r9+UiPsezvyDSPb7IvRk4ypYs2s=", + "dev": true, + "requires": { + "acorn": "^3.0.4" + }, + "dependencies": { + "acorn": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-3.3.0.tgz", + "integrity": "sha1-ReN/s56No/JbruP/U2niu18iAXo=", + "dev": true + } + } + }, + "ajv": { + "version": "4.11.8", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-4.11.8.tgz", + "integrity": "sha1-gv+wKynmYq5TvcIK8VlHcGc5xTY=", + "dev": true, + "requires": { + "co": "^4.6.0", + "json-stable-stringify": "^1.0.1" + } + }, + "ansi-escapes": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-1.4.0.tgz", + "integrity": "sha1-06ioOzGapneTZisT52HHkRQiMG4=", + "dev": true + }, + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true + }, + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, + "requires": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + } + }, + "cli-cursor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-1.0.2.tgz", + "integrity": "sha1-ZNo/fValRBLll5S9Ytw1KV6PKYc=", + "dev": true, + "requires": { + "restore-cursor": "^1.0.1" + } + }, + "doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, + "eslint": { + "version": "3.19.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-3.19.0.tgz", + "integrity": "sha1-yPxiAcf0DdCJQbh8CFdnOGpnmsw=", + "dev": true, + "requires": { + "babel-code-frame": "^6.16.0", + "chalk": "^1.1.3", + "concat-stream": "^1.5.2", + "debug": "^2.1.1", + "doctrine": "^2.0.0", + "escope": "^3.6.0", + "espree": "^3.4.0", + "esquery": "^1.0.0", + "estraverse": "^4.2.0", + "esutils": "^2.0.2", + "file-entry-cache": "^2.0.0", + "glob": "^7.0.3", + "globals": "^9.14.0", + "ignore": "^3.2.0", + "imurmurhash": "^0.1.4", + "inquirer": "^0.12.0", + "is-my-json-valid": "^2.10.0", + "is-resolvable": "^1.0.0", + "js-yaml": "^3.5.1", + "json-stable-stringify": "^1.0.0", + "levn": "^0.3.0", + "lodash": "^4.0.0", + "mkdirp": "^0.5.0", + "natural-compare": "^1.4.0", + "optionator": "^0.8.2", + "path-is-inside": "^1.0.1", + "pluralize": "^1.2.1", + "progress": "^1.1.8", + "require-uncached": "^1.0.2", + "shelljs": "^0.7.5", + "strip-bom": "^3.0.0", + "strip-json-comments": "~2.0.1", + "table": "^3.7.8", + "text-table": "~0.2.0", + "user-home": "^2.0.0" + } + }, + "espree": { + "version": "3.5.4", + "resolved": "https://registry.npmjs.org/espree/-/espree-3.5.4.tgz", + "integrity": "sha512-yAcIQxtmMiB/jL32dzEp2enBeidsB7xWPLNiw3IIkpVds1P+h7qF9YwJq1yUNzp2OKXgAprs4F61ih66UsoD1A==", + "dev": true, + "requires": { + "acorn": "^5.5.0", + "acorn-jsx": "^3.0.0" + } + }, + "figures": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz", + "integrity": "sha1-y+Hjr/zxzUS4DK3+0o3Hk6lwHS4=", + "dev": true, + "requires": { + "escape-string-regexp": "^1.0.5", + "object-assign": "^4.1.0" + } + }, + "file-entry-cache": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-2.0.0.tgz", + "integrity": "sha1-w5KZDD5oR4PYOLjISkXYoEhFg2E=", + "dev": true, + "requires": { + "flat-cache": "^1.2.1", + "object-assign": "^4.0.1" + } + }, + "flat-cache": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-1.3.4.tgz", + "integrity": "sha512-VwyB3Lkgacfik2vhqR4uv2rvebqmDvFu4jlN/C1RzWoJEo8I7z4Q404oiqYCkq41mni8EzQnm95emU9seckwtg==", + "dev": true, + "requires": { + "circular-json": "^0.3.1", + "graceful-fs": "^4.1.2", + "rimraf": "~2.6.2", + "write": "^0.2.1" + } + }, + "globals": { + "version": "9.18.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz", + "integrity": "sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ==", + "dev": true + }, + "ignore": { + "version": "3.3.10", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.10.tgz", + "integrity": "sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug==", + "dev": true + }, + "inquirer": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-0.12.0.tgz", + "integrity": "sha1-HvK/1jUE3wvHV4X/+MLEHfEvB34=", + "dev": true, + "requires": { + "ansi-escapes": "^1.1.0", + "ansi-regex": "^2.0.0", + "chalk": "^1.0.0", + "cli-cursor": "^1.0.1", + "cli-width": "^2.0.0", + "figures": "^1.3.5", + "lodash": "^4.3.0", + "readline2": "^1.0.1", + "run-async": "^0.1.0", + "rx-lite": "^3.1.2", + "string-width": "^1.0.1", + "strip-ansi": "^3.0.0", + "through": "^2.3.6" + } + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "dev": true, + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "onetime": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-1.1.0.tgz", + "integrity": "sha1-ofeDj4MUxRbwXs78vEzP4EtO14k=", + "dev": true + }, + "progress": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/progress/-/progress-1.1.8.tgz", + "integrity": "sha1-4mDHj2Fhzdmw5WzD4Khd4Xx6V74=", + "dev": true + }, + "restore-cursor": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-1.0.1.tgz", + "integrity": "sha1-NGYfRohjJ/7SmRR5FSJS35LapUE=", + "dev": true, + "requires": { + "exit-hook": "^1.0.0", + "onetime": "^1.0.0" + } + }, + "run-async": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-0.1.0.tgz", + "integrity": "sha1-yK1KXhEGYeQCp9IbUw4AnyX444k=", + "dev": true, + "requires": { + "once": "^1.3.0" + } + }, + "slice-ansi": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-0.0.4.tgz", + "integrity": "sha1-7b+JA/ZvfOL46v1s7tZeJkyDGzU=", + "dev": true + }, + "string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "dev": true, + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + }, + "strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", + "dev": true + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true + }, + "table": { + "version": "3.8.3", + "resolved": "https://registry.npmjs.org/table/-/table-3.8.3.tgz", + "integrity": "sha1-K7xULw/amGGnVdOUf+/Ys/UThV8=", + "dev": true, + "requires": { + "ajv": "^4.7.0", + "ajv-keywords": "^1.0.0", + "chalk": "^1.1.1", + "lodash": "^4.0.0", + "slice-ansi": "0.0.4", + "string-width": "^2.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, + "string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dev": true, + "requires": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + } + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "^3.0.0" + } + } + } + }, + "user-home": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/user-home/-/user-home-2.0.0.tgz", + "integrity": "sha1-nHC/2Babwdy/SGBODwS4tJzenp8=", + "dev": true, + "requires": { + "os-homedir": "^1.0.0" + } + }, + "write": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/write/-/write-0.2.1.tgz", + "integrity": "sha1-X8A4KOJkzqP+kUVUdvejxWbLB1c=", + "dev": true, + "requires": { + "mkdirp": "^0.5.1" + } + } + } + }, + "eslint-plugin-no-unsanitized": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-no-unsanitized/-/eslint-plugin-no-unsanitized-3.0.2.tgz", + "integrity": "sha512-JnwpoH8Sv4QOjrTDutENBHzSnyYtspdjtglYtqUtAHe6f6LLKqykJle+UwFPg23GGwt5hI3amS9CRDezW8GAww==", + "dev": true + }, + "eslint-plugin-security": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-security/-/eslint-plugin-security-1.4.0.tgz", + "integrity": "sha512-xlS7P2PLMXeqfhyf3NpqbvbnW04kN8M9NtmhpR3XGyOvt/vNKS7XPXT5EDbwKW9vCjWH4PpfQvgD/+JgN0VJKA==", + "dev": true, + "requires": { + "safe-regex": "^1.1.0" + } + }, + "eslint-scope": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.0.0.tgz", + "integrity": "sha512-oYrhJW7S0bxAFDvWqzvMPRm6pcgcnWc4QnofCAqRTRfQC0JcwenzGglTtsLyIuuWFfkqDG9vz67cnttSd53djw==", + "dev": true, + "requires": { + "esrecurse": "^4.1.0", + "estraverse": "^4.1.1" + } + }, + "eslint-utils": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.4.3.tgz", + "integrity": "sha512-fbBN5W2xdY45KulGXmLHZ3c3FHfVYmKg0IrAKGOkT/464PQsx2UeIzfz1RmEci+KLm1bBaAzZAh8+/E+XAeZ8Q==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^1.1.0" + } + }, + "eslint-visitor-keys": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.1.0.tgz", + "integrity": "sha512-8y9YjtM1JBJU/A9Kc+SbaOV4y29sSWckBwMHa+FGtVj5gN/sbnKDf6xJUl+8g7FAij9LVaP8C24DUiH/f/2Z9A==", + "dev": true + }, + "espree": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/espree/-/espree-6.1.2.tgz", + "integrity": "sha512-2iUPuuPP+yW1PZaMSDM9eyVf8D5P0Hi8h83YtZ5bPc/zHYjII5khoixIUTMO794NOY8F/ThF1Bo8ncZILarUTA==", + "dev": true, + "requires": { + "acorn": "^7.1.0", + "acorn-jsx": "^5.1.0", + "eslint-visitor-keys": "^1.1.0" + }, + "dependencies": { + "acorn": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.1.0.tgz", + "integrity": "sha512-kL5CuoXA/dgxlBbVrflsflzQ3PAas7RYZB52NOm/6839iVYJgKMJ3cQJD+t2i5+qFa8h3MDpEOJiS64E8JLnSQ==", + "dev": true + } + } + }, + "esquery": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.0.1.tgz", + "integrity": "sha512-SmiyZ5zIWH9VM+SRUReLS5Q8a7GxtRdxEBVZpm98rJM7Sb+A9DVCndXfkeFUd3byderg+EbDkfnevfCwynWaNA==", + "dev": true, + "requires": { + "estraverse": "^4.0.0" + } + }, + "esrecurse": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz", + "integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==", + "dev": true, + "requires": { + "estraverse": "^4.1.0" + } + }, + "estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true + }, + "esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true + }, + "event-emitter": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz", + "integrity": "sha1-34xp7vFkeSPHFXuc6DhAYQsCzDk=", + "dev": true, + "requires": { + "d": "1", + "es5-ext": "~0.10.14" + } + }, + "events": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.0.0.tgz", + "integrity": "sha512-Dc381HFWJzEOhQ+d8pkNon++bk9h6cdAoAj4iE6Q4y6xgTzySWXlKn05/TVNpjnfRqi/X0EpJEJohPjNI3zpVA==", + "dev": true + }, + "evp_bytestokey": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", + "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", + "dev": true, + "requires": { + "md5.js": "^1.3.4", + "safe-buffer": "^5.1.1" + } + }, + "execa": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-0.7.0.tgz", + "integrity": "sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c=", + "dev": true, + "requires": { + "cross-spawn": "^5.0.1", + "get-stream": "^3.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" + }, + "dependencies": { + "cross-spawn": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", + "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", + "dev": true, + "requires": { + "lru-cache": "^4.0.1", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + } + } + }, + "exit-hook": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/exit-hook/-/exit-hook-1.1.1.tgz", + "integrity": "sha1-8FyiM7SMBdVP/wd2XfhQfpXAL/g=", + "dev": true + }, + "expand-brackets": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", + "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", + "dev": true, + "requires": { + "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" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "expand-tilde": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz", + "integrity": "sha1-l+gBqgUt8CRU3kawK/YhZCzchQI=", + "dev": true, + "requires": { + "homedir-polyfill": "^1.0.1" + } + }, + "extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "dev": true, + "requires": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "dependencies": { + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4" + } + } + } + }, + "external-editor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", + "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", + "dev": true, + "requires": { + "chardet": "^0.7.0", + "iconv-lite": "^0.4.24", + "tmp": "^0.0.33" + } + }, + "extglob": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", + "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", + "dev": true, + "requires": { + "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" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "fast-deep-equal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", + "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=", + "dev": true + }, + "fast-json-stable-stringify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", + "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=", + "dev": true + }, + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "dev": true + }, + "figgy-pudding": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/figgy-pudding/-/figgy-pudding-3.5.1.tgz", + "integrity": "sha512-vNKxJHTEKNThjfrdJwHc7brvM6eVevuO5nTj6ez8ZQ1qbXTvGthucRF7S4vf2cr71QVnT70V34v0S1DyQsti0w==", + "dev": true + }, + "figures": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", + "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=", + "dev": true, + "requires": { + "escape-string-regexp": "^1.0.5" + } + }, + "file-entry-cache": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz", + "integrity": "sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==", + "dev": true, + "requires": { + "flat-cache": "^2.0.1" + } + }, + "fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "find-cache-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.1.0.tgz", + "integrity": "sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==", + "dev": true, + "requires": { + "commondir": "^1.0.1", + "make-dir": "^2.0.0", + "pkg-dir": "^3.0.0" + } + }, + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "requires": { + "locate-path": "^3.0.0" + } + }, + "findup-sync": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-3.0.0.tgz", + "integrity": "sha512-YbffarhcicEhOrm4CtrwdKBdCuz576RLdhJDsIfvNtxUuhdRet1qZcsMjqbePtAseKdAnDyM/IyXbu7PRPRLYg==", + "dev": true, + "requires": { + "detect-file": "^1.0.0", + "is-glob": "^4.0.0", + "micromatch": "^3.0.4", + "resolve-dir": "^1.0.1" + } + }, + "flat-cache": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz", + "integrity": "sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==", + "dev": true, + "requires": { + "flatted": "^2.0.0", + "rimraf": "2.6.3", + "write": "1.0.3" + } + }, + "flatted": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.1.tgz", + "integrity": "sha512-a1hQMktqW9Nmqr5aktAux3JMNqaucxGcjtjWnZLHX7yyPCmlSV3M54nGYbqT8K+0GhF3NBgmJCc3ma+WOgX8Jg==", + "dev": true + }, + "flush-write-stream": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.1.1.tgz", + "integrity": "sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "readable-stream": "^2.3.6" + }, + "dependencies": { + "process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "dev": true + }, + "readable-stream": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "for-in": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", + "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", + "dev": true + }, + "fragment-cache": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", + "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", + "dev": true, + "requires": { + "map-cache": "^0.2.2" + } + }, + "from2": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz", + "integrity": "sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8=", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "readable-stream": "^2.0.0" + } + }, + "fs-readdir-recursive": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fs-readdir-recursive/-/fs-readdir-recursive-1.1.0.tgz", + "integrity": "sha512-GNanXlVr2pf02+sPN40XN8HG+ePaNcvM0q5mZBd668Obwb0yD5GiUbZOFgwn8kGMY6I3mdyDJzieUy3PTYyTRA==", + "dev": true + }, + "fs-write-stream-atomic": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz", + "integrity": "sha1-tH31NJPvkR33VzHnCp3tAYnbQMk=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "iferr": "^0.1.5", + "imurmurhash": "^0.1.4", + "readable-stream": "1 || 2" + } + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "fsevents": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.9.tgz", + "integrity": "sha512-oeyj2H3EjjonWcFjD5NvZNE9Rqe4UW+nQBU2HNeKw0koVLEFIhtyETyAakeAM3de7Z/SW5kcA+fZUait9EApnw==", + "dev": true, + "optional": true, + "requires": { + "nan": "^2.12.1", + "node-pre-gyp": "^0.12.0" + }, + "dependencies": { + "abbrev": { + "version": "1.1.1", + "resolved": false, + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", + "dev": true, + "optional": true + }, + "ansi-regex": { + "version": "2.1.1", + "resolved": false, + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true, + "optional": true + }, + "aproba": { + "version": "1.2.0", + "resolved": false, + "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", + "dev": true, + "optional": true + }, + "are-we-there-yet": { + "version": "1.1.5", + "resolved": false, + "integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==", + "dev": true, + "optional": true, + "requires": { + "delegates": "^1.0.0", + "readable-stream": "^2.0.6" + } + }, + "balanced-match": { + "version": "1.0.0", + "resolved": false, + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "dev": true, + "optional": true + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": false, + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "optional": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "chownr": { + "version": "1.1.1", + "resolved": false, + "integrity": "sha512-j38EvO5+LHX84jlo6h4UzmOwi0UgW61WRyPtJz4qaadK5eY3BTS5TY/S1Stc3Uk2lIM6TPevAlULiEJwie860g==", + "dev": true, + "optional": true + }, + "code-point-at": { + "version": "1.1.0", + "resolved": false, + "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", + "dev": true, + "optional": true + }, + "concat-map": { + "version": "0.0.1", + "resolved": false, + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true, + "optional": true + }, + "console-control-strings": { + "version": "1.1.0", + "resolved": false, + "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=", + "dev": true, + "optional": true + }, + "core-util-is": { + "version": "1.0.2", + "resolved": false, + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", + "dev": true, + "optional": true + }, + "debug": { + "version": "4.1.1", + "resolved": false, + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "optional": true, + "requires": { + "ms": "^2.1.1" + } + }, + "deep-extend": { + "version": "0.6.0", + "resolved": false, + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "dev": true, + "optional": true + }, + "delegates": { + "version": "1.0.0", + "resolved": false, + "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=", + "dev": true, + "optional": true + }, + "detect-libc": { + "version": "1.0.3", + "resolved": false, + "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=", + "dev": true, + "optional": true + }, + "fs-minipass": { + "version": "1.2.5", + "resolved": false, + "integrity": "sha512-JhBl0skXjUPCFH7x6x61gQxrKyXsxB5gcgePLZCwfyCGGsTISMoIeObbrvVeP6Xmyaudw4TT43qV2Gz+iyd2oQ==", + "dev": true, + "optional": true, + "requires": { + "minipass": "^2.2.1" + } + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": false, + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true, + "optional": true + }, + "gauge": { + "version": "2.7.4", + "resolved": false, + "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", + "dev": true, + "optional": true, + "requires": { + "aproba": "^1.0.3", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.0", + "object-assign": "^4.1.0", + "signal-exit": "^3.0.0", + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wide-align": "^1.1.0" + } + }, + "glob": { + "version": "7.1.3", + "resolved": false, + "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", + "dev": true, + "optional": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "has-unicode": { + "version": "2.0.1", + "resolved": false, + "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=", + "dev": true, + "optional": true + }, + "iconv-lite": { + "version": "0.4.24", + "resolved": false, + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dev": true, + "optional": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "ignore-walk": { + "version": "3.0.1", + "resolved": false, + "integrity": "sha512-DTVlMx3IYPe0/JJcYP7Gxg7ttZZu3IInhuEhbchuqneY9wWe5Ojy2mXLBaQFUQmo0AW2r3qG7m1mg86js+gnlQ==", + "dev": true, + "optional": true, + "requires": { + "minimatch": "^3.0.4" + } + }, + "inflight": { + "version": "1.0.6", + "resolved": false, + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "optional": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.3", + "resolved": false, + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "dev": true, + "optional": true + }, + "ini": { + "version": "1.3.5", + "resolved": false, + "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==", + "dev": true, + "optional": true + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": false, + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "dev": true, + "optional": true, + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "isarray": { + "version": "1.0.0", + "resolved": false, + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true, + "optional": true + }, + "minimatch": { + "version": "3.0.4", + "resolved": false, + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "optional": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "0.0.8", + "resolved": false, + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", + "dev": true, + "optional": true + }, + "minipass": { + "version": "2.3.5", + "resolved": false, + "integrity": "sha512-Gi1W4k059gyRbyVUZQ4mEqLm0YIUiGYfvxhF6SIlk3ui1WVxMTGfGdQ2SInh3PDrRTVvPKgULkpJtT4RH10+VA==", + "dev": true, + "optional": true, + "requires": { + "safe-buffer": "^5.1.2", + "yallist": "^3.0.0" + } + }, + "minizlib": { + "version": "1.2.1", + "resolved": false, + "integrity": "sha512-7+4oTUOWKg7AuL3vloEWekXY2/D20cevzsrNT2kGWm+39J9hGTCBv8VI5Pm5lXZ/o3/mdR4f8rflAPhnQb8mPA==", + "dev": true, + "optional": true, + "requires": { + "minipass": "^2.2.1" + } + }, + "mkdirp": { + "version": "0.5.1", + "resolved": false, + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "dev": true, + "optional": true, + "requires": { + "minimist": "0.0.8" + } + }, + "ms": { + "version": "2.1.1", + "resolved": false, + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "dev": true, + "optional": true + }, + "needle": { + "version": "2.3.0", + "resolved": false, + "integrity": "sha512-QBZu7aAFR0522EyaXZM0FZ9GLpq6lvQ3uq8gteiDUp7wKdy0lSd2hPlgFwVuW1CBkfEs9PfDQsQzZghLs/psdg==", + "dev": true, + "optional": true, + "requires": { + "debug": "^4.1.0", + "iconv-lite": "^0.4.4", + "sax": "^1.2.4" + } + }, + "node-pre-gyp": { + "version": "0.12.0", + "resolved": false, + "integrity": "sha512-4KghwV8vH5k+g2ylT+sLTjy5wmUOb9vPhnM8NHvRf9dHmnW/CndrFXy2aRPaPST6dugXSdHXfeaHQm77PIz/1A==", + "dev": true, + "optional": true, + "requires": { + "detect-libc": "^1.0.2", + "mkdirp": "^0.5.1", + "needle": "^2.2.1", + "nopt": "^4.0.1", + "npm-packlist": "^1.1.6", + "npmlog": "^4.0.2", + "rc": "^1.2.7", + "rimraf": "^2.6.1", + "semver": "^5.3.0", + "tar": "^4" + } + }, + "nopt": { + "version": "4.0.1", + "resolved": false, + "integrity": "sha1-0NRoWv1UFRk8jHUFYC0NF81kR00=", + "dev": true, + "optional": true, + "requires": { + "abbrev": "1", + "osenv": "^0.1.4" + } + }, + "npm-bundled": { + "version": "1.0.6", + "resolved": false, + "integrity": "sha512-8/JCaftHwbd//k6y2rEWp6k1wxVfpFzB6t1p825+cUb7Ym2XQfhwIC5KwhrvzZRJu+LtDE585zVaS32+CGtf0g==", + "dev": true, + "optional": true + }, + "npm-packlist": { + "version": "1.4.1", + "resolved": false, + "integrity": "sha512-+TcdO7HJJ8peiiYhvPxsEDhF3PJFGUGRcFsGve3vxvxdcpO2Z4Z7rkosRM0kWj6LfbK/P0gu3dzk5RU1ffvFcw==", + "dev": true, + "optional": true, + "requires": { + "ignore-walk": "^3.0.1", + "npm-bundled": "^1.0.1" + } + }, + "npmlog": { + "version": "4.1.2", + "resolved": false, + "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", + "dev": true, + "optional": true, + "requires": { + "are-we-there-yet": "~1.1.2", + "console-control-strings": "~1.1.0", + "gauge": "~2.7.3", + "set-blocking": "~2.0.0" + } + }, + "number-is-nan": { + "version": "1.0.1", + "resolved": false, + "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", + "dev": true, + "optional": true + }, + "object-assign": { + "version": "4.1.1", + "resolved": false, + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", + "dev": true, + "optional": true + }, + "once": { + "version": "1.4.0", + "resolved": false, + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "optional": true, + "requires": { + "wrappy": "1" + } + }, + "os-homedir": { + "version": "1.0.2", + "resolved": false, + "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", + "dev": true, + "optional": true + }, + "os-tmpdir": { + "version": "1.0.2", + "resolved": false, + "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", + "dev": true, + "optional": true + }, + "osenv": { + "version": "0.1.5", + "resolved": false, + "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", + "dev": true, + "optional": true, + "requires": { + "os-homedir": "^1.0.0", + "os-tmpdir": "^1.0.0" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": false, + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true, + "optional": true + }, + "process-nextick-args": { + "version": "2.0.0", + "resolved": false, + "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==", + "dev": true, + "optional": true + }, + "rc": { + "version": "1.2.8", + "resolved": false, + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "dev": true, + "optional": true, + "requires": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "resolved": false, + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true, + "optional": true + } + } + }, + "readable-stream": { + "version": "2.3.6", + "resolved": false, + "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "dev": true, + "optional": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "rimraf": { + "version": "2.6.3", + "resolved": false, + "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", + "dev": true, + "optional": true, + "requires": { + "glob": "^7.1.3" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": false, + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true, + "optional": true + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": false, + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true, + "optional": true + }, + "sax": { + "version": "1.2.4", + "resolved": false, + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", + "dev": true, + "optional": true + }, + "semver": { + "version": "5.7.0", + "resolved": false, + "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==", + "dev": true, + "optional": true + }, + "set-blocking": { + "version": "2.0.0", + "resolved": false, + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", + "dev": true, + "optional": true + }, + "signal-exit": { + "version": "3.0.2", + "resolved": false, + "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", + "dev": true, + "optional": true + }, + "string-width": { + "version": "1.0.2", + "resolved": false, + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "dev": true, + "optional": true, + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": false, + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "optional": true, + "requires": { + "safe-buffer": "~5.1.0" + } + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": false, + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dev": true, + "optional": true, + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "strip-json-comments": { + "version": "2.0.1", + "resolved": false, + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", + "dev": true, + "optional": true + }, + "tar": { + "version": "4.4.8", + "resolved": false, + "integrity": "sha512-LzHF64s5chPQQS0IYBn9IN5h3i98c12bo4NCO7e0sGM2llXQ3p2FGC5sdENN4cTW48O915Sh+x+EXx7XW96xYQ==", + "dev": true, + "optional": true, + "requires": { + "chownr": "^1.1.1", + "fs-minipass": "^1.2.5", + "minipass": "^2.3.4", + "minizlib": "^1.1.1", + "mkdirp": "^0.5.0", + "safe-buffer": "^5.1.2", + "yallist": "^3.0.2" + } + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": false, + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", + "dev": true, + "optional": true + }, + "wide-align": { + "version": "1.1.3", + "resolved": false, + "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", + "dev": true, + "optional": true, + "requires": { + "string-width": "^1.0.2 || 2" + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": false, + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true, + "optional": true + }, + "yallist": { + "version": "3.0.3", + "resolved": false, + "integrity": "sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A==", + "dev": true, + "optional": true + } + } + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", + "dev": true + }, + "generate-function": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.3.1.tgz", + "integrity": "sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ==", + "dev": true, + "requires": { + "is-property": "^1.0.2" + } + }, + "generate-object-property": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/generate-object-property/-/generate-object-property-1.2.0.tgz", + "integrity": "sha1-nA4cQDCM6AT0eDYYuTf6iPmdUNA=", + "dev": true, + "requires": { + "is-property": "^1.0.0" + } + }, + "get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true + }, + "get-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", + "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=", + "dev": true + }, + "get-value": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", + "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=", + "dev": true + }, + "glob": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz", + "integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "glob-parent": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", + "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", + "dev": true, + "requires": { + "is-glob": "^3.1.0", + "path-dirname": "^1.0.0" + }, + "dependencies": { + "is-glob": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", + "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", + "dev": true, + "requires": { + "is-extglob": "^2.1.0" + } + } + } + }, + "global-dirs": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-0.1.1.tgz", + "integrity": "sha1-sxnA3UYH81PzvpzKTHL8FIxJ9EU=", + "dev": true, + "requires": { + "ini": "^1.3.4" + } + }, + "global-modules": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-2.0.0.tgz", + "integrity": "sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A==", + "dev": true, + "requires": { + "global-prefix": "^3.0.0" + }, + "dependencies": { + "global-prefix": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-3.0.0.tgz", + "integrity": "sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg==", + "dev": true, + "requires": { + "ini": "^1.3.5", + "kind-of": "^6.0.2", + "which": "^1.3.1" + } + } + } + }, + "global-prefix": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-1.0.2.tgz", + "integrity": "sha1-2/dDxsFJklk8ZVVoy2btMsASLr4=", + "dev": true, + "requires": { + "expand-tilde": "^2.0.2", + "homedir-polyfill": "^1.0.1", + "ini": "^1.3.4", + "is-windows": "^1.0.1", + "which": "^1.2.14" + } + }, + "globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true + }, + "got": { + "version": "6.7.1", + "resolved": "https://registry.npmjs.org/got/-/got-6.7.1.tgz", + "integrity": "sha1-JAzQV4WpoY5WHcG0S0HHY+8ejbA=", + "dev": true, + "requires": { + "create-error-class": "^3.0.0", + "duplexer3": "^0.1.4", + "get-stream": "^3.0.0", + "is-redirect": "^1.0.0", + "is-retry-allowed": "^1.0.0", + "is-stream": "^1.0.0", + "lowercase-keys": "^1.0.0", + "safe-buffer": "^5.0.1", + "timed-out": "^4.0.0", + "unzip-response": "^2.0.1", + "url-parse-lax": "^1.0.0" + } + }, + "graceful-fs": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.2.tgz", + "integrity": "sha512-IItsdsea19BoLC7ELy13q1iJFNmd7ofZH5+X/pJr90/nRoPEX0DJo1dHDbgtYWOhJhcCgMDTOw84RZ72q6lB+Q==", + "dev": true + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "requires": { + "function-bind": "^1.1.1" + } + }, + "has-ansi": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", + "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", + "dev": true, + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "has-symbols": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.0.tgz", + "integrity": "sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q=", + "dev": true + }, + "has-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", + "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", + "dev": true, + "requires": { + "get-value": "^2.0.6", + "has-values": "^1.0.0", + "isobject": "^3.0.0" + } + }, + "has-values": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", + "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", + "dev": true, + "requires": { + "is-number": "^3.0.0", + "kind-of": "^4.0.0" + }, + "dependencies": { + "kind-of": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", + "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "hash-base": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.0.4.tgz", + "integrity": "sha1-X8hoaEfs1zSZQDMZprCj8/auSRg=", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "hash.js": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", + "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" + } + }, + "hmac-drbg": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", + "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=", + "dev": true, + "requires": { + "hash.js": "^1.0.3", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "homedir-polyfill": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz", + "integrity": "sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==", + "dev": true, + "requires": { + "parse-passwd": "^1.0.0" + } + }, + "hosted-git-info": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.5.tgz", + "integrity": "sha512-kssjab8CvdXfcXMXVcvsXum4Hwdq9XGtRD3TteMEvEbq0LXyiNQr6AprqKqfeaDXze7SxWvRxdpwE6ku7ikLkg==", + "dev": true + }, + "https-browserify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz", + "integrity": "sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=", + "dev": true + }, + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dev": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "ieee754": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz", + "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==", + "dev": true + }, + "iferr": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/iferr/-/iferr-0.1.5.tgz", + "integrity": "sha1-xg7taebY/bazEEofy8ocGS3FtQE=", + "dev": true + }, + "ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "dev": true + }, + "ignore-by-default": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", + "integrity": "sha1-SMptcvbGo68Aqa1K5odr44ieKwk=", + "dev": true + }, + "immediate": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", + "integrity": "sha1-nbHb0Pr43m++D13V5Wu2BigN5ps=" + }, + "import-fresh": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.1.0.tgz", + "integrity": "sha512-PpuksHKGt8rXfWEr9m9EHIpgyyaltBy8+eF6GJM0QCAxMgxCfucMF3mjecK2QsJr0amJW7gTqh5/wht0z2UhEQ==", + "dev": true, + "requires": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + } + }, + "import-lazy": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-2.1.0.tgz", + "integrity": "sha1-BWmOPUXIjo1+nZLLBYTnfwlvPkM=", + "dev": true + }, + "import-local": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-2.0.0.tgz", + "integrity": "sha512-b6s04m3O+s3CGSbqDIyP4R6aAwAeYlVq9+WUWep6iHa8ETRf9yei1U48C5MmfJmV9AiLYYBKPMq/W+/WRpQmCQ==", + "dev": true, + "requires": { + "pkg-dir": "^3.0.0", + "resolve-cwd": "^2.0.0" + } + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "dev": true + }, + "infer-owner": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz", + "integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==", + "dev": true + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "ini": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", + "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==", + "dev": true + }, + "inquirer": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-6.5.2.tgz", + "integrity": "sha512-cntlB5ghuB0iuO65Ovoi8ogLHiWGs/5yNrtUcKjFhSSiVeAIVpD7koaSU9RM8mpXw5YDi9RdYXGQMaOURB7ycQ==", + "dev": true, + "requires": { + "ansi-escapes": "^3.2.0", + "chalk": "^2.4.2", + "cli-cursor": "^2.1.0", + "cli-width": "^2.0.0", + "external-editor": "^3.0.3", + "figures": "^2.0.0", + "lodash": "^4.17.12", + "mute-stream": "0.0.7", + "run-async": "^2.2.0", + "rxjs": "^6.4.0", + "string-width": "^2.1.0", + "strip-ansi": "^5.1.0", + "through": "^2.3.6" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + } + } + }, + "interpret": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.2.0.tgz", + "integrity": "sha512-mT34yGKMNceBQUoVn7iCDKDntA7SC6gycMAWzGx1z/CMCTV7b2AAtXlo3nRyHZ1FelRkQbQjprHSYGwzLtkVbw==", + "dev": true + }, + "invariant": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", + "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", + "dev": true, + "requires": { + "loose-envify": "^1.0.0" + } + }, + "is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", + "dev": true + }, + "is-binary-path": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", + "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", + "dev": true, + "requires": { + "binary-extensions": "^1.0.0" + } + }, + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true + }, + "is-callable": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.4.tgz", + "integrity": "sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA==", + "dev": true + }, + "is-ci": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-1.2.1.tgz", + "integrity": "sha512-s6tfsaQaQi3JNciBH6shVqEDvhGut0SUXr31ag8Pd8BBbVVlcGfWhpPmEOoM6RJ5TFhbypvf5yyRw/VXW1IiWg==", + "dev": true, + "requires": { + "ci-info": "^1.5.0" + } + }, + "is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-date-object": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.1.tgz", + "integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY=", + "dev": true + }, + "is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + }, + "dependencies": { + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "dev": true + } + } + }, + "is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", + "dev": true + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, + "is-glob": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", + "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-installed-globally": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.1.0.tgz", + "integrity": "sha1-Df2Y9akRFxbdU13aZJL2e/PSWoA=", + "dev": true, + "requires": { + "global-dirs": "^0.1.0", + "is-path-inside": "^1.0.0" + } + }, + "is-my-ip-valid": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-my-ip-valid/-/is-my-ip-valid-1.0.0.tgz", + "integrity": "sha512-gmh/eWXROncUzRnIa1Ubrt5b8ep/MGSnfAUI3aRp+sqTCs1tv1Isl8d8F6JmkN3dXKc3ehZMrtiPN9eL03NuaQ==", + "dev": true + }, + "is-my-json-valid": { + "version": "2.20.0", + "resolved": "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.20.0.tgz", + "integrity": "sha512-XTHBZSIIxNsIsZXg7XB5l8z/OBFosl1Wao4tXLpeC7eKU4Vm/kdop2azkPqULwnfGQjmeDIyey9g7afMMtdWAA==", + "dev": true, + "requires": { + "generate-function": "^2.0.0", + "generate-object-property": "^1.1.0", + "is-my-ip-valid": "^1.0.0", + "jsonpointer": "^4.0.0", + "xtend": "^4.0.0" + } + }, + "is-npm": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-1.0.0.tgz", + "integrity": "sha1-8vtjpl5JBbQGyGBydloaTceTufQ=", + "dev": true + }, + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-obj": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", + "integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8=", + "dev": true + }, + "is-path-inside": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.1.tgz", + "integrity": "sha1-jvW33lBDej/cprToZe96pVy0gDY=", + "dev": true, + "requires": { + "path-is-inside": "^1.0.1" + } + }, + "is-plain-obj": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", + "integrity": "sha1-caUMhCnfync8kqOQpKA7OfzVHT4=", + "dev": true + }, + "is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "requires": { + "isobject": "^3.0.1" + } + }, + "is-promise": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz", + "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=", + "dev": true + }, + "is-property": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz", + "integrity": "sha1-V/4cTkhHTt1lsJkR8msc1Ald2oQ=", + "dev": true + }, + "is-redirect": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-redirect/-/is-redirect-1.0.0.tgz", + "integrity": "sha1-HQPd7VO9jbDzDCbk+V02/HyH3CQ=", + "dev": true + }, + "is-regex": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.4.tgz", + "integrity": "sha1-VRdIm1RwkbCTDglWVM7SXul+lJE=", + "dev": true, + "requires": { + "has": "^1.0.1" + } + }, + "is-resolvable": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.1.0.tgz", + "integrity": "sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg==", + "dev": true + }, + "is-retry-allowed": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/is-retry-allowed/-/is-retry-allowed-1.2.0.tgz", + "integrity": "sha512-RUbUeKwvm3XG2VYamhJL1xFktgjvPzL0Hq8C+6yrWIswDy3BIXGqCxhxkc30N9jqK311gVU137K8Ei55/zVJRg==", + "dev": true + }, + "is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", + "dev": true + }, + "is-symbol": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.2.tgz", + "integrity": "sha512-HS8bZ9ox60yCJLH9snBpIwv9pYUAkcuLhSA1oero1UB5y9aiQpRA8y2ex945AOtCZL1lJDeIk3G5LthswI46Lw==", + "dev": true, + "requires": { + "has-symbols": "^1.0.0" + } + }, + "is-windows": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", + "dev": true + }, + "is-wsl": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz", + "integrity": "sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=", + "dev": true + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true + }, + "js-levenshtein": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/js-levenshtein/-/js-levenshtein-1.1.6.tgz", + "integrity": "sha512-X2BB11YZtrRqY4EnQcLX5Rh373zbK4alC1FW7D7MBhL2gtcC17cTnr6DmfHZeS0s2rTHjUTMMHfG7gO8SSdw+g==", + "dev": true + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "js-yaml": { + "version": "3.13.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", + "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "dependencies": { + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true + } + } + }, + "jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true + }, + "json-parse-better-errors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", + "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", + "dev": true + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "json-stable-stringify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz", + "integrity": "sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8=", + "dev": true, + "requires": { + "jsonify": "~0.0.0" + } + }, + "json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", + "dev": true + }, + "json5": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.1.tgz", + "integrity": "sha512-l+3HXD0GEI3huGq1njuqtzYK8OYJyXMkOLtQ53pjWh89tvWS2h6l+1zMkYWqlb57+SiQodKZyvMEFb2X+KrFhQ==", + "dev": true, + "requires": { + "minimist": "^1.2.0" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true + } + } + }, + "jsonify": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz", + "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=", + "dev": true + }, + "jsonpointer": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-4.0.1.tgz", + "integrity": "sha1-T9kss04OnbPInIYi7PUfm5eMbLk=", + "dev": true + }, + "jszip": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.1.5.tgz", + "integrity": "sha512-5W8NUaFRFRqTOL7ZDDrx5qWHJyBXy6velVudIzQUSoqAAYqzSh2Z7/m0Rf1QbmQJccegD0r+YZxBjzqoBiEeJQ==", + "requires": { + "core-js": "~2.3.0", + "es6-promise": "~3.0.2", + "lie": "~3.1.0", + "pako": "~1.0.2", + "readable-stream": "~2.0.6" + }, + "dependencies": { + "core-js": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.3.0.tgz", + "integrity": "sha1-+rg/uwstjchfpjbEudNMdUIMbWU=" + } + } + }, + "kind-of": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", + "dev": true + }, + "latest-version": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-3.1.0.tgz", + "integrity": "sha1-ogU4P+oyKzO1rjsYq+4NwvNW7hU=", + "dev": true, + "requires": { + "package-json": "^4.0.0" + } + }, + "levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", + "dev": true, + "requires": { + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" + } + }, + "lie": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/lie/-/lie-3.1.1.tgz", + "integrity": "sha1-mkNrLMd0bKWd56QfpGmz77dr2H4=", + "requires": { + "immediate": "~3.0.5" + } + }, + "load-json-file": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", + "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "parse-json": "^2.2.0", + "pify": "^2.0.0", + "strip-bom": "^3.0.0" + }, + "dependencies": { + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true + } + } + }, + "loader-runner": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-2.4.0.tgz", + "integrity": "sha512-Jsmr89RcXGIwivFY21FcRrisYZfvLMTWx5kOLc+JTxtpBOG6xML0vzbc6SEQG2FO9/4Fc3wW4LVcB5DmGflaRw==", + "dev": true + }, + "loader-utils": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.2.3.tgz", + "integrity": "sha512-fkpz8ejdnEMG3s37wGL07iSBDg99O9D5yflE9RGNH3hRdx9SOwYfnGYdZOUIZitN8E+E2vkq3MUMYMvPYl5ZZA==", + "dev": true, + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^2.0.0", + "json5": "^1.0.1" + }, + "dependencies": { + "json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "dev": true, + "requires": { + "minimist": "^1.2.0" + } + }, + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true + } + } + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + }, + "dependencies": { + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true + } + } + }, + "lodash": { + "version": "4.17.15", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", + "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", + "dev": true + }, + "loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "dev": true, + "requires": { + "js-tokens": "^3.0.0 || ^4.0.0" + } + }, + "lowercase-keys": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", + "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==", + "dev": true + }, + "lru-cache": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", + "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", + "dev": true, + "requires": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" + } + }, + "make-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", + "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", + "dev": true, + "requires": { + "pify": "^4.0.1", + "semver": "^5.6.0" + } + }, + "mamacro": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/mamacro/-/mamacro-0.0.3.tgz", + "integrity": "sha512-qMEwh+UujcQ+kbz3T6V+wAmO2U8veoq2w+3wY8MquqwVA3jChfwY+Tk52GZKDfACEPjuZ7r2oJLejwpt8jtwTA==", + "dev": true + }, + "map-age-cleaner": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz", + "integrity": "sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w==", + "dev": true, + "requires": { + "p-defer": "^1.0.0" + } + }, + "map-cache": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", + "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=", + "dev": true + }, + "map-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", + "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", + "dev": true, + "requires": { + "object-visit": "^1.0.0" + } + }, + "md5.js": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", + "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", + "dev": true, + "requires": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "mem": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/mem/-/mem-4.3.0.tgz", + "integrity": "sha512-qX2bG48pTqYRVmDB37rn/6PT7LcR8T7oAX3bf99u1Tt1nzxYfxkgqDwUwolPlXweM0XzBOBFzSx4kfp7KP1s/w==", + "dev": true, + "requires": { + "map-age-cleaner": "^0.1.1", + "mimic-fn": "^2.0.0", + "p-is-promise": "^2.0.0" + }, + "dependencies": { + "mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true + } + } + }, + "memory-fs": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.4.1.tgz", + "integrity": "sha1-OpoguEYlI+RHz7x+i7gO1me/xVI=", + "dev": true, + "requires": { + "errno": "^0.1.3", + "readable-stream": "^2.0.1" + } + }, + "micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dev": true, + "requires": { + "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" + } + }, + "miller-rabin": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz", + "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==", + "dev": true, + "requires": { + "bn.js": "^4.0.0", + "brorand": "^1.0.1" + } + }, + "mimic-fn": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", + "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", + "dev": true + }, + "minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", + "dev": true + }, + "minimalistic-crypto-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", + "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=", + "dev": true + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", + "dev": true + }, + "mississippi": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mississippi/-/mississippi-3.0.0.tgz", + "integrity": "sha512-x471SsVjUtBRtcvd4BzKE9kFC+/2TeWgKCgw0bZcw1b9l2X3QX5vCWgF+KaZaYm87Ss//rHnWryupDrgLvmSkA==", + "dev": true, + "requires": { + "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": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", + "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", + "dev": true, + "requires": { + "for-in": "^1.0.2", + "is-extendable": "^1.0.1" + }, + "dependencies": { + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4" + } + } + } + }, + "mkdirp": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "dev": true, + "requires": { + "minimist": "0.0.8" + } + }, + "move-concurrently": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz", + "integrity": "sha1-viwAX9oy4LKa8fBdfEszIUxwH5I=", + "dev": true, + "requires": { + "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": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "mute-stream": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz", + "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=", + "dev": true + }, + "nan": { + "version": "2.14.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz", + "integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==", + "dev": true, + "optional": true + }, + "nanomatch": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", + "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", + "dev": true, + "requires": { + "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" + } + }, + "natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", + "dev": true + }, + "neo-async": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.1.tgz", + "integrity": "sha512-iyam8fBuCUpWeKPGpaNMetEocMt364qkCsfL9JuhjXX6dRnguRVOfk2GZaDpPjcOKiiXCPINZC1GczQ7iTq3Zw==", + "dev": true + }, + "next-tick": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz", + "integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw=", + "dev": true + }, + "nice-try": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", + "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", + "dev": true + }, + "node-libs-browser": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/node-libs-browser/-/node-libs-browser-2.2.1.tgz", + "integrity": "sha512-h/zcD8H9kaDZ9ALUWwlBUDo6TKF8a7qBSCSEGfjTVIYeqsioSKaAX+BN7NgiMGp6iSIXZ3PxgCu8KS3b71YK5Q==", + "dev": true, + "requires": { + "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" + }, + "dependencies": { + "process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "dev": true + }, + "punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", + "dev": true + }, + "readable-stream": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + }, + "dependencies": { + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dev": true, + "requires": { + "safe-buffer": "~5.2.0" + }, + "dependencies": { + "safe-buffer": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz", + "integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==", + "dev": true + } + } + } + } + }, + "node-releases": { + "version": "1.1.36", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.36.tgz", + "integrity": "sha512-ggXhX6QGyJSjj3r+6ml2LqqC28XOWmKtpb+a15/Zpr9V3yoNazxJNlcQDS9bYaid5FReEWHEgToH1mwoUceWwg==", + "dev": true, + "requires": { + "semver": "^6.3.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "nodemon": { + "version": "1.19.4", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-1.19.4.tgz", + "integrity": "sha512-VGPaqQBNk193lrJFotBU8nvWZPqEZY2eIzymy2jjY0fJ9qIsxA0sxQ8ATPl0gZC645gijYEc1jtZvpS8QWzJGQ==", + "dev": true, + "requires": { + "chokidar": "^2.1.8", + "debug": "^3.2.6", + "ignore-by-default": "^1.0.1", + "minimatch": "^3.0.4", + "pstree.remy": "^1.1.7", + "semver": "^5.7.1", + "supports-color": "^5.5.0", + "touch": "^3.1.0", + "undefsafe": "^2.0.2", + "update-notifier": "^2.5.0" + }, + "dependencies": { + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + } + } + }, + "nopt": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz", + "integrity": "sha1-bd0hvSoxQXuScn3Vhfim83YI6+4=", + "dev": true, + "requires": { + "abbrev": "1" + } + }, + "normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dev": true, + "requires": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true + }, + "npm-run-path": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", + "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", + "dev": true, + "requires": { + "path-key": "^2.0.0" + } + }, + "number-is-nan": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", + "dev": true + }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", + "dev": true + }, + "object-copy": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", + "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", + "dev": true, + "requires": { + "copy-descriptor": "^0.1.0", + "define-property": "^0.2.5", + "kind-of": "^3.0.3" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "object-inspect": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.6.0.tgz", + "integrity": "sha512-GJzfBZ6DgDAmnuaM3104jR4s1Myxr3Y3zfIyN4z3UdqN69oSRacNK8UhnobDdC+7J2AHCjGwxQubNJfE70SXXQ==", + "dev": true + }, + "object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true + }, + "object-visit": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", + "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", + "dev": true, + "requires": { + "isobject": "^3.0.0" + } + }, + "object.assign": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", + "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", + "dev": true, + "requires": { + "define-properties": "^1.1.2", + "function-bind": "^1.1.1", + "has-symbols": "^1.0.0", + "object-keys": "^1.0.11" + } + }, + "object.entries": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.0.tgz", + "integrity": "sha512-l+H6EQ8qzGRxbkHOd5I/aHRhHDKoQXQ8g0BYt4uSweQU1/J6dZUOyWh9a2Vky35YCKjzmgxOzta2hH6kf9HuXA==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.12.0", + "function-bind": "^1.1.1", + "has": "^1.0.3" + } + }, + "object.pick": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", + "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", + "dev": true, + "requires": { + "isobject": "^3.0.1" + } + }, + "object.values": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.0.tgz", + "integrity": "sha512-8mf0nKLAoFX6VlNVdhGj31SVYpaNFtUnuoOXWyFEstsWRgU837AK+JYM0iAxwkSzGRbwn8cbFmgbyxj1j4VbXg==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.12.0", + "function-bind": "^1.1.1", + "has": "^1.0.3" + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "onetime": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", + "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", + "dev": true, + "requires": { + "mimic-fn": "^1.0.0" + } + }, + "optionator": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz", + "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=", + "dev": true, + "requires": { + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.4", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "wordwrap": "~1.0.0" + }, + "dependencies": { + "wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", + "dev": true + } + } + }, + "os-browserify": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz", + "integrity": "sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc=", + "dev": true + }, + "os-homedir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", + "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", + "dev": true + }, + "os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", + "dev": true + }, + "output-file-sync": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/output-file-sync/-/output-file-sync-2.0.1.tgz", + "integrity": "sha512-mDho4qm7WgIXIGf4eYU1RHN2UU5tPfVYVSRwDJw0uTmj35DQUt/eNp19N7v6T3SrR0ESTEf2up2CGO73qI35zQ==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.11", + "is-plain-obj": "^1.1.0", + "mkdirp": "^0.5.1" + } + }, + "p-defer": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-defer/-/p-defer-1.0.0.tgz", + "integrity": "sha1-n26xgvbJqozXQwBKfU+WsZaw+ww=", + "dev": true + }, + "p-finally": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", + "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", + "dev": true + }, + "p-is-promise": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-2.1.0.tgz", + "integrity": "sha512-Y3W0wlRPK8ZMRbNq97l4M5otioeA5lm1z7bkNkxCka8HSPjR0xRWmpCmc9utiaLP9Jb1eD8BgeIxTW4AIF45Pg==", + "dev": true + }, + "p-limit": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.1.tgz", + "integrity": "sha512-85Tk+90UCVWvbDavCLKPOLC9vvY8OwEX/RtKF+/1OADJMVlFfEHOiMTPVyxg7mk/dKa+ipdHm0OUkTvCpMTuwg==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "requires": { + "p-limit": "^2.0.0" + } + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true + }, + "package-json": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/package-json/-/package-json-4.0.1.tgz", + "integrity": "sha1-iGmgQBJTZhxMTKPabCEh7VVfXu0=", + "dev": true, + "requires": { + "got": "^6.7.1", + "registry-auth-token": "^3.0.1", + "registry-url": "^3.0.3", + "semver": "^5.1.0" + } + }, + "pako": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.10.tgz", + "integrity": "sha512-0DTvPVU3ed8+HNXOu5Bs+o//Mbdj9VNQMUOe9oKCwh8l0GNwpTDMKCWbRjgtD291AWnkAgkqA/LOnQS8AmS1tw==" + }, + "parallel-transform": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/parallel-transform/-/parallel-transform-1.2.0.tgz", + "integrity": "sha512-P2vSmIu38uIlvdcU7fDkyrxj33gTUy/ABO5ZUbGowxNCopBq/OoD42bP4UmMrJoPyk4Uqf0mu3mtWBhHCZD8yg==", + "dev": true, + "requires": { + "cyclist": "^1.0.1", + "inherits": "^2.0.3", + "readable-stream": "^2.1.5" + }, + "dependencies": { + "process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "dev": true + }, + "readable-stream": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "requires": { + "callsites": "^3.0.0" + } + }, + "parse-asn1": { + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.5.tgz", + "integrity": "sha512-jkMYn1dcJqF6d5CpU689bq7w/b5ALS9ROVSpQDPrZsqqesUJii9qutvoT5ltGedNXMO2e16YUWIghG9KxaViTQ==", + "dev": true, + "requires": { + "asn1.js": "^4.0.0", + "browserify-aes": "^1.0.0", + "create-hash": "^1.1.0", + "evp_bytestokey": "^1.0.0", + "pbkdf2": "^3.0.3", + "safe-buffer": "^5.1.1" + } + }, + "parse-json": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", + "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", + "dev": true, + "requires": { + "error-ex": "^1.2.0" + } + }, + "parse-passwd": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz", + "integrity": "sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY=", + "dev": true + }, + "pascalcase": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", + "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=", + "dev": true + }, + "path-browserify": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-0.0.1.tgz", + "integrity": "sha512-BapA40NHICOS+USX9SN4tyhq+A2RrN/Ws5F0Z5aMHDp98Fl86lX8Oti8B7uN93L4Ifv4fHOEA+pQw87gmMO/lQ==", + "dev": true + }, + "path-dirname": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz", + "integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=", + "dev": true + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true + }, + "path-is-inside": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", + "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=", + "dev": true + }, + "path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", + "dev": true + }, + "path-parse": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", + "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", + "dev": true + }, + "path-type": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz", + "integrity": "sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=", + "dev": true, + "requires": { + "pify": "^2.0.0" + }, + "dependencies": { + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true + } + } + }, + "pbkdf2": { + "version": "3.0.17", + "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.0.17.tgz", + "integrity": "sha512-U/il5MsrZp7mGg3mSQfn742na2T+1/vHDCG5/iTI3X9MKUuYUZVLQhyRsg06mCgDBTd57TxzgZt7P+fYfjRLtA==", + "dev": true, + "requires": { + "create-hash": "^1.1.2", + "create-hmac": "^1.1.4", + "ripemd160": "^2.0.1", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + } + }, + "pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true + }, + "pkg-dir": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", + "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", + "dev": true, + "requires": { + "find-up": "^3.0.0" + } + }, + "pluralize": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-1.2.1.tgz", + "integrity": "sha1-0aIUg/0iu0HlihL6NCGCMUCJfEU=", + "dev": true + }, + "posix-character-classes": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", + "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=", + "dev": true + }, + "prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", + "dev": true + }, + "prepend-http": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz", + "integrity": "sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=", + "dev": true + }, + "private": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/private/-/private-0.1.8.tgz", + "integrity": "sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg==", + "dev": true + }, + "process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=", + "dev": true + }, + "process-nextick-args": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", + "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=" + }, + "progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "dev": true + }, + "promise-inflight": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", + "integrity": "sha1-mEcocL8igTL8vdhoEputEsPAKeM=", + "dev": true + }, + "prr": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", + "integrity": "sha1-0/wRS6BplaRexok/SEzrHXj19HY=", + "dev": true + }, + "pseudomap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", + "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", + "dev": true + }, + "pstree.remy": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.7.tgz", + "integrity": "sha512-xsMgrUwRpuGskEzBFkH8NmTimbZ5PcPup0LA8JJkHIm2IMUbQcpo3yeLNWVrufEYjh8YwtSVh0xz6UeWc5Oh5A==", + "dev": true + }, + "public-encrypt": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz", + "integrity": "sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==", + "dev": true, + "requires": { + "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": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dev": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "pumpify": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-1.5.1.tgz", + "integrity": "sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==", + "dev": true, + "requires": { + "duplexify": "^3.6.0", + "inherits": "^2.0.3", + "pump": "^2.0.0" + }, + "dependencies": { + "pump": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz", + "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==", + "dev": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + } + } + }, + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "dev": true + }, + "querystring": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", + "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=", + "dev": true + }, + "querystring-es3": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz", + "integrity": "sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM=", + "dev": true + }, + "randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "requires": { + "safe-buffer": "^5.1.0" + } + }, + "randomfill": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz", + "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==", + "dev": true, + "requires": { + "randombytes": "^2.0.5", + "safe-buffer": "^5.1.0" + } + }, + "rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "dev": true, + "requires": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true + }, + "strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", + "dev": true + } + } + }, + "read-pkg": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz", + "integrity": "sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg=", + "dev": true, + "requires": { + "load-json-file": "^2.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^2.0.0" + } + }, + "read-pkg-up": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-2.0.0.tgz", + "integrity": "sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4=", + "dev": true, + "requires": { + "find-up": "^2.0.0", + "read-pkg": "^2.0.0" + }, + "dependencies": { + "find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dev": true, + "requires": { + "locate-path": "^2.0.0" + } + }, + "locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "dev": true, + "requires": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + } + }, + "p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dev": true, + "requires": { + "p-try": "^1.0.0" + } + }, + "p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "dev": true, + "requires": { + "p-limit": "^1.1.0" + } + }, + "p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", + "dev": true + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true + } + } + }, + "readable-stream": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.0.6.tgz", + "integrity": "sha1-j5A0HmilPMySh4jaz80Rs265t44=", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "~1.0.0", + "process-nextick-args": "~1.0.6", + "string_decoder": "~0.10.x", + "util-deprecate": "~1.0.1" + } + }, + "readdirp": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", + "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.11", + "micromatch": "^3.1.10", + "readable-stream": "^2.0.2" + } + }, + "readline2": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/readline2/-/readline2-1.0.1.tgz", + "integrity": "sha1-QQWWCP/BVHV7cV2ZidGZ/783LjU=", + "dev": true, + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "mute-stream": "0.0.5" + }, + "dependencies": { + "is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "dev": true, + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "mute-stream": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.5.tgz", + "integrity": "sha1-j7+rsKmKJT0xhDMfno3rc3L6xsA=", + "dev": true + } + } + }, + "rechoir": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", + "integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=", + "dev": true, + "requires": { + "resolve": "^1.1.6" + } + }, + "regenerate": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.0.tgz", + "integrity": "sha512-1G6jJVDWrt0rK99kBjvEtziZNCICAuvIPkSiUFIQxVP06RCVpq3dmDo2oi6ABpYaDYaTRr67BEhL8r1wgEZZKg==", + "dev": true + }, + "regenerate-unicode-properties": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-8.1.0.tgz", + "integrity": "sha512-LGZzkgtLY79GeXLm8Dp0BVLdQlWICzBnJz/ipWUgo59qBaZ+BHtq51P2q1uVZlppMuUAT37SDk39qUbjTWB7bA==", + "dev": true, + "requires": { + "regenerate": "^1.4.0" + } + }, + "regenerator-transform": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.14.1.tgz", + "integrity": "sha512-flVuee02C3FKRISbxhXl9mGzdbWUVHubl1SMaknjxkFB1/iqpJhArQUvRxOOPEc/9tAiX0BaQ28FJH10E4isSQ==", + "dev": true, + "requires": { + "private": "^0.1.6" + } + }, + "regex-not": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", + "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", + "dev": true, + "requires": { + "extend-shallow": "^3.0.2", + "safe-regex": "^1.1.0" + } + }, + "regexpp": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-2.0.1.tgz", + "integrity": "sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw==", + "dev": true + }, + "regexpu-core": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-4.6.0.tgz", + "integrity": "sha512-YlVaefl8P5BnFYOITTNzDvan1ulLOiXJzCNZxduTIosN17b87h3bvG9yHMoHaRuo88H4mQ06Aodj5VtYGGGiTg==", + "dev": true, + "requires": { + "regenerate": "^1.4.0", + "regenerate-unicode-properties": "^8.1.0", + "regjsgen": "^0.5.0", + "regjsparser": "^0.6.0", + "unicode-match-property-ecmascript": "^1.0.4", + "unicode-match-property-value-ecmascript": "^1.1.0" + } + }, + "registry-auth-token": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-3.4.0.tgz", + "integrity": "sha512-4LM6Fw8eBQdwMYcES4yTnn2TqIasbXuwDx3um+QRs7S55aMKCBKBxvPXl2RiUjHwuJLTyYfxSpmfSAjQpcuP+A==", + "dev": true, + "requires": { + "rc": "^1.1.6", + "safe-buffer": "^5.0.1" + } + }, + "registry-url": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-3.1.0.tgz", + "integrity": "sha1-PU74cPc93h138M+aOBQyRE4XSUI=", + "dev": true, + "requires": { + "rc": "^1.0.1" + } + }, + "regjsgen": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.5.1.tgz", + "integrity": "sha512-5qxzGZjDs9w4tzT3TPhCJqWdCc3RLYwy9J2NB0nm5Lz+S273lvWcpjaTGHsT1dc6Hhfq41uSEOw8wBmxrKOuyg==", + "dev": true + }, + "regjsparser": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.6.0.tgz", + "integrity": "sha512-RQ7YyokLiQBomUJuUG8iGVvkgOLxwyZM8k6d3q5SAXpg4r5TZJZigKFvC6PpD+qQ98bCDC5YelPeA3EucDoNeQ==", + "dev": true, + "requires": { + "jsesc": "~0.5.0" + }, + "dependencies": { + "jsesc": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=", + "dev": true + } + } + }, + "remove-trailing-separator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", + "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=", + "dev": true + }, + "repeat-element": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz", + "integrity": "sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==", + "dev": true + }, + "repeat-string": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", + "dev": true + }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", + "dev": true + }, + "require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", + "dev": true + }, + "require-uncached": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/require-uncached/-/require-uncached-1.0.3.tgz", + "integrity": "sha1-Tg1W1slmL9MeQwEcS5WqSZVUIdM=", + "dev": true, + "requires": { + "caller-path": "^0.1.0", + "resolve-from": "^1.0.0" + }, + "dependencies": { + "resolve-from": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-1.0.1.tgz", + "integrity": "sha1-Jsv+k10a7uq7Kbw/5a6wHpPUQiY=", + "dev": true + } + } + }, + "resolve": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.12.0.tgz", + "integrity": "sha512-B/dOmuoAik5bKcD6s6nXDCjzUKnaDvdkRyAk6rsmsKLipWj4797iothd7jmmUhWTfinVMU+wc56rYKsit2Qy4w==", + "dev": true, + "requires": { + "path-parse": "^1.0.6" + } + }, + "resolve-cwd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-2.0.0.tgz", + "integrity": "sha1-AKn3OHVW4nA46uIyyqNypqWbZlo=", + "dev": true, + "requires": { + "resolve-from": "^3.0.0" + }, + "dependencies": { + "resolve-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", + "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=", + "dev": true + } + } + }, + "resolve-dir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-1.0.1.tgz", + "integrity": "sha1-eaQGRMNivoLybv/nOcm7U4IEb0M=", + "dev": true, + "requires": { + "expand-tilde": "^2.0.0", + "global-modules": "^1.0.0" + }, + "dependencies": { + "global-modules": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz", + "integrity": "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==", + "dev": true, + "requires": { + "global-prefix": "^1.0.1", + "is-windows": "^1.0.1", + "resolve-dir": "^1.0.0" + } + } + } + }, + "resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true + }, + "resolve-url": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", + "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=", + "dev": true + }, + "restore-cursor": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", + "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", + "dev": true, + "requires": { + "onetime": "^2.0.0", + "signal-exit": "^3.0.2" + } + }, + "ret": { + "version": "0.1.15", + "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", + "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", + "dev": true + }, + "rimraf": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", + "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "ripemd160": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", + "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", + "dev": true, + "requires": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1" + } + }, + "run-async": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.3.0.tgz", + "integrity": "sha1-A3GrSuC91yDUFm19/aZP96RFpsA=", + "dev": true, + "requires": { + "is-promise": "^2.1.0" + } + }, + "run-queue": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/run-queue/-/run-queue-1.0.3.tgz", + "integrity": "sha1-6Eg5bwV9Ij8kOGkkYY4laUFh7Ec=", + "dev": true, + "requires": { + "aproba": "^1.1.1" + } + }, + "rx-lite": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/rx-lite/-/rx-lite-3.1.2.tgz", + "integrity": "sha1-Gc5QLKVyZl87ZHsQk5+X/RYV8QI=", + "dev": true + }, + "rxjs": { + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.5.3.tgz", + "integrity": "sha512-wuYsAYYFdWTAnAaPoKGNhfpWwKZbJW+HgAJ+mImp+Epl7BG8oNWBCTyRM8gba9k4lk8BgWdoYm21Mo/RYhhbgA==", + "dev": true, + "requires": { + "tslib": "^1.9.0" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "safe-regex": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", + "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", + "dev": true, + "requires": { + "ret": "~0.1.10" + } + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true + }, + "schema-utils": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", + "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", + "dev": true, + "requires": { + "ajv": "^6.1.0", + "ajv-errors": "^1.0.0", + "ajv-keywords": "^3.1.0" + }, + "dependencies": { + "ajv-keywords": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.4.1.tgz", + "integrity": "sha512-RO1ibKvd27e6FEShVFfPALuHI3WjSVNeK5FIsmme/LYRNxjKuNj+Dt7bucLa6NdSv3JcVTyMlm9kGR84z1XpaQ==", + "dev": true + } + } + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + }, + "semver-diff": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-2.1.0.tgz", + "integrity": "sha1-S7uEN8jTfksM8aaP1ybsbWRdbTY=", + "dev": true, + "requires": { + "semver": "^5.0.3" + } + }, + "serialize-javascript": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-2.1.2.tgz", + "integrity": "sha512-rs9OggEUF0V4jUSecXazOYsLfu7OGK2qIn3c7IPBiffz32XniEp/TX9Xmc9LQfK2nQ2QKHvZ2oygKUGU0lG4jQ==", + "dev": true + }, + "set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", + "dev": true + }, + "set-value": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", + "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-extendable": "^0.1.1", + "is-plain-object": "^2.0.3", + "split-string": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=", + "dev": true + }, + "sha.js": { + "version": "2.4.11", + "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", + "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", + "dev": true, + "requires": { + "shebang-regex": "^1.0.0" + } + }, + "shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", + "dev": true + }, + "shelljs": { + "version": "0.7.8", + "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.7.8.tgz", + "integrity": "sha1-3svPh0sNHl+3LhSxZKloMEjprLM=", + "dev": true, + "requires": { + "glob": "^7.0.0", + "interpret": "^1.0.0", + "rechoir": "^0.6.2" + } + }, + "signal-exit": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", + "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", + "dev": true + }, + "slash": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", + "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", + "dev": true + }, + "slice-ansi": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz", + "integrity": "sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.0", + "astral-regex": "^1.0.0", + "is-fullwidth-code-point": "^2.0.0" + } + }, + "snapdragon": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", + "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", + "dev": true, + "requires": { + "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" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "snapdragon-node": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", + "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", + "dev": true, + "requires": { + "define-property": "^1.0.0", + "isobject": "^3.0.0", + "snapdragon-util": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "snapdragon-util": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", + "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", + "dev": true, + "requires": { + "kind-of": "^3.2.0" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "source-list-map": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.1.tgz", + "integrity": "sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw==", + "dev": true + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + }, + "source-map-resolve": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.2.tgz", + "integrity": "sha512-MjqsvNwyz1s0k81Goz/9vRBe9SZdB09Bdw+/zYyO+3CuPk6fouTaxscHkgtE8jKvf01kVfl8riHzERQ/kefaSA==", + "dev": true, + "requires": { + "atob": "^2.1.1", + "decode-uri-component": "^0.2.0", + "resolve-url": "^0.2.1", + "source-map-url": "^0.4.0", + "urix": "^0.1.0" + } + }, + "source-map-url": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz", + "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=", + "dev": true + }, + "spdx-correct": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.0.tgz", + "integrity": "sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q==", + "dev": true, + "requires": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-exceptions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.2.0.tgz", + "integrity": "sha512-2XQACfElKi9SlVb1CYadKDXvoajPgBVPn/gOQLrTvHdElaVhr7ZEbqJaRnJLVNeaI4cMEAgVCeBMKF6MWRDCRA==", + "dev": true + }, + "spdx-expression-parse": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz", + "integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==", + "dev": true, + "requires": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-license-ids": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.5.tgz", + "integrity": "sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q==", + "dev": true + }, + "split-string": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", + "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", + "dev": true, + "requires": { + "extend-shallow": "^3.0.0" + } + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + }, + "ssri": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-6.0.1.tgz", + "integrity": "sha512-3Wge10hNcT1Kur4PDFwEieXSCMCJs/7WvSACcrMYrNp+b8kDL1/0wJch5Ni2WrtwEa2IO8OsVfeKIciKCDx/QA==", + "dev": true, + "requires": { + "figgy-pudding": "^3.5.1" + } + }, + "static-extend": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", + "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", + "dev": true, + "requires": { + "define-property": "^0.2.5", + "object-copy": "^0.1.0" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + } + } + }, + "stream-browserify": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.2.tgz", + "integrity": "sha512-nX6hmklHs/gr2FuxYDltq8fJA1GDlxKQCz8O/IM4atRqBH8OORmBNgfvW5gG10GT/qQ9u0CzIvr2X5Pkt6ntqg==", + "dev": true, + "requires": { + "inherits": "~2.0.1", + "readable-stream": "^2.0.2" + } + }, + "stream-each": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/stream-each/-/stream-each-1.2.3.tgz", + "integrity": "sha512-vlMC2f8I2u/bZGqkdfLQW/13Zihpej/7PmSiMQsbYddxuTsJp8vRe2x2FvVExZg7FaOds43ROAuFJwPR4MTZLw==", + "dev": true, + "requires": { + "end-of-stream": "^1.1.0", + "stream-shift": "^1.0.0" + } + }, + "stream-http": { + "version": "2.8.3", + "resolved": "https://registry.npmjs.org/stream-http/-/stream-http-2.8.3.tgz", + "integrity": "sha512-+TSkfINHDo4J+ZobQLWiMouQYB+UVYFttRA94FpEzzJ7ZdqcL4uUUQ7WkdkI4DSozGmgBUE/a47L+38PenXhUw==", + "dev": true, + "requires": { + "builtin-status-codes": "^3.0.0", + "inherits": "^2.0.1", + "readable-stream": "^2.3.6", + "to-arraybuffer": "^1.0.0", + "xtend": "^4.0.0" + }, + "dependencies": { + "process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "dev": true + }, + "readable-stream": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "stream-shift": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.0.tgz", + "integrity": "sha1-1cdSgl5TZ+eG944Y5EXqIjoVWVI=", + "dev": true + }, + "string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dev": true, + "requires": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "^3.0.0" + } + } + } + }, + "string.prototype.trimleft": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/string.prototype.trimleft/-/string.prototype.trimleft-2.1.0.tgz", + "integrity": "sha512-FJ6b7EgdKxxbDxc79cOlok6Afd++TTs5szo+zJTUyow3ycrRfJVE2pq3vcN53XexvKZu/DJMDfeI/qMiZTrjTw==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "function-bind": "^1.1.1" + } + }, + "string.prototype.trimright": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/string.prototype.trimright/-/string.prototype.trimright-2.1.0.tgz", + "integrity": "sha512-fXZTSV55dNBwv16uw+hh5jkghxSnc5oHq+5K/gXgizHwAvMetdAJlHqqoFC1FSDVPYWLkAKl2cxpUT41sV7nSg==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "function-bind": "^1.1.1" + } + }, + "string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dev": true, + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true + }, + "strip-eof": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", + "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", + "dev": true + }, + "strip-json-comments": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.0.1.tgz", + "integrity": "sha512-VTyMAUfdm047mwKl+u79WIdrZxtFtn+nBxHeb844XBQ9uMNTuTHdx2hc5RiAJYqwTj3wc/xe5HLSdJSkJ+WfZw==", + "dev": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "table": { + "version": "5.4.6", + "resolved": "https://registry.npmjs.org/table/-/table-5.4.6.tgz", + "integrity": "sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug==", + "dev": true, + "requires": { + "ajv": "^6.10.2", + "lodash": "^4.17.14", + "slice-ansi": "^2.1.0", + "string-width": "^3.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + } + } + }, + "tapable": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-1.1.3.tgz", + "integrity": "sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==", + "dev": true + }, + "term-size": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/term-size/-/term-size-1.2.0.tgz", + "integrity": "sha1-RYuDiH8oj8Vtb/+/rSYuJmOO+mk=", + "dev": true, + "requires": { + "execa": "^0.7.0" + } + }, + "terser": { + "version": "4.6.6", + "resolved": "https://registry.npmjs.org/terser/-/terser-4.6.6.tgz", + "integrity": "sha512-4lYPyeNmstjIIESr/ysHg2vUPRGf2tzF9z2yYwnowXVuVzLEamPN1Gfrz7f8I9uEPuHcbFlW4PLIAsJoxXyJ1g==", + "dev": true, + "requires": { + "commander": "^2.20.0", + "source-map": "~0.6.1", + "source-map-support": "~0.5.12" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "source-map-support": { + "version": "0.5.16", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.16.tgz", + "integrity": "sha512-efyLRJDr68D9hBBNIPWFjhpFzURh+KJykQwvMyW5UiZzYwoF6l4YMMDIJJEyFWxWCqfyxLzz6tSfUFR+kXXsVQ==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + } + } + }, + "terser-webpack-plugin": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-1.4.3.tgz", + "integrity": "sha512-QMxecFz/gHQwteWwSo5nTc6UaICqN1bMedC5sMtUc7y3Ha3Q8y6ZO0iCR8pq4RJC8Hjf0FEPEHZqcMB/+DFCrA==", + "dev": true, + "requires": { + "cacache": "^12.0.2", + "find-cache-dir": "^2.1.0", + "is-wsl": "^1.1.0", + "schema-utils": "^1.0.0", + "serialize-javascript": "^2.1.2", + "source-map": "^0.6.1", + "terser": "^4.1.2", + "webpack-sources": "^1.4.0", + "worker-farm": "^1.7.0" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", + "dev": true + }, + "through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", + "dev": true + }, + "through2": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "dev": true, + "requires": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + }, + "dependencies": { + "process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "dev": true + }, + "readable-stream": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "timed-out": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/timed-out/-/timed-out-4.0.1.tgz", + "integrity": "sha1-8y6srFoXW+ol1/q1Zas+2HQe9W8=", + "dev": true + }, + "timers-browserify": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.11.tgz", + "integrity": "sha512-60aV6sgJ5YEbzUdn9c8kYGIqOubPoUdqQCul3SBAsRCZ40s6Y5cMcrW4dt3/k/EsbLVJNl9n6Vz3fTc+k2GeKQ==", + "dev": true, + "requires": { + "setimmediate": "^1.0.4" + } + }, + "tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "dev": true, + "requires": { + "os-tmpdir": "~1.0.2" + } + }, + "to-arraybuffer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz", + "integrity": "sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M=", + "dev": true + }, + "to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", + "dev": true + }, + "to-object-path": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", + "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "to-regex": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", + "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", + "dev": true, + "requires": { + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "regex-not": "^1.0.2", + "safe-regex": "^1.1.0" + } + }, + "to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "dev": true, + "requires": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + } + }, + "touch": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz", + "integrity": "sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==", + "dev": true, + "requires": { + "nopt": "~1.0.10" + } + }, + "tslib": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz", + "integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==", + "dev": true + }, + "tty-browserify": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz", + "integrity": "sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY=", + "dev": true + }, + "type": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz", + "integrity": "sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==", + "dev": true + }, + "type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", + "dev": true, + "requires": { + "prelude-ls": "~1.1.2" + } + }, + "typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", + "dev": true + }, + "undefsafe": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.2.tgz", + "integrity": "sha1-Il9rngM3Zj4Njnz9aG/Cg2zKznY=", + "dev": true, + "requires": { + "debug": "^2.2.0" + } + }, + "unicode-canonical-property-names-ecmascript": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz", + "integrity": "sha512-jDrNnXWHd4oHiTZnx/ZG7gtUTVp+gCcTTKr8L0HjlwphROEW3+Him+IpvC+xcJEFegapiMZyZe02CyuOnRmbnQ==", + "dev": true + }, + "unicode-match-property-ecmascript": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-1.0.4.tgz", + "integrity": "sha512-L4Qoh15vTfntsn4P1zqnHulG0LdXgjSO035fEpdtp6YxXhMT51Q6vgM5lYdG/5X3MjS+k/Y9Xw4SFCY9IkR0rg==", + "dev": true, + "requires": { + "unicode-canonical-property-names-ecmascript": "^1.0.4", + "unicode-property-aliases-ecmascript": "^1.0.4" + } + }, + "unicode-match-property-value-ecmascript": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-1.1.0.tgz", + "integrity": "sha512-hDTHvaBk3RmFzvSl0UVrUmC3PuW9wKVnpoUDYH0JDkSIovzw+J5viQmeYHxVSBptubnr7PbH2e0fnpDRQnQl5g==", + "dev": true + }, + "unicode-property-aliases-ecmascript": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-1.0.5.tgz", + "integrity": "sha512-L5RAqCfXqAwR3RriF8pM0lU0w4Ryf/GgzONwi6KnL1taJQa7x1TCxdJnILX59WIGOwR57IVxn7Nej0fz1Ny6fw==", + "dev": true + }, + "union-value": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", + "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", + "dev": true, + "requires": { + "arr-union": "^3.1.0", + "get-value": "^2.0.6", + "is-extendable": "^0.1.1", + "set-value": "^2.0.1" + } + }, + "unique-filename": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz", + "integrity": "sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==", + "dev": true, + "requires": { + "unique-slug": "^2.0.0" + } + }, + "unique-slug": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.2.tgz", + "integrity": "sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w==", + "dev": true, + "requires": { + "imurmurhash": "^0.1.4" + } + }, + "unique-string": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-1.0.0.tgz", + "integrity": "sha1-nhBXzKhRq7kzmPizOuGHuZyuwRo=", + "dev": true, + "requires": { + "crypto-random-string": "^1.0.0" + } + }, + "unset-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", + "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", + "dev": true, + "requires": { + "has-value": "^0.3.1", + "isobject": "^3.0.0" + }, + "dependencies": { + "has-value": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", + "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", + "dev": true, + "requires": { + "get-value": "^2.0.3", + "has-values": "^0.1.4", + "isobject": "^2.0.0" + }, + "dependencies": { + "isobject": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", + "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", + "dev": true, + "requires": { + "isarray": "1.0.0" + } + } + } + }, + "has-values": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", + "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=", + "dev": true + } + } + }, + "unzip-response": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/unzip-response/-/unzip-response-2.0.1.tgz", + "integrity": "sha1-0vD3N9FrBhXnKmk17QQhRXLVb5c=", + "dev": true + }, + "upath": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz", + "integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==", + "dev": true + }, + "update-notifier": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-2.5.0.tgz", + "integrity": "sha512-gwMdhgJHGuj/+wHJJs9e6PcCszpxR1b236igrOkUofGhqJuG+amlIKwApH1IW1WWl7ovZxsX49lMBWLxSdm5Dw==", + "dev": true, + "requires": { + "boxen": "^1.2.1", + "chalk": "^2.0.1", + "configstore": "^3.0.0", + "import-lazy": "^2.1.0", + "is-ci": "^1.0.10", + "is-installed-globally": "^0.1.0", + "is-npm": "^1.0.0", + "latest-version": "^3.0.0", + "semver-diff": "^2.0.0", + "xdg-basedir": "^3.0.0" + } + }, + "uri-js": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", + "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", + "dev": true, + "requires": { + "punycode": "^2.1.0" + } + }, + "urix": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", + "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=", + "dev": true + }, + "url": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/url/-/url-0.11.0.tgz", + "integrity": "sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE=", + "dev": true, + "requires": { + "punycode": "1.3.2", + "querystring": "0.2.0" + }, + "dependencies": { + "punycode": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", + "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=", + "dev": true + } + } + }, + "url-parse-lax": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-1.0.0.tgz", + "integrity": "sha1-evjzA2Rem9eaJy56FKxovAYJ2nM=", + "dev": true, + "requires": { + "prepend-http": "^1.0.1" + } + }, + "use": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", + "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==", + "dev": true + }, + "util": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/util/-/util-0.11.1.tgz", + "integrity": "sha512-HShAsny+zS2TZfaXxD9tYj4HQGlBezXZMZuM/S5PKLLoZkShZiGk9o5CzukI1LVHZvjdvZ2Sj1aW/Ndn2NB/HQ==", + "dev": true, + "requires": { + "inherits": "2.0.3" + }, + "dependencies": { + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "dev": true + } + } + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + }, + "uuid": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.3.tgz", + "integrity": "sha512-pW0No1RGHgzlpHJO1nsVrHKpOEIxkGg1xB+v0ZmdNH5OAeAwzAVrCnI2/6Mtx+Uys6iaylxa+D3g4j63IKKjSQ==", + "dev": true + }, + "v8-compile-cache": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.1.0.tgz", + "integrity": "sha512-usZBT3PW+LOjM25wbqIlZwPeJV+3OSz3M1k1Ws8snlW39dZyYL9lOGC5FgPVHfk0jKmjiDV8Z0mIbVQPiwFs7g==", + "dev": true + }, + "validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, + "requires": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "vm-browserify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.0.tgz", + "integrity": "sha512-iq+S7vZJE60yejDYM0ek6zg308+UZsdtPExWP9VZoCFCz1zkJoXFnAX7aZfd/ZwrkidzdUZL0C/ryW+JwAiIGw==", + "dev": true + }, + "watchpack": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.6.0.tgz", + "integrity": "sha512-i6dHe3EyLjMmDlU1/bGQpEw25XSjkJULPuAVKCbNRefQVq48yXKUpwg538F7AZTf9kyr57zj++pQFltUa5H7yA==", + "dev": true, + "requires": { + "chokidar": "^2.0.2", + "graceful-fs": "^4.1.2", + "neo-async": "^2.5.0" + } + }, + "webpack": { + "version": "4.41.2", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-4.41.2.tgz", + "integrity": "sha512-Zhw69edTGfbz9/8JJoyRQ/pq8FYUoY0diOXqW0T6yhgdhCv6wr0hra5DwwWexNRns2Z2+gsnrNcbe9hbGBgk/A==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.8.5", + "@webassemblyjs/helper-module-context": "1.8.5", + "@webassemblyjs/wasm-edit": "1.8.5", + "@webassemblyjs/wasm-parser": "1.8.5", + "acorn": "^6.2.1", + "ajv": "^6.10.2", + "ajv-keywords": "^3.4.1", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^4.1.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.1", + "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.1", + "watchpack": "^1.6.0", + "webpack-sources": "^1.4.1" + }, + "dependencies": { + "acorn": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.3.0.tgz", + "integrity": "sha512-/czfa8BwS88b9gWQVhc8eknunSA2DoJpJyTQkhheIf5E48u1N0R4q/YxxsAeqRrmK9TQ/uYfgLDfZo91UlANIA==", + "dev": true + }, + "ajv-keywords": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.4.1.tgz", + "integrity": "sha512-RO1ibKvd27e6FEShVFfPALuHI3WjSVNeK5FIsmme/LYRNxjKuNj+Dt7bucLa6NdSv3JcVTyMlm9kGR84z1XpaQ==", + "dev": true + }, + "eslint-scope": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.3.tgz", + "integrity": "sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg==", + "dev": true, + "requires": { + "esrecurse": "^4.1.0", + "estraverse": "^4.1.1" + } + } + } + }, + "webpack-cli": { + "version": "3.3.9", + "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-3.3.9.tgz", + "integrity": "sha512-xwnSxWl8nZtBl/AFJCOn9pG7s5CYUYdZxmmukv+fAHLcBIHM36dImfpQg3WfShZXeArkWlf6QRw24Klcsv8a5A==", + "dev": true, + "requires": { + "chalk": "2.4.2", + "cross-spawn": "6.0.5", + "enhanced-resolve": "4.1.0", + "findup-sync": "3.0.0", + "global-modules": "2.0.0", + "import-local": "2.0.0", + "interpret": "1.2.0", + "loader-utils": "1.2.3", + "supports-color": "6.1.0", + "v8-compile-cache": "2.0.3", + "yargs": "13.2.4" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "cliui": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", + "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", + "dev": true, + "requires": { + "string-width": "^3.1.0", + "strip-ansi": "^5.2.0", + "wrap-ansi": "^5.1.0" + } + }, + "enhanced-resolve": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-4.1.0.tgz", + "integrity": "sha512-F/7vkyTtyc/llOIn8oWclcB25KdRaiPBpZYDgJHgh/UHtpgT2p2eldQgtQnLtUvfMKPKxbRaQM/hHkvLHt1Vng==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "memory-fs": "^0.4.0", + "tapable": "^1.0.0" + } + }, + "execa": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", + "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", + "dev": true, + "requires": { + "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" + } + }, + "get-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "dev": true, + "requires": { + "pump": "^3.0.0" + } + }, + "invert-kv": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-2.0.0.tgz", + "integrity": "sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA==", + "dev": true + }, + "lcid": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lcid/-/lcid-2.0.0.tgz", + "integrity": "sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA==", + "dev": true, + "requires": { + "invert-kv": "^2.0.0" + } + }, + "os-locale": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-3.1.0.tgz", + "integrity": "sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q==", + "dev": true, + "requires": { + "execa": "^1.0.0", + "lcid": "^2.0.0", + "mem": "^4.0.0" + } + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "v8-compile-cache": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.0.3.tgz", + "integrity": "sha512-CNmdbwQMBjwr9Gsmohvm0pbL954tJrNzf6gWL3K+QMQf00PF7ERGrEiLgjuU3mKreLC2MeGhUsNV9ybTbLgd3w==", + "dev": true + }, + "y18n": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", + "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==", + "dev": true + }, + "yargs": { + "version": "13.2.4", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.2.4.tgz", + "integrity": "sha512-HG/DWAJa1PAnHT9JAhNa8AbAv3FPaiLzioSjCcmuXXhP8MlpHO5vwls4g4j6n30Z74GVQj8Xa62dWVx1QCGklg==", + "dev": true, + "requires": { + "cliui": "^5.0.0", + "find-up": "^3.0.0", + "get-caller-file": "^2.0.1", + "os-locale": "^3.1.0", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^3.0.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^13.1.0" + } + } + } + }, + "webpack-log": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/webpack-log/-/webpack-log-2.0.0.tgz", + "integrity": "sha512-cX8G2vR/85UYG59FgkoMamwHUIkSSlV3bBMRsbxVXVUk2j6NleCKjQ/WE9eYg9WY4w25O9w8wKP4rzNZFmUcUg==", + "dev": true, + "requires": { + "ansi-colors": "^3.0.0", + "uuid": "^3.3.2" + } + }, + "webpack-sources": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.4.3.tgz", + "integrity": "sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ==", + "dev": true, + "requires": { + "source-list-map": "^2.0.0", + "source-map": "~0.6.1" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "which-module": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", + "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", + "dev": true + }, + "widest-line": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-2.0.1.tgz", + "integrity": "sha512-Ba5m9/Fa4Xt9eb2ELXt77JxVDV8w7qQrH0zS/TWSJdLyAwQjWoOzpzj5lwVftDz6n/EOu3tNACS84v509qwnJA==", + "dev": true, + "requires": { + "string-width": "^2.1.1" + } + }, + "worker-farm": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/worker-farm/-/worker-farm-1.7.0.tgz", + "integrity": "sha512-rvw3QTZc8lAxyVrqcSGVm5yP/IJ2UcB3U0graE3LCFoZ0Yn2x4EoVSqJKdB/T5M+FLcRPjz4TDacRf3OCfNUzw==", + "dev": true, + "requires": { + "errno": "~0.1.7" + } + }, + "worker-loader": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/worker-loader/-/worker-loader-2.0.0.tgz", + "integrity": "sha512-tnvNp4K3KQOpfRnD20m8xltE3eWh89Ye+5oj7wXEEHKac1P4oZ6p9oTj8/8ExqoSBnk9nu5Pr4nKfQ1hn2APJw==", + "dev": true, + "requires": { + "loader-utils": "^1.0.0", + "schema-utils": "^0.4.0" + }, + "dependencies": { + "ajv-keywords": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.4.1.tgz", + "integrity": "sha512-RO1ibKvd27e6FEShVFfPALuHI3WjSVNeK5FIsmme/LYRNxjKuNj+Dt7bucLa6NdSv3JcVTyMlm9kGR84z1XpaQ==", + "dev": true + }, + "schema-utils": { + "version": "0.4.7", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-0.4.7.tgz", + "integrity": "sha512-v/iwU6wvwGK8HbU9yi3/nhGzP0yGSuhQMzL6ySiec1FSrZZDkhm4noOSWzrNFo/jEc+SJY6jRTwuwbSXJPDUnQ==", + "dev": true, + "requires": { + "ajv": "^6.1.0", + "ajv-keywords": "^3.1.0" + } + } + } + }, + "wrap-ansi": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", + "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.0", + "string-width": "^3.0.0", + "strip-ansi": "^5.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + } + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "write": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/write/-/write-1.0.3.tgz", + "integrity": "sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig==", + "dev": true, + "requires": { + "mkdirp": "^0.5.1" + } + }, + "write-file-atomic": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.4.3.tgz", + "integrity": "sha512-GaETH5wwsX+GcnzhPgKcKjJ6M2Cq3/iZp1WyY/X1CSqrW+jVNM9Y7D8EC2sM4ZG/V8wZlSniJnCKWPmBYAucRQ==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.11", + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.2" + } + }, + "xdg-basedir": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-3.0.0.tgz", + "integrity": "sha1-SWsswQnsqNus/i3HK2A8F8WHCtQ=", + "dev": true + }, + "xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "dev": true + }, + "yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", + "dev": true + }, + "yargs-parser": { + "version": "13.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.1.tgz", + "integrity": "sha512-oVAVsHz6uFrg3XQheFII8ESO2ssAf9luWuAd6Wexsu4F3OtIW0o8IribPXYrD4WC24LWtPrJlGy87y5udK+dxQ==", + "dev": true, + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + }, + "dependencies": { + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true + } + } + } + } +} diff --git a/cvat-data/package.json b/cvat-data/package.json new file mode 100644 index 00000000..59840b82 --- /dev/null +++ b/cvat-data/package.json @@ -0,0 +1,34 @@ +{ + "name": "cvat-data", + "version": "0.1.0", + "description": "", + "main": "src/js/cvat-data.js", + "devDependencies": { + "@babel/cli": "^7.4.4", + "@babel/core": "^7.4.4", + "@babel/preset-env": "^7.4.4", + "babel-loader": "^8.0.6", + "copy-webpack-plugin": "^5.0.5", + "eslint": "^6.4.0", + "eslint-config-airbnb-base": "^14.0.0", + "eslint-plugin-import": "^2.18.2", + "eslint-plugin-no-unsafe-innerhtml": "^1.0.16", + "eslint-plugin-no-unsanitized": "^3.0.2", + "eslint-plugin-security": "^1.4.0", + "nodemon": "^1.19.2", + "webpack": "^4.39.3", + "webpack-cli": "^3.3.7", + "worker-loader": "^2.0.0" + }, + "dependencies": { + "async-mutex": "^0.1.4", + "jszip": "3.1.5" + }, + "scripts": { + "patch": "cd src/js && patch --dry-run --forward -p0 < 3rdparty_patch.diff >> /dev/null && patch -p0 < 3rdparty_patch.diff; true", + "build": "npm run patch; webpack --config ./webpack.config.js", + "server": "npm run patch; nodemon --watch config --exec 'webpack-dev-server --config ./webpack.config.js --mode=development --open'" + }, + "author": "Intel", + "license": "MIT" +} diff --git a/cvat-data/src/js/3rdparty/Decoder.js b/cvat-data/src/js/3rdparty/Decoder.js new file mode 100644 index 00000000..cb8519f4 --- /dev/null +++ b/cvat-data/src/js/3rdparty/Decoder.js @@ -0,0 +1,888 @@ +// universal module definition +(function (root, factory) { + if (typeof define === 'function' && define.amd) { + // AMD. Register as an anonymous module. + define([], factory); + } else if (typeof exports === 'object') { + // Node. Does not work with strict CommonJS, but + // only CommonJS-like environments that support module.exports, + // like Node. + module.exports = factory(); + } else { + // Browser globals (root is window) + root.Decoder = factory(); + } +}(this, function () { + + var global; + + function initglobal(){ + global = this; + if (!global){ + if (typeof window != "undefined"){ + global = window; + }else if (typeof self != "undefined"){ + global = self; + }; + }; + }; + initglobal(); + + + function error(message) { + console.error(message); + console.trace(); + }; + + + function assert(condition, message) { + if (!condition) { + error(message); + }; + }; + + + + + var getModule = function(par_broadwayOnHeadersDecoded, par_broadwayOnPictureDecoded){ + + + /*var ModuleX = { + 'print': function(text) { console.log('stdout: ' + text); }, + 'printErr': function(text) { console.log('stderr: ' + text); } + };*/ + + + /* + + The reason why this is all packed into one file is that this file can also function as worker. + you can integrate the file into your build system and provide the original file to be loaded into a worker. + + */ + + //var Module = (function(){ + + +var Module=typeof Module!=="undefined"?Module:{};var moduleOverrides={};var key;for(key in Module){if(Module.hasOwnProperty(key)){moduleOverrides[key]=Module[key]}}var arguments_=[];var thisProgram="./this.program";var quit_=function(status,toThrow){throw toThrow};var ENVIRONMENT_IS_WEB=false;var ENVIRONMENT_IS_WORKER=true;var scriptDirectory="";function locateFile(path){if(Module["locateFile"]){return Module["locateFile"](path,scriptDirectory)}return scriptDirectory+path}var read_,readAsync,readBinary,setWindowTitle;if(ENVIRONMENT_IS_WEB||ENVIRONMENT_IS_WORKER){if(ENVIRONMENT_IS_WORKER){scriptDirectory=self.location.href}else if(document.currentScript){scriptDirectory=document.currentScript.src}if(scriptDirectory.indexOf("blob:")!==0){scriptDirectory=scriptDirectory.substr(0,scriptDirectory.lastIndexOf("/")+1)}else{scriptDirectory=""}{read_=function shell_read(url){var xhr=new XMLHttpRequest;xhr.open("GET",url,false);xhr.send(null);return xhr.responseText};if(ENVIRONMENT_IS_WORKER){readBinary=function readBinary(url){var xhr=new XMLHttpRequest;xhr.open("GET",url,false);xhr.responseType="arraybuffer";xhr.send(null);return new Uint8Array(xhr.response)}}readAsync=function readAsync(url,onload,onerror){var xhr=new XMLHttpRequest;xhr.open("GET",url,true);xhr.responseType="arraybuffer";xhr.onload=function xhr_onload(){if(xhr.status==200||xhr.status==0&&xhr.response){onload(xhr.response);return}onerror()};xhr.onerror=onerror;xhr.send(null)}}setWindowTitle=function(title){document.title=title}}else{}var out=Module["print"]||console.log.bind(console);var err=Module["printErr"]||console.warn.bind(console);for(key in moduleOverrides){if(moduleOverrides.hasOwnProperty(key)){Module[key]=moduleOverrides[key]}}moduleOverrides=null;if(Module["arguments"])arguments_=Module["arguments"];if(Module["thisProgram"])thisProgram=Module["thisProgram"];if(Module["quit"])quit_=Module["quit"];var asm2wasmImports={"f64-rem":function(x,y){return x%y},"debugger":function(){}};var functionPointers=new Array(0);var wasmBinary;if(Module["wasmBinary"])wasmBinary=Module["wasmBinary"];var noExitRuntime;if(Module["noExitRuntime"])noExitRuntime=Module["noExitRuntime"];if(typeof WebAssembly!=="object"){err("no native wasm support detected")}var wasmMemory;var wasmTable=new WebAssembly.Table({"initial":10,"maximum":10,"element":"anyfunc"});var ABORT=false;var EXITSTATUS=0;var UTF8Decoder=typeof TextDecoder!=="undefined"?new TextDecoder("utf8"):undefined;function UTF8ArrayToString(u8Array,idx,maxBytesToRead){var endIdx=idx+maxBytesToRead;var endPtr=idx;while(u8Array[endPtr]&&!(endPtr>=endIdx))++endPtr;if(endPtr-idx>16&&u8Array.subarray&&UTF8Decoder){return UTF8Decoder.decode(u8Array.subarray(idx,endPtr))}else{var str="";while(idx>10,56320|ch&1023)}}}return str}function UTF8ToString(ptr,maxBytesToRead){return ptr?UTF8ArrayToString(HEAPU8,ptr,maxBytesToRead):""}var UTF16Decoder=typeof TextDecoder!=="undefined"?new TextDecoder("utf-16le"):undefined;var WASM_PAGE_SIZE=65536;var buffer,HEAP8,HEAPU8,HEAP16,HEAPU16,HEAP32,HEAPU32,HEAPF32,HEAPF64;function updateGlobalBufferAndViews(buf){buffer=buf;Module["HEAP8"]=HEAP8=new Int8Array(buf);Module["HEAP16"]=HEAP16=new Int16Array(buf);Module["HEAP32"]=HEAP32=new Int32Array(buf);Module["HEAPU8"]=HEAPU8=new Uint8Array(buf);Module["HEAPU16"]=HEAPU16=new Uint16Array(buf);Module["HEAPU32"]=HEAPU32=new Uint32Array(buf);Module["HEAPF32"]=HEAPF32=new Float32Array(buf);Module["HEAPF64"]=HEAPF64=new Float64Array(buf)}var DYNAMIC_BASE=5254064,DYNAMICTOP_PTR=10992;var INITIAL_TOTAL_MEMORY=Module["TOTAL_MEMORY"]||104857600;if(Module["wasmMemory"]){wasmMemory=Module["wasmMemory"]}else{wasmMemory=new WebAssembly.Memory({"initial":INITIAL_TOTAL_MEMORY/WASM_PAGE_SIZE,"maximum":INITIAL_TOTAL_MEMORY/WASM_PAGE_SIZE})}if(wasmMemory){buffer=wasmMemory.buffer}INITIAL_TOTAL_MEMORY=buffer.byteLength;updateGlobalBufferAndViews(buffer);HEAP32[DYNAMICTOP_PTR>>2]=DYNAMIC_BASE;function callRuntimeCallbacks(callbacks){while(callbacks.length>0){var callback=callbacks.shift();if(typeof callback=="function"){callback();continue}var func=callback.func;if(typeof func==="number"){if(callback.arg===undefined){Module["dynCall_v"](func)}else{Module["dynCall_vi"](func,callback.arg)}}else{func(callback.arg===undefined?null:callback.arg)}}}var __ATPRERUN__=[];var __ATINIT__=[];var __ATMAIN__=[];var __ATPOSTRUN__=[];var runtimeInitialized=false;function preRun(){if(Module["preRun"]){if(typeof Module["preRun"]=="function")Module["preRun"]=[Module["preRun"]];while(Module["preRun"].length){addOnPreRun(Module["preRun"].shift())}}callRuntimeCallbacks(__ATPRERUN__)}function initRuntime(){runtimeInitialized=true;callRuntimeCallbacks(__ATINIT__)}function preMain(){callRuntimeCallbacks(__ATMAIN__)}function postRun(){if(Module["postRun"]){if(typeof Module["postRun"]=="function")Module["postRun"]=[Module["postRun"]];while(Module["postRun"].length){addOnPostRun(Module["postRun"].shift())}}callRuntimeCallbacks(__ATPOSTRUN__)}function addOnPreRun(cb){__ATPRERUN__.unshift(cb)}function addOnPostRun(cb){__ATPOSTRUN__.unshift(cb)}var runDependencies=0;var runDependencyWatcher=null;var dependenciesFulfilled=null;function addRunDependency(id){runDependencies++;if(Module["monitorRunDependencies"]){Module["monitorRunDependencies"](runDependencies)}}function removeRunDependency(id){runDependencies--;if(Module["monitorRunDependencies"]){Module["monitorRunDependencies"](runDependencies)}if(runDependencies==0){if(runDependencyWatcher!==null){clearInterval(runDependencyWatcher);runDependencyWatcher=null}if(dependenciesFulfilled){var callback=dependenciesFulfilled;dependenciesFulfilled=null;callback()}}}Module["preloadedImages"]={};Module["preloadedAudios"]={};function abort(what){if(Module["onAbort"]){Module["onAbort"](what)}what+="";out(what);err(what);ABORT=true;EXITSTATUS=1;what="abort("+what+"). Build with -s ASSERTIONS=1 for more info.";throw new WebAssembly.RuntimeError(what)}var dataURIPrefix="data:application/octet-stream;base64,";function isDataURI(filename){return String.prototype.startsWith?filename.startsWith(dataURIPrefix):filename.indexOf(dataURIPrefix)===0}var wasmBinaryFile="avc.wasm";if(!isDataURI(wasmBinaryFile)){wasmBinaryFile=locateFile(wasmBinaryFile)}function getBinary(){try{if(wasmBinary){return new Uint8Array(wasmBinary)}if(readBinary){return readBinary(wasmBinaryFile)}else{throw"both async and sync fetching of the wasm failed"}}catch(err){abort(err)}}function getBinaryPromise(){if(!wasmBinary&&(ENVIRONMENT_IS_WEB||ENVIRONMENT_IS_WORKER)&&typeof fetch==="function"){return fetch(wasmBinaryFile,{credentials:"same-origin"}).then(function(response){if(!response["ok"]){throw"failed to load wasm binary file at '"+wasmBinaryFile+"'"}return response["arrayBuffer"]()}).catch(function(){return getBinary()})}return new Promise(function(resolve,reject){resolve(getBinary())})}function createWasm(){var info={"env":asmLibraryArg,"wasi_unstable":asmLibraryArg,"global":{"NaN":NaN,Infinity:Infinity},"global.Math":Math,"asm2wasm":asm2wasmImports};function receiveInstance(instance,module){var exports=instance.exports;Module["asm"]=exports;removeRunDependency("wasm-instantiate")}addRunDependency("wasm-instantiate");function receiveInstantiatedSource(output){receiveInstance(output["instance"])}function instantiateArrayBuffer(receiver){return getBinaryPromise().then(function(binary){return WebAssembly.instantiate(binary,info)}).then(receiver,function(reason){err("failed to asynchronously prepare wasm: "+reason);abort(reason)})}function instantiateAsync(){if(!wasmBinary&&typeof WebAssembly.instantiateStreaming==="function"&&!isDataURI(wasmBinaryFile)&&typeof fetch==="function"){fetch(wasmBinaryFile,{credentials:"same-origin"}).then(function(response){var result=WebAssembly.instantiateStreaming(response,info);return result.then(receiveInstantiatedSource,function(reason){err("wasm streaming compile failed: "+reason);err("falling back to ArrayBuffer instantiation");instantiateArrayBuffer(receiveInstantiatedSource)})})}else{return instantiateArrayBuffer(receiveInstantiatedSource)}}if(Module["instantiateWasm"]){try{var exports=Module["instantiateWasm"](info,receiveInstance);return exports}catch(e){err("Module.instantiateWasm callback failed with error: "+e);return false}}instantiateAsync();return{}}Module["asm"]=createWasm;var PATH={splitPath:function(filename){var splitPathRe=/^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/;return splitPathRe.exec(filename).slice(1)},normalizeArray:function(parts,allowAboveRoot){var up=0;for(var i=parts.length-1;i>=0;i--){var last=parts[i];if(last==="."){parts.splice(i,1)}else if(last===".."){parts.splice(i,1);up++}else if(up){parts.splice(i,1);up--}}if(allowAboveRoot){for(;up;up--){parts.unshift("..")}}return parts},normalize:function(path){var isAbsolute=path.charAt(0)==="/",trailingSlash=path.substr(-1)==="/";path=PATH.normalizeArray(path.split("/").filter(function(p){return!!p}),!isAbsolute).join("/");if(!path&&!isAbsolute){path="."}if(path&&trailingSlash){path+="/"}return(isAbsolute?"/":"")+path},dirname:function(path){var result=PATH.splitPath(path),root=result[0],dir=result[1];if(!root&&!dir){return"."}if(dir){dir=dir.substr(0,dir.length-1)}return root+dir},basename:function(path){if(path==="/")return"/";var lastSlash=path.lastIndexOf("/");if(lastSlash===-1)return path;return path.substr(lastSlash+1)},extname:function(path){return PATH.splitPath(path)[3]},join:function(){var paths=Array.prototype.slice.call(arguments,0);return PATH.normalize(paths.join("/"))},join2:function(l,r){return PATH.normalize(l+"/"+r)}};var SYSCALLS={buffers:[null,[],[]],printChar:function(stream,curr){var buffer=SYSCALLS.buffers[stream];if(curr===0||curr===10){(stream===1?out:err)(UTF8ArrayToString(buffer,0));buffer.length=0}else{buffer.push(curr)}},varargs:0,get:function(varargs){SYSCALLS.varargs+=4;var ret=HEAP32[SYSCALLS.varargs-4>>2];return ret},getStr:function(){var ret=UTF8ToString(SYSCALLS.get());return ret},get64:function(){var low=SYSCALLS.get(),high=SYSCALLS.get();return low},getZero:function(){SYSCALLS.get()}};function _fd_write(fd,iov,iovcnt,pnum){try{var num=0;for(var i=0;i>2];var len=HEAP32[iov+(i*8+4)>>2];for(var j=0;j>2]=num;return 0}catch(e){if(typeof FS==="undefined"||!(e instanceof FS.ErrnoError))abort(e);return e.errno}}function ___wasi_fd_write(){return _fd_write.apply(null,arguments)}function _broadwayOnHeadersDecoded(){par_broadwayOnHeadersDecoded()}Module["_broadwayOnHeadersDecoded"]=_broadwayOnHeadersDecoded;function _broadwayOnPictureDecoded($buffer,width,height){par_broadwayOnPictureDecoded($buffer,width,height)}Module["_broadwayOnPictureDecoded"]=_broadwayOnPictureDecoded;function _emscripten_get_heap_size(){return HEAP8.length}function abortOnCannotGrowMemory(requestedSize){abort("OOM")}function _emscripten_resize_heap(requestedSize){abortOnCannotGrowMemory(requestedSize)}function _emscripten_memcpy_big(dest,src,num){HEAPU8.set(HEAPU8.subarray(src,src+num),dest)}var asmGlobalArg={};var asmLibraryArg={"g":___wasi_fd_write,"__memory_base":1024,"__table_base":0,"f":_broadwayOnHeadersDecoded,"e":_broadwayOnPictureDecoded,"b":_emscripten_get_heap_size,"d":_emscripten_memcpy_big,"a":_emscripten_resize_heap,"c":abort,"memory":wasmMemory,"table":wasmTable};var asm=Module["asm"](asmGlobalArg,asmLibraryArg,buffer);Module["asm"]=asm;var _broadwayCreateStream=Module["_broadwayCreateStream"]=function(){return Module["asm"]["h"].apply(null,arguments)};var _broadwayExit=Module["_broadwayExit"]=function(){return Module["asm"]["i"].apply(null,arguments)};var _broadwayGetMajorVersion=Module["_broadwayGetMajorVersion"]=function(){return Module["asm"]["j"].apply(null,arguments)};var _broadwayGetMinorVersion=Module["_broadwayGetMinorVersion"]=function(){return Module["asm"]["k"].apply(null,arguments)};var _broadwayInit=Module["_broadwayInit"]=function(){return Module["asm"]["l"].apply(null,arguments)};var _broadwayPlayStream=Module["_broadwayPlayStream"]=function(){return Module["asm"]["m"].apply(null,arguments)};Module["asm"]=asm;var calledRun;dependenciesFulfilled=function runCaller(){if(!calledRun)run();if(!calledRun)dependenciesFulfilled=runCaller};function run(args){args=args||arguments_;if(runDependencies>0){return}preRun();if(runDependencies>0)return;function doRun(){if(calledRun)return;calledRun=true;if(ABORT)return;initRuntime();preMain();if(Module["onRuntimeInitialized"])Module["onRuntimeInitialized"]();postRun()}if(Module["setStatus"]){Module["setStatus"]("Running...");setTimeout(function(){setTimeout(function(){Module["setStatus"]("")},1);doRun()},1)}else{doRun()}}Module["run"]=run;if(Module["preInit"]){if(typeof Module["preInit"]=="function")Module["preInit"]=[Module["preInit"]];while(Module["preInit"].length>0){Module["preInit"].pop()()}}noExitRuntime=true;run(); + // return Module; + //})(); + + var resultModule; + if (typeof global !== "undefined"){ + if (global.Module){ + resultModule = global.Module; + }; + }; + if (typeof Module != "undefined"){ + resultModule = Module; + }; + + resultModule._broadwayOnHeadersDecoded = par_broadwayOnHeadersDecoded; + resultModule._broadwayOnPictureDecoded = par_broadwayOnPictureDecoded; + + var moduleIsReady = false; + var cbFun; + var moduleReady = function(){ + moduleIsReady = true; + if (cbFun){ + cbFun(resultModule); + } + }; + + resultModule.onRuntimeInitialized = function(){ + moduleReady(resultModule); + }; + return function(callback){ + if (moduleIsReady){ + callback(resultModule); + }else{ + cbFun = callback; + }; + }; + }; + + return (function(){ + "use strict"; + + + var nowValue = function(){ + return (new Date()).getTime(); + }; + + if (typeof performance != "undefined"){ + if (performance.now){ + nowValue = function(){ + return performance.now(); + }; + }; + }; + + + var Decoder = function(parOptions){ + this.options = parOptions || {}; + + this.now = nowValue; + + var asmInstance; + + var fakeWindow = { + }; + + var toU8Array; + var toU32Array; + + var onPicFun = function ($buffer, width, height) { + var buffer = this.pictureBuffers[$buffer]; + if (!buffer) { + buffer = this.pictureBuffers[$buffer] = toU8Array($buffer, (width * height * 3) / 2); + }; + + var infos; + var doInfo = false; + if (this.infoAr.length){ + doInfo = true; + infos = this.infoAr; + }; + this.infoAr = []; + + if (this.options.rgb){ + if (!asmInstance){ + asmInstance = getAsm(width, height); + }; + asmInstance.inp.set(buffer); + asmInstance.doit(); + + var copyU8 = new Uint8Array(asmInstance.outSize); + copyU8.set( asmInstance.out ); + + if (doInfo){ + infos[0].finishDecoding = nowValue(); + }; + + this.onPictureDecoded(copyU8, width, height, infos); + return; + + }; + + if (doInfo){ + infos[0].finishDecoding = nowValue(); + }; + this.onPictureDecoded(buffer, width, height, infos); + }.bind(this); + + var ignore = false; + + if (this.options.sliceMode){ + onPicFun = function ($buffer, width, height, $sliceInfo) { + if (ignore){ + return; + }; + var buffer = this.pictureBuffers[$buffer]; + if (!buffer) { + buffer = this.pictureBuffers[$buffer] = toU8Array($buffer, (width * height * 3) / 2); + }; + var sliceInfo = this.pictureBuffers[$sliceInfo]; + if (!sliceInfo) { + sliceInfo = this.pictureBuffers[$sliceInfo] = toU32Array($sliceInfo, 18); + }; + + var infos; + var doInfo = false; + if (this.infoAr.length){ + doInfo = true; + infos = this.infoAr; + }; + this.infoAr = []; + + /*if (this.options.rgb){ + + no rgb in slice mode + + };*/ + + infos[0].finishDecoding = nowValue(); + var sliceInfoAr = []; + for (var i = 0; i < 20; ++i){ + sliceInfoAr.push(sliceInfo[i]); + }; + infos[0].sliceInfoAr = sliceInfoAr; + + this.onPictureDecoded(buffer, width, height, infos); + }.bind(this); + }; + + var ModuleCallback = getModule.apply(fakeWindow, [function () { + }, onPicFun]); + + + var MAX_STREAM_BUFFER_LENGTH = 1024 * 1024; + + var instance = this; + this.onPictureDecoded = function (buffer, width, height, infos) { + + }; + + this.onDecoderReady = function(){}; + + var bufferedCalls = []; + this.decode = function decode(typedAr, parInfo, copyDoneFun) { + bufferedCalls.push([typedAr, parInfo, copyDoneFun]); + }; + + ModuleCallback(function(Module){ + var HEAP8 = Module.HEAP8; + var HEAPU8 = Module.HEAPU8; + var HEAP16 = Module.HEAP16; + var HEAP32 = Module.HEAP32; + // from old constructor + Module._broadwayInit(); + + /** + * Creates a typed array from a HEAP8 pointer. + */ + toU8Array = function(ptr, length) { + return HEAPU8.subarray(ptr, ptr + length); + }; + toU32Array = function(ptr, length) { + //var tmp = HEAPU8.subarray(ptr, ptr + (length * 4)); + return new Uint32Array(HEAPU8.buffer, ptr, length); + }; + instance.streamBuffer = toU8Array(Module._broadwayCreateStream(MAX_STREAM_BUFFER_LENGTH), MAX_STREAM_BUFFER_LENGTH); + instance.pictureBuffers = {}; + // collect extra infos that are provided with the nal units + instance.infoAr = []; + + /** + * Decodes a stream buffer. This may be one single (unframed) NAL unit without the + * start code, or a sequence of NAL units with framing start code prefixes. This + * function overwrites stream buffer allocated by the codec with the supplied buffer. + */ + + var sliceNum = 0; + if (instance.options.sliceMode){ + sliceNum = instance.options.sliceNum; + + instance.decode = function decode(typedAr, parInfo, copyDoneFun) { + instance.infoAr.push(parInfo); + parInfo.startDecoding = nowValue(); + var nals = parInfo.nals; + var i; + if (!nals){ + nals = []; + parInfo.nals = nals; + var l = typedAr.length; + var foundSomething = false; + var lastFound = 0; + var lastStart = 0; + for (i = 0; i < l; ++i){ + if (typedAr[i] === 1){ + if ( + typedAr[i - 1] === 0 && + typedAr[i - 2] === 0 + ){ + var startPos = i - 2; + if (typedAr[i - 3] === 0){ + startPos = i - 3; + }; + // its a nal; + if (foundSomething){ + nals.push({ + offset: lastFound, + end: startPos, + type: typedAr[lastStart] & 31 + }); + }; + lastFound = startPos; + lastStart = startPos + 3; + if (typedAr[i - 3] === 0){ + lastStart = startPos + 4; + }; + foundSomething = true; + }; + }; + }; + if (foundSomething){ + nals.push({ + offset: lastFound, + end: i, + type: typedAr[lastStart] & 31 + }); + }; + }; + + var currentSlice = 0; + var playAr; + var offset = 0; + for (i = 0; i < nals.length; ++i){ + if (nals[i].type === 1 || nals[i].type === 5){ + if (currentSlice === sliceNum){ + playAr = typedAr.subarray(nals[i].offset, nals[i].end); + instance.streamBuffer[offset] = 0; + offset += 1; + instance.streamBuffer.set(playAr, offset); + offset += playAr.length; + }; + currentSlice += 1; + }else{ + playAr = typedAr.subarray(nals[i].offset, nals[i].end); + instance.streamBuffer[offset] = 0; + offset += 1; + instance.streamBuffer.set(playAr, offset); + offset += playAr.length; + Module._broadwayPlayStream(offset); + offset = 0; + }; + }; + copyDoneFun(); + Module._broadwayPlayStream(offset); + }; + + }else{ + instance.decode = function decode(typedAr, parInfo) { + // console.info("Decoding: " + buffer.length); + // collect infos + if (parInfo){ + instance.infoAr.push(parInfo); + parInfo.startDecoding = nowValue(); + }; + + instance.streamBuffer.set(typedAr); + Module._broadwayPlayStream(typedAr.length); + }; + }; + + if (bufferedCalls.length){ + var bi = 0; + for (bi = 0; bi < bufferedCalls.length; ++bi){ + instance.decode(bufferedCalls[bi][0], bufferedCalls[bi][1], bufferedCalls[bi][2]); + }; + bufferedCalls = []; + }; + + instance.onDecoderReady(instance); + + }); + + + }; + + + Decoder.prototype = { + + }; + + + + + /* + + asm.js implementation of a yuv to rgb convertor + provided by @soliton4 + + based on + http://www.wordsaretoys.com/2013/10/18/making-yuv-conversion-a-little-faster/ + + */ + + + // factory to create asm.js yuv -> rgb convertor for a given resolution + var asmInstances = {}; + var getAsm = function(parWidth, parHeight){ + var idStr = "" + parWidth + "x" + parHeight; + if (asmInstances[idStr]){ + return asmInstances[idStr]; + }; + + var lumaSize = parWidth * parHeight; + var chromaSize = (lumaSize|0) >> 2; + + var inpSize = lumaSize + chromaSize + chromaSize; + var outSize = parWidth * parHeight * 4; + var cacheSize = Math.pow(2, 24) * 4; + var size = inpSize + outSize + cacheSize; + + var chunkSize = Math.pow(2, 24); + var heapSize = chunkSize; + while (heapSize < size){ + heapSize += chunkSize; + }; + var heap = new ArrayBuffer(heapSize); + + var res = asmFactory(global, {}, heap); + res.init(parWidth, parHeight); + asmInstances[idStr] = res; + + res.heap = heap; + res.out = new Uint8Array(heap, 0, outSize); + res.inp = new Uint8Array(heap, outSize, inpSize); + res.outSize = outSize; + + return res; + }; + + + function asmFactory(stdlib, foreign, heap) { + "use asm"; + + var imul = stdlib.Math.imul; + var min = stdlib.Math.min; + var max = stdlib.Math.max; + var pow = stdlib.Math.pow; + var out = new stdlib.Uint8Array(heap); + var out32 = new stdlib.Uint32Array(heap); + var inp = new stdlib.Uint8Array(heap); + var mem = new stdlib.Uint8Array(heap); + var mem32 = new stdlib.Uint32Array(heap); + + // for double algo + /*var vt = 1.370705; + var gt = 0.698001; + var gt2 = 0.337633; + var bt = 1.732446;*/ + + var width = 0; + var height = 0; + var lumaSize = 0; + var chromaSize = 0; + var inpSize = 0; + var outSize = 0; + + var inpStart = 0; + var outStart = 0; + + var widthFour = 0; + + var cacheStart = 0; + + + function init(parWidth, parHeight){ + parWidth = parWidth|0; + parHeight = parHeight|0; + + var i = 0; + var s = 0; + + width = parWidth; + widthFour = imul(parWidth, 4)|0; + height = parHeight; + lumaSize = imul(width|0, height|0)|0; + chromaSize = (lumaSize|0) >> 2; + outSize = imul(imul(width, height)|0, 4)|0; + inpSize = (((lumaSize + chromaSize)|0) + chromaSize)|0; + + outStart = 0; + inpStart = (outStart + outSize)|0; + cacheStart = (inpStart + inpSize)|0; + + // initializing memory (to be on the safe side) + s = ~~(+pow(+2, +24)); + s = imul(s, 4)|0; + + for (i = 0|0; ((i|0) < (s|0))|0; i = (i + 4)|0){ + mem32[((cacheStart + i)|0) >> 2] = 0; + }; + }; + + function doit(){ + var ystart = 0; + var ustart = 0; + var vstart = 0; + + var y = 0; + var yn = 0; + var u = 0; + var v = 0; + + var o = 0; + + var line = 0; + var col = 0; + + var usave = 0; + var vsave = 0; + + var ostart = 0; + var cacheAdr = 0; + + ostart = outStart|0; + + ystart = inpStart|0; + ustart = (ystart + lumaSize|0)|0; + vstart = (ustart + chromaSize)|0; + + for (line = 0; (line|0) < (height|0); line = (line + 2)|0){ + usave = ustart; + vsave = vstart; + for (col = 0; (col|0) < (width|0); col = (col + 2)|0){ + y = inp[ystart >> 0]|0; + yn = inp[((ystart + width)|0) >> 0]|0; + + u = inp[ustart >> 0]|0; + v = inp[vstart >> 0]|0; + + cacheAdr = (((((y << 16)|0) + ((u << 8)|0))|0) + v)|0; + o = mem32[((cacheStart >> 2) + cacheAdr)|0]|0; + if (o){}else{ + o = yuv2rgbcalc(y,u,v)|0; + mem32[((cacheStart >> 2) + cacheAdr)|0] = o|0; + }; + mem32[ostart >> 2] = o; + + cacheAdr = (((((yn << 16)|0) + ((u << 8)|0))|0) + v)|0; + o = mem32[((cacheStart >> 2) + cacheAdr)|0]|0; + if (o){}else{ + o = yuv2rgbcalc(yn,u,v)|0; + mem32[((cacheStart >> 2) + cacheAdr)|0] = o|0; + }; + mem32[((ostart + widthFour)|0) >> 2] = o; + + //yuv2rgb5(y, u, v, ostart); + //yuv2rgb5(yn, u, v, (ostart + widthFour)|0); + ostart = (ostart + 4)|0; + + // next step only for y. u and v stay the same + ystart = (ystart + 1)|0; + y = inp[ystart >> 0]|0; + yn = inp[((ystart + width)|0) >> 0]|0; + + //yuv2rgb5(y, u, v, ostart); + cacheAdr = (((((y << 16)|0) + ((u << 8)|0))|0) + v)|0; + o = mem32[((cacheStart >> 2) + cacheAdr)|0]|0; + if (o){}else{ + o = yuv2rgbcalc(y,u,v)|0; + mem32[((cacheStart >> 2) + cacheAdr)|0] = o|0; + }; + mem32[ostart >> 2] = o; + + //yuv2rgb5(yn, u, v, (ostart + widthFour)|0); + cacheAdr = (((((yn << 16)|0) + ((u << 8)|0))|0) + v)|0; + o = mem32[((cacheStart >> 2) + cacheAdr)|0]|0; + if (o){}else{ + o = yuv2rgbcalc(yn,u,v)|0; + mem32[((cacheStart >> 2) + cacheAdr)|0] = o|0; + }; + mem32[((ostart + widthFour)|0) >> 2] = o; + ostart = (ostart + 4)|0; + + //all positions inc 1 + + ystart = (ystart + 1)|0; + ustart = (ustart + 1)|0; + vstart = (vstart + 1)|0; + }; + ostart = (ostart + widthFour)|0; + ystart = (ystart + width)|0; + + }; + + }; + + function yuv2rgbcalc(y, u, v){ + y = y|0; + u = u|0; + v = v|0; + + var r = 0; + var g = 0; + var b = 0; + + var o = 0; + + var a0 = 0; + var a1 = 0; + var a2 = 0; + var a3 = 0; + var a4 = 0; + + a0 = imul(1192, (y - 16)|0)|0; + a1 = imul(1634, (v - 128)|0)|0; + a2 = imul(832, (v - 128)|0)|0; + a3 = imul(400, (u - 128)|0)|0; + a4 = imul(2066, (u - 128)|0)|0; + + r = (((a0 + a1)|0) >> 10)|0; + g = (((((a0 - a2)|0) - a3)|0) >> 10)|0; + b = (((a0 + a4)|0) >> 10)|0; + + if ((((r & 255)|0) != (r|0))|0){ + r = min(255, max(0, r|0)|0)|0; + }; + if ((((g & 255)|0) != (g|0))|0){ + g = min(255, max(0, g|0)|0)|0; + }; + if ((((b & 255)|0) != (b|0))|0){ + b = min(255, max(0, b|0)|0)|0; + }; + + o = 255; + o = (o << 8)|0; + o = (o + b)|0; + o = (o << 8)|0; + o = (o + g)|0; + o = (o << 8)|0; + o = (o + r)|0; + + return o|0; + + }; + + + + return { + init: init, + doit: doit + }; + }; + + + /* + potential worker initialization + + */ + + + if (typeof self != "undefined"){ + var isWorker = false; + var decoder; + var reuseMemory = false; + var sliceMode = false; + var sliceNum = 0; + var sliceCnt = 0; + var lastSliceNum = 0; + var sliceInfoAr; + var lastBuf; + var awaiting = 0; + var pile = []; + var startDecoding; + var finishDecoding; + var timeDecoding; + + var memAr = []; + var getMem = function(length){ + if (memAr.length){ + var u = memAr.shift(); + while (u && u.byteLength !== length){ + u = memAr.shift(); + }; + if (u){ + return u; + }; + }; + return new ArrayBuffer(length); + }; + + var copySlice = function(source, target, infoAr, width, height){ + + var length = width * height; + var length4 = length / 4 + var plane2 = length; + var plane3 = length + length4; + + var copy16 = function(parBegin, parEnd){ + var i = 0; + for (i = 0; i < 16; ++i){ + var begin = parBegin + (width * i); + var end = parEnd + (width * i) + target.set(source.subarray(begin, end), begin); + }; + }; + var copy8 = function(parBegin, parEnd){ + var i = 0; + for (i = 0; i < 8; ++i){ + var begin = parBegin + ((width / 2) * i); + var end = parEnd + ((width / 2) * i) + target.set(source.subarray(begin, end), begin); + }; + }; + var copyChunk = function(begin, end){ + target.set(source.subarray(begin, end), begin); + }; + + var begin = infoAr[0]; + var end = infoAr[1]; + if (end > 0){ + copy16(begin, end); + copy8(infoAr[2], infoAr[3]); + copy8(infoAr[4], infoAr[5]); + }; + begin = infoAr[6]; + end = infoAr[7]; + if (end > 0){ + copy16(begin, end); + copy8(infoAr[8], infoAr[9]); + copy8(infoAr[10], infoAr[11]); + }; + + begin = infoAr[12]; + end = infoAr[15]; + if (end > 0){ + copyChunk(begin, end); + copyChunk(infoAr[13], infoAr[16]); + copyChunk(infoAr[14], infoAr[17]); + }; + + }; + + var sliceMsgFun = function(){}; + + var setSliceCnt = function(parSliceCnt){ + sliceCnt = parSliceCnt; + lastSliceNum = sliceCnt - 1; + }; + + + self.addEventListener('message', function(e) { + + if (isWorker){ + if (reuseMemory){ + if (e.data.reuse){ + memAr.push(e.data.reuse); + }; + }; + if (e.data.buf){ + if (sliceMode && awaiting !== 0){ + pile.push(e.data); + }else{ + decoder.decode( + new Uint8Array(e.data.buf, e.data.offset || 0, e.data.length), + e.data.info, + function(){ + if (sliceMode && sliceNum !== lastSliceNum){ + postMessage(e.data, [e.data.buf]); + }; + } + ); + }; + return; + }; + + if (e.data.slice){ + // update ref pic + var copyStart = nowValue(); + copySlice(new Uint8Array(e.data.slice), lastBuf, e.data.infos[0].sliceInfoAr, e.data.width, e.data.height); + // is it the one? then we need to update it + if (e.data.theOne){ + copySlice(lastBuf, new Uint8Array(e.data.slice), sliceInfoAr, e.data.width, e.data.height); + if (timeDecoding > e.data.infos[0].timeDecoding){ + e.data.infos[0].timeDecoding = timeDecoding; + }; + e.data.infos[0].timeCopy += (nowValue() - copyStart); + }; + // move on + postMessage(e.data, [e.data.slice]); + + // next frame in the pipe? + awaiting -= 1; + if (awaiting === 0 && pile.length){ + var data = pile.shift(); + decoder.decode( + new Uint8Array(data.buf, data.offset || 0, data.length), + data.info, + function(){ + if (sliceMode && sliceNum !== lastSliceNum){ + postMessage(data, [data.buf]); + }; + } + ); + }; + return; + }; + + if (e.data.setSliceCnt){ + setSliceCnt(e.data.sliceCnt); + return; + }; + + }else{ + if (e.data && e.data.type === "Broadway.js - Worker init"){ + isWorker = true; + decoder = new Decoder(e.data.options); + + if (e.data.options.sliceMode){ + reuseMemory = true; + sliceMode = true; + sliceNum = e.data.options.sliceNum; + setSliceCnt(e.data.options.sliceCnt); + + decoder.onPictureDecoded = function (buffer, width, height, infos) { + + // buffer needs to be copied because we give up ownership + var copyU8 = new Uint8Array(getMem(buffer.length)); + copySlice(buffer, copyU8, infos[0].sliceInfoAr, width, height); + + startDecoding = infos[0].startDecoding; + finishDecoding = infos[0].finishDecoding; + timeDecoding = finishDecoding - startDecoding; + infos[0].timeDecoding = timeDecoding; + infos[0].timeCopy = 0; + + postMessage({ + slice: copyU8.buffer, + sliceNum: sliceNum, + width: width, + height: height, + infos: infos + }, [copyU8.buffer]); // 2nd parameter is used to indicate transfer of ownership + + awaiting = sliceCnt - 1; + + lastBuf = buffer; + sliceInfoAr = infos[0].sliceInfoAr; + + }; + + }else if (e.data.options.reuseMemory){ + reuseMemory = true; + decoder.onPictureDecoded = function (buffer, width, height, infos) { + + // buffer needs to be copied because we give up ownership + var copyU8 = new Uint8Array(getMem(buffer.length)); + copyU8.set( buffer, 0, buffer.length ); + + postMessage({ + buf: copyU8.buffer, + length: buffer.length, + width: width, + height: height, + infos: infos + }, [copyU8.buffer]); // 2nd parameter is used to indicate transfer of ownership + + }; + + }else{ + decoder.onPictureDecoded = function (buffer, width, height, infos) { + if (buffer) { + buffer = new Uint8Array(buffer); + }; + + // buffer needs to be copied because we give up ownership + var copyU8 = new Uint8Array(buffer.length); + copyU8.set( buffer, 0, buffer.length ); + + postMessage({ + buf: copyU8.buffer, + length: buffer.length, + width: width, + height: height, + infos: infos + }, [copyU8.buffer]); // 2nd parameter is used to indicate transfer of ownership + + }; + }; + postMessage({ consoleLog: "broadway worker initialized" }); + }; + }; + + + }, false); + }; + + Decoder.nowValue = nowValue; + + return Decoder; + + })(); + + +})); + diff --git a/cvat-data/src/js/3rdparty/Decoder.worker.js b/cvat-data/src/js/3rdparty/Decoder.worker.js new file mode 100644 index 00000000..cb8519f4 --- /dev/null +++ b/cvat-data/src/js/3rdparty/Decoder.worker.js @@ -0,0 +1,888 @@ +// universal module definition +(function (root, factory) { + if (typeof define === 'function' && define.amd) { + // AMD. Register as an anonymous module. + define([], factory); + } else if (typeof exports === 'object') { + // Node. Does not work with strict CommonJS, but + // only CommonJS-like environments that support module.exports, + // like Node. + module.exports = factory(); + } else { + // Browser globals (root is window) + root.Decoder = factory(); + } +}(this, function () { + + var global; + + function initglobal(){ + global = this; + if (!global){ + if (typeof window != "undefined"){ + global = window; + }else if (typeof self != "undefined"){ + global = self; + }; + }; + }; + initglobal(); + + + function error(message) { + console.error(message); + console.trace(); + }; + + + function assert(condition, message) { + if (!condition) { + error(message); + }; + }; + + + + + var getModule = function(par_broadwayOnHeadersDecoded, par_broadwayOnPictureDecoded){ + + + /*var ModuleX = { + 'print': function(text) { console.log('stdout: ' + text); }, + 'printErr': function(text) { console.log('stderr: ' + text); } + };*/ + + + /* + + The reason why this is all packed into one file is that this file can also function as worker. + you can integrate the file into your build system and provide the original file to be loaded into a worker. + + */ + + //var Module = (function(){ + + +var Module=typeof Module!=="undefined"?Module:{};var moduleOverrides={};var key;for(key in Module){if(Module.hasOwnProperty(key)){moduleOverrides[key]=Module[key]}}var arguments_=[];var thisProgram="./this.program";var quit_=function(status,toThrow){throw toThrow};var ENVIRONMENT_IS_WEB=false;var ENVIRONMENT_IS_WORKER=true;var scriptDirectory="";function locateFile(path){if(Module["locateFile"]){return Module["locateFile"](path,scriptDirectory)}return scriptDirectory+path}var read_,readAsync,readBinary,setWindowTitle;if(ENVIRONMENT_IS_WEB||ENVIRONMENT_IS_WORKER){if(ENVIRONMENT_IS_WORKER){scriptDirectory=self.location.href}else if(document.currentScript){scriptDirectory=document.currentScript.src}if(scriptDirectory.indexOf("blob:")!==0){scriptDirectory=scriptDirectory.substr(0,scriptDirectory.lastIndexOf("/")+1)}else{scriptDirectory=""}{read_=function shell_read(url){var xhr=new XMLHttpRequest;xhr.open("GET",url,false);xhr.send(null);return xhr.responseText};if(ENVIRONMENT_IS_WORKER){readBinary=function readBinary(url){var xhr=new XMLHttpRequest;xhr.open("GET",url,false);xhr.responseType="arraybuffer";xhr.send(null);return new Uint8Array(xhr.response)}}readAsync=function readAsync(url,onload,onerror){var xhr=new XMLHttpRequest;xhr.open("GET",url,true);xhr.responseType="arraybuffer";xhr.onload=function xhr_onload(){if(xhr.status==200||xhr.status==0&&xhr.response){onload(xhr.response);return}onerror()};xhr.onerror=onerror;xhr.send(null)}}setWindowTitle=function(title){document.title=title}}else{}var out=Module["print"]||console.log.bind(console);var err=Module["printErr"]||console.warn.bind(console);for(key in moduleOverrides){if(moduleOverrides.hasOwnProperty(key)){Module[key]=moduleOverrides[key]}}moduleOverrides=null;if(Module["arguments"])arguments_=Module["arguments"];if(Module["thisProgram"])thisProgram=Module["thisProgram"];if(Module["quit"])quit_=Module["quit"];var asm2wasmImports={"f64-rem":function(x,y){return x%y},"debugger":function(){}};var functionPointers=new Array(0);var wasmBinary;if(Module["wasmBinary"])wasmBinary=Module["wasmBinary"];var noExitRuntime;if(Module["noExitRuntime"])noExitRuntime=Module["noExitRuntime"];if(typeof WebAssembly!=="object"){err("no native wasm support detected")}var wasmMemory;var wasmTable=new WebAssembly.Table({"initial":10,"maximum":10,"element":"anyfunc"});var ABORT=false;var EXITSTATUS=0;var UTF8Decoder=typeof TextDecoder!=="undefined"?new TextDecoder("utf8"):undefined;function UTF8ArrayToString(u8Array,idx,maxBytesToRead){var endIdx=idx+maxBytesToRead;var endPtr=idx;while(u8Array[endPtr]&&!(endPtr>=endIdx))++endPtr;if(endPtr-idx>16&&u8Array.subarray&&UTF8Decoder){return UTF8Decoder.decode(u8Array.subarray(idx,endPtr))}else{var str="";while(idx>10,56320|ch&1023)}}}return str}function UTF8ToString(ptr,maxBytesToRead){return ptr?UTF8ArrayToString(HEAPU8,ptr,maxBytesToRead):""}var UTF16Decoder=typeof TextDecoder!=="undefined"?new TextDecoder("utf-16le"):undefined;var WASM_PAGE_SIZE=65536;var buffer,HEAP8,HEAPU8,HEAP16,HEAPU16,HEAP32,HEAPU32,HEAPF32,HEAPF64;function updateGlobalBufferAndViews(buf){buffer=buf;Module["HEAP8"]=HEAP8=new Int8Array(buf);Module["HEAP16"]=HEAP16=new Int16Array(buf);Module["HEAP32"]=HEAP32=new Int32Array(buf);Module["HEAPU8"]=HEAPU8=new Uint8Array(buf);Module["HEAPU16"]=HEAPU16=new Uint16Array(buf);Module["HEAPU32"]=HEAPU32=new Uint32Array(buf);Module["HEAPF32"]=HEAPF32=new Float32Array(buf);Module["HEAPF64"]=HEAPF64=new Float64Array(buf)}var DYNAMIC_BASE=5254064,DYNAMICTOP_PTR=10992;var INITIAL_TOTAL_MEMORY=Module["TOTAL_MEMORY"]||104857600;if(Module["wasmMemory"]){wasmMemory=Module["wasmMemory"]}else{wasmMemory=new WebAssembly.Memory({"initial":INITIAL_TOTAL_MEMORY/WASM_PAGE_SIZE,"maximum":INITIAL_TOTAL_MEMORY/WASM_PAGE_SIZE})}if(wasmMemory){buffer=wasmMemory.buffer}INITIAL_TOTAL_MEMORY=buffer.byteLength;updateGlobalBufferAndViews(buffer);HEAP32[DYNAMICTOP_PTR>>2]=DYNAMIC_BASE;function callRuntimeCallbacks(callbacks){while(callbacks.length>0){var callback=callbacks.shift();if(typeof callback=="function"){callback();continue}var func=callback.func;if(typeof func==="number"){if(callback.arg===undefined){Module["dynCall_v"](func)}else{Module["dynCall_vi"](func,callback.arg)}}else{func(callback.arg===undefined?null:callback.arg)}}}var __ATPRERUN__=[];var __ATINIT__=[];var __ATMAIN__=[];var __ATPOSTRUN__=[];var runtimeInitialized=false;function preRun(){if(Module["preRun"]){if(typeof Module["preRun"]=="function")Module["preRun"]=[Module["preRun"]];while(Module["preRun"].length){addOnPreRun(Module["preRun"].shift())}}callRuntimeCallbacks(__ATPRERUN__)}function initRuntime(){runtimeInitialized=true;callRuntimeCallbacks(__ATINIT__)}function preMain(){callRuntimeCallbacks(__ATMAIN__)}function postRun(){if(Module["postRun"]){if(typeof Module["postRun"]=="function")Module["postRun"]=[Module["postRun"]];while(Module["postRun"].length){addOnPostRun(Module["postRun"].shift())}}callRuntimeCallbacks(__ATPOSTRUN__)}function addOnPreRun(cb){__ATPRERUN__.unshift(cb)}function addOnPostRun(cb){__ATPOSTRUN__.unshift(cb)}var runDependencies=0;var runDependencyWatcher=null;var dependenciesFulfilled=null;function addRunDependency(id){runDependencies++;if(Module["monitorRunDependencies"]){Module["monitorRunDependencies"](runDependencies)}}function removeRunDependency(id){runDependencies--;if(Module["monitorRunDependencies"]){Module["monitorRunDependencies"](runDependencies)}if(runDependencies==0){if(runDependencyWatcher!==null){clearInterval(runDependencyWatcher);runDependencyWatcher=null}if(dependenciesFulfilled){var callback=dependenciesFulfilled;dependenciesFulfilled=null;callback()}}}Module["preloadedImages"]={};Module["preloadedAudios"]={};function abort(what){if(Module["onAbort"]){Module["onAbort"](what)}what+="";out(what);err(what);ABORT=true;EXITSTATUS=1;what="abort("+what+"). Build with -s ASSERTIONS=1 for more info.";throw new WebAssembly.RuntimeError(what)}var dataURIPrefix="data:application/octet-stream;base64,";function isDataURI(filename){return String.prototype.startsWith?filename.startsWith(dataURIPrefix):filename.indexOf(dataURIPrefix)===0}var wasmBinaryFile="avc.wasm";if(!isDataURI(wasmBinaryFile)){wasmBinaryFile=locateFile(wasmBinaryFile)}function getBinary(){try{if(wasmBinary){return new Uint8Array(wasmBinary)}if(readBinary){return readBinary(wasmBinaryFile)}else{throw"both async and sync fetching of the wasm failed"}}catch(err){abort(err)}}function getBinaryPromise(){if(!wasmBinary&&(ENVIRONMENT_IS_WEB||ENVIRONMENT_IS_WORKER)&&typeof fetch==="function"){return fetch(wasmBinaryFile,{credentials:"same-origin"}).then(function(response){if(!response["ok"]){throw"failed to load wasm binary file at '"+wasmBinaryFile+"'"}return response["arrayBuffer"]()}).catch(function(){return getBinary()})}return new Promise(function(resolve,reject){resolve(getBinary())})}function createWasm(){var info={"env":asmLibraryArg,"wasi_unstable":asmLibraryArg,"global":{"NaN":NaN,Infinity:Infinity},"global.Math":Math,"asm2wasm":asm2wasmImports};function receiveInstance(instance,module){var exports=instance.exports;Module["asm"]=exports;removeRunDependency("wasm-instantiate")}addRunDependency("wasm-instantiate");function receiveInstantiatedSource(output){receiveInstance(output["instance"])}function instantiateArrayBuffer(receiver){return getBinaryPromise().then(function(binary){return WebAssembly.instantiate(binary,info)}).then(receiver,function(reason){err("failed to asynchronously prepare wasm: "+reason);abort(reason)})}function instantiateAsync(){if(!wasmBinary&&typeof WebAssembly.instantiateStreaming==="function"&&!isDataURI(wasmBinaryFile)&&typeof fetch==="function"){fetch(wasmBinaryFile,{credentials:"same-origin"}).then(function(response){var result=WebAssembly.instantiateStreaming(response,info);return result.then(receiveInstantiatedSource,function(reason){err("wasm streaming compile failed: "+reason);err("falling back to ArrayBuffer instantiation");instantiateArrayBuffer(receiveInstantiatedSource)})})}else{return instantiateArrayBuffer(receiveInstantiatedSource)}}if(Module["instantiateWasm"]){try{var exports=Module["instantiateWasm"](info,receiveInstance);return exports}catch(e){err("Module.instantiateWasm callback failed with error: "+e);return false}}instantiateAsync();return{}}Module["asm"]=createWasm;var PATH={splitPath:function(filename){var splitPathRe=/^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/;return splitPathRe.exec(filename).slice(1)},normalizeArray:function(parts,allowAboveRoot){var up=0;for(var i=parts.length-1;i>=0;i--){var last=parts[i];if(last==="."){parts.splice(i,1)}else if(last===".."){parts.splice(i,1);up++}else if(up){parts.splice(i,1);up--}}if(allowAboveRoot){for(;up;up--){parts.unshift("..")}}return parts},normalize:function(path){var isAbsolute=path.charAt(0)==="/",trailingSlash=path.substr(-1)==="/";path=PATH.normalizeArray(path.split("/").filter(function(p){return!!p}),!isAbsolute).join("/");if(!path&&!isAbsolute){path="."}if(path&&trailingSlash){path+="/"}return(isAbsolute?"/":"")+path},dirname:function(path){var result=PATH.splitPath(path),root=result[0],dir=result[1];if(!root&&!dir){return"."}if(dir){dir=dir.substr(0,dir.length-1)}return root+dir},basename:function(path){if(path==="/")return"/";var lastSlash=path.lastIndexOf("/");if(lastSlash===-1)return path;return path.substr(lastSlash+1)},extname:function(path){return PATH.splitPath(path)[3]},join:function(){var paths=Array.prototype.slice.call(arguments,0);return PATH.normalize(paths.join("/"))},join2:function(l,r){return PATH.normalize(l+"/"+r)}};var SYSCALLS={buffers:[null,[],[]],printChar:function(stream,curr){var buffer=SYSCALLS.buffers[stream];if(curr===0||curr===10){(stream===1?out:err)(UTF8ArrayToString(buffer,0));buffer.length=0}else{buffer.push(curr)}},varargs:0,get:function(varargs){SYSCALLS.varargs+=4;var ret=HEAP32[SYSCALLS.varargs-4>>2];return ret},getStr:function(){var ret=UTF8ToString(SYSCALLS.get());return ret},get64:function(){var low=SYSCALLS.get(),high=SYSCALLS.get();return low},getZero:function(){SYSCALLS.get()}};function _fd_write(fd,iov,iovcnt,pnum){try{var num=0;for(var i=0;i>2];var len=HEAP32[iov+(i*8+4)>>2];for(var j=0;j>2]=num;return 0}catch(e){if(typeof FS==="undefined"||!(e instanceof FS.ErrnoError))abort(e);return e.errno}}function ___wasi_fd_write(){return _fd_write.apply(null,arguments)}function _broadwayOnHeadersDecoded(){par_broadwayOnHeadersDecoded()}Module["_broadwayOnHeadersDecoded"]=_broadwayOnHeadersDecoded;function _broadwayOnPictureDecoded($buffer,width,height){par_broadwayOnPictureDecoded($buffer,width,height)}Module["_broadwayOnPictureDecoded"]=_broadwayOnPictureDecoded;function _emscripten_get_heap_size(){return HEAP8.length}function abortOnCannotGrowMemory(requestedSize){abort("OOM")}function _emscripten_resize_heap(requestedSize){abortOnCannotGrowMemory(requestedSize)}function _emscripten_memcpy_big(dest,src,num){HEAPU8.set(HEAPU8.subarray(src,src+num),dest)}var asmGlobalArg={};var asmLibraryArg={"g":___wasi_fd_write,"__memory_base":1024,"__table_base":0,"f":_broadwayOnHeadersDecoded,"e":_broadwayOnPictureDecoded,"b":_emscripten_get_heap_size,"d":_emscripten_memcpy_big,"a":_emscripten_resize_heap,"c":abort,"memory":wasmMemory,"table":wasmTable};var asm=Module["asm"](asmGlobalArg,asmLibraryArg,buffer);Module["asm"]=asm;var _broadwayCreateStream=Module["_broadwayCreateStream"]=function(){return Module["asm"]["h"].apply(null,arguments)};var _broadwayExit=Module["_broadwayExit"]=function(){return Module["asm"]["i"].apply(null,arguments)};var _broadwayGetMajorVersion=Module["_broadwayGetMajorVersion"]=function(){return Module["asm"]["j"].apply(null,arguments)};var _broadwayGetMinorVersion=Module["_broadwayGetMinorVersion"]=function(){return Module["asm"]["k"].apply(null,arguments)};var _broadwayInit=Module["_broadwayInit"]=function(){return Module["asm"]["l"].apply(null,arguments)};var _broadwayPlayStream=Module["_broadwayPlayStream"]=function(){return Module["asm"]["m"].apply(null,arguments)};Module["asm"]=asm;var calledRun;dependenciesFulfilled=function runCaller(){if(!calledRun)run();if(!calledRun)dependenciesFulfilled=runCaller};function run(args){args=args||arguments_;if(runDependencies>0){return}preRun();if(runDependencies>0)return;function doRun(){if(calledRun)return;calledRun=true;if(ABORT)return;initRuntime();preMain();if(Module["onRuntimeInitialized"])Module["onRuntimeInitialized"]();postRun()}if(Module["setStatus"]){Module["setStatus"]("Running...");setTimeout(function(){setTimeout(function(){Module["setStatus"]("")},1);doRun()},1)}else{doRun()}}Module["run"]=run;if(Module["preInit"]){if(typeof Module["preInit"]=="function")Module["preInit"]=[Module["preInit"]];while(Module["preInit"].length>0){Module["preInit"].pop()()}}noExitRuntime=true;run(); + // return Module; + //})(); + + var resultModule; + if (typeof global !== "undefined"){ + if (global.Module){ + resultModule = global.Module; + }; + }; + if (typeof Module != "undefined"){ + resultModule = Module; + }; + + resultModule._broadwayOnHeadersDecoded = par_broadwayOnHeadersDecoded; + resultModule._broadwayOnPictureDecoded = par_broadwayOnPictureDecoded; + + var moduleIsReady = false; + var cbFun; + var moduleReady = function(){ + moduleIsReady = true; + if (cbFun){ + cbFun(resultModule); + } + }; + + resultModule.onRuntimeInitialized = function(){ + moduleReady(resultModule); + }; + return function(callback){ + if (moduleIsReady){ + callback(resultModule); + }else{ + cbFun = callback; + }; + }; + }; + + return (function(){ + "use strict"; + + + var nowValue = function(){ + return (new Date()).getTime(); + }; + + if (typeof performance != "undefined"){ + if (performance.now){ + nowValue = function(){ + return performance.now(); + }; + }; + }; + + + var Decoder = function(parOptions){ + this.options = parOptions || {}; + + this.now = nowValue; + + var asmInstance; + + var fakeWindow = { + }; + + var toU8Array; + var toU32Array; + + var onPicFun = function ($buffer, width, height) { + var buffer = this.pictureBuffers[$buffer]; + if (!buffer) { + buffer = this.pictureBuffers[$buffer] = toU8Array($buffer, (width * height * 3) / 2); + }; + + var infos; + var doInfo = false; + if (this.infoAr.length){ + doInfo = true; + infos = this.infoAr; + }; + this.infoAr = []; + + if (this.options.rgb){ + if (!asmInstance){ + asmInstance = getAsm(width, height); + }; + asmInstance.inp.set(buffer); + asmInstance.doit(); + + var copyU8 = new Uint8Array(asmInstance.outSize); + copyU8.set( asmInstance.out ); + + if (doInfo){ + infos[0].finishDecoding = nowValue(); + }; + + this.onPictureDecoded(copyU8, width, height, infos); + return; + + }; + + if (doInfo){ + infos[0].finishDecoding = nowValue(); + }; + this.onPictureDecoded(buffer, width, height, infos); + }.bind(this); + + var ignore = false; + + if (this.options.sliceMode){ + onPicFun = function ($buffer, width, height, $sliceInfo) { + if (ignore){ + return; + }; + var buffer = this.pictureBuffers[$buffer]; + if (!buffer) { + buffer = this.pictureBuffers[$buffer] = toU8Array($buffer, (width * height * 3) / 2); + }; + var sliceInfo = this.pictureBuffers[$sliceInfo]; + if (!sliceInfo) { + sliceInfo = this.pictureBuffers[$sliceInfo] = toU32Array($sliceInfo, 18); + }; + + var infos; + var doInfo = false; + if (this.infoAr.length){ + doInfo = true; + infos = this.infoAr; + }; + this.infoAr = []; + + /*if (this.options.rgb){ + + no rgb in slice mode + + };*/ + + infos[0].finishDecoding = nowValue(); + var sliceInfoAr = []; + for (var i = 0; i < 20; ++i){ + sliceInfoAr.push(sliceInfo[i]); + }; + infos[0].sliceInfoAr = sliceInfoAr; + + this.onPictureDecoded(buffer, width, height, infos); + }.bind(this); + }; + + var ModuleCallback = getModule.apply(fakeWindow, [function () { + }, onPicFun]); + + + var MAX_STREAM_BUFFER_LENGTH = 1024 * 1024; + + var instance = this; + this.onPictureDecoded = function (buffer, width, height, infos) { + + }; + + this.onDecoderReady = function(){}; + + var bufferedCalls = []; + this.decode = function decode(typedAr, parInfo, copyDoneFun) { + bufferedCalls.push([typedAr, parInfo, copyDoneFun]); + }; + + ModuleCallback(function(Module){ + var HEAP8 = Module.HEAP8; + var HEAPU8 = Module.HEAPU8; + var HEAP16 = Module.HEAP16; + var HEAP32 = Module.HEAP32; + // from old constructor + Module._broadwayInit(); + + /** + * Creates a typed array from a HEAP8 pointer. + */ + toU8Array = function(ptr, length) { + return HEAPU8.subarray(ptr, ptr + length); + }; + toU32Array = function(ptr, length) { + //var tmp = HEAPU8.subarray(ptr, ptr + (length * 4)); + return new Uint32Array(HEAPU8.buffer, ptr, length); + }; + instance.streamBuffer = toU8Array(Module._broadwayCreateStream(MAX_STREAM_BUFFER_LENGTH), MAX_STREAM_BUFFER_LENGTH); + instance.pictureBuffers = {}; + // collect extra infos that are provided with the nal units + instance.infoAr = []; + + /** + * Decodes a stream buffer. This may be one single (unframed) NAL unit without the + * start code, or a sequence of NAL units with framing start code prefixes. This + * function overwrites stream buffer allocated by the codec with the supplied buffer. + */ + + var sliceNum = 0; + if (instance.options.sliceMode){ + sliceNum = instance.options.sliceNum; + + instance.decode = function decode(typedAr, parInfo, copyDoneFun) { + instance.infoAr.push(parInfo); + parInfo.startDecoding = nowValue(); + var nals = parInfo.nals; + var i; + if (!nals){ + nals = []; + parInfo.nals = nals; + var l = typedAr.length; + var foundSomething = false; + var lastFound = 0; + var lastStart = 0; + for (i = 0; i < l; ++i){ + if (typedAr[i] === 1){ + if ( + typedAr[i - 1] === 0 && + typedAr[i - 2] === 0 + ){ + var startPos = i - 2; + if (typedAr[i - 3] === 0){ + startPos = i - 3; + }; + // its a nal; + if (foundSomething){ + nals.push({ + offset: lastFound, + end: startPos, + type: typedAr[lastStart] & 31 + }); + }; + lastFound = startPos; + lastStart = startPos + 3; + if (typedAr[i - 3] === 0){ + lastStart = startPos + 4; + }; + foundSomething = true; + }; + }; + }; + if (foundSomething){ + nals.push({ + offset: lastFound, + end: i, + type: typedAr[lastStart] & 31 + }); + }; + }; + + var currentSlice = 0; + var playAr; + var offset = 0; + for (i = 0; i < nals.length; ++i){ + if (nals[i].type === 1 || nals[i].type === 5){ + if (currentSlice === sliceNum){ + playAr = typedAr.subarray(nals[i].offset, nals[i].end); + instance.streamBuffer[offset] = 0; + offset += 1; + instance.streamBuffer.set(playAr, offset); + offset += playAr.length; + }; + currentSlice += 1; + }else{ + playAr = typedAr.subarray(nals[i].offset, nals[i].end); + instance.streamBuffer[offset] = 0; + offset += 1; + instance.streamBuffer.set(playAr, offset); + offset += playAr.length; + Module._broadwayPlayStream(offset); + offset = 0; + }; + }; + copyDoneFun(); + Module._broadwayPlayStream(offset); + }; + + }else{ + instance.decode = function decode(typedAr, parInfo) { + // console.info("Decoding: " + buffer.length); + // collect infos + if (parInfo){ + instance.infoAr.push(parInfo); + parInfo.startDecoding = nowValue(); + }; + + instance.streamBuffer.set(typedAr); + Module._broadwayPlayStream(typedAr.length); + }; + }; + + if (bufferedCalls.length){ + var bi = 0; + for (bi = 0; bi < bufferedCalls.length; ++bi){ + instance.decode(bufferedCalls[bi][0], bufferedCalls[bi][1], bufferedCalls[bi][2]); + }; + bufferedCalls = []; + }; + + instance.onDecoderReady(instance); + + }); + + + }; + + + Decoder.prototype = { + + }; + + + + + /* + + asm.js implementation of a yuv to rgb convertor + provided by @soliton4 + + based on + http://www.wordsaretoys.com/2013/10/18/making-yuv-conversion-a-little-faster/ + + */ + + + // factory to create asm.js yuv -> rgb convertor for a given resolution + var asmInstances = {}; + var getAsm = function(parWidth, parHeight){ + var idStr = "" + parWidth + "x" + parHeight; + if (asmInstances[idStr]){ + return asmInstances[idStr]; + }; + + var lumaSize = parWidth * parHeight; + var chromaSize = (lumaSize|0) >> 2; + + var inpSize = lumaSize + chromaSize + chromaSize; + var outSize = parWidth * parHeight * 4; + var cacheSize = Math.pow(2, 24) * 4; + var size = inpSize + outSize + cacheSize; + + var chunkSize = Math.pow(2, 24); + var heapSize = chunkSize; + while (heapSize < size){ + heapSize += chunkSize; + }; + var heap = new ArrayBuffer(heapSize); + + var res = asmFactory(global, {}, heap); + res.init(parWidth, parHeight); + asmInstances[idStr] = res; + + res.heap = heap; + res.out = new Uint8Array(heap, 0, outSize); + res.inp = new Uint8Array(heap, outSize, inpSize); + res.outSize = outSize; + + return res; + }; + + + function asmFactory(stdlib, foreign, heap) { + "use asm"; + + var imul = stdlib.Math.imul; + var min = stdlib.Math.min; + var max = stdlib.Math.max; + var pow = stdlib.Math.pow; + var out = new stdlib.Uint8Array(heap); + var out32 = new stdlib.Uint32Array(heap); + var inp = new stdlib.Uint8Array(heap); + var mem = new stdlib.Uint8Array(heap); + var mem32 = new stdlib.Uint32Array(heap); + + // for double algo + /*var vt = 1.370705; + var gt = 0.698001; + var gt2 = 0.337633; + var bt = 1.732446;*/ + + var width = 0; + var height = 0; + var lumaSize = 0; + var chromaSize = 0; + var inpSize = 0; + var outSize = 0; + + var inpStart = 0; + var outStart = 0; + + var widthFour = 0; + + var cacheStart = 0; + + + function init(parWidth, parHeight){ + parWidth = parWidth|0; + parHeight = parHeight|0; + + var i = 0; + var s = 0; + + width = parWidth; + widthFour = imul(parWidth, 4)|0; + height = parHeight; + lumaSize = imul(width|0, height|0)|0; + chromaSize = (lumaSize|0) >> 2; + outSize = imul(imul(width, height)|0, 4)|0; + inpSize = (((lumaSize + chromaSize)|0) + chromaSize)|0; + + outStart = 0; + inpStart = (outStart + outSize)|0; + cacheStart = (inpStart + inpSize)|0; + + // initializing memory (to be on the safe side) + s = ~~(+pow(+2, +24)); + s = imul(s, 4)|0; + + for (i = 0|0; ((i|0) < (s|0))|0; i = (i + 4)|0){ + mem32[((cacheStart + i)|0) >> 2] = 0; + }; + }; + + function doit(){ + var ystart = 0; + var ustart = 0; + var vstart = 0; + + var y = 0; + var yn = 0; + var u = 0; + var v = 0; + + var o = 0; + + var line = 0; + var col = 0; + + var usave = 0; + var vsave = 0; + + var ostart = 0; + var cacheAdr = 0; + + ostart = outStart|0; + + ystart = inpStart|0; + ustart = (ystart + lumaSize|0)|0; + vstart = (ustart + chromaSize)|0; + + for (line = 0; (line|0) < (height|0); line = (line + 2)|0){ + usave = ustart; + vsave = vstart; + for (col = 0; (col|0) < (width|0); col = (col + 2)|0){ + y = inp[ystart >> 0]|0; + yn = inp[((ystart + width)|0) >> 0]|0; + + u = inp[ustart >> 0]|0; + v = inp[vstart >> 0]|0; + + cacheAdr = (((((y << 16)|0) + ((u << 8)|0))|0) + v)|0; + o = mem32[((cacheStart >> 2) + cacheAdr)|0]|0; + if (o){}else{ + o = yuv2rgbcalc(y,u,v)|0; + mem32[((cacheStart >> 2) + cacheAdr)|0] = o|0; + }; + mem32[ostart >> 2] = o; + + cacheAdr = (((((yn << 16)|0) + ((u << 8)|0))|0) + v)|0; + o = mem32[((cacheStart >> 2) + cacheAdr)|0]|0; + if (o){}else{ + o = yuv2rgbcalc(yn,u,v)|0; + mem32[((cacheStart >> 2) + cacheAdr)|0] = o|0; + }; + mem32[((ostart + widthFour)|0) >> 2] = o; + + //yuv2rgb5(y, u, v, ostart); + //yuv2rgb5(yn, u, v, (ostart + widthFour)|0); + ostart = (ostart + 4)|0; + + // next step only for y. u and v stay the same + ystart = (ystart + 1)|0; + y = inp[ystart >> 0]|0; + yn = inp[((ystart + width)|0) >> 0]|0; + + //yuv2rgb5(y, u, v, ostart); + cacheAdr = (((((y << 16)|0) + ((u << 8)|0))|0) + v)|0; + o = mem32[((cacheStart >> 2) + cacheAdr)|0]|0; + if (o){}else{ + o = yuv2rgbcalc(y,u,v)|0; + mem32[((cacheStart >> 2) + cacheAdr)|0] = o|0; + }; + mem32[ostart >> 2] = o; + + //yuv2rgb5(yn, u, v, (ostart + widthFour)|0); + cacheAdr = (((((yn << 16)|0) + ((u << 8)|0))|0) + v)|0; + o = mem32[((cacheStart >> 2) + cacheAdr)|0]|0; + if (o){}else{ + o = yuv2rgbcalc(yn,u,v)|0; + mem32[((cacheStart >> 2) + cacheAdr)|0] = o|0; + }; + mem32[((ostart + widthFour)|0) >> 2] = o; + ostart = (ostart + 4)|0; + + //all positions inc 1 + + ystart = (ystart + 1)|0; + ustart = (ustart + 1)|0; + vstart = (vstart + 1)|0; + }; + ostart = (ostart + widthFour)|0; + ystart = (ystart + width)|0; + + }; + + }; + + function yuv2rgbcalc(y, u, v){ + y = y|0; + u = u|0; + v = v|0; + + var r = 0; + var g = 0; + var b = 0; + + var o = 0; + + var a0 = 0; + var a1 = 0; + var a2 = 0; + var a3 = 0; + var a4 = 0; + + a0 = imul(1192, (y - 16)|0)|0; + a1 = imul(1634, (v - 128)|0)|0; + a2 = imul(832, (v - 128)|0)|0; + a3 = imul(400, (u - 128)|0)|0; + a4 = imul(2066, (u - 128)|0)|0; + + r = (((a0 + a1)|0) >> 10)|0; + g = (((((a0 - a2)|0) - a3)|0) >> 10)|0; + b = (((a0 + a4)|0) >> 10)|0; + + if ((((r & 255)|0) != (r|0))|0){ + r = min(255, max(0, r|0)|0)|0; + }; + if ((((g & 255)|0) != (g|0))|0){ + g = min(255, max(0, g|0)|0)|0; + }; + if ((((b & 255)|0) != (b|0))|0){ + b = min(255, max(0, b|0)|0)|0; + }; + + o = 255; + o = (o << 8)|0; + o = (o + b)|0; + o = (o << 8)|0; + o = (o + g)|0; + o = (o << 8)|0; + o = (o + r)|0; + + return o|0; + + }; + + + + return { + init: init, + doit: doit + }; + }; + + + /* + potential worker initialization + + */ + + + if (typeof self != "undefined"){ + var isWorker = false; + var decoder; + var reuseMemory = false; + var sliceMode = false; + var sliceNum = 0; + var sliceCnt = 0; + var lastSliceNum = 0; + var sliceInfoAr; + var lastBuf; + var awaiting = 0; + var pile = []; + var startDecoding; + var finishDecoding; + var timeDecoding; + + var memAr = []; + var getMem = function(length){ + if (memAr.length){ + var u = memAr.shift(); + while (u && u.byteLength !== length){ + u = memAr.shift(); + }; + if (u){ + return u; + }; + }; + return new ArrayBuffer(length); + }; + + var copySlice = function(source, target, infoAr, width, height){ + + var length = width * height; + var length4 = length / 4 + var plane2 = length; + var plane3 = length + length4; + + var copy16 = function(parBegin, parEnd){ + var i = 0; + for (i = 0; i < 16; ++i){ + var begin = parBegin + (width * i); + var end = parEnd + (width * i) + target.set(source.subarray(begin, end), begin); + }; + }; + var copy8 = function(parBegin, parEnd){ + var i = 0; + for (i = 0; i < 8; ++i){ + var begin = parBegin + ((width / 2) * i); + var end = parEnd + ((width / 2) * i) + target.set(source.subarray(begin, end), begin); + }; + }; + var copyChunk = function(begin, end){ + target.set(source.subarray(begin, end), begin); + }; + + var begin = infoAr[0]; + var end = infoAr[1]; + if (end > 0){ + copy16(begin, end); + copy8(infoAr[2], infoAr[3]); + copy8(infoAr[4], infoAr[5]); + }; + begin = infoAr[6]; + end = infoAr[7]; + if (end > 0){ + copy16(begin, end); + copy8(infoAr[8], infoAr[9]); + copy8(infoAr[10], infoAr[11]); + }; + + begin = infoAr[12]; + end = infoAr[15]; + if (end > 0){ + copyChunk(begin, end); + copyChunk(infoAr[13], infoAr[16]); + copyChunk(infoAr[14], infoAr[17]); + }; + + }; + + var sliceMsgFun = function(){}; + + var setSliceCnt = function(parSliceCnt){ + sliceCnt = parSliceCnt; + lastSliceNum = sliceCnt - 1; + }; + + + self.addEventListener('message', function(e) { + + if (isWorker){ + if (reuseMemory){ + if (e.data.reuse){ + memAr.push(e.data.reuse); + }; + }; + if (e.data.buf){ + if (sliceMode && awaiting !== 0){ + pile.push(e.data); + }else{ + decoder.decode( + new Uint8Array(e.data.buf, e.data.offset || 0, e.data.length), + e.data.info, + function(){ + if (sliceMode && sliceNum !== lastSliceNum){ + postMessage(e.data, [e.data.buf]); + }; + } + ); + }; + return; + }; + + if (e.data.slice){ + // update ref pic + var copyStart = nowValue(); + copySlice(new Uint8Array(e.data.slice), lastBuf, e.data.infos[0].sliceInfoAr, e.data.width, e.data.height); + // is it the one? then we need to update it + if (e.data.theOne){ + copySlice(lastBuf, new Uint8Array(e.data.slice), sliceInfoAr, e.data.width, e.data.height); + if (timeDecoding > e.data.infos[0].timeDecoding){ + e.data.infos[0].timeDecoding = timeDecoding; + }; + e.data.infos[0].timeCopy += (nowValue() - copyStart); + }; + // move on + postMessage(e.data, [e.data.slice]); + + // next frame in the pipe? + awaiting -= 1; + if (awaiting === 0 && pile.length){ + var data = pile.shift(); + decoder.decode( + new Uint8Array(data.buf, data.offset || 0, data.length), + data.info, + function(){ + if (sliceMode && sliceNum !== lastSliceNum){ + postMessage(data, [data.buf]); + }; + } + ); + }; + return; + }; + + if (e.data.setSliceCnt){ + setSliceCnt(e.data.sliceCnt); + return; + }; + + }else{ + if (e.data && e.data.type === "Broadway.js - Worker init"){ + isWorker = true; + decoder = new Decoder(e.data.options); + + if (e.data.options.sliceMode){ + reuseMemory = true; + sliceMode = true; + sliceNum = e.data.options.sliceNum; + setSliceCnt(e.data.options.sliceCnt); + + decoder.onPictureDecoded = function (buffer, width, height, infos) { + + // buffer needs to be copied because we give up ownership + var copyU8 = new Uint8Array(getMem(buffer.length)); + copySlice(buffer, copyU8, infos[0].sliceInfoAr, width, height); + + startDecoding = infos[0].startDecoding; + finishDecoding = infos[0].finishDecoding; + timeDecoding = finishDecoding - startDecoding; + infos[0].timeDecoding = timeDecoding; + infos[0].timeCopy = 0; + + postMessage({ + slice: copyU8.buffer, + sliceNum: sliceNum, + width: width, + height: height, + infos: infos + }, [copyU8.buffer]); // 2nd parameter is used to indicate transfer of ownership + + awaiting = sliceCnt - 1; + + lastBuf = buffer; + sliceInfoAr = infos[0].sliceInfoAr; + + }; + + }else if (e.data.options.reuseMemory){ + reuseMemory = true; + decoder.onPictureDecoded = function (buffer, width, height, infos) { + + // buffer needs to be copied because we give up ownership + var copyU8 = new Uint8Array(getMem(buffer.length)); + copyU8.set( buffer, 0, buffer.length ); + + postMessage({ + buf: copyU8.buffer, + length: buffer.length, + width: width, + height: height, + infos: infos + }, [copyU8.buffer]); // 2nd parameter is used to indicate transfer of ownership + + }; + + }else{ + decoder.onPictureDecoded = function (buffer, width, height, infos) { + if (buffer) { + buffer = new Uint8Array(buffer); + }; + + // buffer needs to be copied because we give up ownership + var copyU8 = new Uint8Array(buffer.length); + copyU8.set( buffer, 0, buffer.length ); + + postMessage({ + buf: copyU8.buffer, + length: buffer.length, + width: width, + height: height, + infos: infos + }, [copyU8.buffer]); // 2nd parameter is used to indicate transfer of ownership + + }; + }; + postMessage({ consoleLog: "broadway worker initialized" }); + }; + }; + + + }, false); + }; + + Decoder.nowValue = nowValue; + + return Decoder; + + })(); + + +})); + diff --git a/cvat-data/src/js/3rdparty/README.md b/cvat-data/src/js/3rdparty/README.md new file mode 100644 index 00000000..d6518b90 --- /dev/null +++ b/cvat-data/src/js/3rdparty/README.md @@ -0,0 +1,88 @@ +## 3rdparty components + +These files are from the [Broadway.js](https://github.com/mbebenita/Broadway) repository: +- Decoder.js +- mp4.js +- avc.wasm + +### Why do we store them here? + +Authors don't provide an npm package, so we need to store these components in our repository. +We use this dependency to decode video chunks from a server and split them to frames on client side. + +We need to run this package in node environent (for example for debug, or for running unit tests). +But there aren't any ways to do that (even with syntetic environment, provided for example by the package ``browser-env``). +For example there are issues with canvas using (webpack doesn't work with binary canvas package for node-js) and others. +So, we have solved to write patch file for this library. +It modifies source code a little to support our scenario of using. + +### How to build awc.wasm and Decoder.js +1. Clone Emscripten SDK, install and activate the latest fastcomp SDK: + ```sh + git clone https://github.com/emscripten-core/emsdk.git && cd emsdk + ``` + ```sh + ./emsdk install latest-fastcomp + ``` + ```sh + ./emsdk activate latest-fastcomp + ``` + +1. Clone Broadway.js + ```sh + git clone https://github.com/mbebenita/Broadway.git && cd Broadway/Decoder + ``` + +1. Edit `make.py`: + - Remove or comment the following options: + `'-s', 'NO_BROWSER=1',`\ + `'-s', 'PRECISE_I64_MATH=0',` + - Remove `"HEAP8", "HEAP16", "HEAP32"` from the `EXPORTED_FUNCTIONS` list. + - Increase total memory to make possible decode 4k videos + (or try to enable `ALLOW_MEMORY_GROWTH`, but this option has not been tested):\ + `'-s', 'TOTAL_MEMORY=' + str(100*1024*1024),` + - Add the following options:\ + `'-s', "ENVIRONMENT='worker'",`\ + `'-s', 'WASM=1',` + +1. Activate emsdk environment and build Broadway.js: + ```sh + . /tmp/emsdk/emsdk_env.sh + ``` + ```sh + python2 make.py + ``` + +1. Copy the following files to cvat-data 3rdparty source folder: + ```sh + cd .. + ``` + ```sh + cp Player/avc.wasm Player/Decoder.js Player/mp4.js /cvat-data/src/ + ``` + ```sh + js/3rdparty + ``` + +### How work with a patch file +```bash + # from cvat-data/src/js + cp -r 3rdparty 3rdparty_edited + # change 3rdparty edited as we need + diff -u 3rdparty 3rdparty_edited/ > 3rdparty_patch.diff + patch -p0 < 3rdparty_patch.diff # apply patch from cvat-data/src/js +``` + +Also these files have been added to ignore for git in all future revisions: +```bash + # from cvat-data dir + git update-index --skip-worktree src/js/3rdparty/*.js +``` + +This behaviour can be reset with: +```bash + # from cvat-data dir + git update-index --no-skip-worktree src/js/3rdparty/*.js +``` + +[Stackoverflow issue](https://stackoverflow.com/questions/4348590/how-can-i-make-git-ignore-future-revisions-to-a-file) diff --git a/cvat-data/src/js/3rdparty/avc.wasm b/cvat-data/src/js/3rdparty/avc.wasm new file mode 100644 index 0000000000000000000000000000000000000000..559b2b3157a0fccbcf3128e8a5d4e371654d2d3e GIT binary patch literal 126815 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 1, this.h >>> 1); + }, + length: function() { + return this.w * this.h; + } + }; + return constructor; +})(); + + + + + +var Bytestream = (function BytestreamClosure() { + function constructor(arrayBuffer, start, length) { + this.bytes = new Uint8Array(arrayBuffer); + this.start = start || 0; + this.pos = this.start; + this.end = (start + length) || this.bytes.length; + } + constructor.prototype = { + get length() { + return this.end - this.start; + }, + get position() { + return this.pos; + }, + get remaining() { + return this.end - this.pos; + }, + readU8Array: function (length) { + if (this.pos > this.end - length) + return null; + var res = this.bytes.subarray(this.pos, this.pos + length); + this.pos += length; + return res; + }, + readU32Array: function (rows, cols, names) { + cols = cols || 1; + if (this.pos > this.end - (rows * cols) * 4) + return null; + if (cols == 1) { + var array = new Uint32Array(rows); + for (var i = 0; i < rows; i++) { + array[i] = this.readU32(); + } + return array; + } else { + var array = new Array(rows); + for (var i = 0; i < rows; i++) { + var row = null; + if (names) { + row = {}; + for (var j = 0; j < cols; j++) { + row[names[j]] = this.readU32(); + } + } else { + row = new Uint32Array(cols); + for (var j = 0; j < cols; j++) { + row[j] = this.readU32(); + } + } + array[i] = row; + } + return array; + } + }, + read8: function () { + return this.readU8() << 24 >> 24; + }, + readU8: function () { + if (this.pos >= this.end) + return null; + return this.bytes[this.pos++]; + }, + read16: function () { + return this.readU16() << 16 >> 16; + }, + readU16: function () { + if (this.pos >= this.end - 1) + return null; + var res = this.bytes[this.pos + 0] << 8 | this.bytes[this.pos + 1]; + this.pos += 2; + return res; + }, + read24: function () { + return this.readU24() << 8 >> 8; + }, + readU24: function () { + var pos = this.pos; + var bytes = this.bytes; + if (pos > this.end - 3) + return null; + var res = bytes[pos + 0] << 16 | bytes[pos + 1] << 8 | bytes[pos + 2]; + this.pos += 3; + return res; + }, + peek32: function (advance) { + var pos = this.pos; + var bytes = this.bytes; + if (pos > this.end - 4) + return null; + var res = bytes[pos + 0] << 24 | bytes[pos + 1] << 16 | bytes[pos + 2] << 8 | bytes[pos + 3]; + if (advance) { + this.pos += 4; + } + return res; + }, + read32: function () { + return this.peek32(true); + }, + readU32: function () { + return this.peek32(true) >>> 0; + }, + read4CC: function () { + var pos = this.pos; + if (pos > this.end - 4) + return null; + var res = ""; + for (var i = 0; i < 4; i++) { + res += String.fromCharCode(this.bytes[pos + i]); + } + this.pos += 4; + return res; + }, + readFP16: function () { + return this.read32() / 65536; + }, + readFP8: function () { + return this.read16() / 256; + }, + readISO639: function () { + var bits = this.readU16(); + var res = ""; + for (var i = 0; i < 3; i++) { + var c = (bits >>> (2 - i) * 5) & 0x1f; + res += String.fromCharCode(c + 0x60); + } + return res; + }, + readUTF8: function (length) { + var res = ""; + for (var i = 0; i < length; i++) { + res += String.fromCharCode(this.readU8()); + } + return res; + }, + readPString: function (max) { + var len = this.readU8(); + assert (len <= max); + var res = this.readUTF8(len); + this.reserved(max - len - 1, 0); + return res; + }, + skip: function (length) { + this.seek(this.pos + length); + }, + reserved: function (length, value) { + for (var i = 0; i < length; i++) { + assert (this.readU8() == value); + } + }, + seek: function (index) { + if (index < 0 || index > this.end) { + error("Index out of bounds (bounds: [0, " + this.end + "], index: " + index + ")."); + } + this.pos = index; + }, + subStream: function (start, length) { + return new Bytestream(this.bytes.buffer, start, length); + } + }; + return constructor; +})(); + + +var PARANOID = true; // Heavy-weight assertions. + +/** + * Reads an mp4 file and constructs a object graph that corresponds to the box/atom + * structure of the file. Mp4 files are based on the ISO Base Media format, which in + * turn is based on the Apple Quicktime format. The Quicktime spec is available at: + * http://developer.apple.com/library/mac/#documentation/QuickTime/QTFF. An mp4 spec + * also exists, but I cannot find it freely available. + * + * Mp4 files contain a tree of boxes (or atoms in Quicktime). The general structure + * is as follows (in a pseudo regex syntax): + * + * Box / Atom Structure: + * + * [size type [version flags] field* box*] + * <32> <4C> <--8--> <24-> <-?-> + * <------------- box size ------------> + * + * The box size indicates the entire size of the box and its children, we can use it + * to skip over boxes that are of no interest. Each box has a type indicated by a + * four character code (4C), this describes how the box should be parsed and is also + * used as an object key name in the resulting box tree. For example, the expression: + * "moov.trak[0].mdia.minf" can be used to access individual boxes in the tree based + * on their 4C name. If two or more boxes with the same 4C name exist in a box, then + * an array is built with that name. + * + */ +var MP4Reader = (function reader() { + var BOX_HEADER_SIZE = 8; + var FULL_BOX_HEADER_SIZE = BOX_HEADER_SIZE + 4; + + function constructor(stream) { + this.stream = stream; + this.tracks = {}; + } + + constructor.prototype = { + readBoxes: function (stream, parent) { + while (stream.peek32()) { + var child = this.readBox(stream); + if (child.type in parent) { + var old = parent[child.type]; + if (!(old instanceof Array)) { + parent[child.type] = [old]; + } + parent[child.type].push(child); + } else { + parent[child.type] = child; + } + } + }, + readBox: function readBox(stream) { + var box = { offset: stream.position }; + + function readHeader() { + box.size = stream.readU32(); + box.type = stream.read4CC(); + } + + function readFullHeader() { + box.version = stream.readU8(); + box.flags = stream.readU24(); + } + + function remainingBytes() { + return box.size - (stream.position - box.offset); + } + + function skipRemainingBytes () { + stream.skip(remainingBytes()); + } + + var readRemainingBoxes = function () { + var subStream = stream.subStream(stream.position, remainingBytes()); + this.readBoxes(subStream, box); + stream.skip(subStream.length); + }.bind(this); + + readHeader(); + + switch (box.type) { + case 'ftyp': + box.name = "File Type Box"; + box.majorBrand = stream.read4CC(); + box.minorVersion = stream.readU32(); + box.compatibleBrands = new Array((box.size - 16) / 4); + for (var i = 0; i < box.compatibleBrands.length; i++) { + box.compatibleBrands[i] = stream.read4CC(); + } + break; + case 'moov': + box.name = "Movie Box"; + readRemainingBoxes(); + break; + case 'mvhd': + box.name = "Movie Header Box"; + readFullHeader(); + assert (box.version == 0); + box.creationTime = stream.readU32(); + box.modificationTime = stream.readU32(); + box.timeScale = stream.readU32(); + box.duration = stream.readU32(); + box.rate = stream.readFP16(); + box.volume = stream.readFP8(); + stream.skip(10); + box.matrix = stream.readU32Array(9); + stream.skip(6 * 4); + box.nextTrackId = stream.readU32(); + break; + case 'trak': + box.name = "Track Box"; + readRemainingBoxes(); + this.tracks[box.tkhd.trackId] = new Track(this, box); + break; + case 'tkhd': + box.name = "Track Header Box"; + readFullHeader(); + assert (box.version == 0); + box.creationTime = stream.readU32(); + box.modificationTime = stream.readU32(); + box.trackId = stream.readU32(); + stream.skip(4); + box.duration = stream.readU32(); + stream.skip(8); + box.layer = stream.readU16(); + box.alternateGroup = stream.readU16(); + box.volume = stream.readFP8(); + stream.skip(2); + box.matrix = stream.readU32Array(9); + box.width = stream.readFP16(); + box.height = stream.readFP16(); + break; + case 'mdia': + box.name = "Media Box"; + readRemainingBoxes(); + break; + case 'mdhd': + box.name = "Media Header Box"; + readFullHeader(); + assert (box.version == 0); + box.creationTime = stream.readU32(); + box.modificationTime = stream.readU32(); + box.timeScale = stream.readU32(); + box.duration = stream.readU32(); + box.language = stream.readISO639(); + stream.skip(2); + break; + case 'hdlr': + box.name = "Handler Reference Box"; + readFullHeader(); + stream.skip(4); + box.handlerType = stream.read4CC(); + stream.skip(4 * 3); + var bytesLeft = box.size - 32; + if (bytesLeft > 0) { + box.name = stream.readUTF8(bytesLeft); + } + break; + case 'minf': + box.name = "Media Information Box"; + readRemainingBoxes(); + break; + case 'stbl': + box.name = "Sample Table Box"; + readRemainingBoxes(); + break; + case 'stsd': + box.name = "Sample Description Box"; + readFullHeader(); + box.sd = []; + var entries = stream.readU32(); + readRemainingBoxes(); + break; + case 'avc1': + stream.reserved(6, 0); + box.dataReferenceIndex = stream.readU16(); + assert (stream.readU16() == 0); // Version + assert (stream.readU16() == 0); // Revision Level + stream.readU32(); // Vendor + stream.readU32(); // Temporal Quality + stream.readU32(); // Spatial Quality + box.width = stream.readU16(); + box.height = stream.readU16(); + box.horizontalResolution = stream.readFP16(); + box.verticalResolution = stream.readFP16(); + assert (stream.readU32() == 0); // Reserved + box.frameCount = stream.readU16(); + box.compressorName = stream.readPString(32); + box.depth = stream.readU16(); + assert (stream.readU16() == 0xFFFF); // Color Table Id + readRemainingBoxes(); + break; + case 'mp4a': + stream.reserved(6, 0); + box.dataReferenceIndex = stream.readU16(); + box.version = stream.readU16(); + stream.skip(2); + stream.skip(4); + box.channelCount = stream.readU16(); + box.sampleSize = stream.readU16(); + box.compressionId = stream.readU16(); + box.packetSize = stream.readU16(); + box.sampleRate = stream.readU32() >>> 16; + + // TODO: Parse other version levels. + assert (box.version == 0); + readRemainingBoxes(); + break; + case 'esds': + box.name = "Elementary Stream Descriptor"; + readFullHeader(); + // TODO: Do we really need to parse this? + skipRemainingBytes(); + break; + case 'avcC': + box.name = "AVC Configuration Box"; + box.configurationVersion = stream.readU8(); + box.avcProfileIndication = stream.readU8(); + box.profileCompatibility = stream.readU8(); + box.avcLevelIndication = stream.readU8(); + box.lengthSizeMinusOne = stream.readU8() & 3; + assert (box.lengthSizeMinusOne == 3, "TODO"); + var count = stream.readU8() & 31; + box.sps = []; + for (var i = 0; i < count; i++) { + box.sps.push(stream.readU8Array(stream.readU16())); + } + var count = stream.readU8() & 31; + box.pps = []; + for (var i = 0; i < count; i++) { + box.pps.push(stream.readU8Array(stream.readU16())); + } + skipRemainingBytes(); + break; + case 'btrt': + box.name = "Bit Rate Box"; + box.bufferSizeDb = stream.readU32(); + box.maxBitrate = stream.readU32(); + box.avgBitrate = stream.readU32(); + break; + case 'stts': + box.name = "Decoding Time to Sample Box"; + readFullHeader(); + box.table = stream.readU32Array(stream.readU32(), 2, ["count", "delta"]); + break; + case 'stss': + box.name = "Sync Sample Box"; + readFullHeader(); + box.samples = stream.readU32Array(stream.readU32()); + break; + case 'stsc': + box.name = "Sample to Chunk Box"; + readFullHeader(); + box.table = stream.readU32Array(stream.readU32(), 3, + ["firstChunk", "samplesPerChunk", "sampleDescriptionId"]); + break; + case 'stsz': + box.name = "Sample Size Box"; + readFullHeader(); + box.sampleSize = stream.readU32(); + var count = stream.readU32(); + if (box.sampleSize == 0) { + box.table = stream.readU32Array(count); + } + break; + case 'stco': + box.name = "Chunk Offset Box"; + readFullHeader(); + box.table = stream.readU32Array(stream.readU32()); + break; + case 'smhd': + box.name = "Sound Media Header Box"; + readFullHeader(); + box.balance = stream.readFP8(); + stream.reserved(2, 0); + break; + case 'mdat': + box.name = "Media Data Box"; + assert (box.size >= 8, "Cannot parse large media data yet."); + box.data = stream.readU8Array(remainingBytes()); + break; + default: + skipRemainingBytes(); + break; + }; + return box; + }, + read: function () { + var start = (new Date).getTime(); + this.file = {}; + this.readBoxes(this.stream, this.file); + console.info("Parsed stream in " + ((new Date).getTime() - start) + " ms"); + }, + traceSamples: function () { + var video = this.tracks[1]; + var audio = this.tracks[2]; + + console.info("Video Samples: " + video.getSampleCount()); + console.info("Audio Samples: " + audio.getSampleCount()); + + var vi = 0; + var ai = 0; + + for (var i = 0; i < 100; i++) { + var vo = video.sampleToOffset(vi); + var ao = audio.sampleToOffset(ai); + + var vs = video.sampleToSize(vi, 1); + var as = audio.sampleToSize(ai, 1); + + if (vo < ao) { + console.info("V Sample " + vi + " Offset : " + vo + ", Size : " + vs); + vi ++; + } else { + console.info("A Sample " + ai + " Offset : " + ao + ", Size : " + as); + ai ++; + } + } + } + }; + return constructor; +})(); + +var Track = (function track () { + function constructor(file, trak) { + this.file = file; + this.trak = trak; + } + + constructor.prototype = { + getSampleSizeTable: function () { + return this.trak.mdia.minf.stbl.stsz.table; + }, + getSampleCount: function () { + return this.getSampleSizeTable().length; + }, + /** + * Computes the size of a range of samples, returns zero if length is zero. + */ + sampleToSize: function (start, length) { + var table = this.getSampleSizeTable(); + var size = 0; + for (var i = start; i < start + length; i++) { + size += table[i]; + } + return size; + }, + /** + * Computes the chunk that contains the specified sample, as well as the offset of + * the sample in the computed chunk. + */ + sampleToChunk: function (sample) { + + /* Samples are grouped in chunks which may contain a variable number of samples. + * The sample-to-chunk table in the stsc box describes how samples are arranged + * in chunks. Each table row corresponds to a set of consecutive chunks with the + * same number of samples and description ids. For example, the following table: + * + * +-------------+-------------------+----------------------+ + * | firstChunk | samplesPerChunk | sampleDescriptionId | + * +-------------+-------------------+----------------------+ + * | 1 | 3 | 23 | + * | 3 | 1 | 23 | + * | 5 | 1 | 24 | + * +-------------+-------------------+----------------------+ + * + * describes 5 chunks with a total of (2 * 3) + (2 * 1) + (1 * 1) = 9 samples, + * each chunk containing samples 3, 3, 1, 1, 1 in chunk order, or + * chunks 1, 1, 1, 2, 2, 2, 3, 4, 5 in sample order. + * + * This function determines the chunk that contains a specified sample by iterating + * over every entry in the table. It also returns the position of the sample in the + * chunk which can be used to compute the sample's exact position in the file. + * + * TODO: Determine if we should memoize this function. + */ + + var table = this.trak.mdia.minf.stbl.stsc.table; + + if (table.length === 1) { + var row = table[0]; + assert (row.firstChunk === 1); + return { + index: Math.floor(sample / row.samplesPerChunk), + offset: sample % row.samplesPerChunk + }; + } + + var totalChunkCount = 0; + for (var i = 0; i < table.length; i++) { + var row = table[i]; + if (i > 0) { + var previousRow = table[i - 1]; + var previousChunkCount = row.firstChunk - previousRow.firstChunk; + var previousSampleCount = previousRow.samplesPerChunk * previousChunkCount; + if (sample >= previousSampleCount) { + sample -= previousSampleCount; + if (i == table.length - 1) { + return { + index: totalChunkCount + previousChunkCount + Math.floor(sample / row.samplesPerChunk), + offset: sample % row.samplesPerChunk + }; + } + } else { + return { + index: totalChunkCount + Math.floor(sample / previousRow.samplesPerChunk), + offset: sample % previousRow.samplesPerChunk + }; + } + totalChunkCount += previousChunkCount; + } + } + assert(false); + }, + chunkToOffset: function (chunk) { + var table = this.trak.mdia.minf.stbl.stco.table; + return table[chunk]; + }, + sampleToOffset: function (sample) { + var res = this.sampleToChunk(sample); + var offset = this.chunkToOffset(res.index); + return offset + this.sampleToSize(sample - res.offset, res.offset); + }, + /** + * Computes the sample at the specified time. + */ + timeToSample: function (time) { + /* In the time-to-sample table samples are grouped by their duration. The count field + * indicates the number of consecutive samples that have the same duration. For example, + * the following table: + * + * +-------+-------+ + * | count | delta | + * +-------+-------+ + * | 4 | 3 | + * | 2 | 1 | + * | 3 | 2 | + * +-------+-------+ + * + * describes 9 samples with a total time of (4 * 3) + (2 * 1) + (3 * 2) = 20. + * + * This function determines the sample at the specified time by iterating over every + * entry in the table. + * + * TODO: Determine if we should memoize this function. + */ + var table = this.trak.mdia.minf.stbl.stts.table; + var sample = 0; + for (var i = 0; i < table.length; i++) { + var delta = table[i].count * table[i].delta; + if (time >= delta) { + time -= delta; + sample += table[i].count; + } else { + return sample + Math.floor(time / table[i].delta); + } + } + }, + /** + * Gets the total time of the track. + */ + getTotalTime: function () { + if (PARANOID) { + var table = this.trak.mdia.minf.stbl.stts.table; + var duration = 0; + for (var i = 0; i < table.length; i++) { + duration += table[i].count * table[i].delta; + } + assert (this.trak.mdia.mdhd.duration == duration); + } + return this.trak.mdia.mdhd.duration; + }, + getTotalTimeInSeconds: function () { + return this.timeToSeconds(this.getTotalTime()); + }, + getTimeScale: function () { + return this.trak.mdia.mdhd.timeScale; + }, + /** + * Converts time units to real time (seconds). + */ + timeToSeconds: function (time) { + return time / this.getTimeScale(); + }, + /** + * Converts real time (seconds) to time units. + */ + secondsToTime: function (seconds) { + return seconds * this.getTimeScale(); + }, + foo: function () { + /* + for (var i = 0; i < this.getSampleCount(); i++) { + var res = this.sampleToChunk(i); + console.info("Sample " + i + " -> " + res.index + " % " + res.offset + + " @ " + this.chunkToOffset(res.index) + + " @@ " + this.sampleToOffset(i)); + } + console.info("Total Time: " + this.timeToSeconds(this.getTotalTime())); + var total = this.getTotalTimeInSeconds(); + for (var i = 50; i < total; i += 0.1) { + // console.info("Time: " + i.toFixed(2) + " " + this.secondsToTime(i)); + + console.info("Time: " + i.toFixed(2) + " " + this.timeToSample(this.secondsToTime(i))); + } + */ + }, + /** + * AVC samples contain one or more NAL units each of which have a length prefix. + * This function returns an array of NAL units without their length prefixes. + */ + getSampleNALUnits: function (sample) { + var bytes = this.file.stream.bytes; + var offset = this.sampleToOffset(sample); + var end = offset + this.sampleToSize(sample, 1); + var nalUnits = []; + while(end - offset > 0) { + var length = (new Bytestream(bytes.buffer, offset)).readU32(); + nalUnits.push(bytes.subarray(offset + 4, offset + length + 4)); + offset = offset + length + 4; + } + return nalUnits; + } + }; + return constructor; +})(); + + +// Only add setZeroTimeout to the window object, and hide everything +// else in a closure. (http://dbaron.org/log/20100309-faster-timeouts) +(function() { + var timeouts = []; + var messageName = "zero-timeout-message"; + + // Like setTimeout, but only takes a function argument. There's + // no time argument (always zero) and no arguments (you have to + // use a closure). + function setZeroTimeout(fn) { + timeouts.push(fn); + window.postMessage(messageName, "*"); + } + + function handleMessage(event) { + if (event.source == window && event.data == messageName) { + event.stopPropagation(); + if (timeouts.length > 0) { + var fn = timeouts.shift(); + fn(); + } + } + } + + window.addEventListener("message", handleMessage, true); + + // Add the one thing we want added to the window object. + window.setZeroTimeout = setZeroTimeout; +})(); + +var MP4Player = (function reader() { + var defaultConfig = { + filter: "original", + filterHorLuma: "optimized", + filterVerLumaEdge: "optimized", + getBoundaryStrengthsA: "optimized" + }; + + function constructor(stream, useWorkers, webgl, render) { + this.stream = stream; + this.useWorkers = useWorkers; + this.webgl = webgl; + this.render = render; + + this.statistics = { + videoStartTime: 0, + videoPictureCounter: 0, + windowStartTime: 0, + windowPictureCounter: 0, + fps: 0, + fpsMin: 1000, + fpsMax: -1000, + webGLTextureUploadTime: 0 + }; + + this.onStatisticsUpdated = function () {}; + + this.avc = new Player({ + useWorker: useWorkers, + reuseMemory: true, + webgl: webgl, + size: { + width: 640, + height: 368 + } + }); + + this.webgl = this.avc.webgl; + + var self = this; + this.avc.onPictureDecoded = function(){ + updateStatistics.call(self); + }; + + this.canvas = this.avc.canvas; + } + + function updateStatistics() { + var s = this.statistics; + s.videoPictureCounter += 1; + s.windowPictureCounter += 1; + var now = Date.now(); + if (!s.videoStartTime) { + s.videoStartTime = now; + } + var videoElapsedTime = now - s.videoStartTime; + s.elapsed = videoElapsedTime / 1000; + if (videoElapsedTime < 1000) { + return; + } + + if (!s.windowStartTime) { + s.windowStartTime = now; + return; + } else if ((now - s.windowStartTime) > 1000) { + var windowElapsedTime = now - s.windowStartTime; + var fps = (s.windowPictureCounter / windowElapsedTime) * 1000; + s.windowStartTime = now; + s.windowPictureCounter = 0; + + if (fps < s.fpsMin) s.fpsMin = fps; + if (fps > s.fpsMax) s.fpsMax = fps; + s.fps = fps; + } + + var fps = (s.videoPictureCounter / videoElapsedTime) * 1000; + s.fpsSinceStart = fps; + this.onStatisticsUpdated(this.statistics); + return; + } + + constructor.prototype = { + readAll: function(callback) { + console.info("MP4Player::readAll()"); + this.stream.readAll(null, function (buffer) { + this.reader = new MP4Reader(new Bytestream(buffer)); + this.reader.read(); + var video = this.reader.tracks[1]; + this.size = new Size(video.trak.tkhd.width, video.trak.tkhd.height); + console.info("MP4Player::readAll(), length: " + this.reader.stream.length); + if (callback) callback(); + }.bind(this)); + }, + play: function() { + var reader = this.reader; + + if (!reader) { + this.readAll(this.play.bind(this)); + return; + }; + + var video = reader.tracks[1]; + var audio = reader.tracks[2]; + + var avc = reader.tracks[1].trak.mdia.minf.stbl.stsd.avc1.avcC; + var sps = avc.sps[0]; + var pps = avc.pps[0]; + + /* Decode Sequence & Picture Parameter Sets */ + this.avc.decode(sps); + this.avc.decode(pps); + + /* Decode Pictures */ + var pic = 0; + setTimeout(function foo() { + var avc = this.avc; + video.getSampleNALUnits(pic).forEach(function (nal) { + avc.decode(nal); + }); + pic ++; + if (pic < 3000) { + setTimeout(foo.bind(this), 1); + }; + }.bind(this), 1); + } + }; + + return constructor; +})(); + +var Broadway = (function broadway() { + function constructor(div) { + var src = div.attributes.src ? div.attributes.src.value : undefined; + var width = div.attributes.width ? div.attributes.width.value : 640; + var height = div.attributes.height ? div.attributes.height.value : 480; + + var controls = document.createElement('div'); + controls.setAttribute('style', "z-index: 100; position: absolute; bottom: 0px; background-color: rgba(0,0,0,0.8); height: 30px; width: 100%; text-align: left;"); + this.info = document.createElement('div'); + this.info.setAttribute('style', "font-size: 14px; font-weight: bold; padding: 6px; color: lime;"); + controls.appendChild(this.info); + div.appendChild(controls); + + var useWorkers = div.attributes.workers ? div.attributes.workers.value == "true" : false; + var render = div.attributes.render ? div.attributes.render.value == "true" : false; + + var webgl = "auto"; + if (div.attributes.webgl){ + if (div.attributes.webgl.value == "true"){ + webgl = true; + }; + if (div.attributes.webgl.value == "false"){ + webgl = false; + }; + }; + + var infoStrPre = "Click canvas to load and play - "; + var infoStr = ""; + if (useWorkers){ + infoStr += "worker thread "; + }else{ + infoStr += "main thread "; + }; + + this.player = new MP4Player(new Stream(src), useWorkers, webgl, render); + this.canvas = this.player.canvas; + this.canvas.onclick = function () { + this.play(); + }.bind(this); + div.appendChild(this.canvas); + + + infoStr += " - webgl: " + this.player.webgl; + this.info.innerHTML = infoStrPre + infoStr; + + + this.score = null; + this.player.onStatisticsUpdated = function (statistics) { + if (statistics.videoPictureCounter % 10 != 0) { + return; + } + var info = ""; + if (statistics.fps) { + info += " fps: " + statistics.fps.toFixed(2); + } + if (statistics.fpsSinceStart) { + info += " avg: " + statistics.fpsSinceStart.toFixed(2); + } + var scoreCutoff = 1200; + if (statistics.videoPictureCounter < scoreCutoff) { + this.score = scoreCutoff - statistics.videoPictureCounter; + } else if (statistics.videoPictureCounter == scoreCutoff) { + this.score = statistics.fpsSinceStart.toFixed(2); + } + // info += " score: " + this.score; + + this.info.innerHTML = infoStr + info; + }.bind(this); + } + constructor.prototype = { + play: function () { + this.player.play(); + } + }; + return constructor; +})(); + + +return { + Size, + Track, + MP4Reader, + MP4Player, + Bytestream, + Broadway, +} + +})(); \ No newline at end of file diff --git a/cvat-data/src/js/3rdparty_patch.diff b/cvat-data/src/js/3rdparty_patch.diff new file mode 100644 index 00000000..540a1513 --- /dev/null +++ b/cvat-data/src/js/3rdparty_patch.diff @@ -0,0 +1,162 @@ +Binary files 3rdparty/avc.wasm and 3rdparty_edited/avc.wasm differ +diff -u 3rdparty/Decoder.js 3rdparty_edited/Decoder.js +--- 3rdparty/Decoder.js 2019-12-16 13:01:04.315399742 +0300 ++++ 3rdparty_edited/Decoder.js 2019-12-16 12:48:52.995423455 +0300 +@@ -63,10 +63,7 @@ + //var Module = (function(){ + + +-var Module=typeof Module!=="undefined"?Module:{};var moduleOverrides={};var key;for(key in Module){if(Module.hasOwnProperty(key)){moduleOverrides[key]=Module[key]}}Module["arguments"]=[];Module["thisProgram"]="./this.program";Module["quit"]=(function(status,toThrow){throw toThrow});Module["preRun"]=[];Module["postRun"]=[];var ENVIRONMENT_IS_WEB=false;var ENVIRONMENT_IS_WORKER=false;var ENVIRONMENT_IS_NODE=false;var ENVIRONMENT_IS_SHELL=false;if(Module["ENVIRONMENT"]){if(Module["ENVIRONMENT"]==="WEB"){ENVIRONMENT_IS_WEB=true}else if(Module["ENVIRONMENT"]==="WORKER"){ENVIRONMENT_IS_WORKER=true}else if(Module["ENVIRONMENT"]==="NODE"){ENVIRONMENT_IS_NODE=true}else if(Module["ENVIRONMENT"]==="SHELL"){ENVIRONMENT_IS_SHELL=true}else{throw new Error("Module['ENVIRONMENT'] value is not valid. must be one of: WEB|WORKER|NODE|SHELL.")}}else{ENVIRONMENT_IS_WEB=typeof window==="object";ENVIRONMENT_IS_WORKER=typeof importScripts==="function";ENVIRONMENT_IS_NODE=typeof process==="object"&&typeof null==="function"&&!ENVIRONMENT_IS_WEB&&!ENVIRONMENT_IS_WORKER;ENVIRONMENT_IS_SHELL=!ENVIRONMENT_IS_WEB&&!ENVIRONMENT_IS_NODE&&!ENVIRONMENT_IS_WORKER}if(ENVIRONMENT_IS_NODE){var nodeFS;var nodePath;Module["read"]=function shell_read(filename,binary){var ret;if(!nodeFS)nodeFS=(null)("fs");if(!nodePath)nodePath=(null)("path");filename=nodePath["normalize"](filename);ret=nodeFS["readFileSync"](filename);return binary?ret:ret.toString()};Module["readBinary"]=function readBinary(filename){var ret=Module["read"](filename,true);if(!ret.buffer){ret=new Uint8Array(ret)}assert(ret.buffer);return ret};if(process["argv"].length>1){Module["thisProgram"]=process["argv"][1].replace(/\\/g,"/")}Module["arguments"]=process["argv"].slice(2);if(typeof module!=="undefined"){module["exports"]=Module}process["on"]("uncaughtException",(function(ex){if(!(ex instanceof ExitStatus)){throw ex}}));process["on"]("unhandledRejection",(function(reason,p){process["exit"](1)}));Module["inspect"]=(function(){return"[Emscripten Module object]"})}else if(ENVIRONMENT_IS_SHELL){if(typeof read!="undefined"){Module["read"]=function shell_read(f){return read(f)}}Module["readBinary"]=function readBinary(f){var data;if(typeof readbuffer==="function"){return new Uint8Array(readbuffer(f))}data=read(f,"binary");assert(typeof data==="object");return data};if(typeof scriptArgs!="undefined"){Module["arguments"]=scriptArgs}else if(typeof arguments!="undefined"){Module["arguments"]=arguments}if(typeof quit==="function"){Module["quit"]=(function(status,toThrow){quit(status)})}}else if(ENVIRONMENT_IS_WEB||ENVIRONMENT_IS_WORKER){Module["read"]=function shell_read(url){var xhr=new XMLHttpRequest;xhr.open("GET",url,false);xhr.send(null);return xhr.responseText};if(ENVIRONMENT_IS_WORKER){Module["readBinary"]=function readBinary(url){var xhr=new XMLHttpRequest;xhr.open("GET",url,false);xhr.responseType="arraybuffer";xhr.send(null);return new Uint8Array(xhr.response)}}Module["readAsync"]=function readAsync(url,onload,onerror){var xhr=new XMLHttpRequest;xhr.open("GET",url,true);xhr.responseType="arraybuffer";xhr.onload=function xhr_onload(){if(xhr.status==200||xhr.status==0&&xhr.response){onload(xhr.response);return}onerror()};xhr.onerror=onerror;xhr.send(null)};Module["setWindowTitle"]=(function(title){document.title=title})}else{throw new Error("not compiled for this environment")}Module["print"]=typeof console!=="undefined"?console.log.bind(console):typeof print!=="undefined"?print:null;Module["printErr"]=typeof printErr!=="undefined"?printErr:typeof console!=="undefined"&&console.warn.bind(console)||Module["print"];Module.print=Module["print"];Module.printErr=Module["printErr"];for(key in moduleOverrides){if(moduleOverrides.hasOwnProperty(key)){Module[key]=moduleOverrides[key]}}moduleOverrides=undefined;var STACK_ALIGN=16;function staticAlloc(size){assert(!staticSealed);var ret=STATICTOP;STATICTOP=STATICTOP+size+15&-16;return ret}function alignMemory(size,factor){if(!factor)factor=STACK_ALIGN;var ret=size=Math.ceil(size/factor)*factor;return ret}var asm2wasmImports={"f64-rem":(function(x,y){return x%y}),"debugger":(function(){debugger})};var functionPointers=new Array(0);var GLOBAL_BASE=1024;var ABORT=0;var EXITSTATUS=0;function assert(condition,text){if(!condition){abort("Assertion failed: "+text)}}function Pointer_stringify(ptr,length){if(length===0||!ptr)return"";var hasUtf=0;var t;var i=0;while(1){t=HEAPU8[ptr+i>>0];hasUtf|=t;if(t==0&&!length)break;i++;if(length&&i==length)break}if(!length)length=i;var ret="";if(hasUtf<128){var MAX_CHUNK=1024;var curr;while(length>0){curr=String.fromCharCode.apply(String,HEAPU8.subarray(ptr,ptr+Math.min(length,MAX_CHUNK)));ret=ret?ret+curr:curr;ptr+=MAX_CHUNK;length-=MAX_CHUNK}return ret}return UTF8ToString(ptr)}var UTF8Decoder=typeof TextDecoder!=="undefined"?new TextDecoder("utf8"):undefined;function UTF8ArrayToString(u8Array,idx){var endPtr=idx;while(u8Array[endPtr])++endPtr;if(endPtr-idx>16&&u8Array.subarray&&UTF8Decoder){return UTF8Decoder.decode(u8Array.subarray(idx,endPtr))}else{var u0,u1,u2,u3,u4,u5;var str="";while(1){u0=u8Array[idx++];if(!u0)return str;if(!(u0&128)){str+=String.fromCharCode(u0);continue}u1=u8Array[idx++]&63;if((u0&224)==192){str+=String.fromCharCode((u0&31)<<6|u1);continue}u2=u8Array[idx++]&63;if((u0&240)==224){u0=(u0&15)<<12|u1<<6|u2}else{u3=u8Array[idx++]&63;if((u0&248)==240){u0=(u0&7)<<18|u1<<12|u2<<6|u3}else{u4=u8Array[idx++]&63;if((u0&252)==248){u0=(u0&3)<<24|u1<<18|u2<<12|u3<<6|u4}else{u5=u8Array[idx++]&63;u0=(u0&1)<<30|u1<<24|u2<<18|u3<<12|u4<<6|u5}}}if(u0<65536){str+=String.fromCharCode(u0)}else{var ch=u0-65536;str+=String.fromCharCode(55296|ch>>10,56320|ch&1023)}}}}function UTF8ToString(ptr){return UTF8ArrayToString(HEAPU8,ptr)}var UTF16Decoder=typeof TextDecoder!=="undefined"?new TextDecoder("utf-16le"):undefined;var WASM_PAGE_SIZE=65536;var ASMJS_PAGE_SIZE=16777216;function alignUp(x,multiple){if(x%multiple>0){x+=multiple-x%multiple}return x}var buffer,HEAP8,HEAPU8,HEAP16,HEAPU16,HEAP32,HEAPU32,HEAPF32,HEAPF64;function updateGlobalBuffer(buf){Module["buffer"]=buffer=buf}function updateGlobalBufferViews(){Module["HEAP8"]=HEAP8=new Int8Array(buffer);Module["HEAP16"]=HEAP16=new Int16Array(buffer);Module["HEAP32"]=HEAP32=new Int32Array(buffer);Module["HEAPU8"]=HEAPU8=new Uint8Array(buffer);Module["HEAPU16"]=HEAPU16=new Uint16Array(buffer);Module["HEAPU32"]=HEAPU32=new Uint32Array(buffer);Module["HEAPF32"]=HEAPF32=new Float32Array(buffer);Module["HEAPF64"]=HEAPF64=new Float64Array(buffer)}var STATIC_BASE,STATICTOP,staticSealed;var STACK_BASE,STACKTOP,STACK_MAX;var DYNAMIC_BASE,DYNAMICTOP_PTR;STATIC_BASE=STATICTOP=STACK_BASE=STACKTOP=STACK_MAX=DYNAMIC_BASE=DYNAMICTOP_PTR=0;staticSealed=false;function abortOnCannotGrowMemory(){abort("Cannot enlarge memory arrays. Either (1) compile with -s TOTAL_MEMORY=X with X higher than the current value "+TOTAL_MEMORY+", (2) compile with -s ALLOW_MEMORY_GROWTH=1 which allows increasing the size at runtime, or (3) if you want malloc to return NULL (0) instead of this abort, compile with -s ABORTING_MALLOC=0 ")}function enlargeMemory(){abortOnCannotGrowMemory()}var TOTAL_STACK=Module["TOTAL_STACK"]||5242880;var TOTAL_MEMORY=Module["TOTAL_MEMORY"]||52428800;if(TOTAL_MEMORY0){var callback=callbacks.shift();if(typeof callback=="function"){callback();continue}var func=callback.func;if(typeof func==="number"){if(callback.arg===undefined){Module["dynCall_v"](func)}else{Module["dynCall_vi"](func,callback.arg)}}else{func(callback.arg===undefined?null:callback.arg)}}}var __ATPRERUN__=[];var __ATINIT__=[];var __ATMAIN__=[];var __ATEXIT__=[];var __ATPOSTRUN__=[];var runtimeInitialized=false;var runtimeExited=false;function preRun(){if(Module["preRun"]){if(typeof Module["preRun"]=="function")Module["preRun"]=[Module["preRun"]];while(Module["preRun"].length){addOnPreRun(Module["preRun"].shift())}}callRuntimeCallbacks(__ATPRERUN__)}function ensureInitRuntime(){if(runtimeInitialized)return;runtimeInitialized=true;callRuntimeCallbacks(__ATINIT__)}function preMain(){callRuntimeCallbacks(__ATMAIN__)}function exitRuntime(){callRuntimeCallbacks(__ATEXIT__);runtimeExited=true}function postRun(){if(Module["postRun"]){if(typeof Module["postRun"]=="function")Module["postRun"]=[Module["postRun"]];while(Module["postRun"].length){addOnPostRun(Module["postRun"].shift())}}callRuntimeCallbacks(__ATPOSTRUN__)}function addOnPreRun(cb){__ATPRERUN__.unshift(cb)}function addOnPostRun(cb){__ATPOSTRUN__.unshift(cb)}var Math_abs=Math.abs;var Math_cos=Math.cos;var Math_sin=Math.sin;var Math_tan=Math.tan;var Math_acos=Math.acos;var Math_asin=Math.asin;var Math_atan=Math.atan;var Math_atan2=Math.atan2;var Math_exp=Math.exp;var Math_log=Math.log;var Math_sqrt=Math.sqrt;var Math_ceil=Math.ceil;var Math_floor=Math.floor;var Math_pow=Math.pow;var Math_imul=Math.imul;var Math_fround=Math.fround;var Math_round=Math.round;var Math_min=Math.min;var Math_max=Math.max;var Math_clz32=Math.clz32;var Math_trunc=Math.trunc;var runDependencies=0;var runDependencyWatcher=null;var dependenciesFulfilled=null;function addRunDependency(id){runDependencies++;if(Module["monitorRunDependencies"]){Module["monitorRunDependencies"](runDependencies)}}function removeRunDependency(id){runDependencies--;if(Module["monitorRunDependencies"]){Module["monitorRunDependencies"](runDependencies)}if(runDependencies==0){if(runDependencyWatcher!==null){clearInterval(runDependencyWatcher);runDependencyWatcher=null}if(dependenciesFulfilled){var callback=dependenciesFulfilled;dependenciesFulfilled=null;callback()}}}Module["preloadedImages"]={};Module["preloadedAudios"]={};var dataURIPrefix="data:application/octet-stream;base64,";function isDataURI(filename){return String.prototype.startsWith?filename.startsWith(dataURIPrefix):filename.indexOf(dataURIPrefix)===0}function integrateWasmJS(){var wasmTextFile="avc.wast";var wasmBinaryFile="avc.wasm";var asmjsCodeFile="avc.temp.asm.js";if(typeof Module["locateFile"]==="function"){if(!isDataURI(wasmTextFile)){wasmTextFile=Module["locateFile"](wasmTextFile)}if(!isDataURI(wasmBinaryFile)){wasmBinaryFile=Module["locateFile"](wasmBinaryFile)}if(!isDataURI(asmjsCodeFile)){asmjsCodeFile=Module["locateFile"](asmjsCodeFile)}}var wasmPageSize=64*1024;var info={"global":null,"env":null,"asm2wasm":asm2wasmImports,"parent":Module};var exports=null;function mergeMemory(newBuffer){var oldBuffer=Module["buffer"];if(newBuffer.byteLength>2];return ret}),getStr:(function(){var ret=Pointer_stringify(SYSCALLS.get());return ret}),get64:(function(){var low=SYSCALLS.get(),high=SYSCALLS.get();if(low>=0)assert(high===0);else assert(high===-1);return low}),getZero:(function(){assert(SYSCALLS.get()===0)})};function ___syscall140(which,varargs){SYSCALLS.varargs=varargs;try{var stream=SYSCALLS.getStreamFromFD(),offset_high=SYSCALLS.get(),offset_low=SYSCALLS.get(),result=SYSCALLS.get(),whence=SYSCALLS.get();var offset=offset_low;FS.llseek(stream,offset,whence);HEAP32[result>>2]=stream.position;if(stream.getdents&&offset===0&&whence===0)stream.getdents=null;return 0}catch(e){if(typeof FS==="undefined"||!(e instanceof FS.ErrnoError))abort(e);return-e.errno}}function ___syscall146(which,varargs){SYSCALLS.varargs=varargs;try{var stream=SYSCALLS.get(),iov=SYSCALLS.get(),iovcnt=SYSCALLS.get();var ret=0;if(!___syscall146.buffers){___syscall146.buffers=[null,[],[]];___syscall146.printChar=(function(stream,curr){var buffer=___syscall146.buffers[stream];assert(buffer);if(curr===0||curr===10){(stream===1?Module["print"]:Module["printErr"])(UTF8ArrayToString(buffer,0));buffer.length=0}else{buffer.push(curr)}})}for(var i=0;i>2];var len=HEAP32[iov+(i*8+4)>>2];for(var j=0;j>2]=value;return value}DYNAMICTOP_PTR=staticAlloc(4);STACK_BASE=STACKTOP=alignMemory(STATICTOP);STACK_MAX=STACK_BASE+TOTAL_STACK;DYNAMIC_BASE=alignMemory(STACK_MAX);HEAP32[DYNAMICTOP_PTR>>2]=DYNAMIC_BASE;staticSealed=true;Module["wasmTableSize"]=10;Module["wasmMaxTableSize"]=10;Module.asmGlobalArg={};Module.asmLibraryArg={"abort":abort,"enlargeMemory":enlargeMemory,"getTotalMemory":getTotalMemory,"abortOnCannotGrowMemory":abortOnCannotGrowMemory,"___setErrNo":___setErrNo,"___syscall140":___syscall140,"___syscall146":___syscall146,"___syscall54":___syscall54,"___syscall6":___syscall6,"_broadwayOnHeadersDecoded":_broadwayOnHeadersDecoded,"_broadwayOnPictureDecoded":_broadwayOnPictureDecoded,"_emscripten_memcpy_big":_emscripten_memcpy_big,"DYNAMICTOP_PTR":DYNAMICTOP_PTR,"STACKTOP":STACKTOP};var asm=Module["asm"](Module.asmGlobalArg,Module.asmLibraryArg,buffer);Module["asm"]=asm;var _broadwayCreateStream=Module["_broadwayCreateStream"]=(function(){return Module["asm"]["_broadwayCreateStream"].apply(null,arguments)});var _broadwayExit=Module["_broadwayExit"]=(function(){return Module["asm"]["_broadwayExit"].apply(null,arguments)});var _broadwayGetMajorVersion=Module["_broadwayGetMajorVersion"]=(function(){return Module["asm"]["_broadwayGetMajorVersion"].apply(null,arguments)});var _broadwayGetMinorVersion=Module["_broadwayGetMinorVersion"]=(function(){return Module["asm"]["_broadwayGetMinorVersion"].apply(null,arguments)});var _broadwayInit=Module["_broadwayInit"]=(function(){return Module["asm"]["_broadwayInit"].apply(null,arguments)});var _broadwayPlayStream=Module["_broadwayPlayStream"]=(function(){return Module["asm"]["_broadwayPlayStream"].apply(null,arguments)});Module["asm"]=asm;function ExitStatus(status){this.name="ExitStatus";this.message="Program terminated with exit("+status+")";this.status=status}ExitStatus.prototype=new Error;ExitStatus.prototype.constructor=ExitStatus;var initialStackTop;dependenciesFulfilled=function runCaller(){if(!Module["calledRun"])run();if(!Module["calledRun"])dependenciesFulfilled=runCaller};function run(args){args=args||Module["arguments"];if(runDependencies>0){return}preRun();if(runDependencies>0)return;if(Module["calledRun"])return;function doRun(){if(Module["calledRun"])return;Module["calledRun"]=true;if(ABORT)return;ensureInitRuntime();preMain();if(Module["onRuntimeInitialized"])Module["onRuntimeInitialized"]();postRun()}if(Module["setStatus"]){Module["setStatus"]("Running...");setTimeout((function(){setTimeout((function(){Module["setStatus"]("")}),1);doRun()}),1)}else{doRun()}}Module["run"]=run;function exit(status,implicit){if(implicit&&Module["noExitRuntime"]&&status===0){return}if(Module["noExitRuntime"]){}else{ABORT=true;EXITSTATUS=status;STACKTOP=initialStackTop;exitRuntime();if(Module["onExit"])Module["onExit"](status)}if(ENVIRONMENT_IS_NODE){process["exit"](status)}Module["quit"](status,new ExitStatus(status))}Module["exit"]=exit;function abort(what){if(Module["onAbort"]){Module["onAbort"](what)}if(what!==undefined){Module.print(what);Module.printErr(what);what=JSON.stringify(what)}else{what=""}ABORT=true;EXITSTATUS=1;throw"abort("+what+"). Build with -s ASSERTIONS=1 for more info."}Module["abort"]=abort;if(Module["preInit"]){if(typeof Module["preInit"]=="function")Module["preInit"]=[Module["preInit"]];while(Module["preInit"].length>0){Module["preInit"].pop()()}}Module["noExitRuntime"]=true;run() +- +- +- ++var Module=typeof Module!=="undefined"?Module:{};var moduleOverrides={};var key;for(key in Module){if(Module.hasOwnProperty(key)){moduleOverrides[key]=Module[key]}}var arguments_=[];var thisProgram="./this.program";var quit_=function(status,toThrow){throw toThrow};var ENVIRONMENT_IS_WEB=false;var ENVIRONMENT_IS_WORKER=true;var scriptDirectory="";function locateFile(path){if(Module["locateFile"]){return Module["locateFile"](path,scriptDirectory)}return scriptDirectory+path}var read_,readAsync,readBinary,setWindowTitle;if(ENVIRONMENT_IS_WEB||ENVIRONMENT_IS_WORKER){if(ENVIRONMENT_IS_WORKER){scriptDirectory=self.location.href}else if(document.currentScript){scriptDirectory=document.currentScript.src}if(scriptDirectory.indexOf("blob:")!==0){scriptDirectory=scriptDirectory.substr(0,scriptDirectory.lastIndexOf("/")+1)}else{scriptDirectory=""}{read_=function shell_read(url){var xhr=new XMLHttpRequest;xhr.open("GET",url,false);xhr.send(null);return xhr.responseText};if(ENVIRONMENT_IS_WORKER){readBinary=function readBinary(url){var xhr=new XMLHttpRequest;xhr.open("GET",url,false);xhr.responseType="arraybuffer";xhr.send(null);return new Uint8Array(xhr.response)}}readAsync=function readAsync(url,onload,onerror){var xhr=new XMLHttpRequest;xhr.open("GET",url,true);xhr.responseType="arraybuffer";xhr.onload=function xhr_onload(){if(xhr.status==200||xhr.status==0&&xhr.response){onload(xhr.response);return}onerror()};xhr.onerror=onerror;xhr.send(null)}}setWindowTitle=function(title){document.title=title}}else{}var out=Module["print"]||console.log.bind(console);var err=Module["printErr"]||console.warn.bind(console);for(key in moduleOverrides){if(moduleOverrides.hasOwnProperty(key)){Module[key]=moduleOverrides[key]}}moduleOverrides=null;if(Module["arguments"])arguments_=Module["arguments"];if(Module["thisProgram"])thisProgram=Module["thisProgram"];if(Module["quit"])quit_=Module["quit"];var asm2wasmImports={"f64-rem":function(x,y){return x%y},"debugger":function(){}};var functionPointers=new Array(0);var wasmBinary;if(Module["wasmBinary"])wasmBinary=Module["wasmBinary"];var noExitRuntime;if(Module["noExitRuntime"])noExitRuntime=Module["noExitRuntime"];if(typeof WebAssembly!=="object"){err("no native wasm support detected")}var wasmMemory;var wasmTable=new WebAssembly.Table({"initial":10,"maximum":10,"element":"anyfunc"});var ABORT=false;var EXITSTATUS=0;var UTF8Decoder=typeof TextDecoder!=="undefined"?new TextDecoder("utf8"):undefined;function UTF8ArrayToString(u8Array,idx,maxBytesToRead){var endIdx=idx+maxBytesToRead;var endPtr=idx;while(u8Array[endPtr]&&!(endPtr>=endIdx))++endPtr;if(endPtr-idx>16&&u8Array.subarray&&UTF8Decoder){return UTF8Decoder.decode(u8Array.subarray(idx,endPtr))}else{var str="";while(idx>10,56320|ch&1023)}}}return str}function UTF8ToString(ptr,maxBytesToRead){return ptr?UTF8ArrayToString(HEAPU8,ptr,maxBytesToRead):""}var UTF16Decoder=typeof TextDecoder!=="undefined"?new TextDecoder("utf-16le"):undefined;var WASM_PAGE_SIZE=65536;var buffer,HEAP8,HEAPU8,HEAP16,HEAPU16,HEAP32,HEAPU32,HEAPF32,HEAPF64;function updateGlobalBufferAndViews(buf){buffer=buf;Module["HEAP8"]=HEAP8=new Int8Array(buf);Module["HEAP16"]=HEAP16=new Int16Array(buf);Module["HEAP32"]=HEAP32=new Int32Array(buf);Module["HEAPU8"]=HEAPU8=new Uint8Array(buf);Module["HEAPU16"]=HEAPU16=new Uint16Array(buf);Module["HEAPU32"]=HEAPU32=new Uint32Array(buf);Module["HEAPF32"]=HEAPF32=new Float32Array(buf);Module["HEAPF64"]=HEAPF64=new Float64Array(buf)}var DYNAMIC_BASE=5254064,DYNAMICTOP_PTR=10992;var INITIAL_TOTAL_MEMORY=Module["TOTAL_MEMORY"]||104857600;if(Module["wasmMemory"]){wasmMemory=Module["wasmMemory"]}else{wasmMemory=new WebAssembly.Memory({"initial":INITIAL_TOTAL_MEMORY/WASM_PAGE_SIZE,"maximum":INITIAL_TOTAL_MEMORY/WASM_PAGE_SIZE})}if(wasmMemory){buffer=wasmMemory.buffer}INITIAL_TOTAL_MEMORY=buffer.byteLength;updateGlobalBufferAndViews(buffer);HEAP32[DYNAMICTOP_PTR>>2]=DYNAMIC_BASE;function callRuntimeCallbacks(callbacks){while(callbacks.length>0){var callback=callbacks.shift();if(typeof callback=="function"){callback();continue}var func=callback.func;if(typeof func==="number"){if(callback.arg===undefined){Module["dynCall_v"](func)}else{Module["dynCall_vi"](func,callback.arg)}}else{func(callback.arg===undefined?null:callback.arg)}}}var __ATPRERUN__=[];var __ATINIT__=[];var __ATMAIN__=[];var __ATPOSTRUN__=[];var runtimeInitialized=false;function preRun(){if(Module["preRun"]){if(typeof Module["preRun"]=="function")Module["preRun"]=[Module["preRun"]];while(Module["preRun"].length){addOnPreRun(Module["preRun"].shift())}}callRuntimeCallbacks(__ATPRERUN__)}function initRuntime(){runtimeInitialized=true;callRuntimeCallbacks(__ATINIT__)}function preMain(){callRuntimeCallbacks(__ATMAIN__)}function postRun(){if(Module["postRun"]){if(typeof Module["postRun"]=="function")Module["postRun"]=[Module["postRun"]];while(Module["postRun"].length){addOnPostRun(Module["postRun"].shift())}}callRuntimeCallbacks(__ATPOSTRUN__)}function addOnPreRun(cb){__ATPRERUN__.unshift(cb)}function addOnPostRun(cb){__ATPOSTRUN__.unshift(cb)}var runDependencies=0;var runDependencyWatcher=null;var dependenciesFulfilled=null;function addRunDependency(id){runDependencies++;if(Module["monitorRunDependencies"]){Module["monitorRunDependencies"](runDependencies)}}function removeRunDependency(id){runDependencies--;if(Module["monitorRunDependencies"]){Module["monitorRunDependencies"](runDependencies)}if(runDependencies==0){if(runDependencyWatcher!==null){clearInterval(runDependencyWatcher);runDependencyWatcher=null}if(dependenciesFulfilled){var callback=dependenciesFulfilled;dependenciesFulfilled=null;callback()}}}Module["preloadedImages"]={};Module["preloadedAudios"]={};function abort(what){if(Module["onAbort"]){Module["onAbort"](what)}what+="";out(what);err(what);ABORT=true;EXITSTATUS=1;what="abort("+what+"). Build with -s ASSERTIONS=1 for more info.";throw new WebAssembly.RuntimeError(what)}var dataURIPrefix="data:application/octet-stream;base64,";function isDataURI(filename){return String.prototype.startsWith?filename.startsWith(dataURIPrefix):filename.indexOf(dataURIPrefix)===0}var wasmBinaryFile="avc.wasm";if(!isDataURI(wasmBinaryFile)){wasmBinaryFile=locateFile(wasmBinaryFile)}function getBinary(){try{if(wasmBinary){return new Uint8Array(wasmBinary)}if(readBinary){return readBinary(wasmBinaryFile)}else{throw"both async and sync fetching of the wasm failed"}}catch(err){abort(err)}}function getBinaryPromise(){if(!wasmBinary&&(ENVIRONMENT_IS_WEB||ENVIRONMENT_IS_WORKER)&&typeof fetch==="function"){return fetch(wasmBinaryFile,{credentials:"same-origin"}).then(function(response){if(!response["ok"]){throw"failed to load wasm binary file at '"+wasmBinaryFile+"'"}return response["arrayBuffer"]()}).catch(function(){return getBinary()})}return new Promise(function(resolve,reject){resolve(getBinary())})}function createWasm(){var info={"env":asmLibraryArg,"wasi_unstable":asmLibraryArg,"global":{"NaN":NaN,Infinity:Infinity},"global.Math":Math,"asm2wasm":asm2wasmImports};function receiveInstance(instance,module){var exports=instance.exports;Module["asm"]=exports;removeRunDependency("wasm-instantiate")}addRunDependency("wasm-instantiate");function receiveInstantiatedSource(output){receiveInstance(output["instance"])}function instantiateArrayBuffer(receiver){return getBinaryPromise().then(function(binary){return WebAssembly.instantiate(binary,info)}).then(receiver,function(reason){err("failed to asynchronously prepare wasm: "+reason);abort(reason)})}function instantiateAsync(){if(!wasmBinary&&typeof WebAssembly.instantiateStreaming==="function"&&!isDataURI(wasmBinaryFile)&&typeof fetch==="function"){fetch(wasmBinaryFile,{credentials:"same-origin"}).then(function(response){var result=WebAssembly.instantiateStreaming(response,info);return result.then(receiveInstantiatedSource,function(reason){err("wasm streaming compile failed: "+reason);err("falling back to ArrayBuffer instantiation");instantiateArrayBuffer(receiveInstantiatedSource)})})}else{return instantiateArrayBuffer(receiveInstantiatedSource)}}if(Module["instantiateWasm"]){try{var exports=Module["instantiateWasm"](info,receiveInstance);return exports}catch(e){err("Module.instantiateWasm callback failed with error: "+e);return false}}instantiateAsync();return{}}Module["asm"]=createWasm;var PATH={splitPath:function(filename){var splitPathRe=/^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/;return splitPathRe.exec(filename).slice(1)},normalizeArray:function(parts,allowAboveRoot){var up=0;for(var i=parts.length-1;i>=0;i--){var last=parts[i];if(last==="."){parts.splice(i,1)}else if(last===".."){parts.splice(i,1);up++}else if(up){parts.splice(i,1);up--}}if(allowAboveRoot){for(;up;up--){parts.unshift("..")}}return parts},normalize:function(path){var isAbsolute=path.charAt(0)==="/",trailingSlash=path.substr(-1)==="/";path=PATH.normalizeArray(path.split("/").filter(function(p){return!!p}),!isAbsolute).join("/");if(!path&&!isAbsolute){path="."}if(path&&trailingSlash){path+="/"}return(isAbsolute?"/":"")+path},dirname:function(path){var result=PATH.splitPath(path),root=result[0],dir=result[1];if(!root&&!dir){return"."}if(dir){dir=dir.substr(0,dir.length-1)}return root+dir},basename:function(path){if(path==="/")return"/";var lastSlash=path.lastIndexOf("/");if(lastSlash===-1)return path;return path.substr(lastSlash+1)},extname:function(path){return PATH.splitPath(path)[3]},join:function(){var paths=Array.prototype.slice.call(arguments,0);return PATH.normalize(paths.join("/"))},join2:function(l,r){return PATH.normalize(l+"/"+r)}};var SYSCALLS={buffers:[null,[],[]],printChar:function(stream,curr){var buffer=SYSCALLS.buffers[stream];if(curr===0||curr===10){(stream===1?out:err)(UTF8ArrayToString(buffer,0));buffer.length=0}else{buffer.push(curr)}},varargs:0,get:function(varargs){SYSCALLS.varargs+=4;var ret=HEAP32[SYSCALLS.varargs-4>>2];return ret},getStr:function(){var ret=UTF8ToString(SYSCALLS.get());return ret},get64:function(){var low=SYSCALLS.get(),high=SYSCALLS.get();return low},getZero:function(){SYSCALLS.get()}};function _fd_write(fd,iov,iovcnt,pnum){try{var num=0;for(var i=0;i>2];var len=HEAP32[iov+(i*8+4)>>2];for(var j=0;j>2]=num;return 0}catch(e){if(typeof FS==="undefined"||!(e instanceof FS.ErrnoError))abort(e);return e.errno}}function ___wasi_fd_write(){return _fd_write.apply(null,arguments)}function _broadwayOnHeadersDecoded(){par_broadwayOnHeadersDecoded()}Module["_broadwayOnHeadersDecoded"]=_broadwayOnHeadersDecoded;function _broadwayOnPictureDecoded($buffer,width,height){par_broadwayOnPictureDecoded($buffer,width,height)}Module["_broadwayOnPictureDecoded"]=_broadwayOnPictureDecoded;function _emscripten_get_heap_size(){return HEAP8.length}function abortOnCannotGrowMemory(requestedSize){abort("OOM")}function _emscripten_resize_heap(requestedSize){abortOnCannotGrowMemory(requestedSize)}function _emscripten_memcpy_big(dest,src,num){HEAPU8.set(HEAPU8.subarray(src,src+num),dest)}var asmGlobalArg={};var asmLibraryArg={"g":___wasi_fd_write,"__memory_base":1024,"__table_base":0,"f":_broadwayOnHeadersDecoded,"e":_broadwayOnPictureDecoded,"b":_emscripten_get_heap_size,"d":_emscripten_memcpy_big,"a":_emscripten_resize_heap,"c":abort,"memory":wasmMemory,"table":wasmTable};var asm=Module["asm"](asmGlobalArg,asmLibraryArg,buffer);Module["asm"]=asm;var _broadwayCreateStream=Module["_broadwayCreateStream"]=function(){return Module["asm"]["h"].apply(null,arguments)};var _broadwayExit=Module["_broadwayExit"]=function(){return Module["asm"]["i"].apply(null,arguments)};var _broadwayGetMajorVersion=Module["_broadwayGetMajorVersion"]=function(){return Module["asm"]["j"].apply(null,arguments)};var _broadwayGetMinorVersion=Module["_broadwayGetMinorVersion"]=function(){return Module["asm"]["k"].apply(null,arguments)};var _broadwayInit=Module["_broadwayInit"]=function(){return Module["asm"]["l"].apply(null,arguments)};var _broadwayPlayStream=Module["_broadwayPlayStream"]=function(){return Module["asm"]["m"].apply(null,arguments)};Module["asm"]=asm;var calledRun;dependenciesFulfilled=function runCaller(){if(!calledRun)run();if(!calledRun)dependenciesFulfilled=runCaller};function run(args){args=args||arguments_;if(runDependencies>0){return}preRun();if(runDependencies>0)return;function doRun(){if(calledRun)return;calledRun=true;if(ABORT)return;initRuntime();preMain();if(Module["onRuntimeInitialized"])Module["onRuntimeInitialized"]();postRun()}if(Module["setStatus"]){Module["setStatus"]("Running...");setTimeout(function(){setTimeout(function(){Module["setStatus"]("")},1);doRun()},1)}else{doRun()}}Module["run"]=run;if(Module["preInit"]){if(typeof Module["preInit"]=="function")Module["preInit"]=[Module["preInit"]];while(Module["preInit"].length>0){Module["preInit"].pop()()}}noExitRuntime=true;run(); + // return Module; + //})(); + +@@ -471,7 +468,7 @@ + lumaSize = imul(width|0, height|0)|0; + chromaSize = (lumaSize|0) >> 2; + outSize = imul(imul(width, height)|0, 4)|0; +- inpSize = ((lumaSize + chromaSize)|0 + chromaSize)|0; ++ inpSize = (((lumaSize + chromaSize)|0) + chromaSize)|0; + + outStart = 0; + inpStart = (outStart + outSize)|0; +@@ -524,18 +521,18 @@ + v = inp[vstart >> 0]|0; + + cacheAdr = (((((y << 16)|0) + ((u << 8)|0))|0) + v)|0; +- o = mem32[((cacheStart + cacheAdr)|0) >> 2]|0; ++ o = mem32[((cacheStart >> 2) + cacheAdr)|0]|0; + if (o){}else{ + o = yuv2rgbcalc(y,u,v)|0; +- mem32[((cacheStart + cacheAdr)|0) >> 2] = o|0; ++ mem32[((cacheStart >> 2) + cacheAdr)|0] = o|0; + }; + mem32[ostart >> 2] = o; + + cacheAdr = (((((yn << 16)|0) + ((u << 8)|0))|0) + v)|0; +- o = mem32[((cacheStart + cacheAdr)|0) >> 2]|0; ++ o = mem32[((cacheStart >> 2) + cacheAdr)|0]|0; + if (o){}else{ + o = yuv2rgbcalc(yn,u,v)|0; +- mem32[((cacheStart + cacheAdr)|0) >> 2] = o|0; ++ mem32[((cacheStart >> 2) + cacheAdr)|0] = o|0; + }; + mem32[((ostart + widthFour)|0) >> 2] = o; + +@@ -550,19 +547,19 @@ + + //yuv2rgb5(y, u, v, ostart); + cacheAdr = (((((y << 16)|0) + ((u << 8)|0))|0) + v)|0; +- o = mem32[((cacheStart + cacheAdr)|0) >> 2]|0; ++ o = mem32[((cacheStart >> 2) + cacheAdr)|0]|0; + if (o){}else{ + o = yuv2rgbcalc(y,u,v)|0; +- mem32[((cacheStart + cacheAdr)|0) >> 2] = o|0; ++ mem32[((cacheStart >> 2) + cacheAdr)|0] = o|0; + }; + mem32[ostart >> 2] = o; + + //yuv2rgb5(yn, u, v, (ostart + widthFour)|0); + cacheAdr = (((((yn << 16)|0) + ((u << 8)|0))|0) + v)|0; +- o = mem32[((cacheStart + cacheAdr)|0) >> 2]|0; ++ o = mem32[((cacheStart >> 2) + cacheAdr)|0]|0; + if (o){}else{ + o = yuv2rgbcalc(yn,u,v)|0; +- mem32[((cacheStart + cacheAdr)|0) >> 2] = o|0; ++ mem32[((cacheStart >> 2) + cacheAdr)|0] = o|0; + }; + mem32[((ostart + widthFour)|0) >> 2] = o; + ostart = (ostart + 4)|0; +diff -u 3rdparty/mp4.js 3rdparty_edited/mp4.js +--- 3rdparty/mp4.js 2019-11-18 16:46:21.009764774 +0300 ++++ 3rdparty_edited/mp4.js 2019-12-16 12:48:52.995423455 +0300 +@@ -1,3 +1,5 @@ ++module.exports = (function(){ ++ + 'use strict'; + + +@@ -9,7 +11,7 @@ + + + /** +- * Represents a 2-dimensional size value. ++ * Represents a 2-dimensional size value. + */ + var Size = (function size() { + function constructor(w, h) { +@@ -791,14 +793,14 @@ + height: 368 + } + }); +- ++ + this.webgl = this.avc.webgl; +- ++ + var self = this; + this.avc.onPictureDecoded = function(){ + updateStatistics.call(self); + }; +- ++ + this.canvas = this.avc.canvas; + } + +@@ -897,10 +899,10 @@ + this.info.setAttribute('style', "font-size: 14px; font-weight: bold; padding: 6px; color: lime;"); + controls.appendChild(this.info); + div.appendChild(controls); +- ++ + var useWorkers = div.attributes.workers ? div.attributes.workers.value == "true" : false; + var render = div.attributes.render ? div.attributes.render.value == "true" : false; +- ++ + var webgl = "auto"; + if (div.attributes.webgl){ + if (div.attributes.webgl.value == "true"){ +@@ -910,7 +912,7 @@ + webgl = false; + }; + }; +- ++ + var infoStrPre = "Click canvas to load and play - "; + var infoStr = ""; + if (useWorkers){ +@@ -925,11 +927,11 @@ + this.play(); + }.bind(this); + div.appendChild(this.canvas); +- +- ++ ++ + infoStr += " - webgl: " + this.player.webgl; + this.info.innerHTML = infoStrPre + infoStr; +- ++ + + this.score = null; + this.player.onStatisticsUpdated = function (statistics) { +@@ -961,3 +963,15 @@ + }; + return constructor; + })(); ++ ++ ++return { ++ Size, ++ Track, ++ MP4Reader, ++ MP4Player, ++ Bytestream, ++ Broadway, ++} ++ ++})(); +\ No newline at end of file diff --git a/cvat-data/src/js/cvat-data.js b/cvat-data/src/js/cvat-data.js new file mode 100644 index 00000000..8484e9ac --- /dev/null +++ b/cvat-data/src/js/cvat-data.js @@ -0,0 +1,350 @@ +/* +* Copyright (C) 2019 Intel Corporation +* SPDX-License-Identifier: MIT +*/ + +/* global + require:true +*/ + +const { Mutex } = require('async-mutex'); +// eslint-disable-next-line max-classes-per-file +const { MP4Reader, Bytestream } = require('./3rdparty/mp4'); +const ZipDecoder = require('./unzip_imgs.worker'); +const H264Decoder = require('./3rdparty/Decoder.worker'); + +const BlockType = Object.freeze({ + MP4VIDEO: 'mp4video', + ARCHIVE: 'archive', +}); + +class FrameProvider { + constructor(blockType, blockSize, cachedBlockCount, + decodedBlocksCacheSize = 5, maxWorkerThreadCount = 2) { + this._frames = {}; + this._cachedBlockCount = Math.max(1, cachedBlockCount); // number of stored blocks + this._decodedBlocksCacheSize = decodedBlocksCacheSize; + this._blocksRanges = []; + this._blocks = {}; + this._blockSize = blockSize; + this._running = false; + this._blockType = blockType; + this._currFrame = -1; + this._requestedBlockDecode = null; + this._width = null; + this._height = null; + this._decodingBlocks = {}; + this._decodeThreadCount = 0; + this._timerId = setTimeout(this._worker.bind(this), 100); + this._mutex = new Mutex(); + this._promisedFrames = {}; + this._maxWorkerThreadCount = maxWorkerThreadCount; + } + + async _worker() { + if (this._requestedBlockDecode !== null + && this._decodeThreadCount < this._maxWorkerThreadCount) { + await this.startDecode(); + } + this._timerId = setTimeout(this._worker.bind(this), 100); + } + + isChunkCached(start, end) { + return (`${start}:${end}` in this._blocksRanges); + } + + /* This method removes extra data from a cache when memory overflow */ + async _cleanup() { + if (this._blocksRanges.length > this._cachedBlockCount) { + const shifted = this._blocksRanges.shift(); // get the oldest block + const [start, end] = shifted.split(':').map((el) => +el); + delete this._blocks[start / this._blockSize]; + for (let i = start; i <= end; i++) { + delete this._frames[i]; + } + } + + // delete frames whose are not in areas of current frame + const distance = Math.floor(this._decodedBlocksCacheSize / 2); + for (let i = 0; i < this._blocksRanges.length; i++) { + const [start, end] = this._blocksRanges[i].split(':').map((el) => +el); + if (end < this._currFrame - distance * this._blockSize + || start > this._currFrame + distance * this._blockSize) { + for (let j = start; j <= end; j++) { + delete this._frames[j]; + } + } + } + } + + async requestDecodeBlock(block, start, end, resolveCallback, rejectCallback) { + const release = await this._mutex.acquire(); + try { + if (this._requestedBlockDecode !== null) { + if (start === this._requestedBlockDecode.start + && end === this._requestedBlockDecode.end) { + this._requestedBlockDecode.resolveCallback = resolveCallback; + this._requestedBlockDecode.rejectCallback = rejectCallback; + } else if (this._requestedBlockDecode.rejectCallback) { + this._requestedBlockDecode.rejectCallback(); + } + } + if (!(`${start}:${end}` in this._decodingBlocks)) { + this._requestedBlockDecode = { + block: block || this._blocks[Math.floor(start / this._blockSize)], + start, + end, + resolveCallback, + rejectCallback, + }; + } else { + this._decodingBlocks[`${start}:${end}`].rejectCallback = rejectCallback; + this._decodingBlocks[`${start}:${end}`].resolveCallback = resolveCallback; + } + } finally { + release(); + } + } + + isRequestExist() { + return this._requestedBlockDecode !== null; + } + + setRenderSize(width, height) { + this._width = width; + this._height = height; + } + + /* Method returns frame from collection. Else method returns 0 */ + async frame(frameNumber) { + this._currFrame = frameNumber; + return new Promise((resolve, reject) => { + if (frameNumber in this._frames) { + if (this._frames[frameNumber] !== null) { + resolve(this._frames[frameNumber]); + } else { + this._promisedFrames[frameNumber] = { + resolve, + reject, + }; + } + } else { + resolve(null); + } + }); + } + + isNextChunkExists(frameNumber) { + const nextChunkNum = Math.floor(frameNumber / this._blockSize) + 1; + if (this._blocks[nextChunkNum] === 'loading') { + return true; + } + + return nextChunkNum in this._blocks; + } + + /* + Method start asynchronic decode a block of data + + @param block - is a data from a server as is (ts file or archive) + @param start {number} - is the first frame of a block + @param end {number} - is the last frame of a block + 1 + @param callback - callback) + + */ + + setReadyToLoading(chunkNumber) { + this._blocks[chunkNumber] = 'loading'; + } + + static cropImage(imageBuffer, imageWidth, imageHeight, xOffset, yOffset, width, height) { + if (xOffset === 0 && width === imageWidth + && yOffset === 0 && height === imageHeight) { + return new ImageData(new Uint8ClampedArray(imageBuffer), width, height); + } + const source = new Uint32Array(imageBuffer); + + const bufferSize = width * height * 4; + const buffer = new ArrayBuffer(bufferSize); + const rgbaInt32 = new Uint32Array(buffer); + const rgbaInt8Clamped = new Uint8ClampedArray(buffer); + + if (imageWidth === width) { + return new ImageData( + new Uint8ClampedArray(imageBuffer, yOffset * 4, bufferSize), + width, + height, + ); + } + + let writeIdx = 0; + for (let row = yOffset; row < height; row++) { + const start = row * imageWidth + xOffset; + rgbaInt32.set(source.subarray(start, start + width), writeIdx); + writeIdx += width; + } + + return new ImageData(rgbaInt8Clamped, width, height); + } + + async startDecode() { + const release = await this._mutex.acquire(); + try { + const height = this._height; + const width = this._width; + const { start, end, block } = this._requestedBlockDecode; + + this._blocksRanges.push(`${start}:${end}`); + this._decodingBlocks[`${start}:${end}`] = this._requestedBlockDecode; + this._requestedBlockDecode = null; + this._blocks[Math.floor((start + 1) / this._blockSize)] = block; + for (let i = start; i <= end; i++) { + this._frames[i] = null; + } + this._cleanup(); + if (this._blockType === BlockType.MP4VIDEO) { + const worker = new H264Decoder(); + let index = start; + + worker.onmessage = (e) => { + if (e.data.consoleLog) { // ignore initialization message + return; + } + + const scaleFactor = Math.ceil(this._height / e.data.height); + this._frames[index] = FrameProvider.cropImage( + e.data.buf, e.data.width, e.data.height, 0, 0, + Math.floor(width / scaleFactor), Math.floor(height / scaleFactor), + ); + + if (this._decodingBlocks[`${start}:${end}`].resolveCallback) { + this._decodingBlocks[`${start}:${end}`].resolveCallback(index); + } + + if (index in this._promisedFrames) { + this._promisedFrames[index].resolve(this._frames[index]); + delete this._promisedFrames[index]; + } + if (index === end) { + this._decodeThreadCount--; + delete this._decodingBlocks[`${start}:${end}`]; + worker.terminate(); + } + index++; + }; + + worker.onerror = (e) => { + worker.terminate(); + this._decodeThreadCount--; + + for (let i = index; i <= end; i++) { + if (i in this._promisedFrames) { + this._promisedFrames[i].reject(); + delete this._promisedFrames[i]; + } + } + + if (this._decodingBlocks[`${start}:${end}`].rejectCallback) { + this._decodingBlocks[`${start}:${end}`].rejectCallback(Error(e)); + } + delete this._decodingBlocks[`${start}:${end}`]; + }; + + worker.postMessage({ + type: 'Broadway.js - Worker init', + options: { + rgb: true, + reuseMemory: false, + }, + }); + + const reader = new MP4Reader(new Bytestream(block)); + reader.read(); + const video = reader.tracks[1]; + + const avc = reader.tracks[1].trak.mdia.minf.stbl.stsd.avc1.avcC; + const sps = avc.sps[0]; + const pps = avc.pps[0]; + + /* Decode Sequence & Picture Parameter Sets */ + worker.postMessage({ buf: sps, offset: 0, length: sps.length }); + worker.postMessage({ buf: pps, offset: 0, length: pps.length }); + + /* Decode Pictures */ + for (let sample = 0; sample < video.getSampleCount(); sample++) { + video.getSampleNALUnits(sample).forEach((nal) => { + worker.postMessage({ buf: nal, offset: 0, length: nal.length }); + }); + } + this._decodeThreadCount++; + } else { + const worker = new ZipDecoder(); + let index = start; + + worker.onerror = (e) => { + for (let i = start; i <= end; i++) { + if (i in this._promisedFrames) { + this._promisedFrames[i].reject(); + delete this._promisedFrames[i]; + } + } + if (this._decodingBlocks[`${start}:${end}`].rejectCallback) { + this._decodingBlocks[`${start}:${end}`].rejectCallback(Error(e)); + } + this._decodeThreadCount--; + worker.terminate(); + }; + + worker.onmessage = (event) => { + this._frames[event.data.index] = event.data.data; + + if (this._decodingBlocks[`${start}:${end}`].resolveCallback) { + this._decodingBlocks[`${start}:${end}`].resolveCallback(event.data.index); + } + + if (event.data.index in this._promisedFrames) { + this._promisedFrames[event.data.index].resolve( + this._frames[event.data.index], + ); + delete this._promisedFrames[event.data.index]; + } + + if (index === end) { + worker.terminate(); + delete this._decodingBlocks[`${start}:${end}`]; + this._decodeThreadCount--; + } + index++; + }; + + worker.postMessage({ block, start, end }); + this._decodeThreadCount++; + } + } finally { + release(); + } + } + + get decodeThreadCount() { + return this._decodeThreadCount; + } + + get decodedBlocksCacheSize() { + return this._decodedBlocksCacheSize; + } + + /* + Method returns a list of cached ranges + Is an array of strings like "start:end" + */ + get cachedFrames() { + return [...this._blocksRanges].sort( + (a, b) => a.split(':')[0] - b.split(':')[0], + ); + } +} + +module.exports = { + FrameProvider, + BlockType, +}; diff --git a/cvat-data/src/js/unzip_imgs.worker.js b/cvat-data/src/js/unzip_imgs.worker.js new file mode 100644 index 00000000..f704e098 --- /dev/null +++ b/cvat-data/src/js/unzip_imgs.worker.js @@ -0,0 +1,35 @@ +/* +* Copyright (C) 2019 Intel Corporation +* SPDX-License-Identifier: MIT +*/ + +/* global + require:true +*/ + +const JSZip = require('jszip'); + +onmessage = (e) => { + const zip = new JSZip(); + if (e.data) { + const { start, end, block } = e.data; + + zip.loadAsync(block).then((_zip) => { + let index = start; + _zip.forEach((relativePath) => { + const fileIndex = index++; + if (fileIndex <= end) { + _zip.file(relativePath).async('blob').then((fileData) => { + createImageBitmap(fileData).then((img) => { + postMessage({ + fileName: relativePath, + index: fileIndex, + data: img, + }); + }); + }); + } + }); + }); + } +}; diff --git a/cvat-data/webpack.config.js b/cvat-data/webpack.config.js new file mode 100644 index 00000000..1b3d09f7 --- /dev/null +++ b/cvat-data/webpack.config.js @@ -0,0 +1,64 @@ +/* global + require:true, + __dirname:true, +*/ + +const path = require('path'); +const CopyPlugin = require('copy-webpack-plugin'); + +const cvatData = { + target: 'web', + mode: 'production', + entry: './src/js/cvat-data.js', + output: { + path: path.resolve(__dirname, 'dist'), + filename: 'cvat-data.min.js', + library: 'cvatData', + libraryTarget: 'window', + }, + module: { + rules: [ + { + test: /.js?$/, + exclude: /node_modules/, + use: { + loader: 'babel-loader', + options: { + presets: [ + ['@babel/preset-env', { + targets: '> 2.5%', // https://github.com/browserslist/browserslist + }], + ], + sourceType: 'unambiguous', + }, + }, + }, { + test: /\.worker\.js$/, + exclude: /3rdparty/, + use: { + loader: 'worker-loader', + options: { + publicPath: '/', + name: '[name].js', + }, + }, + }, { + test: /3rdparty\/.*\.worker\.js$/, + use: { + loader: 'worker-loader', + options: { + publicPath: '/3rdparty/', + name: '3rdparty/[name].js', + }, + }, + }, + ], + }, + plugins: [ + new CopyPlugin([ + './src/js/3rdparty/avc.wasm', + ]), + ], +}; + +module.exports = cvatData; diff --git a/cvat-ui/package-lock.json b/cvat-ui/package-lock.json index b4631163..838e0b83 100644 --- a/cvat-ui/package-lock.json +++ b/cvat-ui/package-lock.json @@ -1609,9 +1609,9 @@ "dev": true }, "readable-stream": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", - "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", "dev": true, "requires": { "core-util-is": "~1.0.0", @@ -2929,6 +2929,65 @@ "toggle-selection": "^1.0.6" } }, + "copy-webpack-plugin": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-5.1.1.tgz", + "integrity": "sha512-P15M5ZC8dyCjQHWwd4Ia/dm0SgVvZJMYeykVIVYXbGyqO4dWB5oyPHp9i7wjwo5LhtlhKbiBCdS2NvM07Wlybg==", + "dev": true, + "requires": { + "cacache": "^12.0.3", + "find-cache-dir": "^2.1.0", + "glob-parent": "^3.1.0", + "globby": "^7.1.1", + "is-glob": "^4.0.1", + "loader-utils": "^1.2.3", + "minimatch": "^3.0.4", + "normalize-path": "^3.0.0", + "p-limit": "^2.2.1", + "schema-utils": "^1.0.0", + "serialize-javascript": "^2.1.2", + "webpack-log": "^2.0.0" + }, + "dependencies": { + "globby": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/globby/-/globby-7.1.1.tgz", + "integrity": "sha1-+yzP+UAfhgCUXfral0QMypcrhoA=", + "dev": true, + "requires": { + "array-union": "^1.0.1", + "dir-glob": "^2.0.0", + "glob": "^7.1.2", + "ignore": "^3.3.5", + "pify": "^3.0.0", + "slash": "^1.0.0" + } + }, + "ignore": { + "version": "3.3.10", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.10.tgz", + "integrity": "sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug==", + "dev": true + }, + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + }, + "schema-utils": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", + "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", + "dev": true, + "requires": { + "ajv": "^6.1.0", + "ajv-errors": "^1.0.0", + "ajv-keywords": "^3.1.0" + } + } + } + }, "core-js": { "version": "2.6.10", "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.10.tgz", @@ -3455,6 +3514,32 @@ "randombytes": "^2.0.0" } }, + "dir-glob": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-2.2.2.tgz", + "integrity": "sha512-f9LBi5QWzIW3I6e//uxZoLBlUt9kcp66qo0sSCxL6YZKc75R1c4MFCoe/LaZiBGmgujvQdxc5Bn3QhfyvK5Hsw==", + "dev": true, + "requires": { + "path-type": "^3.0.0" + }, + "dependencies": { + "path-type": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", + "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", + "dev": true, + "requires": { + "pify": "^3.0.0" + } + }, + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + } + } + }, "dns-equal": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/dns-equal/-/dns-equal-1.0.0.tgz", @@ -5756,13 +5841,13 @@ "dev": true }, "globule": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/globule/-/globule-1.2.1.tgz", - "integrity": "sha512-g7QtgWF4uYSL5/dn71WxubOrS7JVGCnFPEnoeChJmBnyR9Mw8nGoEwOgJL/RC2Te0WhbsEUCejfH8SZNJ+adYQ==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/globule/-/globule-1.3.1.tgz", + "integrity": "sha512-OVyWOHgw29yosRHCHo7NncwR1hW5ew0W/UrvtwvjefVJeQ26q4/8r8FmPsSF1hJ93IgWkyv16pCTz6WblMzm/g==", "dev": true, "requires": { "glob": "~7.1.1", - "lodash": "~4.17.10", + "lodash": "~4.17.12", "minimatch": "~3.0.2" } }, @@ -6538,13 +6623,10 @@ "dev": true }, "is-finite": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.0.2.tgz", - "integrity": "sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko=", - "dev": true, - "requires": { - "number-is-nan": "^1.0.0" - } + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.1.0.tgz", + "integrity": "sha512-cdyMtqX/BOqqNBBiKlIVkytNHm49MtMlYyn1zxzvJKWmFMlGzm+ry5BBfYyeY9YmNKbRSo/o7OX9w9ale0wg3w==", + "dev": true }, "is-fullwidth-code-point": { "version": "2.0.0", @@ -6702,9 +6784,9 @@ "dev": true }, "js-base64": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.5.1.tgz", - "integrity": "sha512-M7kLczedRMYX4L8Mdh4MzyAMM9O5osx+4FcOQuTvr3A9F2D9S5JXheN0ewNbrvK2UatkTRhL5ejGmGSjNMiZuw==", + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.5.2.tgz", + "integrity": "sha512-Vg8czh0Q7sFBSUMWWArX/miJeBWYBPpdU/3M/DKSaekLMqrqVPaedp+5mZhie/r0lgrcaYBfwXatEew6gwgiQQ==", "dev": true }, "js-levenshtein": { @@ -7662,9 +7744,9 @@ } }, "node-sass": { - "version": "4.13.0", - "resolved": "https://registry.npmjs.org/node-sass/-/node-sass-4.13.0.tgz", - "integrity": "sha512-W1XBrvoJ1dy7VsvTAS5q1V45lREbTlZQqFbiHb3R3OTTCma0XBtuG6xZ6Z4506nR4lmHPTqVRwxT6KgtWC97CA==", + "version": "4.13.1", + "resolved": "https://registry.npmjs.org/node-sass/-/node-sass-4.13.1.tgz", + "integrity": "sha512-TTWFx+ZhyDx1Biiez2nB0L3YrCZ/8oHagaDalbuBSlqXgUPsdkUSzJsVxeDO9LtPB49+Fh3WQl3slABo6AotNw==", "dev": true, "requires": { "async-foreach": "^0.1.3", @@ -10822,6 +10904,12 @@ "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", "dev": true }, + "slash": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz", + "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=", + "dev": true + }, "slice-ansi": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz", @@ -11202,9 +11290,9 @@ "dev": true }, "readable-stream": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", - "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", "dev": true, "requires": { "core-util-is": "~1.0.0", @@ -11614,6 +11702,12 @@ "ajv-keywords": "^3.1.0" } }, + "serialize-javascript": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-2.1.2.tgz", + "integrity": "sha512-rs9OggEUF0V4jUSecXazOYsLfu7OGK2qIn3c7IPBiffz32XniEp/TX9Xmc9LQfK2nQ2QKHvZ2oygKUGU0lG4jQ==", + "dev": true + }, "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", @@ -12671,6 +12765,28 @@ "errno": "~0.1.7" } }, + "worker-loader": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/worker-loader/-/worker-loader-2.0.0.tgz", + "integrity": "sha512-tnvNp4K3KQOpfRnD20m8xltE3eWh89Ye+5oj7wXEEHKac1P4oZ6p9oTj8/8ExqoSBnk9nu5Pr4nKfQ1hn2APJw==", + "dev": true, + "requires": { + "loader-utils": "^1.0.0", + "schema-utils": "^0.4.0" + }, + "dependencies": { + "schema-utils": { + "version": "0.4.7", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-0.4.7.tgz", + "integrity": "sha512-v/iwU6wvwGK8HbU9yi3/nhGzP0yGSuhQMzL6ySiec1FSrZZDkhm4noOSWzrNFo/jEc+SJY6jRTwuwbSXJPDUnQ==", + "dev": true, + "requires": { + "ajv": "^6.1.0", + "ajv-keywords": "^3.1.0" + } + } + } + }, "wrap-ansi": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", diff --git a/cvat-ui/package.json b/cvat-ui/package.json index 6e88b275..d4e08fbf 100644 --- a/cvat-ui/package.json +++ b/cvat-ui/package.json @@ -23,6 +23,7 @@ "@typescript-eslint/parser": "^2.19.2", "babel-loader": "^8.0.6", "babel-plugin-import": "^1.12.2", + "copy-webpack-plugin": "^5.1.1", "css-loader": "^3.2.0", "eslint": "^6.8.0", "eslint-config-airbnb-typescript": "^7.0.0", @@ -42,7 +43,8 @@ "typescript": "^3.7.3", "webpack": "^4.42.1", "webpack-cli": "^3.3.8", - "webpack-dev-server": "^3.8.0" + "webpack-dev-server": "^3.8.0", + "worker-loader": "^2.0.0" }, "dependencies": { "@types/react": "^16.9.2", diff --git a/cvat-ui/src/actions/annotation-actions.ts b/cvat-ui/src/actions/annotation-actions.ts index 02300fc9..0d32cc8d 100644 --- a/cvat-ui/src/actions/annotation-actions.ts +++ b/cvat-ui/src/actions/annotation-actions.ts @@ -657,7 +657,7 @@ export function switchPlay(playing: boolean): AnyAction { }; } -export function changeFrameAsync(toFrame: number): +export function changeFrameAsync(toFrame: number, fillBuffer?: boolean, frameStep?: number): ThunkAction, {}, {}, AnyAction> { return async (dispatch: ActionCreator): Promise => { const state: CombinedState = getStore().getState(); @@ -675,7 +675,13 @@ ThunkAction, {}, {}, AnyAction> { payload: { number: state.annotation.player.frame.number, data: state.annotation.player.frame.data, + filename: state.annotation.player.frame.filename, + delay: state.annotation.player.frame.delay, + changeTime: state.annotation.player.frame.changeTime, states: state.annotation.annotations.states, + minZ: state.annotation.annotations.zLayer.min, + maxZ: state.annotation.annotations.zLayer.max, + curZ: state.annotation.annotations.zLayer.cur, }, }); @@ -694,7 +700,7 @@ ThunkAction, {}, {}, AnyAction> { to: toFrame, }, ); - const data = await job.frames.get(toFrame); + const data = await job.frames.get(toFrame, fillBuffer, frameStep); const states = await job.annotations.get(toFrame, showAllInterpolationTracks, filters); const [minZ, maxZ] = computeZRange(states); const currentTime = new Date().getTime(); @@ -720,21 +726,25 @@ ThunkAction, {}, {}, AnyAction> { payload: { number: toFrame, data, + filename: data.filename, states, minZ, maxZ, + curZ: maxZ, changeTime: currentTime + delay, delay, }, }); } catch (error) { - dispatch({ - type: AnnotationActionTypes.CHANGE_FRAME_FAILED, - payload: { - number: toFrame, - error, - }, - }); + if (error !== 'not needed') { + dispatch({ + type: AnnotationActionTypes.CHANGE_FRAME_FAILED, + payload: { + number: toFrame, + error, + }, + }); + } } }; } @@ -945,6 +955,9 @@ export function getJobAsync( const frameNumber = Math.max(Math.min(job.stopFrame, initialFrame), job.startFrame); const frameData = await job.frames.get(frameNumber); + // call first getting of frame data before rendering interface + // to load and decode first chunk + await frameData.data(); const states = await job.annotations .get(frameNumber, showAllInterpolationTracks, filters); const [minZ, maxZ] = computeZRange(states); @@ -958,6 +971,7 @@ export function getJobAsync( job, states, frameNumber, + frameFilename: frameData.filename, frameData, colors, filters, @@ -965,6 +979,7 @@ export function getJobAsync( maxZ, }, }); + dispatch(changeFrameAsync(frameNumber, false)); } catch (error) { dispatch({ type: AnnotationActionTypes.GET_JOB_FAILED, diff --git a/cvat-ui/src/actions/tasks-actions.ts b/cvat-ui/src/actions/tasks-actions.ts index 33c0d962..ff1f3e56 100644 --- a/cvat-ui/src/actions/tasks-actions.ts +++ b/cvat-ui/src/actions/tasks-actions.ts @@ -389,6 +389,7 @@ ThunkAction, {}, {}, AnyAction> { labels: data.labels, z_order: data.advanced.zOrder, image_quality: 70, + use_zip_chunks: data.advanced.useZipChunks, }; if (data.advanced.bugTracker) { @@ -412,6 +413,9 @@ ThunkAction, {}, {}, AnyAction> { if (data.advanced.imageQuality) { description.image_quality = data.advanced.imageQuality; } + if (data.advanced.dataChunkSize) { + description.data_chunk_size = data.advanced.dataChunkSize; + } const taskInstance = new cvat.classes.Task(description); taskInstance.clientFiles = data.files.local; diff --git a/cvat-ui/src/components/annotation-page/standard-workspace/canvas-wrapper.tsx b/cvat-ui/src/components/annotation-page/standard-workspace/canvas-wrapper.tsx index 4d55d31b..4cf77599 100644 --- a/cvat-ui/src/components/annotation-page/standard-workspace/canvas-wrapper.tsx +++ b/cvat-ui/src/components/annotation-page/standard-workspace/canvas-wrapper.tsx @@ -36,6 +36,7 @@ interface Props { annotations: any[]; frameData: any; frameAngle: number; + frameFetching: boolean; frame: number; opacity: number; colorBy: ColorBy; @@ -125,6 +126,7 @@ export default class CanvasWrapperComponent extends React.PureComponent { contrastLevel, saturationLevel, workspace, + frameFetching, } = this.props; if (prevProps.sidebarCollapsed !== sidebarCollapsed) { @@ -199,6 +201,15 @@ export default class CanvasWrapperComponent extends React.PureComponent { canvasInstance.rotate(frameAngle); } + const loadingAnimation = window.document.getElementById('cvat_canvas_loading_animation'); + if (loadingAnimation && frameFetching !== prevProps.frameFetching) { + if (frameFetching) { + loadingAnimation.classList.remove('cvat_canvas_hidden'); + } else { + loadingAnimation.classList.add('cvat_canvas_hidden'); + } + } + this.activateOnCanvas(); } diff --git a/cvat-ui/src/components/annotation-page/styles.scss b/cvat-ui/src/components/annotation-page/styles.scss index 005ff868..5c6f2eba 100644 --- a/cvat-ui/src/components/annotation-page/styles.scss +++ b/cvat-ui/src/components/annotation-page/styles.scss @@ -119,6 +119,7 @@ overflow: hidden; text-overflow: ellipsis; user-select: none; + word-break: break-all; } .cvat-player-frame-url-icon { diff --git a/cvat-ui/src/components/annotation-page/top-bar/player-navigation.tsx b/cvat-ui/src/components/annotation-page/top-bar/player-navigation.tsx index b5c846d0..164fd614 100644 --- a/cvat-ui/src/components/annotation-page/top-bar/player-navigation.tsx +++ b/cvat-ui/src/components/annotation-page/top-bar/player-navigation.tsx @@ -17,6 +17,7 @@ interface Props { startFrame: number; stopFrame: number; frameNumber: number; + frameFilename: string; inputFrameRef: React.RefObject; onSliderChange(value: SliderValue): void; onInputChange(value: number): void; @@ -28,6 +29,7 @@ function PlayerNavigation(props: Props): JSX.Element { startFrame, stopFrame, frameNumber, + frameFilename, inputFrameRef, onSliderChange, onInputChange, @@ -58,8 +60,8 @@ function PlayerNavigation(props: Props): JSX.Element { - - filename.png + + {frameFilename} diff --git a/cvat-ui/src/components/annotation-page/top-bar/top-bar.tsx b/cvat-ui/src/components/annotation-page/top-bar/top-bar.tsx index 53648454..6f4afb2b 100644 --- a/cvat-ui/src/components/annotation-page/top-bar/top-bar.tsx +++ b/cvat-ui/src/components/annotation-page/top-bar/top-bar.tsx @@ -19,6 +19,7 @@ interface Props { saving: boolean; savingStatuses: string[]; frameNumber: number; + frameFilename: string; inputFrameRef: React.RefObject; startFrame: number; stopFrame: number; @@ -50,6 +51,7 @@ export default function AnnotationTopBarComponent(props: Props): JSX.Element { redoAction, playing, frameNumber, + frameFilename, inputFrameRef, startFrame, stopFrame, @@ -98,6 +100,7 @@ export default function AnnotationTopBarComponent(props: Props): JSX.Element { startFrame={startFrame} stopFrame={stopFrame} frameNumber={frameNumber} + frameFilename={frameFilename} inputFrameRef={inputFrameRef} onSliderChange={onSliderChange} onInputChange={onInputChange} diff --git a/cvat-ui/src/components/create-task-page/advanced-configuration-form.tsx b/cvat-ui/src/components/create-task-page/advanced-configuration-form.tsx index 7a769a12..7ffcbbc0 100644 --- a/cvat-ui/src/components/create-task-page/advanced-configuration-form.tsx +++ b/cvat-ui/src/components/create-task-page/advanced-configuration-form.tsx @@ -29,6 +29,8 @@ export interface AdvancedConfiguration { frameFilter?: string; lfs: boolean; repository?: string; + useZipChunks: boolean; + dataChunkSize?: number; } type Props = FormComponentProps & { @@ -36,6 +38,52 @@ type Props = FormComponentProps & { installedGit: boolean; }; +function isPositiveInteger(_: any, value: any, callback: any): void { + if (!value) { + callback(); + return; + } + + const intValue = +value; + if (Number.isNaN(intValue) + || !Number.isInteger(intValue) || intValue < 1) { + callback('Value must be a positive integer'); + } + + callback(); +} + +function isNonNegativeInteger(_: any, value: any, callback: any): void { + if (!value) { + callback(); + return; + } + + const intValue = +value; + if (Number.isNaN(intValue) || intValue < 0) { + callback('Value must be a non negative integer'); + } + + callback(); +} + +function isIntegerRange(min: number, max: number, _: any, value: any, callback: any): void { + if (!value) { + callback(); + return; + } + + const intValue = +value; + if (Number.isNaN(intValue) + || !Number.isInteger(intValue) + || intValue < min || intValue > max + ) { + callback(`Value must be an integer [${min}, ${max}]`); + } + + callback(); +} + class AdvancedConfigurationForm extends React.PureComponent { public submit(): Promise { return new Promise((resolve, reject) => { @@ -49,6 +97,16 @@ class AdvancedConfigurationForm extends React.PureComponent { const filteredValues = { ...values }; delete filteredValues.frameStep; + if (values.overlapSize && +values.segmentSize <= +values.overlapSize) { + reject(new Error('Overlap size must be more than segment size')); + } + + if (typeof (values.startFrame) !== 'undefined' && typeof (values.stopFrame) !== 'undefined' + && +values.stopFrame < +values.startFrame + ) { + reject(new Error('Stop frame must be more or equal start frame')); + } + onSubmit({ ...values, frameFilter: values.frameStep ? `step=${values.frameStep}` : undefined, @@ -94,14 +152,14 @@ class AdvancedConfigurationForm extends React.PureComponent { initialValue: 70, rules: [{ required: true, - message: 'This field is required', + message: 'The field is required.', + }, { + validator: isIntegerRange.bind(null, 5, 100), }], })( } />, )} @@ -116,7 +174,11 @@ class AdvancedConfigurationForm extends React.PureComponent { return ( Overlap size}> - {form.getFieldDecorator('overlapSize')( + {form.getFieldDecorator('overlapSize', { + rules: [{ + validator: isNonNegativeInteger, + }], + })( , )} @@ -130,7 +192,11 @@ class AdvancedConfigurationForm extends React.PureComponent { return ( Segment size}> - {form.getFieldDecorator('segmentSize')( + {form.getFieldDecorator('segmentSize', { + rules: [{ + validator: isPositiveInteger, + }], + })( , )} @@ -143,7 +209,11 @@ class AdvancedConfigurationForm extends React.PureComponent { return ( Start frame}> - {form.getFieldDecorator('startFrame')( + {form.getFieldDecorator('startFrame', { + rules: [{ + validator: isNonNegativeInteger, + }], + })( { return ( Stop frame}> - {form.getFieldDecorator('stopFrame')( + {form.getFieldDecorator('stopFrame', { + rules: [{ + validator: isNonNegativeInteger, + }], + })( { return ( Frame step}> - {form.getFieldDecorator('frameStep')( + {form.getFieldDecorator('frameStep', { + rules: [{ + validator: isPositiveInteger, + }], + })( { ); } + private renderUzeZipChunks(): JSX.Element { + const { form } = this.props; + return ( + + {form.getFieldDecorator('useZipChunks', { + initialValue: true, + valuePropName: 'checked', + })( + + + Use zip chunks + + , + )} + + ); + } + + private renderChunkSize(): JSX.Element { + const { form } = this.props; + + return ( + Chunk size}> + + Defines a number of frames to be packed in + a chunk when send from client to server. + Server defines automatically if empty. +
+ Recommended values: +
+ 1080p or less: 36 +
+ 2k or less: 8 - 16 +
+ 4k or less: 4 - 8 +
+ More: 1 - 4 + + )} + > + {form.getFieldDecorator('dataChunkSize', { + rules: [{ + validator: isPositiveInteger, + }], + })( + , + )} +
+
+ ); + } + public render(): JSX.Element { const { installedGit } = this.props; @@ -300,6 +432,12 @@ class AdvancedConfigurationForm extends React.PureComponent {
+ + + {this.renderUzeZipChunks()} + + + {this.renderImageQuality()} @@ -324,6 +462,12 @@ class AdvancedConfigurationForm extends React.PureComponent { + + + {this.renderChunkSize()} + + + { installedGit ? this.renderGit() : null} diff --git a/cvat-ui/src/components/create-task-page/create-task-content.tsx b/cvat-ui/src/components/create-task-page/create-task-content.tsx index 4bf825ed..ca81c2d7 100644 --- a/cvat-ui/src/components/create-task-page/create-task-content.tsx +++ b/cvat-ui/src/components/create-task-page/create-task-content.tsx @@ -43,6 +43,7 @@ const defaultState = { advanced: { zOrder: false, lfs: false, + useZipChunks: true, }, labels: [], files: { @@ -141,10 +142,10 @@ export default class CreateTaskContent extends React.PureComponent }).then((): void => { const { onCreate } = this.props; onCreate(this.state); - }).catch((): void => { + }).catch((error: Error): void => { notification.error({ message: 'Could not create a task', - description: 'Please, check configuration you specified', + description: error.toString(), }); }); }; diff --git a/cvat-ui/src/components/task-page/details.tsx b/cvat-ui/src/components/task-page/details.tsx index 2c690330..ff708376 100644 --- a/cvat-ui/src/components/task-page/details.tsx +++ b/cvat-ui/src/components/task-page/details.tsx @@ -44,6 +44,8 @@ interface State { export default class DetailsComponent extends React.PureComponent { private mounted: boolean; + private previewImageElement: HTMLImageElement; + private previewWrapperRef: React.RefObject; constructor(props: Props) { super(props); @@ -51,6 +53,8 @@ export default class DetailsComponent extends React.PureComponent const { taskInstance } = props; this.mounted = false; + this.previewImageElement = new Image(); + this.previewWrapperRef = React.createRef(); this.state = { name: taskInstance.name, bugTracker: taskInstance.bugTracker, @@ -60,9 +64,25 @@ export default class DetailsComponent extends React.PureComponent } public componentDidMount(): void { - const { taskInstance } = this.props; + const { taskInstance, previewImage } = this.props; + const { previewImageElement, previewWrapperRef } = this; this.mounted = true; + previewImageElement.onload = () => { + const { height, width } = previewImageElement; + if (width > height) { + previewImageElement.style.width = '100%'; + } else { + previewImageElement.style.height = '100%'; + } + }; + + previewImageElement.src = previewImage; + previewImageElement.alt = 'Preview'; + if (previewWrapperRef.current) { + previewWrapperRef.current.appendChild(previewImageElement); + } + getReposData(taskInstance.id) .then((data): void => { if (data !== null && this.mounted) { @@ -135,11 +155,11 @@ export default class DetailsComponent extends React.PureComponent } private renderPreview(): JSX.Element { - const { previewImage } = this.props; + const { previewWrapperRef } = this; + + // Add image on mount after get its width and height to fit it into wrapper return ( -
- Preview -
+
); } diff --git a/cvat-ui/src/components/task-page/styles.scss b/cvat-ui/src/components/task-page/styles.scss index e7e85068..7feb0344 100644 --- a/cvat-ui/src/components/task-page/styles.scss +++ b/cvat-ui/src/components/task-page/styles.scss @@ -76,15 +76,14 @@ } .cvat-task-preview-wrapper { - display: flex; - justify-content: flex-start; overflow: hidden; margin-bottom: 20px; - - > .cvat-task-preview { - max-width: 252px; - max-height: 144px; - } + width: 252px; + height: 144px; + display: table-cell; + text-align: center; + vertical-align: middle; + background-color: $background-color-2; } .cvat-user-selector { diff --git a/cvat-ui/src/containers/annotation-page/standard-workspace/canvas-wrapper.tsx b/cvat-ui/src/containers/annotation-page/standard-workspace/canvas-wrapper.tsx index 75645fc2..75845dc8 100644 --- a/cvat-ui/src/containers/annotation-page/standard-workspace/canvas-wrapper.tsx +++ b/cvat-ui/src/containers/annotation-page/standard-workspace/canvas-wrapper.tsx @@ -55,6 +55,7 @@ interface StateToProps { annotations: any[]; frameData: any; frameAngle: number; + frameFetching: boolean; frame: number; opacity: number; colorBy: ColorBy; @@ -129,6 +130,7 @@ function mapStateToProps(state: CombinedState): StateToProps { frame: { data: frameData, number: frame, + fetching: frameFetching, }, frameAngles, }, @@ -175,6 +177,7 @@ function mapStateToProps(state: CombinedState): StateToProps { jobInstance, frameData, frameAngle: frameAngles[frame - jobInstance.startFrame], + frameFetching, frame, activatedStateID, activatedAttributeID, diff --git a/cvat-ui/src/containers/annotation-page/top-bar/top-bar.tsx b/cvat-ui/src/containers/annotation-page/top-bar/top-bar.tsx index 381db156..14fc4ef3 100644 --- a/cvat-ui/src/containers/annotation-page/top-bar/top-bar.tsx +++ b/cvat-ui/src/containers/annotation-page/top-bar/top-bar.tsx @@ -32,6 +32,7 @@ import { CombinedState, FrameSpeed, Workspace } from 'reducers/interfaces'; interface StateToProps { jobInstance: any; frameNumber: number; + frameFilename: string; frameStep: number; frameSpeed: FrameSpeed; frameDelay: number; @@ -47,7 +48,7 @@ interface StateToProps { } interface DispatchToProps { - onChangeFrame(frame: number): void; + onChangeFrame(frame: number, fillBuffer?: boolean, frameStep?: number): void; onSwitchPlay(playing: boolean): void; onSaveAnnotation(sessionInstance: any): void; showStatistics(sessionInstance: any): void; @@ -63,6 +64,7 @@ function mapStateToProps(state: CombinedState): StateToProps { player: { playing, frame: { + filename: frameFilename, number: frameNumber, delay: frameDelay, }, @@ -103,6 +105,7 @@ function mapStateToProps(state: CombinedState): StateToProps { saving, savingStatuses, frameNumber, + frameFilename, jobInstance, undoAction: history.undo.length ? history.undo[history.undo.length - 1][0] : undefined, redoAction: history.redo.length ? history.redo[history.redo.length - 1][0] : undefined, @@ -114,8 +117,8 @@ function mapStateToProps(state: CombinedState): StateToProps { function mapDispatchToProps(dispatch: any): DispatchToProps { return { - onChangeFrame(frame: number): void { - dispatch(changeFrameAsync(frame)); + onChangeFrame(frame: number, fillBuffer?: boolean, frameStep?: number): void { + dispatch(changeFrameAsync(frame, fillBuffer, frameStep)); }, onSwitchPlay(playing: boolean): void { dispatch(switchPlay(playing)); @@ -208,7 +211,10 @@ class AnnotationTopBarContainer extends React.PureComponent { setTimeout(() => { const { playing: stillPlaying } = this.props; if (stillPlaying) { - onChangeFrame(frameNumber + 1 + framesSkiped); + onChangeFrame( + frameNumber + 1 + framesSkiped, + stillPlaying, framesSkiped + 1, + ); } }, frameDelay); } else { @@ -451,6 +457,7 @@ class AnnotationTopBarContainer extends React.PureComponent { stopFrame, }, frameNumber, + frameFilename, undoAction, redoAction, workspace, @@ -623,6 +630,7 @@ class AnnotationTopBarContainer extends React.PureComponent { startFrame={startFrame} stopFrame={stopFrame} frameNumber={frameNumber} + frameFilename={frameFilename} inputFrameRef={this.inputFrameRef} undoAction={undoAction} redoAction={redoAction} diff --git a/cvat-ui/src/reducers/annotation-reducer.ts b/cvat-ui/src/reducers/annotation-reducer.ts index 1dd788b9..14ac3eb6 100644 --- a/cvat-ui/src/reducers/annotation-reducer.ts +++ b/cvat-ui/src/reducers/annotation-reducer.ts @@ -43,6 +43,7 @@ const defaultState: AnnotationState = { player: { frame: { number: 0, + filename: '', data: null, fetching: false, delay: 0, @@ -114,6 +115,7 @@ export default (state = defaultState, action: AnyAction): AnnotationState => { job, states, frameNumber: number, + frameFilename: filename, colors, filters, frameData: data, @@ -148,6 +150,7 @@ export default (state = defaultState, action: AnyAction): AnnotationState => { ...state.player, frame: { ...state.player.frame, + filename, number, data, }, @@ -195,9 +198,11 @@ export default (state = defaultState, action: AnyAction): AnnotationState => { const { number, data, + filename, states, minZ, maxZ, + curZ, delay, changeTime, } = action.payload; @@ -212,6 +217,7 @@ export default (state = defaultState, action: AnyAction): AnnotationState => { ...state.player, frame: { data, + filename, number, fetching: false, changeTime, @@ -225,7 +231,7 @@ export default (state = defaultState, action: AnyAction): AnnotationState => { zLayer: { min: minZ, max: maxZ, - cur: maxZ, + cur: curZ, }, }, }; diff --git a/cvat-ui/src/reducers/interfaces.ts b/cvat-ui/src/reducers/interfaces.ts index 903f43a6..94d76c06 100644 --- a/cvat-ui/src/reducers/interfaces.ts +++ b/cvat-ui/src/reducers/interfaces.ts @@ -323,6 +323,7 @@ export interface AnnotationState { player: { frame: { number: number; + filename: string; data: any | null; fetching: boolean; delay: number; diff --git a/cvat-ui/webpack.config.js b/cvat-ui/webpack.config.js index 4c9c67f1..5d1d6d69 100644 --- a/cvat-ui/webpack.config.js +++ b/cvat-ui/webpack.config.js @@ -8,6 +8,7 @@ const path = require('path'); const HtmlWebpackPlugin = require("html-webpack-plugin"); const TsconfigPathsPlugin = require('tsconfig-paths-webpack-plugin'); const Dotenv = require('dotenv-webpack'); +const CopyPlugin = require('copy-webpack-plugin'); module.exports = { target: 'web', @@ -73,7 +74,26 @@ module.exports = { }, } ] - }], + }, { + test: /3rdparty\/.*\.worker\.js$/, + use: { + loader: 'worker-loader', + options: { + publicPath: '/', + name: '3rdparty/[name].js', + }, + }, + }, { + test: /\.worker\.js$/, + exclude: /3rdparty/, + use: { + loader: 'worker-loader', + options: { + publicPath: '/', + name: '[name].js', + }, + }, + },], }, plugins: [ new HtmlWebpackPlugin({ @@ -83,6 +103,12 @@ module.exports = { new Dotenv({ systemvars: true, }), + new CopyPlugin([ + { + from: '../cvat-data/src/js/3rdparty/avc.wasm', + to: '3rdparty/', + }, + ]), ], node: { fs: 'empty' }, }; diff --git a/cvat/apps/annotation/annotation.py b/cvat/apps/annotation/annotation.py index 70054255..a172066b 100644 --- a/cvat/apps/annotation/annotation.py +++ b/cvat/apps/annotation/annotation.py @@ -120,7 +120,7 @@ class Annotation: self._MAX_ANNO_SIZE=30000 self._frame_info = {} self._frame_mapping = {} - self._frame_step = db_task.get_frame_step() + self._frame_step = db_task.data.get_frame_step() db_labels = self._db_task.label_set.all().prefetch_related('attributespec_set').order_by('pk') @@ -177,20 +177,20 @@ class Annotation: return self._get_attribute_id(label_id, attribute_name, 'immutable') def _init_frame_info(self): - if self._db_task.mode == "interpolation": + if hasattr(self._db_task.data, 'video'): self._frame_info = { frame: { "path": "frame_{:06d}".format(frame), - "width": self._db_task.video.width, - "height": self._db_task.video.height, - } for frame in range(self._db_task.size) + "width": self._db_task.data.video.width, + "height": self._db_task.data.video.height, + } for frame in range(self._db_task.data.size) } else: self._frame_info = {db_image.frame: { "path": db_image.path, "width": db_image.width, "height": db_image.height, - } for db_image in self._db_task.image_set.all()} + } for db_image in self._db_task.data.images.all()} self._frame_mapping = { self._get_filename(info["path"]): frame for frame, info in self._frame_info.items() @@ -202,15 +202,15 @@ class Annotation: ("task", OrderedDict([ ("id", str(self._db_task.id)), ("name", self._db_task.name), - ("size", str(self._db_task.size)), + ("size", str(self._db_task.data.size)), ("mode", self._db_task.mode), ("overlap", str(self._db_task.overlap)), ("bugtracker", self._db_task.bug_tracker), ("created", str(timezone.localtime(self._db_task.created_date))), ("updated", str(timezone.localtime(self._db_task.updated_date))), - ("start_frame", str(self._db_task.start_frame)), - ("stop_frame", str(self._db_task.stop_frame)), - ("frame_filter", self._db_task.frame_filter), + ("start_frame", str(self._db_task.data.start_frame)), + ("stop_frame", str(self._db_task.data.stop_frame)), + ("frame_filter", self._db_task.data.frame_filter), ("z_order", str(self._db_task.z_order)), ("labels", [ @@ -250,13 +250,13 @@ class Annotation: ("dumped", str(timezone.localtime(timezone.now()))) ]) - if self._db_task.mode == "interpolation": + if hasattr(self._db_task.data, "video"): self._meta["task"]["original_size"] = OrderedDict([ - ("width", str(self._db_task.video.width)), - ("height", str(self._db_task.video.height)) + ("width", str(self._db_task.data.video.width)), + ("height", str(self._db_task.data.video.height)) ]) # Add source to dumped file - self._meta["source"] = str(os.path.basename(self._db_task.video.path)) + self._meta["source"] = str(os.path.basename(self._db_task.data.video.path)) def _export_attributes(self, attributes): exported_attributes = [] @@ -271,7 +271,7 @@ class Annotation: def _export_tracked_shape(self, shape): return Annotation.TrackedShape( type=shape["type"], - frame=self._db_task.start_frame + shape["frame"] * self._frame_step, + frame=self._db_task.data.start_frame + shape["frame"] * self._frame_step, points=shape["points"], occluded=shape["occluded"], outside=shape.get("outside", False), @@ -284,7 +284,7 @@ class Annotation: return Annotation.LabeledShape( type=shape["type"], label=self._get_label_name(shape["label_id"]), - frame=self._db_task.start_frame + shape["frame"] * self._frame_step, + frame=self._db_task.data.start_frame + shape["frame"] * self._frame_step, points=shape["points"], occluded=shape["occluded"], z_order=shape.get("z_order", 0), @@ -294,7 +294,7 @@ class Annotation: def _export_tag(self, tag): return Annotation.Tag( - frame=self._db_task.start_frame + tag["frame"] * self._frame_step, + frame=self._db_task.data.start_frame + tag["frame"] * self._frame_step, label=self._get_label_name(tag["label_id"]), group=tag.get("group", 0), attributes=self._export_attributes(tag["attributes"]), @@ -303,16 +303,11 @@ class Annotation: def group_by_frame(self): def _get_frame(annotations, shape): db_image = self._frame_info[shape["frame"]] - frame = self._db_task.start_frame + shape["frame"] * self._frame_step - rpath = db_image['path'].split(os.path.sep) - if len(rpath) != 1: - rpath = os.path.sep.join(rpath[rpath.index(".upload")+1:]) - else: - rpath = rpath[0] + frame = self._db_task.data.start_frame + shape["frame"] * self._frame_step if frame not in annotations: annotations[frame] = Annotation.Frame( frame=frame, - name=rpath, + name=db_image['path'], height=db_image["height"], width=db_image["width"], labeled_shapes=[], @@ -322,7 +317,7 @@ class Annotation: annotations = {} data_manager = DataManager(self._annotation_ir) - for shape in sorted(data_manager.to_shapes(self._db_task.size), key=lambda s: s.get("z_order", 0)): + for shape in sorted(data_manager.to_shapes(self._db_task.data.size), key=lambda shape: shape.get("z_order", 0)): _get_frame(annotations, shape).labeled_shapes.append(self._export_labeled_shape(shape)) for tag in self._annotation_ir.tags: @@ -338,7 +333,7 @@ class Annotation: @property def tracks(self): for track in self._annotation_ir.tracks: - tracked_shapes = TrackManager.get_interpolated_shapes(track, 0, self._db_task.size) + tracked_shapes = TrackManager.get_interpolated_shapes(track, 0, self._db_task.data.size) for tracked_shape in tracked_shapes: tracked_shape["attributes"] += track["attributes"] @@ -360,7 +355,7 @@ class Annotation: def _import_tag(self, tag): _tag = tag._asdict() label_id = self._get_label_id(_tag.pop('label')) - _tag['frame'] = (int(_tag['frame']) - self._db_task.start_frame) // self._frame_step + _tag['frame'] = (int(_tag['frame']) - self._db_task.data.start_frame) // self._frame_step _tag['label_id'] = label_id _tag['attributes'] = [self._import_attribute(label_id, attrib) for attrib in _tag['attributes'] if self._get_attribute_id(label_id, attrib.name)] @@ -375,7 +370,7 @@ class Annotation: def _import_shape(self, shape): _shape = shape._asdict() label_id = self._get_label_id(_shape.pop('label')) - _shape['frame'] = (int(_shape['frame']) - self._db_task.start_frame) // self._frame_step + _shape['frame'] = (int(_shape['frame']) - self._db_task.data.start_frame) // self._frame_step _shape['label_id'] = label_id _shape['attributes'] = [self._import_attribute(label_id, attrib) for attrib in _shape['attributes'] if self._get_attribute_id(label_id, attrib.name)] @@ -385,12 +380,12 @@ class Annotation: _track = track._asdict() label_id = self._get_label_id(_track.pop('label')) _track['frame'] = (min(int(shape.frame) for shape in _track['shapes']) - \ - self._db_task.start_frame) // self._frame_step + self._db_task.data.start_frame) // self._frame_step _track['label_id'] = label_id _track['attributes'] = [] _track['shapes'] = [shape._asdict() for shape in _track['shapes']] for shape in _track['shapes']: - shape['frame'] = (int(shape['frame']) - self._db_task.start_frame) // self._frame_step + shape['frame'] = (int(shape['frame']) - self._db_task.data.start_frame) // self._frame_step _track['attributes'] = [self._import_attribute(label_id, attrib) for attrib in shape['attributes'] if self._get_immutable_attribute_id(label_id, attrib.name)] shape['attributes'] = [self._import_attribute(label_id, attrib) for attrib in shape['attributes'] diff --git a/cvat/apps/annotation/format.py b/cvat/apps/annotation/format.py index 497c3812..a4b8bb45 100644 --- a/cvat/apps/annotation/format.py +++ b/cvat/apps/annotation/format.py @@ -3,12 +3,10 @@ # SPDX-License-Identifier: MIT from cvat.apps.annotation import models -from django.conf import settings from django.core.exceptions import ObjectDoesNotExist from cvat.apps.annotation.serializers import AnnotationFormatSerializer from django.core.files import File -import os from copy import deepcopy def register_format(format_file): diff --git a/cvat/apps/auto_annotation/image_loader.py b/cvat/apps/auto_annotation/image_loader.py index 9b4367c5..a3fddfb1 100644 --- a/cvat/apps/auto_annotation/image_loader.py +++ b/cvat/apps/auto_annotation/image_loader.py @@ -4,21 +4,19 @@ # SPDX-License-Identifier: MIT import cv2 +import numpy as np class ImageLoader(): - def __init__(self, image_list): - self.image_list = image_list - - def __getitem__(self, i): - return self.image_list[i] + def __init__(self, frame_provider): + self._frame_provider = frame_provider def __iter__(self): - for imagename in self.image_list: - yield self._load_image(imagename) + for frame in self._frame_provider.get_frames(self._frame_provider.Quality.ORIGINAL): + yield self._load_image(frame) def __len__(self): - return len(self.image_list) + return len(self._frame_provider) @staticmethod - def _load_image(path_to_image): - return cv2.imread(path_to_image) + def _load_image(image): + return cv2.imdecode(np.fromstring(image.read(), np.uint8), cv2.IMREAD_COLOR) diff --git a/cvat/apps/auto_annotation/model_manager.py b/cvat/apps/auto_annotation/model_manager.py index 27f6563a..02d65df2 100644 --- a/cvat/apps/auto_annotation/model_manager.py +++ b/cvat/apps/auto_annotation/model_manager.py @@ -3,7 +3,6 @@ # SPDX-License-Identifier: MIT import django_rq -import fnmatch import numpy as np import os import rq @@ -19,6 +18,7 @@ from cvat.apps.engine.models import Task as TaskModel from cvat.apps.authentication.auth import has_admin_role from cvat.apps.engine.serializers import LabeledDataSerializer from cvat.apps.engine.annotation import put_task_data, patch_task_data +from cvat.apps.engine.frame_provider import FrameProvider from .models import AnnotationModel, FrameworkChoice from .model_loader import load_labelmap @@ -208,19 +208,6 @@ def delete(dl_model_id): else: raise Exception("Requested DL model {} doesn't exist".format(dl_model_id)) -def get_image_data(path_to_data): - def get_image_key(item): - return int(os.path.splitext(os.path.basename(item))[0]) - - image_list = [] - for root, _, filenames in os.walk(path_to_data): - for filename in fnmatch.filter(filenames, "*.jpg"): - image_list.append(os.path.join(root, filename)) - - image_list.sort(key=get_image_key) - return ImageLoader(image_list) - - def run_inference_thread(tid, model_file, weights_file, labels_mapping, attributes, convertation_file, reset, user, restricted=True): def update_progress(job, progress): job.refresh() @@ -241,7 +228,7 @@ def run_inference_thread(tid, model_file, weights_file, labels_mapping, attribut result = None slogger.glob.info("auto annotation with openvino toolkit for task {}".format(tid)) result = run_inference_engine_annotation( - data=get_image_data(db_task.get_data_dirname()), + data=ImageLoader(FrameProvider(db_task.data)), model_file=model_file, weights_file=weights_file, labels_mapping=labels_mapping, diff --git a/cvat/apps/auto_segmentation/views.py b/cvat/apps/auto_segmentation/views.py index 1f47d1ec..baf16944 100644 --- a/cvat/apps/auto_segmentation/views.py +++ b/cvat/apps/auto_segmentation/views.py @@ -11,10 +11,9 @@ from cvat.apps.authentication.decorators import login_required from cvat.apps.engine.models import Task as TaskModel from cvat.apps.engine.serializers import LabeledDataSerializer from cvat.apps.engine.annotation import put_task_data +from cvat.apps.engine.frame_provider import FrameProvider import django_rq -import fnmatch -import json import os import rq @@ -26,13 +25,7 @@ import sys import skimage.io from skimage.measure import find_contours, approximate_polygon - -def load_image_into_numpy(image): - (im_width, im_height) = image.size - return np.array(image.getdata()).reshape((im_height, im_width, 3)).astype(np.uint8) - - -def run_tensorflow_auto_segmentation(image_list, labels_mapping, treshold): +def run_tensorflow_auto_segmentation(frame_provider, labels_mapping, treshold): def _convert_to_int(boolean_mask): return boolean_mask.astype(np.uint8) @@ -88,16 +81,17 @@ def run_tensorflow_auto_segmentation(image_list, labels_mapping, treshold): ## RUN OBJECT DETECTION result = {} - for image_num, image_path in enumerate(image_list): + frames = frame_provider.get_frames(frame_provider.Quality.ORIGINAL) + for image_num, image_bytes in enumerate(frames): job.refresh() if 'cancel' in job.meta: del job.meta['cancel'] job.save() return None - job.meta['progress'] = image_num * 100 / len(image_list) + job.meta['progress'] = image_num * 100 / len(frame_provider) job.save_meta() - image = skimage.io.imread(image_path) + image = skimage.io.imread(image_bytes) # for multiple image detection, "batch size" must be equal to number of images r = model.detect([image], verbose=1) @@ -117,20 +111,6 @@ def run_tensorflow_auto_segmentation(image_list, labels_mapping, treshold): return result - -def make_image_list(path_to_data): - def get_image_key(item): - return int(os.path.splitext(os.path.basename(item))[0]) - - image_list = [] - for root, _, filenames in os.walk(path_to_data): - for filename in fnmatch.filter(filenames, '*.jpg'): - image_list.append(os.path.join(root, filename)) - - image_list.sort(key=get_image_key) - return image_list - - def convert_to_cvat_format(data): result = { "tracks": [], @@ -166,12 +146,12 @@ def create_thread(tid, labels_mapping, user): # Get job indexes and segment length db_task = TaskModel.objects.get(pk=tid) # Get image list - image_list = make_image_list(db_task.get_data_dirname()) + frame_provider = FrameProvider(db_task.data) # Run auto segmentation by tf result = None slogger.glob.info("auto segmentation with tensorflow framework for task {}".format(tid)) - result = run_tensorflow_auto_segmentation(image_list, labels_mapping, TRESHOLD) + result = run_tensorflow_auto_segmentation(frame_provider, labels_mapping, TRESHOLD) if result is None: slogger.glob.info('auto segmentation for task {} canceled by user'.format(tid)) diff --git a/cvat/apps/dataset_manager/bindings.py b/cvat/apps/dataset_manager/bindings.py index d1d98af2..5215e25f 100644 --- a/cvat/apps/dataset_manager/bindings.py +++ b/cvat/apps/dataset_manager/bindings.py @@ -4,56 +4,47 @@ # SPDX-License-Identifier: MIT from collections import OrderedDict -import os -import os.path as osp from django.db import transaction from cvat.apps.annotation.annotation import Annotation from cvat.apps.engine.annotation import TaskAnnotation -from cvat.apps.engine.models import Task, ShapeType, AttributeType +from cvat.apps.engine.models import ShapeType, AttributeType import datumaro.components.extractor as datumaro from datumaro.util.image import Image -class CvatImagesDirExtractor(datumaro.Extractor): - _SUPPORTED_FORMATS = ['.png', '.jpg'] - - def __init__(self, url): +class CvatImagesExtractor(datumaro.Extractor): + def __init__(self, url, frame_provider): super().__init__() - items = [] - for (dirpath, _, filenames) in os.walk(url): - for name in filenames: - path = osp.join(dirpath, name) - if self._is_image(path): - item_id = Task.get_image_frame(path) - item = datumaro.DatasetItem(id=item_id, image=path) - items.append((item.id, item)) - - items = sorted(items, key=lambda e: int(e[0])) - items = OrderedDict(items) - self._items = items - + self._frame_provider = frame_provider self._subsets = None def __iter__(self): - for item in self._items.values(): - yield item + frames = self._frame_provider.get_frames( + self._frame_provider.Quality.ORIGINAL, + self._frame_provider.Type.NUMPY_ARRAY) + for item_id, image in enumerate(frames): + yield datumaro.DatasetItem( + id=item_id, + image=Image(image), + ) def __len__(self): - return len(self._items) + return len(self._frame_provider) def subsets(self): return self._subsets - def _is_image(self, path): - for ext in self._SUPPORTED_FORMATS: - if osp.isfile(path) and path.endswith(ext): - return True - return False - + def get(self, item_id, subset=None, path=None): + if path or subset: + raise KeyError() + return datumaro.DatasetItem( + id=item_id, + image=self._frame_provider[item_id].getvalue() + ) class CvatAnnotationsExtractor(datumaro.Extractor): def __init__(self, url, cvat_annotations): @@ -170,7 +161,6 @@ class CvatAnnotationsExtractor(datumaro.Extractor): return item_anno - class CvatTaskExtractor(CvatAnnotationsExtractor): def __init__(self, url, db_task, user): cvat_annotations = TaskAnnotation(db_task.id, user) @@ -254,4 +244,4 @@ def import_dm_annotations(dm_dataset, cvat_task_anno): group=group_map.get(ann.group, 0), attributes=[cvat_task_anno.Attribute(name=n, value=str(v)) for n, v in ann.attributes.items()], - )) \ No newline at end of file + )) diff --git a/cvat/apps/dataset_manager/export_templates/plugins/cvat_rest_api_task_images.py b/cvat/apps/dataset_manager/export_templates/plugins/cvat_rest_api_task_images.py index 2bf1b507..a4e92f8c 100644 --- a/cvat/apps/dataset_manager/export_templates/plugins/cvat_rest_api_task_images.py +++ b/cvat/apps/dataset_manager/export_templates/plugins/cvat_rest_api_task_images.py @@ -45,7 +45,7 @@ class cvat_rest_api_task_images(datumaro.SourceExtractor): self._connect() os.makedirs(self._cache_dir, exist_ok=True) self._cvat_cli.tasks_frame(task_id=self._config.task_id, - frame_ids=[item_id], outdir=self._cache_dir) + frame_ids=[item_id], outdir=self._cache_dir, quality='original') def _connect(self): if self._session is not None: @@ -126,6 +126,7 @@ class cvat_rest_api_task_images(datumaro.SourceExtractor): def __len__(self): return len(self._items) + # pylint: disable=no-self-use def subsets(self): return None diff --git a/cvat/apps/dataset_manager/task.py b/cvat/apps/dataset_manager/task.py index 4c5e9410..4fdfbee3 100644 --- a/cvat/apps/dataset_manager/task.py +++ b/cvat/apps/dataset_manager/task.py @@ -16,6 +16,7 @@ import django_rq from cvat.apps.engine.log import slogger from cvat.apps.engine.models import Task +from cvat.apps.engine.frame_provider import FrameProvider from .util import current_function_name, make_zip_archive _CVAT_ROOT_DIR = __file__[:__file__.rfind('cvat/')] @@ -23,7 +24,7 @@ _DATUMARO_REPO_PATH = osp.join(_CVAT_ROOT_DIR, 'datumaro') sys.path.append(_DATUMARO_REPO_PATH) from datumaro.components.project import Project, Environment import datumaro.components.extractor as datumaro -from .bindings import CvatImagesDirExtractor, CvatTaskExtractor +from .bindings import CvatImagesExtractor, CvatTaskExtractor _MODULE_NAME = __package__ + '.' + osp.splitext(osp.basename(__file__))[0] @@ -77,11 +78,11 @@ class TaskProject: def _create(self): self._project = Project.generate(self._project_dir) self._project.add_source('task_%s' % self._db_task.id, { - 'url': self._db_task.get_data_dirname(), 'format': _TASK_IMAGES_EXTRACTOR, }) self._project.env.extractors.register(_TASK_IMAGES_EXTRACTOR, - CvatImagesDirExtractor) + lambda url: CvatImagesExtractor(url, + FrameProvider(self._db_task.data))) self._init_dataset() self._dataset.define_categories(self._generate_categories()) @@ -91,18 +92,19 @@ class TaskProject: def _load(self): self._project = Project.load(self._project_dir) self._project.env.extractors.register(_TASK_IMAGES_EXTRACTOR, - CvatImagesDirExtractor) + lambda url: CvatImagesExtractor(url, + FrameProvider(self._db_task.data))) def _import_from_task(self, user): self._project = Project.generate(self._project_dir, config={'project_name': self._db_task.name}) self._project.add_source('task_%s_images' % self._db_task.id, { - 'url': self._db_task.get_data_dirname(), 'format': _TASK_IMAGES_EXTRACTOR, }) self._project.env.extractors.register(_TASK_IMAGES_EXTRACTOR, - CvatImagesDirExtractor) + lambda url: CvatImagesExtractor(url, + FrameProvider(self._db_task.data))) self._project.add_source('task_%s_anno' % self._db_task.id, { 'format': _TASK_ANNO_EXTRACTOR, @@ -173,9 +175,9 @@ class TaskProject: images_meta = { 'images': items, } - db_video = getattr(self._db_task, 'video', None) + db_video = getattr(self._db_task.data, 'video', None) if db_video is not None: - for i in range(self._db_task.size): + for i in range(self._db_task.data.size): frame_info = { 'id': i, 'width': db_video.width, @@ -183,7 +185,7 @@ class TaskProject: } items.append(frame_info) else: - for db_image in self._db_task.image_set.all(): + for db_image in self._db_task.data.images.all(): frame_info = { 'id': db_image.frame, 'name': osp.basename(db_image.path), @@ -345,4 +347,4 @@ def get_export_formats(): if fmt['tag'] in available_formats: public_formats.append(fmt) - return public_formats \ No newline at end of file + return public_formats diff --git a/cvat/apps/engine/admin.py b/cvat/apps/engine/admin.py index a7b11099..7336db03 100644 --- a/cvat/apps/engine/admin.py +++ b/cvat/apps/engine/admin.py @@ -56,7 +56,7 @@ class SegmentAdmin(admin.ModelAdmin): class TaskAdmin(admin.ModelAdmin): date_hierarchy = 'updated_date' - readonly_fields = ('size', 'created_date', 'updated_date', 'overlap') + readonly_fields = ('created_date', 'updated_date', 'overlap') list_display = ('name', 'mode', 'owner', 'assignee', 'created_date', 'updated_date') search_fields = ('name', 'mode', 'owner__username', 'owner__first_name', 'owner__last_name', 'owner__email', 'assignee__username', 'assignee__first_name', diff --git a/cvat/apps/engine/annotation.py b/cvat/apps/engine/annotation.py index acb9a6d5..bacfd0d7 100644 --- a/cvat/apps/engine/annotation.py +++ b/cvat/apps/engine/annotation.py @@ -656,7 +656,7 @@ class JobAnnotation: class TaskAnnotation: def __init__(self, pk, user): self.user = user - self.db_task = models.Task.objects.prefetch_related("image_set").get(id=pk) + self.db_task = models.Task.objects.prefetch_related("data__images").get(id=pk) # Postgres doesn't guarantee an order by default without explicit order_by self.db_jobs = models.Job.objects.select_related("segment").filter(segment__task_id=pk).order_by('id') diff --git a/cvat/apps/engine/data_manager.py b/cvat/apps/engine/data_manager.py index 00586ea5..bbbd847e 100644 --- a/cvat/apps/engine/data_manager.py +++ b/cvat/apps/engine/data_manager.py @@ -1,3 +1,7 @@ +# Copyright (C) 2019 Intel Corporation +# +# SPDX-License-Identifier: MIT + import copy import numpy as np diff --git a/cvat/apps/engine/frame_provider.py b/cvat/apps/engine/frame_provider.py new file mode 100644 index 00000000..19cf587c --- /dev/null +++ b/cvat/apps/engine/frame_provider.py @@ -0,0 +1,149 @@ +# Copyright (C) 2019 Intel Corporation +# +# SPDX-License-Identifier: MIT + +import math +from io import BytesIO +from enum import Enum + +import numpy as np +from PIL import Image + +from cvat.apps.engine.media_extractors import VideoReader, ZipReader +from cvat.apps.engine.models import DataChoice +from cvat.apps.engine.mime_types import mimetypes + + +class FrameProvider(): + class Quality(Enum): + COMPRESSED = 0 + ORIGINAL = 100 + + class Type(Enum): + BUFFER = 0 + PIL = 1 + NUMPY_ARRAY = 2 + + def __init__(self, db_data): + self._db_data = db_data + if db_data.compressed_chunk_type == DataChoice.IMAGESET: + self._compressed_chunk_reader_class = ZipReader + elif db_data.compressed_chunk_type == DataChoice.VIDEO: + self._compressed_chunk_reader_class = VideoReader + else: + raise Exception('Unsupported chunk type') + + if db_data.original_chunk_type == DataChoice.IMAGESET: + self._original_chunk_reader_class = ZipReader + elif db_data.original_chunk_type == DataChoice.VIDEO: + self._original_chunk_reader_class = VideoReader + else: + raise Exception('Unsupported chunk type') + + self._extracted_compressed_chunk = None + self._compressed_chunk_reader = None + self._extracted_original_chunk = None + self._original_chunk_reader = None + + def __len__(self): + return self._db_data.size + + def _validate_frame_number(self, frame_number): + frame_number_ = int(frame_number) + if frame_number_ < 0 or frame_number_ >= self._db_data.size: + raise Exception('Incorrect requested frame number: {}'.format(frame_number_)) + + chunk_number = frame_number_ // self._db_data.chunk_size + frame_offset = frame_number_ % self._db_data.chunk_size + + return frame_number_, chunk_number, frame_offset + + def _validate_chunk_number(self, chunk_number): + chunk_number_ = int(chunk_number) + if chunk_number_ < 0 or chunk_number_ >= math.ceil(self._db_data.size / self._db_data.chunk_size): + raise Exception('requested chunk does not exist') + + return chunk_number_ + + @staticmethod + def _av_frame_to_png_bytes(av_frame): + pil_img = av_frame.to_image() + buf = BytesIO() + pil_img.save(buf, format='PNG') + buf.seek(0) + return buf + + def _get_frame(self, frame_number, chunk_path_getter, extracted_chunk, chunk_reader, reader_class): + _, chunk_number, frame_offset = self._validate_frame_number(frame_number) + chunk_path = chunk_path_getter(chunk_number) + if chunk_number != extracted_chunk: + extracted_chunk = chunk_number + chunk_reader = reader_class([chunk_path]) + + frame, frame_name = chunk_reader[frame_offset] + if reader_class is VideoReader: + return (self._av_frame_to_png_bytes(frame), 'image/png') + + return (frame, mimetypes.guess_type(frame_name)) + + def _get_frames(self, chunk_path_getter, reader_class, out_type): + for chunk_idx in range(math.ceil(self._db_data.size / self._db_data.chunk_size)): + chunk_path = chunk_path_getter(chunk_idx) + chunk_reader = reader_class([chunk_path]) + for frame, _ in chunk_reader: + if out_type == self.Type.BUFFER: + yield self._av_frame_to_png_bytes(frame) if reader_class is VideoReader else frame + elif out_type == self.Type.PIL: + yield frame.to_image() if reader_class is VideoReader else Image.open(frame) + elif out_type == self.Type.NUMPY_ARRAY: + if reader_class is VideoReader: + image = np.array(frame.to_image()) + else: + image = np.array(Image.open(frame)) + if len(image.shape) == 3 and image.shape[2] in {3, 4}: + image[:, :, :3] = image[:, :, 2::-1] # RGB to BGR + yield image + else: + raise Exception('unsupported output type') + + def get_preview(self): + return self._db_data.get_preview_path() + + def get_chunk(self, chunk_number, quality=Quality.ORIGINAL): + chunk_number = self._validate_chunk_number(chunk_number) + if quality == self.Quality.ORIGINAL: + return self._db_data.get_original_chunk_path(chunk_number) + elif quality == self.Quality.COMPRESSED: + return self._db_data.get_compressed_chunk_path(chunk_number) + + def get_frame(self, frame_number, quality=Quality.ORIGINAL): + if quality == self.Quality.ORIGINAL: + return self._get_frame( + frame_number=frame_number, + chunk_path_getter=self._db_data.get_original_chunk_path, + extracted_chunk=self._extracted_original_chunk, + chunk_reader=self._original_chunk_reader, + reader_class=self._original_chunk_reader_class, + ) + elif quality == self.Quality.COMPRESSED: + return self._get_frame( + frame_number=frame_number, + chunk_path_getter=self._db_data.get_compressed_chunk_path, + extracted_chunk=self._extracted_compressed_chunk, + chunk_reader=self._compressed_chunk_reader, + reader_class=self._compressed_chunk_reader_class, + ) + + def get_frames(self, quality=Quality.ORIGINAL, out_type=Type.BUFFER): + if quality == self.Quality.ORIGINAL: + return self._get_frames( + chunk_path_getter=self._db_data.get_original_chunk_path, + reader_class=self._original_chunk_reader_class, + out_type=out_type, + ) + elif quality == self.Quality.COMPRESSED: + return self._get_frames( + chunk_path_getter=self._db_data.get_compressed_chunk_path, + reader_class=self._compressed_chunk_reader_class, + out_type=out_type, + ) diff --git a/cvat/apps/engine/media_extractors.py b/cvat/apps/engine/media_extractors.py index 018671e1..a775365d 100644 --- a/cvat/apps/engine/media_extractors.py +++ b/cvat/apps/engine/media_extractors.py @@ -1,18 +1,22 @@ +# Copyright (C) 2019 Intel Corporation +# +# SPDX-License-Identifier: MIT + import os import tempfile import shutil -import numpy as np +import zipfile +from io import BytesIO +import itertools +from abc import ABC, abstractmethod -from ffmpy import FFmpeg +import av +import av.datasets +import numpy as np from pyunpack import Archive from PIL import Image -import mimetypes -_SCRIPT_DIR = os.path.realpath(os.path.dirname(__file__)) -MEDIA_MIMETYPES_FILES = [ - os.path.join(_SCRIPT_DIR, "media.mimetypes"), -] -mimetypes.init(files=MEDIA_MIMETYPES_FILES) +from cvat.apps.engine.mime_types import mimetypes def get_mime(name): for type_name, type_def in MEDIA_TYPES.items(): @@ -21,110 +25,85 @@ def get_mime(name): return 'unknown' -class MediaExtractor: - def __init__(self, source_path, dest_path, image_quality, step, start, stop): - self._source_path = source_path - self._dest_path = dest_path - self._image_quality = image_quality +class IMediaReader(ABC): + def __init__(self, source_path, step, start, stop): + self._source_path = sorted(source_path) self._step = step self._start = start self._stop = stop - def get_source_name(self): - return self._source_path + @staticmethod + def create_tmp_dir(): + return tempfile.mkdtemp(prefix='cvat-', suffix='.data') -#Note step, start, stop have no affect -class ImageListExtractor(MediaExtractor): - def __init__(self, source_path, dest_path, image_quality, step=1, start=0, stop=0): - if not source_path: - raise Exception('No image found') - super().__init__( - source_path=sorted(source_path), - dest_path=dest_path, - image_quality=image_quality, - step=1, - start=0, - stop=0, - ) + @staticmethod + def delete_tmp_dir(tmp_dir): + if tmp_dir: + shutil.rmtree(tmp_dir) + @abstractmethod def __iter__(self): - return iter(self._source_path) + pass + @abstractmethod def __getitem__(self, k): - return self._source_path[k] - - def __len__(self): - return len(self._source_path) + pass + + @abstractmethod + def save_preview(self, preview_path): + pass + + def slice_by_size(self, size): + # stopFrame should be included + it = itertools.islice(self, self._start, self._stop + 1 if self._stop else None) + frames = list(itertools.islice(it, 0, size * self._step, self._step)) + while frames: + yield frames + frames = list(itertools.islice(it, 0, size * self._step, self._step)) + @property + @abstractmethod + def image_names(self): + pass + + @abstractmethod + def get_image_size(self): + pass - def save_image(self, k, dest_path): - image = Image.open(self[k]) - # Ensure image data fits into 8bit per pixel before RGB conversion as PIL clips values on conversion - if image.mode == "I": - # Image mode is 32bit integer pixels. - # Autoscale pixels by factor 2**8 / im_data.max() to fit into 8bit - im_data = np.array(image) - im_data = im_data * (2**8 / im_data.max()) - image = Image.fromarray(im_data.astype(np.int32)) - image = image.convert('RGB') - image.save(dest_path, quality=self._image_quality, optimize=True) - height = image.height - width = image.width - image.close() - return width, height - -class PDFExtractor(MediaExtractor): - def __init__(self, source_path, dest_path, image_quality, step=1, start=0, stop=0): +#Note step, start, stop have no affect +class ImageListReader(IMediaReader): + def __init__(self, source_path, step=1, start=0, stop=0): if not source_path: - raise Exception('No PDF found') - - from pdf2image import convert_from_path - self._temp_directory = tempfile.mkdtemp(prefix='cvat-') + raise Exception('No image found') super().__init__( - source_path=source_path[0], - dest_path=dest_path, - image_quality=image_quality, + source_path=source_path, step=1, start=0, stop=0, ) - self._dimensions = [] - file_ = convert_from_path(self._source_path) - self._basename = os.path.splitext(os.path.basename(self._source_path))[0] - for page_num, page in enumerate(file_): - output = os.path.join(self._temp_directory, self._basename + str(page_num) + '.jpg') - self._dimensions.append(page.size) - page.save(output, 'JPEG') - - self._length = len(os.listdir(self._temp_directory)) - - def _get_imagepath(self, k): - img_path = os.path.join(self._temp_directory, self._basename + str(k) + '.jpg') - return img_path - def __iter__(self): - i = 0 - while os.path.exists(self._get_imagepath(i)): - yield self._get_imagepath(i) - i += 1 - - def __del__(self): - if self._temp_directory: - shutil.rmtree(self._temp_directory) + return zip(self._source_path, self.image_names) def __getitem__(self, k): - return self._get_imagepath(k) + return (self._source_path[k], self.image_names[k]) def __len__(self): - return self._length + return len(self._source_path) + + def save_preview(self, preview_path): + shutil.copyfile(self._source_path[0], preview_path) + + @property + def image_names(self): + return self._source_path - def save_image(self, k, dest_path): - shutil.copyfile(self[k], dest_path) - return self._dimensions[k] + def get_image_size(self): + img = Image.open(self._source_path[0]) + return img.width, img.height #Note step, start, stop have no affect -class DirectoryExtractor(ImageListExtractor): - def __init__(self, source_path, dest_path, image_quality, step=1, start=0, stop=0): +class DirectoryReader(ImageListReader): + def __init__(self, source_path, step=1, start=0, stop=0): image_paths = [] for source in source_path: for root, _, files in os.walk(source): @@ -132,89 +111,302 @@ class DirectoryExtractor(ImageListExtractor): paths = filter(lambda x: get_mime(x) == 'image', paths) image_paths.extend(paths) super().__init__( - source_path=sorted(image_paths), - dest_path=dest_path, - image_quality=image_quality, + source_path=image_paths, step=1, start=0, stop=0, ) #Note step, start, stop have no affect -class ArchiveExtractor(DirectoryExtractor): - def __init__(self, source_path, dest_path, image_quality, step=1, start=0, stop=0): - Archive(source_path[0]).extractall(dest_path) +class ArchiveReader(DirectoryReader): + def __init__(self, source_path, step=1, start=0, stop=0): + self._tmp_dir = self.create_tmp_dir() + self._archive_source = source_path[0] + Archive(self._archive_source).extractall(self._tmp_dir) + super().__init__( + source_path=[self._tmp_dir], + step=1, + start=0, + stop=0, + ) + + def __del__(self): + if (self._tmp_dir): + self.delete_tmp_dir(self._tmp_dir) + + @property + def image_names(self): + return [os.path.join(os.path.dirname(self._archive_source), os.path.relpath(p, self._tmp_dir)) for p in super().image_names] + +#Note step, start, stop have no affect +class PdfReader(DirectoryReader): + def __init__(self, source_path, step=1, start=0, stop=0): + if not source_path: + raise Exception('No PDF found') + + from pdf2image import convert_from_path + self._pdf_source = source_path[0] + self._tmp_dir = self.create_tmp_dir() + file_ = convert_from_path(self._pdf_source) + basename = os.path.splitext(os.path.basename(self._pdf_source))[0] + for page_num, page in enumerate(file_): + output = os.path.join(self._tmp_dir, '{}{:09d}.jpeg'.format(basename, page_num)) + page.save(output, 'JPEG') + super().__init__( - source_path=[dest_path], - dest_path=dest_path, - image_quality=image_quality, + source_path=[self._tmp_dir], step=1, start=0, stop=0, ) -class VideoExtractor(MediaExtractor): - def __init__(self, source_path, dest_path, image_quality, step=1, start=0, stop=0): - from cvat.apps.engine.log import slogger - _dest_path = tempfile.mkdtemp(prefix='cvat-', suffix='.data') + def __del__(self): + if (self._tmp_dir): + self.delete_tmp_dir(self._tmp_dir) + + @property + def image_names(self): + return [os.path.join(os.path.dirname(self._pdf_source), os.path.relpath(p, self._tmp_dir)) for p in super().image_names] + +class ZipReader(IMediaReader): + def __init__(self, source_path, step=1, start=0, stop=0): + self._zip_source = zipfile.ZipFile(source_path[0], mode='r') + file_list = [f for f in self._zip_source.namelist() if get_mime(f) == 'image'] + super().__init__(file_list, step, start, stop) + + def __iter__(self): + for f in zip(self._source_path, self.image_names): + yield (BytesIO(self._zip_source.read(f[0])), f[1]) + + def __len__(self): + return len(self._source_path) + + def __getitem__(self, k): + return (BytesIO(self._zip_source.read(self._source_path[k])), self.image_names[k]) + + def __del__(self): + self._zip_source.close() + + def save_preview(self, preview_path): + with open(preview_path, 'wb') as f: + f.write(self._zip_source.read(self._source_path[0])) + + def get_image_size(self): + img = Image.open(BytesIO(self._zip_source.read(self._source_path[0]))) + return img.width, img.height + + @property + def image_names(self): + return [os.path.join(os.path.dirname(self._zip_source.filename), p) for p in self._source_path] + +class VideoReader(IMediaReader): + def __init__(self, source_path, step=1, start=0, stop=0): + self._output_fps = 25 + super().__init__( - source_path=source_path[0], - dest_path=_dest_path, - image_quality=image_quality, + source_path=source_path, step=step, start=start, stop=stop, - ) - # translate inversed range 1:95 to 2:32 - translated_quality = 96 - self._image_quality - translated_quality = round((((translated_quality - 1) * (31 - 2)) / (95 - 1)) + 2) - self._tmp_output = tempfile.mkdtemp(prefix='cvat-', suffix='.data') - target_path = os.path.join(self._tmp_output, '%d.jpg') - output_opts = '-start_number 0 -b:v 10000k -vsync 0 -an -y -q:v ' + str(translated_quality) - filters = '' - if self._stop > 0: - filters = 'between(n,' + str(self._start) + ',' + str(self._stop) + ')' - elif self._start > 0: - filters = 'gte(n,' + str(self._start) + ')' - if self._step > 1: - filters += ('*' if filters else '') + 'not(mod(n-' + str(self._start) + ',' + str(self._step) + '))' - if filters: - output_opts += " -vf select=\"'" + filters + "'\"" - - ff = FFmpeg( - inputs = {self._source_path: None}, - outputs = {target_path: output_opts}) - - slogger.glob.info("FFMpeg cmd: {} ".format(ff.cmd)) - ff.run() - - def _getframepath(self, k): - return "{0}/{1}.jpg".format(self._tmp_output, k) + ) def __iter__(self): - i = 0 - while os.path.exists(self._getframepath(i)): - yield self._getframepath(i) - i += 1 + def decode_frames(container): + for packet in container.demux(): + if packet.stream.type == 'video': + for frame in packet.decode(): + yield frame - def __del__(self): - if self._tmp_output: - shutil.rmtree(self._tmp_output) + container = self._get_av_container() + source_video_stream = container.streams.video[0] + source_video_stream.thread_type = 'AUTO' + image_names = self.image_names - def __getitem__(self, k): - return self._getframepath(k) + return itertools.zip_longest(decode_frames(container), image_names, fillvalue=image_names[0]) def __len__(self): - return len(os.listdir(self._tmp_output)) + container = self._get_av_container() + # Not for all containers return real value + length = container.streams.video[0].frames + return length + + def __getitem__(self, k): + return next(itertools.islice(self, k, k + 1)) + + def _get_av_container(self): + return av.open(av.datasets.curated(self._source_path[0])) + + def save_preview(self, preview_path): + container = self._get_av_container() + stream = container.streams.video[0] + preview = next(container.decode(stream)) + preview.to_image().save(preview_path) + + @property + def image_names(self): + return self._source_path + + def get_image_size(self): + image = (next(iter(self)))[0] + return image.width, image.height + +class IChunkWriter(ABC): + def __init__(self, quality): + self._image_quality = quality + + @staticmethod + def _compress_image(image_path, quality): + image = image_path.to_image() if isinstance(image_path, av.VideoFrame) else Image.open(image_path) + # Ensure image data fits into 8bit per pixel before RGB conversion as PIL clips values on conversion + if image.mode == "I": + # Image mode is 32bit integer pixels. + # Autoscale pixels by factor 2**8 / im_data.max() to fit into 8bit + im_data = np.array(image) + im_data = im_data * (2**8 / im_data.max()) + image = Image.fromarray(im_data.astype(np.int32)) + converted_image = image.convert('RGB') + image.close() + buf = BytesIO() + converted_image.save(buf, format='JPEG', quality=quality, optimize=True) + buf.seek(0) + width, height = converted_image.size + converted_image.close() + return width, height, buf + + @abstractmethod + def save_as_chunk(self, images, chunk_path): + pass + +class ZipChunkWriter(IChunkWriter): + def save_as_chunk(self, images, chunk_path): + with zipfile.ZipFile(chunk_path, 'x') as zip_chunk: + for idx, (image, image_name) in enumerate(images): + arcname = '{:06d}{}'.format(idx, os.path.splitext(image_name)[1]) + if isinstance(image, BytesIO): + zip_chunk.writestr(arcname, image.getvalue()) + else: + zip_chunk.write(filename=image, arcname=arcname) + # return empty list because ZipChunkWriter write files as is + # and does not decode it to know img size. + return [] + +class ZipCompressedChunkWriter(IChunkWriter): + def save_as_chunk(self, images, chunk_path): + image_sizes = [] + with zipfile.ZipFile(chunk_path, 'x') as zip_chunk: + for idx, (image, _) in enumerate(images): + w, h, image_buf = self._compress_image(image, self._image_quality) + image_sizes.append((w, h)) + arcname = '{:06d}.jpeg'.format(idx) + zip_chunk.writestr(arcname, image_buf.getvalue()) + + return image_sizes + +class Mpeg4ChunkWriter(IChunkWriter): + def __init__(self, _): + super().__init__(17) + self._output_fps = 25 + + @staticmethod + def _create_av_container(path, w, h, rate, pix_format, options): + container = av.open(path, 'w') + video_stream = container.add_stream('libx264', rate=rate) + video_stream.pix_fmt = pix_format + video_stream.width = w + video_stream.height = h + video_stream.options = options + + return container, video_stream + + def save_as_chunk(self, images, chunk_path): + if not images: + raise Exception('no images to save') + + input_w = images[0][0].width + input_h = images[0][0].height + pix_format = images[0][0].format.name + + output_container, output_v_stream = self._create_av_container( + path=chunk_path, + w=input_w, + h=input_h, + rate=self._output_fps, + pix_format=pix_format, + options={ + "crf": str(self._image_quality), + "preset": "ultrafast", + }, + ) - def save_image(self, k, dest_path): - shutil.copyfile(self[k], dest_path) + self._encode_images(images, output_container, output_v_stream) + output_container.close() + return [(input_w, input_h)] + + @staticmethod + def _encode_images(images, container, stream): + for frame, _ in images: + # let libav set the correct pts and time_base + frame.pts = None + frame.time_base = None + + for packet in stream.encode(frame): + container.mux(packet) + + # Flush streams + for packet in stream.encode(): + container.mux(packet) + +class Mpeg4CompressedChunkWriter(Mpeg4ChunkWriter): + def __init__(self, quality): + # translate inversed range [1:100] to [0:51] + self._image_quality = round(51 * (100 - quality) / 99) + self._output_fps = 25 + + + def save_as_chunk(self, images, chunk_path): + if not images: + raise Exception('no images to save') + + input_w = images[0][0].width + input_h = images[0][0].height + + downscale_factor = 1 + while input_h / downscale_factor >= 1080: + downscale_factor *= 2 + + output_h = input_h // downscale_factor + output_w = input_w // downscale_factor + + # width and height must be divisible by 2 + if output_h % 2: + output_h += 1 + if output_w % 2: + output_w +=1 + + output_container, output_v_stream = self._create_av_container( + path=chunk_path, + w=output_w, + h=output_h, + rate=self._output_fps, + pix_format='yuv420p', + options={ + 'profile': 'baseline', + 'coder': '0', + 'crf': str(self._image_quality), + 'wpredp': '0', + 'flags': '-loop' + }, + ) + + self._encode_images(images, output_container, output_v_stream) + output_container.close() + return [(input_w, input_h)] def _is_archive(path): mime = mimetypes.guess_type(path) mime_type = mime[0] encoding = mime[1] - supportedArchives = ['application/zip', 'application/x-rar-compressed', + supportedArchives = ['application/x-rar-compressed', 'application/x-tar', 'application/x-7z-compressed', 'application/x-cpio', 'gzip', 'bzip2'] return mime_type in supportedArchives or encoding in supportedArchives @@ -236,6 +428,13 @@ def _is_pdf(path): mime = mimetypes.guess_type(path) return mime[0] == 'application/pdf' +def _is_zip(path): + mime = mimetypes.guess_type(path) + mime_type = mime[0] + encoding = mime[1] + supportedArchives = ['application/zip'] + return mime_type in supportedArchives or encoding in supportedArchives + # 'has_mime_type': function receives 1 argument - path to file. # Should return True if file has specified media type. # 'extractor': class that extracts images from specified media. @@ -247,32 +446,38 @@ def _is_pdf(path): MEDIA_TYPES = { 'image': { 'has_mime_type': _is_image, - 'extractor': ImageListExtractor, + 'extractor': ImageListReader, 'mode': 'annotation', 'unique': False, }, 'video': { 'has_mime_type': _is_video, - 'extractor': VideoExtractor, + 'extractor': VideoReader, 'mode': 'interpolation', 'unique': True, }, 'archive': { 'has_mime_type': _is_archive, - 'extractor': ArchiveExtractor, + 'extractor': ArchiveReader, 'mode': 'annotation', 'unique': True, }, 'directory': { 'has_mime_type': _is_dir, - 'extractor': DirectoryExtractor, + 'extractor': DirectoryReader, 'mode': 'annotation', 'unique': False, }, 'pdf': { 'has_mime_type': _is_pdf, - 'extractor': PDFExtractor, + 'extractor': PdfReader, 'mode': 'annotation', 'unique': True, }, + 'zip': { + 'has_mime_type': _is_zip, + 'extractor': ZipReader, + 'mode': 'annotation', + 'unique': True, + } } diff --git a/cvat/apps/engine/migrations/0020_remove_task_flipped.py b/cvat/apps/engine/migrations/0020_remove_task_flipped.py index 1c09cea2..7ca57e88 100644 --- a/cvat/apps/engine/migrations/0020_remove_task_flipped.py +++ b/cvat/apps/engine/migrations/0020_remove_task_flipped.py @@ -3,13 +3,54 @@ from django.db import migrations from django.conf import settings -from cvat.apps.engine.task import get_image_meta_cache from cvat.apps.engine.models import Job, ShapeType +from cvat.apps.engine.media_extractors import get_mime from PIL import Image - +from ast import literal_eval import os +def make_image_meta_cache(db_task): + with open(db_task.get_image_meta_cache_path(), 'w') as meta_file: + cache = { + 'original_size': [] + } + + if db_task.mode == 'interpolation': + image = Image.open(db_task.get_frame_path(0)) + cache['original_size'].append({ + 'width': image.size[0], + 'height': image.size[1] + }) + image.close() + else: + filenames = [] + for root, _, files in os.walk(db_task.get_upload_dirname()): + fullnames = map(lambda f: os.path.join(root, f), files) + images = filter(lambda x: get_mime(x) == 'image', fullnames) + filenames.extend(images) + filenames.sort() + + for image_path in filenames: + image = Image.open(image_path) + cache['original_size'].append({ + 'width': image.size[0], + 'height': image.size[1] + }) + image.close() + + meta_file.write(str(cache)) + + +def get_image_meta_cache(db_task): + try: + with open(db_task.get_image_meta_cache_path()) as meta_cache_file: + return literal_eval(meta_cache_file.read()) + except Exception: + make_image_meta_cache(db_task) + with open(db_task.get_image_meta_cache_path()) as meta_cache_file: + return literal_eval(meta_cache_file.read()) + def _flip_shape(shape, size): if shape.type == ShapeType.RECTANGLE: diff --git a/cvat/apps/engine/migrations/0024_auto_20191023_1025.py b/cvat/apps/engine/migrations/0024_auto_20191023_1025.py new file mode 100644 index 00000000..7ec65bcf --- /dev/null +++ b/cvat/apps/engine/migrations/0024_auto_20191023_1025.py @@ -0,0 +1,461 @@ +# Generated by Django 2.2.4 on 2019-10-23 10:25 + +import os +import re +import shutil +import glob +import logging +import sys +import traceback +import itertools +import multiprocessing +import time + +from django.db import migrations, models +import django.db.models.deletion +from django.conf import settings + +from cvat.apps.engine.media_extractors import (VideoReader, ArchiveReader, ZipReader, + PdfReader , ImageListReader, Mpeg4ChunkWriter, + ZipChunkWriter, ZipCompressedChunkWriter, get_mime) +from cvat.apps.engine.models import DataChoice + +MIGRATION_THREAD_COUNT = 2 + +def fix_path(path): + ind = path.find('.upload') + if ind != -1: + path = path[ind + len('.upload') + 1:] + return path + +def get_frame_step(frame_filter): + match = re.search("step\s*=\s*([1-9]\d*)", frame_filter) + return int(match.group(1)) if match else 1 + +def get_task_on_disk(): + folders = [os.path.relpath(f, settings.DATA_ROOT) + for f in glob.glob(os.path.join(settings.DATA_ROOT, '*'), recursive=False)] + + return set(int(f) for f in folders if f.isdigit()) + +def get_frame_path(task_data_dir, frame): + d1 = str(int(frame) // 10000) + d2 = str(int(frame) // 100) + path = os.path.join(task_data_dir, d1, d2, + str(frame) + '.jpg') + + return path + +def slice_by_size(frames, size): + it = itertools.islice(frames, 0, None) + frames = list(itertools.islice(it, 0, size , 1)) + while frames: + yield frames + frames = list(itertools.islice(it, 0, size, 1)) + +def migrate_task_data(db_task_id, db_data_id, original_video, original_images, size, start_frame, + stop_frame, frame_filter, image_quality, chunk_size, return_dict): + try: + db_data_dir = os.path.join(settings.MEDIA_DATA_ROOT, str(db_data_id)) + compressed_cache_dir = os.path.join(db_data_dir, 'compressed') + original_cache_dir = os.path.join(db_data_dir, 'original') + old_db_task_dir = os.path.join(settings.DATA_ROOT, str(db_task_id)) + old_task_data_dir = os.path.join(old_db_task_dir, 'data') + if os.path.exists(old_task_data_dir) and size != 0: + if original_video: + if os.path.exists(original_video): + reader = VideoReader([original_video], get_frame_step(frame_filter), start_frame, stop_frame) + original_chunk_writer = Mpeg4ChunkWriter(100) + compressed_chunk_writer = ZipCompressedChunkWriter(image_quality) + + for chunk_idx, chunk_images in enumerate(reader.slice_by_size(chunk_size)): + original_chunk_path = os.path.join(original_cache_dir, '{}.mp4'.format(chunk_idx)) + original_chunk_writer.save_as_chunk(chunk_images, original_chunk_path) + + compressed_chunk_path = os.path.join(compressed_cache_dir, '{}.zip'.format(chunk_idx)) + compressed_chunk_writer.save_as_chunk(chunk_images, compressed_chunk_path) + + reader.save_preview(os.path.join(db_data_dir, 'preview.jpeg')) + else: + original_chunk_writer = ZipChunkWriter(100) + for chunk_idx, chunk_image_ids in enumerate(slice_by_size(range(size), chunk_size)): + chunk_images = [] + for image_id in chunk_image_ids: + image_path = get_frame_path(old_task_data_dir, image_id) + chunk_images.append((image_path, image_path)) + + original_chunk_path = os.path.join(original_cache_dir, '{}.zip'.format(chunk_idx)) + original_chunk_writer.save_as_chunk(chunk_images, original_chunk_path) + + compressed_chunk_path = os.path.join(compressed_cache_dir, '{}.zip'.format(chunk_idx)) + os.symlink(original_chunk_path, compressed_chunk_path) + shutil.copyfile(get_frame_path(old_task_data_dir, image_id), os.path.join(db_data_dir, 'preview.jpeg')) + else: + reader = None + if os.path.exists(original_images[0]): # task created from images + reader = ImageListReader(original_images) + else: # task created from archive or pdf + archives = [] + pdfs = [] + zips = [] + for p in glob.iglob(os.path.join(db_data_dir, 'raw', '**', '*'), recursive=True): + mime_type = get_mime(p) + if mime_type == 'archive': + archives.append(p) + elif mime_type == 'pdf': + pdfs.append(p) + elif mime_type == 'zip': + zips.append(p) + if archives: + reader = ArchiveReader(archives, get_frame_step(frame_filter), start_frame, stop_frame) + elif zips: + reader = ZipReader(archives, get_frame_step(frame_filter), start_frame, stop_frame) + elif pdfs: + reader = PdfReader(pdfs, get_frame_step(frame_filter), start_frame, stop_frame) + + if not reader: + original_chunk_writer = ZipChunkWriter(100) + for chunk_idx, chunk_image_ids in enumerate(slice_by_size(range(size), chunk_size)): + chunk_images = [] + for image_id in chunk_image_ids: + image_path = get_frame_path(old_task_data_dir, image_id) + chunk_images.append((image_path, image_path)) + + original_chunk_path = os.path.join(original_cache_dir, '{}.zip'.format(chunk_idx)) + original_chunk_writer.save_as_chunk(chunk_images, original_chunk_path) + + compressed_chunk_path = os.path.join(compressed_cache_dir, '{}.zip'.format(chunk_idx)) + os.symlink(original_chunk_path, compressed_chunk_path) + shutil.copyfile(get_frame_path(old_task_data_dir, image_id), os.path.join(db_data_dir, 'preview.jpeg')) + else: + original_chunk_writer = ZipChunkWriter(100) + compressed_chunk_writer = ZipCompressedChunkWriter(image_quality) + + for chunk_idx, chunk_images in enumerate(reader.slice_by_size(chunk_size)): + compressed_chunk_path = os.path.join(compressed_cache_dir, '{}.zip'.format(chunk_idx)) + compressed_chunk_writer.save_as_chunk(chunk_images, compressed_chunk_path) + + original_chunk_path = os.path.join(original_cache_dir, '{}.zip'.format(chunk_idx)) + original_chunk_writer.save_as_chunk(chunk_images, original_chunk_path) + + reader.save_preview(os.path.join(db_data_dir, 'preview.jpeg')) + shutil.rmtree(old_db_task_dir) + return_dict[db_task_id] = (True, '') + except Exception as e: + traceback.print_exc(file=sys.stderr) + return_dict[db_task_id] = (False, str(e)) + return 0 + +def migrate_task_schema(db_task, Data, log): + log.info('Start schema migration of task ID {}.'.format(db_task.id)) + try: + # create folders + new_task_dir = os.path.join(settings.TASKS_ROOT, str(db_task.id)) + os.makedirs(new_task_dir, exist_ok=True) + os.makedirs(os.path.join(new_task_dir, 'artifacts'), exist_ok=True) + new_task_logs_dir = os.path.join(new_task_dir, 'logs') + os.makedirs(new_task_logs_dir, exist_ok=True) + + # create Data object + db_data = Data.objects.create( + size=db_task.size, + image_quality=db_task.image_quality, + start_frame=db_task.start_frame, + stop_frame=db_task.stop_frame, + frame_filter=db_task.frame_filter, + compressed_chunk_type = DataChoice.IMAGESET, + original_chunk_type = DataChoice.VIDEO if db_task.mode == 'interpolation' else DataChoice.IMAGESET, + ) + db_data.save() + + db_task.data = db_data + + db_data_dir = os.path.join(settings.MEDIA_DATA_ROOT, str(db_data.id)) + os.makedirs(db_data_dir, exist_ok=True) + compressed_cache_dir = os.path.join(db_data_dir, 'compressed') + os.makedirs(compressed_cache_dir, exist_ok=True) + + original_cache_dir = os.path.join(db_data_dir, 'original') + os.makedirs(original_cache_dir, exist_ok=True) + + old_db_task_dir = os.path.join(settings.DATA_ROOT, str(db_task.id)) + + # move logs + for log_file in ('task.log', 'client.log'): + task_log_file = os.path.join(old_db_task_dir, log_file) + if os.path.isfile(task_log_file): + shutil.move(task_log_file, new_task_logs_dir) + + if hasattr(db_task, 'video'): + db_task.video.data = db_data + db_task.video.path = fix_path(db_task.video.path) + db_task.video.save() + + for db_image in db_task.image_set.all(): + db_image.data = db_data + db_image.path = fix_path(db_image.path) + db_image.save() + + old_raw_dir = os.path.join(old_db_task_dir, '.upload') + new_raw_dir = os.path.join(db_data_dir, 'raw') + + for client_file in db_task.clientfile_set.all(): + client_file.file = client_file.file.path.replace(old_raw_dir, new_raw_dir) + client_file.save() + + for server_file in db_task.serverfile_set.all(): + server_file.file = server_file.file.replace(old_raw_dir, new_raw_dir) + server_file.save() + + for remote_file in db_task.remotefile_set.all(): + remote_file.file = remote_file.file.replace(old_raw_dir, new_raw_dir) + remote_file.save() + + db_task.save() + + #move old raw data + if os.path.exists(old_raw_dir): + shutil.move(old_raw_dir, new_raw_dir) + + return (db_task.id, db_data.id) + + except Exception as e: + log.error('Cannot migrate schema for the task: {}'.format(db_task.id)) + log.error(str(e)) + traceback.print_exc(file=sys.stderr) + +def create_data_objects(apps, schema_editor): + migration_name = os.path.splitext(os.path.basename(__file__))[0] + migration_log_file = '{}.log'.format(migration_name) + stdout = sys.stdout + stderr = sys.stderr + # redirect all stdout to the file + log_file_object = open(os.path.join(settings.MIGRATIONS_LOGS_ROOT, migration_log_file), 'w') + sys.stdout = log_file_object + sys.stderr = log_file_object + + log = logging.getLogger(migration_name) + log.addHandler(logging.StreamHandler(stdout)) + log.addHandler(logging.StreamHandler(log_file_object)) + log.setLevel(logging.INFO) + + disk_tasks = get_task_on_disk() + + Task = apps.get_model('engine', 'Task') + Data = apps.get_model('engine', 'Data') + + db_tasks = Task.objects + task_count = db_tasks.count() + log.info('\nStart schema migration...') + migrated_db_tasks = [] + for counter, db_task in enumerate(db_tasks.all().iterator()): + res = migrate_task_schema(db_task, Data, log) + log.info('Schema migration for the task {} completed. Progress {}/{}'.format(db_task.id, counter+1, task_count)) + if res: + migrated_db_tasks.append(res) + + log.info('\nSchema migration is finished...') + log.info('\nStart data migration...') + + manager = multiprocessing.Manager() + return_dict = manager.dict() + + def create_process(db_task_id, db_data_id): + db_data = Data.objects.get(pk=db_data_id) + db_data_dir = os.path.join(settings.MEDIA_DATA_ROOT, str(db_data_id)) + new_raw_dir = os.path.join(db_data_dir, 'raw') + + original_video = None + original_images = None + if hasattr(db_data, 'video'): + original_video = os.path.join(new_raw_dir, db_data.video.path) + else: + original_images = [os.path.realpath(os.path.join(new_raw_dir, db_image.path)) for db_image in db_data.images.all()] + + args = (db_task_id, db_data_id, original_video, original_images, db_data.size, + db_data.start_frame, db_data.stop_frame, db_data.frame_filter, db_data.image_quality, db_data.chunk_size, return_dict) + + return multiprocessing.Process(target=migrate_task_data, args=args) + + results = {} + task_idx = 0 + while True: + for res_idx in list(results.keys()): + res = results[res_idx] + if not res.is_alive(): + del results[res_idx] + if res.exitcode == 0: + ret_code, message = return_dict[res_idx] + if ret_code: + counter = (task_idx - len(results)) + progress = (100 * counter) / task_count + log.info('Data migration for the task {} completed. Progress: {:.02f}% | {}/{}.'.format(res_idx, progress, counter, task_count)) + else: + log.error('Cannot migrate data for the task: {}'.format(res_idx)) + log.error(str(message)) + if res_idx in disk_tasks: + disk_tasks.remove(res_idx) + else: + log.error('#Cannot migrate data for the task: {}'.format(res_idx)) + + while task_idx < len(migrated_db_tasks) and len(results) < MIGRATION_THREAD_COUNT: + log.info('Start data migration for the task {}, data ID {}'.format(migrated_db_tasks[task_idx][0], migrated_db_tasks[task_idx][1])) + results[migrated_db_tasks[task_idx][0]] = create_process(*migrated_db_tasks[task_idx]) + results[migrated_db_tasks[task_idx][0]].start() + task_idx += 1 + + if len(results) == 0: + break + + time.sleep(5) + + if disk_tasks: + suspicious_tasks_dir = os.path.join(settings.DATA_ROOT, 'suspicious_tasks') + os.makedirs(suspicious_tasks_dir, exist_ok=True) + for tid in disk_tasks: + suspicious_task_path = os.path.join(settings.DATA_ROOT, str(tid)) + try: + shutil.move(suspicious_task_path, suspicious_tasks_dir) + except Exception as e: + log.error('Cannot move data for the suspicious task {}, \ + that is not represented in the database.'.format(suspicious_task_path)) + log.error(str(e)) + + # DL models migration + if apps.is_installed('auto_annotation'): + DLModel = apps.get_model('auto_annotation', 'AnnotationModel') + + for db_model in DLModel.objects.all(): + try: + old_location = os.path.join(settings.BASE_DIR, 'models', str(db_model.id)) + new_location = os.path.join(settings.BASE_DIR, 'data', 'models', str(db_model.id)) + + if os.path.isdir(old_location): + shutil.move(old_location, new_location) + + db_model.model_file.name = db_model.model_file.name.replace(old_location, new_location) + db_model.weights_file.name = db_model.weights_file.name.replace(old_location, new_location) + db_model.labelmap_file.name = db_model.labelmap_file.name.replace(old_location, new_location) + db_model.interpretation_file.name = db_model.interpretation_file.name.replace(old_location, new_location) + + db_model.save() + except Exception as e: + log.error('Cannot migrate data for the DL model: {}'.format(db_model.id)) + log.error(str(e)) + + log_file_object.close() + sys.stdout = stdout + sys.stderr = stderr + +class Migration(migrations.Migration): + + dependencies = [ + ('engine', '0023_auto_20200113_1323'), + ] + + operations = [ + migrations.CreateModel( + name='Data', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('chunk_size', models.PositiveIntegerField(default=36)), + ('size', models.PositiveIntegerField(default=0)), + ('image_quality', models.PositiveSmallIntegerField(default=50)), + ('start_frame', models.PositiveIntegerField(default=0)), + ('stop_frame', models.PositiveIntegerField(default=0)), + ('frame_filter', models.CharField(blank=True, default='', max_length=256)), + ('compressed_chunk_type', models.CharField(choices=[('video', 'VIDEO'), ('imageset', 'IMAGESET'), ('list', 'LIST')], default=DataChoice('imageset'), max_length=32)), + ('original_chunk_type', models.CharField(choices=[('video', 'VIDEO'), ('imageset', 'IMAGESET'), ('list', 'LIST')], default=DataChoice('imageset'), max_length=32)), + ], + options={ + 'default_permissions': (), + }, + ), + migrations.AddField( + model_name='task', + name='data', + field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='tasks', to='engine.Data'), + ), + migrations.AddField( + model_name='image', + name='data', + field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='images', to='engine.Data'), + ), + migrations.AddField( + model_name='video', + name='data', + field=models.OneToOneField(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='video', to='engine.Data'), + ), + migrations.AddField( + model_name='clientfile', + name='data', + field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='client_files', to='engine.Data'), + ), + migrations.AddField( + model_name='remotefile', + name='data', + field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='remote_files', to='engine.Data'), + ), + migrations.AddField( + model_name='serverfile', + name='data', + field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='server_files', to='engine.Data'), + ), + migrations.RunPython( + code=create_data_objects + ), + migrations.RemoveField( + model_name='image', + name='task', + ), + migrations.RemoveField( + model_name='remotefile', + name='task', + ), + migrations.RemoveField( + model_name='serverfile', + name='task', + ), + migrations.RemoveField( + model_name='task', + name='frame_filter', + ), + migrations.RemoveField( + model_name='task', + name='image_quality', + ), + migrations.RemoveField( + model_name='task', + name='size', + ), + migrations.RemoveField( + model_name='task', + name='start_frame', + ), + migrations.RemoveField( + model_name='task', + name='stop_frame', + ), + migrations.RemoveField( + model_name='video', + name='task', + ), + migrations.AlterField( + model_name='image', + name='path', + field=models.CharField(default='', max_length=1024), + ), + migrations.AlterField( + model_name='video', + name='path', + field=models.CharField(default='', max_length=1024), + ), + migrations.AlterUniqueTogether( + name='clientfile', + unique_together={('data', 'file')}, + ), + migrations.RemoveField( + model_name='clientfile', + name='task', + ), + ] diff --git a/cvat/apps/engine/migrations/0025_auto_20200324_1222.py b/cvat/apps/engine/migrations/0025_auto_20200324_1222.py new file mode 100644 index 00000000..dd908d52 --- /dev/null +++ b/cvat/apps/engine/migrations/0025_auto_20200324_1222.py @@ -0,0 +1,18 @@ +# Generated by Django 2.2.10 on 2020-03-24 12:22 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('engine', '0024_auto_20191023_1025'), + ] + + operations = [ + migrations.AlterField( + model_name='data', + name='chunk_size', + field=models.PositiveIntegerField(null=True), + ), + ] diff --git a/cvat/apps/engine/mime_types.py b/cvat/apps/engine/mime_types.py new file mode 100644 index 00000000..d4a08302 --- /dev/null +++ b/cvat/apps/engine/mime_types.py @@ -0,0 +1,13 @@ +# Copyright (C) 2019 Intel Corporation +# +# SPDX-License-Identifier: MIT + +import os +import mimetypes + + +_SCRIPT_DIR = os.path.realpath(os.path.dirname(__file__)) +MEDIA_MIMETYPES_FILES = [ + os.path.join(_SCRIPT_DIR, "media.mimetypes"), +] +mimetypes.init(files=MEDIA_MIMETYPES_FILES) diff --git a/cvat/apps/engine/models.py b/cvat/apps/engine/models.py index a513cf5a..c43c12c5 100644 --- a/cvat/apps/engine/models.py +++ b/cvat/apps/engine/models.py @@ -1,11 +1,9 @@ -# Copyright (C) 2018 Intel Corporation +# Copyright (C) 2018-2019 Intel Corporation # # SPDX-License-Identifier: MIT from enum import Enum - import re -import shlex import os from django.db import models @@ -27,12 +25,102 @@ class StatusChoice(str, Enum): COMPLETED = 'completed' @classmethod - def choices(self): - return tuple((x.value, x.name) for x in self) + def choices(cls): + return tuple((x.value, x.name) for x in cls) def __str__(self): return self.value +class DataChoice(str, Enum): + VIDEO = 'video' + IMAGESET = 'imageset' + LIST = 'list' + + @classmethod + def choices(cls): + return tuple((x.value, x.name) for x in cls) + + def __str__(self): + return self.value + +class Data(models.Model): + chunk_size = models.PositiveIntegerField(null=True) + size = models.PositiveIntegerField(default=0) + image_quality = models.PositiveSmallIntegerField(default=50) + start_frame = models.PositiveIntegerField(default=0) + stop_frame = models.PositiveIntegerField(default=0) + frame_filter = models.CharField(max_length=256, default="", blank=True) + compressed_chunk_type = models.CharField(max_length=32, choices=DataChoice.choices(), + default=DataChoice.IMAGESET) + original_chunk_type = models.CharField(max_length=32, choices=DataChoice.choices(), + default=DataChoice.IMAGESET) + + class Meta: + default_permissions = () + + def get_frame_step(self): + match = re.search("step\s*=\s*([1-9]\d*)", self.frame_filter) + return int(match.group(1)) if match else 1 + + def get_data_dirname(self): + return os.path.join(settings.MEDIA_DATA_ROOT, str(self.id)) + + def get_upload_dirname(self): + return os.path.join(self.get_data_dirname(), "raw") + + def get_compressed_cache_dirname(self): + return os.path.join(self.get_data_dirname(), "compressed") + + def get_original_cache_dirname(self): + return os.path.join(self.get_data_dirname(), "original") + + @staticmethod + def _get_chunk_name(chunk_number, chunk_type): + if chunk_type == DataChoice.VIDEO: + ext = 'mp4' + elif chunk_type == DataChoice.IMAGESET: + ext = 'zip' + else: + ext = 'list' + + return '{}.{}'.format(chunk_number, ext) + + def _get_compressed_chunk_name(self, chunk_number): + return self._get_chunk_name(chunk_number, self.compressed_chunk_type) + + def _get_original_chunk_name(self, chunk_number): + return self._get_chunk_name(chunk_number, self.original_chunk_type) + + def get_original_chunk_path(self, chunk_number): + return os.path.join(self.get_original_cache_dirname(), + self._get_original_chunk_name(chunk_number)) + + def get_compressed_chunk_path(self, chunk_number): + return os.path.join(self.get_compressed_cache_dirname(), + self._get_compressed_chunk_name(chunk_number)) + + def get_preview_path(self): + return os.path.join(self.get_data_dirname(), 'preview.jpeg') + +class Video(models.Model): + data = models.OneToOneField(Data, on_delete=models.CASCADE, related_name="video", null=True) + path = models.CharField(max_length=1024, default='') + width = models.PositiveIntegerField() + height = models.PositiveIntegerField() + + class Meta: + default_permissions = () + +class Image(models.Model): + data = models.ForeignKey(Data, on_delete=models.CASCADE, related_name="images", null=True) + path = models.CharField(max_length=1024, default='') + frame = models.PositiveIntegerField() + width = models.PositiveIntegerField() + height = models.PositiveIntegerField() + + class Meta: + default_permissions = () + class Project(models.Model): name = SafeCharField(max_length=256) owner = models.ForeignKey(User, null=True, blank=True, @@ -54,7 +142,6 @@ class Task(models.Model): null=True, blank=True, related_name="tasks", related_query_name="task") name = SafeCharField(max_length=256) - size = models.PositiveIntegerField() mode = models.CharField(max_length=32) owner = models.ForeignKey(User, null=True, blank=True, on_delete=models.SET_NULL, related_name="owners") @@ -67,52 +154,28 @@ class Task(models.Model): # Zero means that there are no limits (default) segment_size = models.PositiveIntegerField(default=0) z_order = models.BooleanField(default=False) - image_quality = models.PositiveSmallIntegerField(default=50) - start_frame = models.PositiveIntegerField(default=0) - stop_frame = models.PositiveIntegerField(default=0) - frame_filter = models.CharField(max_length=256, default="", blank=True) status = models.CharField(max_length=32, choices=StatusChoice.choices(), default=StatusChoice.ANNOTATION) + data = models.ForeignKey(Data, on_delete=models.CASCADE, null=True, related_name="tasks") # Extend default permission model class Meta: default_permissions = () - def get_frame_path(self, frame): - d1 = str(int(frame) // 10000) - d2 = str(int(frame) // 100) - path = os.path.join(self.get_data_dirname(), d1, d2, - str(frame) + '.jpg') - - return path - - @staticmethod - def get_image_frame(image_path): - assert image_path.endswith('.jpg') - index = os.path.splitext(os.path.basename(image_path))[0] - return int(index) - - def get_frame_step(self): - match = re.search("step\s*=\s*([1-9]\d*)", self.frame_filter) - return int(match.group(1)) if match else 1 - - def get_upload_dirname(self): - return os.path.join(self.get_task_dirname(), ".upload") - - def get_data_dirname(self): - return os.path.join(self.get_task_dirname(), "data") + def get_task_dirname(self): + return os.path.join(settings.TASKS_ROOT, str(self.id)) - def get_log_path(self): - return os.path.join(self.get_task_dirname(), "task.log") + def get_task_logs_dirname(self): + return os.path.join(self.get_task_dirname(), 'logs') def get_client_log_path(self): - return os.path.join(self.get_task_dirname(), "client.log") + return os.path.join(self.get_task_logs_dirname(), "client.log") - def get_image_meta_cache_path(self): - return os.path.join(self.get_task_dirname(), "image_meta.cache") + def get_log_path(self): + return os.path.join(self.get_task_logs_dirname(), "task.log") - def get_task_dirname(self): - return os.path.join(settings.DATA_ROOT, str(self.id)) + def get_task_artifacts_dirname(self): + return os.path.join(self.get_task_dirname(), 'artifacts') def __str__(self): return self.name @@ -129,21 +192,21 @@ class MyFileSystemStorage(FileSystemStorage): return name def upload_path_handler(instance, filename): - return os.path.join(instance.task.get_upload_dirname(), filename) + return os.path.join(instance.data.get_upload_dirname(), filename) # For client files which the user is uploaded class ClientFile(models.Model): - task = models.ForeignKey(Task, on_delete=models.CASCADE) + data = models.ForeignKey(Data, on_delete=models.CASCADE, null=True, related_name='client_files') file = models.FileField(upload_to=upload_path_handler, max_length=1024, storage=MyFileSystemStorage()) class Meta: default_permissions = () - unique_together = ("task", "file") + unique_together = ("data", "file") # For server files on the mounted share class ServerFile(models.Model): - task = models.ForeignKey(Task, on_delete=models.CASCADE) + data = models.ForeignKey(Data, on_delete=models.CASCADE, null=True, related_name='server_files') file = models.CharField(max_length=1024) class Meta: @@ -151,31 +214,12 @@ class ServerFile(models.Model): # For URLs class RemoteFile(models.Model): - task = models.ForeignKey(Task, on_delete=models.CASCADE) + data = models.ForeignKey(Data, on_delete=models.CASCADE, null=True, related_name='remote_files') file = models.CharField(max_length=1024) class Meta: default_permissions = () -class Video(models.Model): - task = models.OneToOneField(Task, on_delete=models.CASCADE) - path = models.CharField(max_length=1024) - width = models.PositiveIntegerField() - height = models.PositiveIntegerField() - - class Meta: - default_permissions = () - -class Image(models.Model): - task = models.ForeignKey(Task, on_delete=models.CASCADE) - path = models.CharField(max_length=1024) - frame = models.PositiveIntegerField() - width = models.PositiveIntegerField() - height = models.PositiveIntegerField() - - class Meta: - default_permissions = () - class Segment(models.Model): task = models.ForeignKey(Task, on_delete=models.CASCADE) start_frame = models.IntegerField() @@ -212,8 +256,8 @@ class AttributeType(str, Enum): SELECT = 'select' @classmethod - def choices(self): - return tuple((x.value, x.name) for x in self) + def choices(cls): + return tuple((x.value, x.name) for x in cls) def __str__(self): return self.value @@ -252,8 +296,8 @@ class ShapeType(str, Enum): CUBOID = 'cuboid' @classmethod - def choices(self): - return tuple((x.value, x.name) for x in self) + def choices(cls): + return tuple((x.value, x.name) for x in cls) def __str__(self): return self.value diff --git a/cvat/apps/engine/serializers.py b/cvat/apps/engine/serializers.py index e225dd23..da0cd5d7 100644 --- a/cvat/apps/engine/serializers.py +++ b/cvat/apps/engine/serializers.py @@ -80,7 +80,7 @@ class ClientFileSerializer(serializers.ModelSerializer): # pylint: disable=no-self-use def to_representation(self, instance): if instance: - upload_dir = instance.task.get_upload_dirname() + upload_dir = instance.data.get_upload_dirname() return instance.file.path[len(upload_dir) + 1:] else: return instance @@ -116,38 +116,6 @@ class RqStatusSerializer(serializers.Serializer): "Queued", "Started", "Finished", "Failed"]) message = serializers.CharField(allow_blank=True, default="") -class TaskDataSerializer(serializers.ModelSerializer): - client_files = ClientFileSerializer(many=True, source='clientfile_set', - default=[]) - server_files = ServerFileSerializer(many=True, source='serverfile_set', - default=[]) - remote_files = RemoteFileSerializer(many=True, source='remotefile_set', - default=[]) - - class Meta: - model = models.Task - fields = ('client_files', 'server_files', 'remote_files') - - # pylint: disable=no-self-use - def update(self, instance, validated_data): - client_files = validated_data.pop('clientfile_set') - server_files = validated_data.pop('serverfile_set') - remote_files = validated_data.pop('remotefile_set') - - for file in client_files: - client_file = models.ClientFile(task=instance, **file) - client_file.save() - - for file in server_files: - server_file = models.ServerFile(task=instance, **file) - server_file.save() - - for file in remote_files: - remote_file = models.RemoteFile(task=instance, **file) - remote_file.save() - - return instance - class WriteOnceMixin: """Adds support for write once fields to serializers. @@ -193,36 +161,93 @@ class WriteOnceMixin: return extra_kwargs -class TaskSerializer(WriteOnceMixin, serializers.ModelSerializer): - labels = LabelSerializer(many=True, source='label_set', partial=True) - segments = SegmentSerializer(many=True, source='segment_set', read_only=True) +class DataSerializer(serializers.ModelSerializer): image_quality = serializers.IntegerField(min_value=0, max_value=100) + use_zip_chunks = serializers.BooleanField(default=False) + client_files = ClientFileSerializer(many=True, default=[]) + server_files = ServerFileSerializer(many=True, default=[]) + remote_files = RemoteFileSerializer(many=True, default=[]) class Meta: - model = models.Task - fields = ('url', 'id', 'name', 'size', 'mode', 'owner', 'assignee', - 'bug_tracker', 'created_date', 'updated_date', 'overlap', - 'segment_size', 'z_order', 'status', 'labels', 'segments', - 'image_quality', 'start_frame', 'stop_frame', 'frame_filter', - 'project') - read_only_fields = ('size', 'mode', 'created_date', 'updated_date', - 'status') - write_once_fields = ('overlap', 'segment_size', 'image_quality') - ordering = ['-id'] + model = models.Data + fields = ('chunk_size', 'size', 'image_quality', 'start_frame', 'stop_frame', 'frame_filter', + 'compressed_chunk_type', 'original_chunk_type', 'client_files', 'server_files', 'remote_files', 'use_zip_chunks') + # pylint: disable=no-self-use def validate_frame_filter(self, value): match = re.search("step\s*=\s*([1-9]\d*)", value) if not match: raise serializers.ValidationError("Invalid frame filter expression") return value + # pylint: disable=no-self-use + def validate_chunk_size(self, value): + if not value > 0: + raise serializers.ValidationError('Chunk size must be a positive integer') + return value + + # pylint: disable=no-self-use + def validate(self, data): + if 'start_frame' in data and 'stop_frame' in data \ + and data['start_frame'] > data['stop_frame']: + raise serializers.ValidationError('Stop frame must be more or equal start frame') + return data + + # pylint: disable=no-self-use + def create(self, validated_data): + client_files = validated_data.pop('client_files') + server_files = validated_data.pop('server_files') + remote_files = validated_data.pop('remote_files') + validated_data.pop('use_zip_chunks') + db_data = models.Data.objects.create(**validated_data) + + data_path = db_data.get_data_dirname() + if os.path.isdir(data_path): + shutil.rmtree(data_path) + + os.makedirs(db_data.get_compressed_cache_dirname()) + os.makedirs(db_data.get_original_cache_dirname()) + + for f in client_files: + client_file = models.ClientFile(data=db_data, **f) + client_file.save() + + for f in server_files: + server_file = models.ServerFile(data=db_data, **f) + server_file.save() + + for f in remote_files: + remote_file = models.RemoteFile(data=db_data, **f) + remote_file.save() + + db_data.save() + return db_data + +class TaskSerializer(WriteOnceMixin, serializers.ModelSerializer): + labels = LabelSerializer(many=True, source='label_set', partial=True) + segments = SegmentSerializer(many=True, source='segment_set', read_only=True) + data_chunk_size = serializers.ReadOnlyField(source='data.chunk_size') + data_compressed_chunk_type = serializers.ReadOnlyField(source='data.compressed_chunk_type') + data_original_chunk_type = serializers.ReadOnlyField(source='data.original_chunk_type') + size = serializers.ReadOnlyField(source='data.size') + image_quality = serializers.ReadOnlyField(source='data.image_quality') + data = serializers.ReadOnlyField(source='data.id') + + class Meta: + model = models.Task + fields = ('url', 'id', 'name', 'mode', 'owner', 'assignee', + 'bug_tracker', 'created_date', 'updated_date', 'overlap', + 'segment_size', 'z_order', 'status', 'labels', 'segments', + 'project', 'data_chunk_size', 'data_compressed_chunk_type', 'data_original_chunk_type', 'size', 'image_quality', 'data') + read_only_fields = ('mode', 'created_date', 'updated_date', 'status', 'data_chunk_size', + 'data_compressed_chunk_type', 'data_original_chunk_type', 'size', 'image_quality', 'data') + write_once_fields = ('overlap', 'segment_size') + ordering = ['-id'] + # pylint: disable=no-self-use def create(self, validated_data): labels = validated_data.pop('label_set') - db_task = models.Task.objects.create(size=0, **validated_data) - db_task.start_frame = validated_data.get('start_frame', 0) - db_task.stop_frame = validated_data.get('stop_frame', 0) - db_task.frame_filter = validated_data.get('frame_filter', '') + db_task = models.Task.objects.create(**validated_data) for label in labels: attributes = label.pop('attributespec_set') db_label = models.Label.objects.create(task=db_task, **label) @@ -233,11 +258,10 @@ class TaskSerializer(WriteOnceMixin, serializers.ModelSerializer): if os.path.isdir(task_path): shutil.rmtree(task_path) - upload_dir = db_task.get_upload_dirname() - os.makedirs(upload_dir) - output_dir = db_task.get_data_dirname() - os.makedirs(output_dir) + os.makedirs(db_task.get_task_logs_dirname()) + os.makedirs(db_task.get_task_artifacts_dirname()) + db_task.save() return db_task # pylint: disable=no-self-use @@ -248,11 +272,6 @@ class TaskSerializer(WriteOnceMixin, serializers.ModelSerializer): instance.bug_tracker = validated_data.get('bug_tracker', instance.bug_tracker) instance.z_order = validated_data.get('z_order', instance.z_order) - instance.image_quality = validated_data.get('image_quality', - instance.image_quality) - instance.start_frame = validated_data.get('start_frame', instance.start_frame) - instance.stop_frame = validated_data.get('stop_frame', instance.stop_frame) - instance.frame_filter = validated_data.get('frame_filter', instance.frame_filter) instance.project = validated_data.get('project', instance.project) labels = validated_data.get('label_set', []) for label in labels: @@ -346,9 +365,35 @@ class AboutSerializer(serializers.Serializer): description = serializers.CharField(max_length=2048) version = serializers.CharField(max_length=64) -class ImageMetaSerializer(serializers.Serializer): +class FrameMetaSerializer(serializers.Serializer): width = serializers.IntegerField() height = serializers.IntegerField() + name = serializers.CharField(max_length=1024) + +class DataMetaSerializer(serializers.ModelSerializer): + frames = FrameMetaSerializer(many=True, allow_null=True) + image_quality = serializers.IntegerField(min_value=0, max_value=100) + + class Meta: + model = models.Data + fields = ( + 'chunk_size', + 'size', + 'image_quality', + 'start_frame', + 'stop_frame', + 'frame_filter', + 'frames', + ) + read_only_fields = ( + 'chunk_size', + 'size', + 'image_quality', + 'start_frame', + 'stop_frame', + 'frame_filter', + 'frames', + ) class AttributeValSerializer(serializers.Serializer): spec_id = serializers.IntegerField() diff --git a/cvat/apps/engine/static/engine/js/3rdparty/Decoder.worker.js b/cvat/apps/engine/static/engine/js/3rdparty/Decoder.worker.js new file mode 100644 index 00000000..23f3206a --- /dev/null +++ b/cvat/apps/engine/static/engine/js/3rdparty/Decoder.worker.js @@ -0,0 +1,2 @@ +!function(e){var n={};function t(r){if(n[r])return n[r].exports;var a=n[r]={i:r,l:!1,exports:{}};return e[r].call(a.exports,a,a.exports,t),a.l=!0,a.exports}t.m=e,t.c=n,t.d=function(e,n,r){t.o(e,n)||Object.defineProperty(e,n,{enumerable:!0,get:r})},t.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},t.t=function(e,n){if(1&n&&(e=t(e)),8&n)return e;if(4&n&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(t.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&n&&"string"!=typeof e)for(var a in e)t.d(r,a,function(n){return e[n]}.bind(null,a));return r},t.n=function(e){var n=e&&e.__esModule?function(){return e.default}:function(){return e};return t.d(n,"a",n),n},t.o=function(e,n){return Object.prototype.hasOwnProperty.call(e,n)},t.p="",t(t.s=0)}([function(e,n,t){var r,a,i;a=[],void 0===(i="function"==typeof(r=function(){var e;!function(){(e=this)||("undefined"!=typeof window?e=window:"undefined"!=typeof self&&(e=self))}();var n=function(n,t){var r,a=void 0!==a?a:{},i={};for(r in a)a.hasOwnProperty(r)&&(i[r]=a[r]);var o,f=[],u=!1,s=!0,c="";(u||s)&&(s?c=self.location.href:document.currentScript&&(c=document.currentScript.src),c=0!==c.indexOf("blob:")?c.substr(0,c.lastIndexOf("/")+1):"",s&&(o=function(e){var n=new XMLHttpRequest;return n.open("GET",e,!1),n.responseType="arraybuffer",n.send(null),new Uint8Array(n.response)}));var d=a.print||console.log.bind(console),l=a.printErr||console.warn.bind(console);for(r in i)i.hasOwnProperty(r)&&(a[r]=i[r]);i=null,a.arguments&&(f=a.arguments),a.thisProgram&&a.thisProgram,a.quit&&a.quit;var p,y,h={"f64-rem":function(e,n){return e%n},debugger:function(){}};new Array(0),a.wasmBinary&&(p=a.wasmBinary),a.noExitRuntime&&a.noExitRuntime,"object"!=typeof WebAssembly&&l("no native wasm support detected");var v,m,g,b,w=new WebAssembly.Table({initial:10,maximum:10,element:"anyfunc"}),A=!1,M="undefined"!=typeof TextDecoder?new TextDecoder("utf8"):void 0;function P(e,n,t){for(var r=n+t,a=n;e[a]&&!(a>=r);)++a;if(a-n>16&&e.subarray&&M)return M.decode(e.subarray(n,a));for(var i="";n>10,56320|1023&s)}}else i+=String.fromCharCode((31&o)<<6|f)}else i+=String.fromCharCode(o)}return i}"undefined"!=typeof TextDecoder&&new TextDecoder("utf-16le");var D,S=a.TOTAL_MEMORY||104857600;function _(e){for(;e.length>0;){var n=e.shift();if("function"!=typeof n){var t=n.func;"number"==typeof t?void 0===n.arg?a.dynCall_v(t):a.dynCall_vi(t,n.arg):t(void 0===n.arg?null:n.arg)}else n()}}(y=a.wasmMemory?a.wasmMemory:new WebAssembly.Memory({initial:S/65536,maximum:S/65536}))&&(v=y.buffer),S=v.byteLength,v=D=v,a.HEAP8=m=new Int8Array(D),a.HEAP16=new Int16Array(D),a.HEAP32=b=new Int32Array(D),a.HEAPU8=g=new Uint8Array(D),a.HEAPU16=new Uint16Array(D),a.HEAPU32=new Uint32Array(D),a.HEAPF32=new Float32Array(D),a.HEAPF64=new Float64Array(D),b[2748]=5254064;var R=[],U=[],E=[],I=[],O=0,x=null,B=null;function C(e){throw a.onAbort&&a.onAbort(e),d(e+=""),l(e),A=!0,e="abort("+e+"). Build with -s ASSERTIONS=1 for more info.",new WebAssembly.RuntimeError(e)}a.preloadedImages={},a.preloadedAudios={};var H="data:application/octet-stream;base64,";function T(e){return String.prototype.startsWith?e.startsWith(H):0===e.indexOf(H)}var W,j="avc.wasm";function F(){try{if(p)return new Uint8Array(p);if(o)return o(j);throw"both async and sync fetching of the wasm failed"}catch(e){C(e)}}T(j)||(W=j,j=a.locateFile?a.locateFile(W,c):c+W),a.asm=function(){var e={env:V,wasi_unstable:V,global:{NaN:NaN,Infinity:1/0},"global.Math":Math,asm2wasm:h};function n(e,n){var t=e.exports;a.asm=t,function(e){if(O--,a.monitorRunDependencies&&a.monitorRunDependencies(O),0==O&&(null!==x&&(clearInterval(x),x=null),B)){var n=B;B=null,n()}}()}function t(e){n(e.instance)}function r(n){return(p||!u&&!s||"function"!=typeof fetch?new Promise((function(e,n){e(F())})):fetch(j,{credentials:"same-origin"}).then((function(e){if(!e.ok)throw"failed to load wasm binary file at '"+j+"'";return e.arrayBuffer()})).catch((function(){return F()}))).then((function(n){return WebAssembly.instantiate(n,e)})).then(n,(function(e){l("failed to asynchronously prepare wasm: "+e),C(e)}))}if(O++,a.monitorRunDependencies&&a.monitorRunDependencies(O),a.instantiateWasm)try{return a.instantiateWasm(e,n)}catch(e){return l("Module.instantiateWasm callback failed with error: "+e),!1}return function(){if(p||"function"!=typeof WebAssembly.instantiateStreaming||T(j)||"function"!=typeof fetch)return r(t);fetch(j,{credentials:"same-origin"}).then((function(n){return WebAssembly.instantiateStreaming(n,e).then(t,(function(e){l("wasm streaming compile failed: "+e),l("falling back to ArrayBuffer instantiation"),r(t)}))}))}(),{}};var N={buffers:[null,[],[]],printChar:function(e,n){var t=N.buffers[e];0===n||10===n?((1===e?d:l)(P(t,0)),t.length=0):t.push(n)},varargs:0,get:function(e){return N.varargs+=4,b[N.varargs-4>>2]},getStr:function(){var e,n;return(e=N.get())?P(g,e,n):""},get64:function(){var e=N.get();return N.get(),e},getZero:function(){N.get()}};function k(e,n,t,r){try{for(var a=0,i=0;i>2],f=b[n+(8*i+4)>>2],u=0;u>2]=a,0}catch(e){return"undefined"!=typeof FS&&e instanceof FS.ErrnoError||C(e),e.errno}}function z(){n()}function L(e,n,r){t(e,n,r)}a._broadwayOnHeadersDecoded=z,a._broadwayOnPictureDecoded=L;var q,G,V={g:function(){return k.apply(null,arguments)},__memory_base:1024,__table_base:0,f:z,e:L,b:function(){return m.length},d:function(e,n,t){g.set(g.subarray(n,n+t),e)},a:function(e){C("OOM")},c:C,memory:y,table:w},X=a.asm({},V,v);function Y(e){function n(){q||(q=!0,A||(_(U),_(E),a.onRuntimeInitialized&&a.onRuntimeInitialized(),function(){if(a.postRun)for("function"==typeof a.postRun&&(a.postRun=[a.postRun]);a.postRun.length;)e=a.postRun.shift(),I.unshift(e);var e;_(I)}()))}e=e||f,O>0||(function(){if(a.preRun)for("function"==typeof a.preRun&&(a.preRun=[a.preRun]);a.preRun.length;)e=a.preRun.shift(),R.unshift(e);var e;_(R)}(),O>0||(a.setStatus?(a.setStatus("Running..."),setTimeout((function(){setTimeout((function(){a.setStatus("")}),1),n()}),1)):n()))}if(a.asm=X,a._broadwayCreateStream=function(){return a.asm.h.apply(null,arguments)},a._broadwayExit=function(){return a.asm.i.apply(null,arguments)},a._broadwayGetMajorVersion=function(){return a.asm.j.apply(null,arguments)},a._broadwayGetMinorVersion=function(){return a.asm.k.apply(null,arguments)},a._broadwayInit=function(){return a.asm.l.apply(null,arguments)},a._broadwayPlayStream=function(){return a.asm.m.apply(null,arguments)},a.asm=X,B=function e(){q||Y(),q||(B=e)},a.run=Y,a.preInit)for("function"==typeof a.preInit&&(a.preInit=[a.preInit]);a.preInit.length>0;)a.preInit.pop()();Y(),void 0!==e&&e.Module&&(G=e.Module),void 0!==a&&(G=a),G._broadwayOnHeadersDecoded=n,G._broadwayOnPictureDecoded=t;var Z,J=!1;return G.onRuntimeInitialized=function(){J=!0,Z&&Z(G)},function(e){J?e(G):Z=e}};return function(){"use strict";var t=function(){return(new Date).getTime()};"undefined"!=typeof performance&&performance.now&&(t=function(){return performance.now()});var r=function(e){var r;this.options=e||{},this.now=t;var a,o,f=function(e,n,o){var f,u=this.pictureBuffers[e];u||(u=this.pictureBuffers[e]=a(e,n*o*3/2));var s=!1;if(this.infoAr.length&&(s=!0,f=this.infoAr),this.infoAr=[],this.options.rgb){r||(r=i(n,o)),r.inp.set(u),r.doit();var c=new Uint8Array(r.outSize);return c.set(r.out),s&&(f[0].finishDecoding=t()),void this.onPictureDecoded(c,n,o,f)}s&&(f[0].finishDecoding=t()),this.onPictureDecoded(u,n,o,f)}.bind(this);this.options.sliceMode&&(f=function(e,n,r,i){var f=this.pictureBuffers[e];f||(f=this.pictureBuffers[e]=a(e,n*r*3/2));var u,s=this.pictureBuffers[i];s||(s=this.pictureBuffers[i]=o(i,18)),this.infoAr.length&&(u=this.infoAr),this.infoAr=[],u[0].finishDecoding=t();for(var c=[],d=0;d<20;++d)c.push(s[d]);u[0].sliceInfoAr=c,this.onPictureDecoded(f,n,r,u)}.bind(this));var u=n.apply({},[function(){},f]),s=this;this.onPictureDecoded=function(e,n,t,r){},this.onDecoderReady=function(){};var c=[];this.decode=function(e,n,t){c.push([e,n,t])},u((function(e){e.HEAP8;var n=e.HEAPU8;e.HEAP16,e.HEAP32,e._broadwayInit(),a=function(e,t){return n.subarray(e,e+t)},o=function(e,t){return new Uint32Array(n.buffer,e,t)},s.streamBuffer=a(e._broadwayCreateStream(1048576),1048576),s.pictureBuffers={},s.infoAr=[];var r=0;if(s.options.sliceMode?(r=s.options.sliceNum,s.decode=function(n,a,i){s.infoAr.push(a),a.startDecoding=t();var o,f=a.nals;if(!f){f=[],a.nals=f;var u=n.length,c=!1,d=0,l=0;for(o=0;o>2,f=i+o+o,u=n*t*4,s=f+u+4*Math.pow(2,24),c=Math.pow(2,24),d=c;d>2;m=r(r(l,p)|0,4)|0;v=(y+h|0)+h|0;b=0;g=b+m|0;A=g+v|0;a=~~+o(+2,+24);a=r(a,4)|0;for(t=0|0;(t|0)<(a|0)|0;t=t+4|0){d[(A+t|0)>>2]=0}}function P(){var e=0;var n=0;var t=0;var r=0;var a=0;var i=0;var o=0;var f=0;var u=0;var c=0;var v=0;var m=0;var M=0;var P=0;M=b|0;e=g|0;n=e+y|0|0;t=n+h|0;for(u=0;(u|0)<(p|0);u=u+2|0){v=n;m=t;for(c=0;(c|0)<(l|0);c=c+2|0){r=s[e>>0]|0;a=s[(e+l|0)>>0]|0;i=s[n>>0]|0;o=s[t>>0]|0;P=((r<<16|0)+(i<<8|0)|0)+o|0;f=d[(A>>2)+P|0]|0;if(f){}else{f=D(r,i,o)|0;d[(A>>2)+P|0]=f|0}d[M>>2]=f;P=((a<<16|0)+(i<<8|0)|0)+o|0;f=d[(A>>2)+P|0]|0;if(f){}else{f=D(a,i,o)|0;d[(A>>2)+P|0]=f|0}d[(M+w|0)>>2]=f;M=M+4|0;e=e+1|0;r=s[e>>0]|0;a=s[(e+l|0)>>0]|0;P=((r<<16|0)+(i<<8|0)|0)+o|0;f=d[(A>>2)+P|0]|0;if(f){}else{f=D(r,i,o)|0;d[(A>>2)+P|0]=f|0}d[M>>2]=f;P=((a<<16|0)+(i<<8|0)|0)+o|0;f=d[(A>>2)+P|0]|0;if(f){}else{f=D(a,i,o)|0;d[(A>>2)+P|0]=f|0}d[(M+w|0)>>2]=f;M=M+4|0;e=e+1|0;n=n+1|0;t=t+1|0}M=M+w|0;e=e+l|0}}function D(e,n,t){e=e|0;n=n|0;t=t|0;var o=0;var f=0;var u=0;var s=0;var c=0;var d=0;var l=0;var p=0;var y=0;c=r(1192,e-16|0)|0;d=r(1634,t-128|0)|0;l=r(832,t-128|0)|0;p=r(400,n-128|0)|0;y=r(2066,n-128|0)|0;o=(c+d|0)>>10|0;f=((c-l|0)-p|0)>>10|0;u=(c+y|0)>>10|0;if((o&255|0)!=(o|0)|0){o=a(255,i(0,o|0)|0)|0}if((f&255|0)!=(f|0)|0){f=a(255,i(0,f|0)|0)|0}if((u&255|0)!=(u|0)|0){u=a(255,i(0,u|0)|0)|0}s=255;s=s<<8|0;s=s+u|0;s=s<<8|0;s=s+f|0;s=s<<8|0;s=s+o|0;return s|0}return{init:M,doit:P}}(e,{},l);return p.init(n,t),a[r]=p,p.heap=l,p.out=new Uint8Array(l,0,u),p.inp=new Uint8Array(l,u,f),p.outSize=u,p};if("undefined"!=typeof self){var o,f,u,s,c,d,l=!1,p=!1,y=!1,h=0,v=0,m=0,g=0,b=[],w=[],A=function(e){if(w.length){for(var n=w.shift();n&&n.byteLength!==e;)n=w.shift();if(n)return n}return new ArrayBuffer(e)},M=function(e,n,t,r,a){var i=function(t,a){var i=0;for(i=0;i<16;++i){var o=t+r*i,f=a+r*i;n.set(e.subarray(o,f),o)}},o=function(t,a){var i=0;for(i=0;i<8;++i){var o=t+r/2*i,f=a+r/2*i;n.set(e.subarray(o,f),o)}},f=function(t,r){n.set(e.subarray(t,r),t)},u=t[0],s=t[1];s>0&&(i(u,s),o(t[2],t[3]),o(t[4],t[5])),u=t[6],(s=t[7])>0&&(i(u,s),o(t[8],t[9]),o(t[10],t[11])),u=t[12],(s=t[15])>0&&(f(u,s),f(t[13],t[16]),f(t[14],t[17]))},P=function(e){m=(v=e)-1};self.addEventListener("message",(function(e){if(l){if(p&&e.data.reuse&&w.push(e.data.reuse),e.data.buf)return void(y&&0!==g?b.push(e.data):o.decode(new Uint8Array(e.data.buf,e.data.offset||0,e.data.length),e.data.info,(function(){y&&h!==m&&postMessage(e.data,[e.data.buf])})));if(e.data.slice){var n=t();if(M(new Uint8Array(e.data.slice),u,e.data.infos[0].sliceInfoAr,e.data.width,e.data.height),e.data.theOne&&(M(u,new Uint8Array(e.data.slice),f,e.data.width,e.data.height),d>e.data.infos[0].timeDecoding&&(e.data.infos[0].timeDecoding=d),e.data.infos[0].timeCopy+=t()-n),postMessage(e.data,[e.data.slice]),0==(g-=1)&&b.length){var a=b.shift();o.decode(new Uint8Array(a.buf,a.offset||0,a.length),a.info,(function(){y&&h!==m&&postMessage(a,[a.buf])}))}return}if(e.data.setSliceCnt)return void P(e.data.sliceCnt)}else e.data&&"Broadway.js - Worker init"===e.data.type&&(l=!0,o=new r(e.data.options),e.data.options.sliceMode?(p=!0,y=!0,h=e.data.options.sliceNum,P(e.data.options.sliceCnt),o.onPictureDecoded=function(e,n,t,r){var a=new Uint8Array(A(e.length));M(e,a,r[0].sliceInfoAr,n),s=r[0].startDecoding,c=r[0].finishDecoding,d=c-s,r[0].timeDecoding=d,r[0].timeCopy=0,postMessage({slice:a.buffer,sliceNum:h,width:n,height:t,infos:r},[a.buffer]),g=v-1,u=e,f=r[0].sliceInfoAr}):e.data.options.reuseMemory?(p=!0,o.onPictureDecoded=function(e,n,t,r){var a=new Uint8Array(A(e.length));a.set(e,0,e.length),postMessage({buf:a.buffer,length:e.length,width:n,height:t,infos:r},[a.buffer])}):o.onPictureDecoded=function(e,n,t,r){e&&(e=new Uint8Array(e));var a=new Uint8Array(e.length);a.set(e,0,e.length),postMessage({buf:a.buffer,length:e.length,width:n,height:t,infos:r},[a.buffer])},postMessage({consoleLog:"broadway worker initialized"}))}),!1)}return r.nowValue=t,r}()})?r.apply(n,a):r)||(e.exports=i)}]); +//# sourceMappingURL=Decoder.worker.js.map \ No newline at end of file diff --git a/cvat/apps/engine/static/engine/js/3rdparty/avc.wasm b/cvat/apps/engine/static/engine/js/3rdparty/avc.wasm new file mode 100644 index 0000000000000000000000000000000000000000..559b2b3157a0fccbcf3128e8a5d4e371654d2d3e GIT binary patch literal 126815 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 { - this.save(); - return false; - }, 'keydown'); + Mousetrap.bind(shortkeys.save_work.value, Logger.shortkeyLogDecorator( + () => { + this.save(); + return false; + }, + ), 'keydown'); } autoSave(enabled, time) { diff --git a/cvat/apps/engine/static/engine/js/annotationUI.js b/cvat/apps/engine/static/engine/js/annotationUI.js index 5ce8f5f8..bc763dfe 100644 --- a/cvat/apps/engine/static/engine/js/annotationUI.js +++ b/cvat/apps/engine/static/engine/js/annotationUI.js @@ -96,7 +96,7 @@ function setupFrameFilters() { const brightnessRange = $('#playerBrightnessRange'); const contrastRange = $('#playerContrastRange'); const saturationRange = $('#playerSaturationRange'); - const frameBackground = $('#frameBackground'); + const canvasBackground = $('#canvasBackground'); const reset = $('#resetPlayerFilterButton'); let brightness = 100; let contrast = 100; @@ -105,7 +105,7 @@ function setupFrameFilters() { const { shortkeys } = window.cvat.config; function updateFilterParameters() { - frameBackground.css('filter', `contrast(${contrast}%) brightness(${brightness}%) saturate(${saturation}%)`); + canvasBackground.css('filter', `contrast(${contrast}%) brightness(${brightness}%) saturate(${saturation}%)`); } brightnessRange.attr('title', ` @@ -488,12 +488,15 @@ function setupMenu(job, task, shapeCollectionModel, } -function buildAnnotationUI(jobData, taskData, imageMetaData, annotationData, annotationFormats, - loadJobEvent) { +function buildAnnotationUI( + jobData, taskData, imageMetaData, + annotationData, annotationFormats, loadJobEvent, +) { // Setup some API window.cvat = { labelsInfo: new LabelsInfo(taskData.labels), translate: new CoordinateTranslator(), + frozen: true, player: { geometry: { scale: 1, @@ -511,6 +514,7 @@ function buildAnnotationUI(jobData, taskData, imageMetaData, annotationData, ann task_id: taskData.id, mode: taskData.mode, images: imageMetaData, + chunk_size: taskData.data_chunk_size, }, search: { value: window.location.search, @@ -646,7 +650,6 @@ function buildAnnotationUI(jobData, taskData, imageMetaData, annotationData, ann playerModel.shift(window.cvat.search.get('frame') || 0, true); const { shortkeys } = window.cvat.config; - setupHelpWindow(shortkeys); setupSettingsWindow(); setupMenu(jobData, taskData, shapeCollectionModel, @@ -708,12 +711,14 @@ function callAnnotationUI(jid) { $.get(`/api/v1/jobs/${jid}`).done((jobData) => { $.when( $.get(`/api/v1/tasks/${jobData.task_id}`), - $.get(`/api/v1/tasks/${jobData.task_id}/frames/meta`), + $.get(`/api/v1/tasks/${jobData.task_id}/data/meta`), $.get(`/api/v1/jobs/${jid}/annotations`), $.get('/api/v1/server/annotation/formats'), ).then((taskData, imageMetaData, annotationData, annotationFormats) => { $('#loadingOverlay').remove(); - setTimeout(() => { + setTimeout(async () => { + window.cvat.config.backendAPI = `${window.location.origin}/api/v1`; + [window.cvatTask] = (await window.cvat.tasks.get({ id: taskData[0].id })); buildAnnotationUI(jobData, taskData[0], imageMetaData[0], annotationData[0], annotationFormats[0], loadJobEvent); }); diff --git a/cvat/apps/engine/static/engine/js/cvat-core.min.js b/cvat/apps/engine/static/engine/js/cvat-core.min.js index 6acd6d73..1d85f74d 100644 --- a/cvat/apps/engine/static/engine/js/cvat-core.min.js +++ b/cvat/apps/engine/static/engine/js/cvat-core.min.js @@ -1,15 +1,15 @@ -window.cvat=function(t){var e={};function n(r){if(e[r])return e[r].exports;var o=e[r]={i:r,l:!1,exports:{}};return t[r].call(o.exports,o,o.exports,n),o.l=!0,o.exports}return n.m=t,n.c=e,n.d=function(t,e,r){n.o(t,e)||Object.defineProperty(t,e,{enumerable:!0,get:r})},n.r=function(t){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})},n.t=function(t,e){if(1&e&&(t=n(t)),8&e)return t;if(4&e&&"object"==typeof t&&t&&t.__esModule)return t;var r=Object.create(null);if(n.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:t}),2&e&&"string"!=typeof t)for(var o in t)n.d(r,o,function(e){return t[e]}.bind(null,o));return r},n.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};return n.d(e,"a",e),e},n.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},n.p="",n(n.s=90)}([function(t,e,n){(function(e){var n=function(t){return t&&t.Math==Math&&t};t.exports=n("object"==typeof globalThis&&globalThis)||n("object"==typeof window&&window)||n("object"==typeof self&&self)||n("object"==typeof e&&e)||Function("return this")()}).call(this,n(30))},function(t,e,n){var r=n(0),o=n(32),i=n(60),s=n(99),a=r.Symbol,c=o("wks");t.exports=function(t){return c[t]||(c[t]=s&&a[t]||(s?a:i)("Symbol."+t))}},function(t,e){t.exports=function(t){try{return!!t()}catch(t){return!0}}},function(t,e,n){var r=n(11);t.exports=function(t){if(!r(t))throw TypeError(String(t)+" is not an object");return t}},function(t,e,n){"use strict";var r=n(31),o=n(110),i=n(27),s=n(17),a=n(74),c=s.set,u=s.getterFor("Array Iterator");t.exports=a(Array,"Array",(function(t,e){c(this,{type:"Array Iterator",target:r(t),index:0,kind:e})}),(function(){var t=u(this),e=t.target,n=t.kind,r=t.index++;return!e||r>=e.length?(t.target=void 0,{value:void 0,done:!0}):"keys"==n?{value:r,done:!1}:"values"==n?{value:e[r],done:!1}:{value:[r,e[r]],done:!1}}),"values"),i.Arguments=i.Array,o("keys"),o("values"),o("entries")},function(t,e,n){n(9),(()=>{const e=n(115),r=n(117),o=n(50);class i extends Error{constructor(t){super(t);const n=(new Date).toISOString(),i=e.os.toString(),s=`${e.name} ${e.version}`,a=r.parse(this)[0],c=`${a.fileName}`,u=a.lineNumber,l=a.columnNumber,{jobID:f,taskID:p,clientID:h}=o;Object.defineProperties(this,Object.freeze({system:{get:()=>i},client:{get:()=>s},time:{get:()=>n},jobID:{get:()=>f},taskID:{get:()=>p},projID:{get:()=>void 0},clientID:{get:()=>h},filename:{get:()=>c},line:{get:()=>u},column:{get:()=>l}}))}async save(){const t={system:this.system,client:this.client,time:this.time,job_id:this.jobID,task_id:this.taskID,proj_id:this.projID,client_id:this.clientID,message:this.message,filename:this.filename,line:this.line,column:this.column,stack:this.stack};try{const e=n(19);await e.server.exception(t)}catch(t){}}}t.exports={Exception:i,ArgumentError:class extends i{constructor(t){super(t)}},DataError:class extends i{constructor(t){super(t)}},ScriptingError:class extends i{constructor(t){super(t)}},PluginError:class extends i{constructor(t){super(t)}},ServerError:class extends i{constructor(t,e){super(t),Object.defineProperties(this,Object.freeze({code:{get:()=>e}}))}}}})()},function(t,e,n){"use strict";var r=n(79),o=n(138),i=Object.prototype.toString;function s(t){return"[object Array]"===i.call(t)}function a(t){return null!==t&&"object"==typeof t}function c(t){return"[object Function]"===i.call(t)}function u(t,e){if(null!=t)if("object"!=typeof t&&(t=[t]),s(t))for(var n=0,r=t.length;n=51&&/native code/.test(R))return!1;var t=R.resolve(1),e=function(t){t((function(){}),(function(){}))};return(t.constructor={})[C]=e,!(t.then((function(){}))instanceof e)})),X=V||!O((function(t){R.all(t).catch((function(){}))})),H=function(t){var e;return!(!g(t)||"function"!=typeof(e=t.then))&&e},K=function(t,e,n){if(!e.notified){e.notified=!0;var r=e.reactions;k((function(){for(var o=e.value,i=1==e.state,s=0;r.length>s;){var a,c,u,l=r[s++],f=i?l.ok:l.fail,p=l.resolve,h=l.reject,d=l.domain;try{f?(i||(2===e.rejection&&tt(t,e),e.rejection=1),!0===f?a=o:(d&&d.enter(),a=f(o),d&&(d.exit(),u=!0)),a===l.promise?h(L("Promise-chain cycle")):(c=H(a))?c.call(a,p,h):p(a)):h(o)}catch(t){d&&!u&&d.exit(),h(t)}}e.reactions=[],e.notified=!1,n&&!e.rejection&&Y(t,e)}))}},Z=function(t,e,n){var r,o;q?((r=z.createEvent("Event")).promise=e,r.reason=n,r.initEvent(t,!1,!0),u.dispatchEvent(r)):r={promise:e,reason:n},(o=u["on"+t])?o(r):"unhandledrejection"===t&&A("Unhandled promise rejection",n)},Y=function(t,e){j.call(u,(function(){var n,r=e.value;if(Q(e)&&(n=P((function(){J?B.emit("unhandledRejection",r,t):Z("unhandledrejection",t,r)})),e.rejection=J||Q(e)?2:1,n.error))throw n.value}))},Q=function(t){return 1!==t.rejection&&!t.parent},tt=function(t,e){j.call(u,(function(){J?B.emit("rejectionHandled",t):Z("rejectionhandled",t,e.value)}))},et=function(t,e,n,r){return function(o){t(e,n,o,r)}},nt=function(t,e,n,r){e.done||(e.done=!0,r&&(e=r),e.value=n,e.state=2,K(t,e,!0))},rt=function(t,e,n,r){if(!e.done){e.done=!0,r&&(e=r);try{if(t===n)throw L("Promise can't be resolved itself");var o=H(n);o?k((function(){var r={done:!1};try{o.call(n,et(rt,t,r,e),et(nt,t,r,e))}catch(n){nt(t,r,n,e)}})):(e.value=n,e.state=1,K(t,e,!1))}catch(n){nt(t,{done:!1},n,e)}}};V&&(R=function(t){y(this,R,N),m(t),r.call(this);var e=$(this);try{t(et(rt,this,e),et(nt,this,e))}catch(t){nt(this,e,t)}},(r=function(t){M(this,{type:N,done:!1,notified:!1,parent:!1,reactions:[],rejection:!1,state:0,value:void 0})}).prototype=h(R.prototype,{then:function(t,e){var n=D(this),r=W(x(this,R));return r.ok="function"!=typeof t||t,r.fail="function"==typeof e&&e,r.domain=J?B.domain:void 0,n.parent=!0,n.reactions.push(r),0!=n.state&&K(this,n,!1),r.promise},catch:function(t){return this.then(void 0,t)}}),o=function(){var t=new r,e=$(t);this.promise=t,this.resolve=et(rt,t,e),this.reject=et(nt,t,e)},E.f=W=function(t){return t===R||t===i?new o(t):G(t)},c||"function"!=typeof f||(s=f.prototype.then,p(f.prototype,"then",(function(t,e){var n=this;return new R((function(t,e){s.call(n,t,e)})).then(t,e)}),{unsafe:!0}),"function"==typeof U&&a({global:!0,enumerable:!0,forced:!0},{fetch:function(t){return S(R,U.apply(u,arguments))}}))),a({global:!0,wrap:!0,forced:V},{Promise:R}),d(R,N,!1,!0),b(N),i=l(N),a({target:N,stat:!0,forced:V},{reject:function(t){var e=W(this);return e.reject.call(void 0,t),e.promise}}),a({target:N,stat:!0,forced:c||V},{resolve:function(t){return S(c&&this===i?R:this,t)}}),a({target:N,stat:!0,forced:X},{all:function(t){var e=this,n=W(e),r=n.resolve,o=n.reject,i=P((function(){var n=m(e.resolve),i=[],s=0,a=1;w(t,(function(t){var c=s++,u=!1;i.push(void 0),a++,n.call(e,t).then((function(t){u||(u=!0,i[c]=t,--a||r(i))}),o)})),--a||r(i)}));return i.error&&o(i.value),n.promise},race:function(t){var e=this,n=W(e),r=n.reject,o=P((function(){var o=m(e.resolve);w(t,(function(t){o.call(e,t).then(n.resolve,r)}))}));return o.error&&r(o.value),n.promise}})},function(t,e,n){var r=n(2);t.exports=!r((function(){return 7!=Object.defineProperty({},"a",{get:function(){return 7}}).a}))},function(t,e){t.exports=function(t){return"object"==typeof t?null!==t:"function"==typeof t}},function(t,e,n){var r=n(10),o=n(14),i=n(22);t.exports=r?function(t,e,n){return o.f(t,e,i(1,n))}:function(t,e,n){return t[e]=n,t}},function(t,e,n){var r=n(0),o=n(40).f,i=n(12),s=n(15),a=n(43),c=n(61),u=n(64);t.exports=function(t,e){var n,l,f,p,h,d=t.target,b=t.global,g=t.stat;if(n=b?r:g?r[d]||a(d,{}):(r[d]||{}).prototype)for(l in e){if(p=e[l],f=t.noTargetGet?(h=o(n,l))&&h.value:n[l],!u(b?l:d+(g?".":"#")+l,t.forced)&&void 0!==f){if(typeof p==typeof f)continue;c(p,f)}(t.sham||f&&f.sham)&&i(p,"sham",!0),s(n,l,p,t)}}},function(t,e,n){var r=n(10),o=n(58),i=n(3),s=n(41),a=Object.defineProperty;e.f=r?a:function(t,e,n){if(i(t),e=s(e,!0),i(n),o)try{return a(t,e,n)}catch(t){}if("get"in n||"set"in n)throw TypeError("Accessors not supported");return"value"in n&&(t[e]=n.value),t}},function(t,e,n){var r=n(0),o=n(32),i=n(12),s=n(7),a=n(43),c=n(59),u=n(17),l=u.get,f=u.enforce,p=String(c).split("toString");o("inspectSource",(function(t){return c.call(t)})),(t.exports=function(t,e,n,o){var c=!!o&&!!o.unsafe,u=!!o&&!!o.enumerable,l=!!o&&!!o.noTargetGet;"function"==typeof n&&("string"!=typeof e||s(n,"name")||i(n,"name",e),f(n).source=p.join("string"==typeof e?e:"")),t!==r?(c?!l&&t[e]&&(u=!0):delete t[e],u?t[e]=n:i(t,e,n)):u?t[e]=n:a(e,n)})(Function.prototype,"toString",(function(){return"function"==typeof this&&l(this).source||c.call(this)}))},function(t,e){var n={}.toString;t.exports=function(t){return n.call(t).slice(8,-1)}},function(t,e,n){var r,o,i,s=n(92),a=n(0),c=n(11),u=n(12),l=n(7),f=n(44),p=n(45),h=a.WeakMap;if(s){var d=new h,b=d.get,g=d.has,m=d.set;r=function(t,e){return m.call(d,t,e),e},o=function(t){return b.call(d,t)||{}},i=function(t){return g.call(d,t)}}else{var y=f("state");p[y]=!0,r=function(t,e){return u(t,y,e),e},o=function(t){return l(t,y)?t[y]:{}},i=function(t){return l(t,y)}}t.exports={set:r,get:o,has:i,enforce:function(t){return i(t)?o(t):r(t,{})},getterFor:function(t){return function(e){var n;if(!c(e)||(n=o(e)).type!==t)throw TypeError("Incompatible receiver, "+t+" required");return n}}}},function(t,e,n){var r=n(94),o=n(0),i=function(t){return"function"==typeof t?t:void 0};t.exports=function(t,e){return arguments.length<2?i(r[t])||i(o[t]):r[t]&&r[t][e]||o[t]&&o[t][e]}},function(t,e,n){n(9),n(119),(()=>{const e=n(124),{ServerError:r}=n(5),o=n(125),i=n(50);function s(t,e){if(t.response){const n=`${e}. `+`${t.message}. ${JSON.stringify(t.response.data)||""}.`;return new r(n,t.response.status)}const n=`${e}. `+`${t.message}.`;return new r(n,0)}const a=new class{constructor(){const a=n(136);a.defaults.withCredentials=!0,a.defaults.xsrfHeaderName="X-CSRFTOKEN",a.defaults.xsrfCookieName="csrftoken";let c=o.get("token");async function u(t=""){const{backendAPI:e}=i;let n=null;try{n=await a.get(`${e}/tasks?${t}`,{proxy:i.proxy})}catch(t){throw s(t,"Could not get tasks from a server")}return n.data.results.count=n.data.count,n.data.results}async function l(t){const{backendAPI:e}=i;try{await a.delete(`${e}/tasks/${t}`)}catch(t){throw s(t,"Could not delete the task from the server")}}c&&(a.defaults.headers.common.Authorization=`Token ${c}`),Object.defineProperties(this,Object.freeze({server:{value:Object.freeze({about:async function(){const{backendAPI:t}=i;let e=null;try{e=await a.get(`${t}/server/about`,{proxy:i.proxy})}catch(t){throw s(t,'Could not get "about" information from the server')}return e.data},share:async function(t){const{backendAPI:e}=i;t=encodeURIComponent(t);let n=null;try{n=await a.get(`${e}/server/share?directory=${t}`,{proxy:i.proxy})}catch(t){throw s(t,'Could not get "share" information from the server')}return n.data},formats:async function(){const{backendAPI:t}=i;let e=null;try{e=await a.get(`${t}/server/annotation/formats`,{proxy:i.proxy})}catch(t){throw s(t,"Could not get annotation formats from the server")}return e.data},datasetFormats:async function(){const{backendAPI:t}=i;let e=null;try{e=await a.get(`${t}/server/dataset/formats`,{proxy:i.proxy}),e=JSON.parse(e.data)}catch(t){throw s(t,"Could not get export formats from the server")}return e},exception:async function(t){const{backendAPI:e}=i;try{await a.post(`${e}/server/exception`,JSON.stringify(t),{proxy:i.proxy,headers:{"Content-Type":"application/json"}})}catch(t){throw s(t,"Could not send an exception to the server")}},login:async function(t,e){const n=[`${encodeURIComponent("username")}=${encodeURIComponent(t)}`,`${encodeURIComponent("password")}=${encodeURIComponent(e)}`].join("&").replace(/%20/g,"+");let r=null;try{r=await a.post(`${i.backendAPI}/auth/login`,n,{proxy:i.proxy})}catch(t){throw s(t,"Could not login on a server")}if(r.headers["set-cookie"]){const t=r.headers["set-cookie"].join(";");a.defaults.headers.common.Cookie=t}c=r.data.key,o.set("token",c),a.defaults.headers.common.Authorization=`Token ${c}`},logout:async function(){try{await a.post(`${i.backendAPI}/auth/logout`,{proxy:i.proxy})}catch(t){throw s(t,"Could not logout from the server")}o.remove("token"),a.defaults.headers.common.Authorization=""},authorized:async function(){try{await t.exports.users.getSelf()}catch(t){if(401===t.code)return!1;throw t}return!0},register:async function(t,e,n,r,o,c){let u=null;try{const s=JSON.stringify({username:t,first_name:e,last_name:n,email:r,password1:o,password2:c});u=await a.post(`${i.backendAPI}/auth/register`,s,{proxy:i.proxy,headers:{"Content-Type":"application/json"}})}catch(e){throw s(e,`Could not register '${t}' user on the server`)}return u.data}}),writable:!1},tasks:{value:Object.freeze({getTasks:u,saveTask:async function(t,e){const{backendAPI:n}=i;try{await a.patch(`${n}/tasks/${t}`,JSON.stringify(e),{proxy:i.proxy,headers:{"Content-Type":"application/json"}})}catch(t){throw s(t,"Could not save the task on the server")}},createTask:async function(t,n,o){const{backendAPI:c}=i,f=new e;for(const t in n)if(Object.prototype.hasOwnProperty.call(n,t))for(let e=0;e{setTimeout((async function i(){try{const s=await a.get(`${c}/tasks/${t}/status`);if(["Queued","Started"].includes(s.data.state))""!==s.data.message&&o(s.data.message),setTimeout(i,1e3);else if("Finished"===s.data.state)e();else if("Failed"===s.data.state){const t="Could not create the task on the server. "+`${s.data.message}.`;n(new r(t,400))}else n(new r(`Unknown task state has been received: ${s.data.state}`,500))}catch(t){n(s(t,"Could not put task to the server"))}}),1e3)})}(p.data.id)}catch(t){throw await l(p.data.id),t}return(await u(`?id=${p.id}`))[0]},deleteTask:l,exportDataset:async function(t,e){const{backendAPI:n}=i;let r=`${n}/tasks/${t}/dataset?format=${e}`;return new Promise((e,n)=>{setTimeout((async function o(){try{202===(await a.get(`${r}`,{proxy:i.proxy})).status?setTimeout(o,3e3):e(r=`${r}&action=download`)}catch(e){n(s(e,`Failed to export the task ${t} as a dataset`))}}))})}}),writable:!1},jobs:{value:Object.freeze({getJob:async function(t){const{backendAPI:e}=i;let n=null;try{n=await a.get(`${e}/jobs/${t}`,{proxy:i.proxy})}catch(t){throw s(t,"Could not get jobs from a server")}return n.data},saveJob:async function(t,e){const{backendAPI:n}=i;try{await a.patch(`${n}/jobs/${t}`,JSON.stringify(e),{proxy:i.proxy,headers:{"Content-Type":"application/json"}})}catch(t){throw s(t,"Could not save the job on the server")}}}),writable:!1},users:{value:Object.freeze({getUsers:async function(t=null){const{backendAPI:e}=i;let n=null;try{n=null===t?await a.get(`${e}/users`,{proxy:i.proxy}):await a.get(`${e}/users/${t}`,{proxy:i.proxy})}catch(t){throw s(t,"Could not get users from the server")}return n.data.results},getSelf:async function(){const{backendAPI:t}=i;let e=null;try{e=await a.get(`${t}/users/self`,{proxy:i.proxy})}catch(t){throw s(t,"Could not get user data from the server")}return e.data}}),writable:!1},frames:{value:Object.freeze({getData:async function(t,e){const{backendAPI:n}=i;let r=null;try{r=await a.get(`${n}/tasks/${t}/frames/${e}`,{proxy:i.proxy,responseType:"blob"})}catch(n){throw s(n,`Could not get frame ${e} for the task ${t} from the server`)}return r.data},getMeta:async function(t){const{backendAPI:e}=i;let n=null;try{n=await a.get(`${e}/tasks/${t}/frames/meta`,{proxy:i.proxy})}catch(e){throw s(e,`Could not get frame meta info for the task ${t} from the server`)}return n.data},getPreview:async function(t){const{backendAPI:e}=i;let n=null;try{n=await a.get(`${e}/tasks/${t}/frames/0`,{proxy:i.proxy,responseType:"blob"})}catch(e){const n=e.response?e.response.status:e.code;throw new r(`Could not get preview frame for the task ${t} from the server`,n)}return n.data}}),writable:!1},annotations:{value:Object.freeze({updateAnnotations:async function(t,e,n,r){const{backendAPI:o}=i;let c=null,u=null;"PUT"===r.toUpperCase()?(c=a.put.bind(a),u=`${o}/${t}s/${e}/annotations`):(c=a.patch.bind(a),u=`${o}/${t}s/${e}/annotations?action=${r}`);let l=null;try{l=await c(u,JSON.stringify(n),{proxy:i.proxy,headers:{"Content-Type":"application/json"}})}catch(n){throw s(n,`Could not ${r} annotations for the ${t} ${e} on the server`)}return l.data},getAnnotations:async function(t,e){const{backendAPI:n}=i;let r=null;try{r=await a.get(`${n}/${t}s/${e}/annotations`,{proxy:i.proxy})}catch(n){throw s(n,`Could not get annotations for the ${t} ${e} from the server`)}return r.data},dumpAnnotations:async function(t,e,n){const{backendAPI:r}=i,o=e.replace(/\//g,"_");let c=`${r}/tasks/${t}/annotations/${o}?format=${n}`;return new Promise((e,n)=>{setTimeout((async function r(){try{202===(await a.get(`${c}`,{proxy:i.proxy})).status?setTimeout(r,3e3):e(c=`${c}&action=download`)}catch(e){n(s(e,`Could not dump annotations for the task ${t} from the server`))}}))})},uploadAnnotations:async function(t,n,r,o){const{backendAPI:c}=i;let u=new e;return u.append("annotation_file",r),new Promise((r,l)=>{setTimeout((async function f(){try{202===(await a.put(`${c}/${t}s/${n}/annotations?format=${o}`,u,{proxy:i.proxy})).status?(u=new e,setTimeout(f,3e3)):r()}catch(e){l(s(e,`Could not upload annotations for the ${t} ${n}`))}}))})}}),writable:!1}}))}};t.exports=a})()},function(t,e,n){(function(e){var n=Object.assign?Object.assign:function(t,e,n,r){for(var o=1;o{const e=Object.freeze({DIR:"DIR",REG:"REG"}),n=Object.freeze({ANNOTATION:"annotation",VALIDATION:"validation",COMPLETED:"completed"}),r=Object.freeze({ANNOTATION:"annotation",INTERPOLATION:"interpolation"}),o=Object.freeze({CHECKBOX:"checkbox",RADIO:"radio",SELECT:"select",NUMBER:"number",TEXT:"text"}),i=Object.freeze({TAG:"tag",SHAPE:"shape",TRACK:"track"}),s=Object.freeze({RECTANGLE:"rectangle",POLYGON:"polygon",POLYLINE:"polyline",POINTS:"points"}),a=Object.freeze({ALL:"all",SHAPE:"shape",NONE:"none"});t.exports={ShareFileType:e,TaskStatus:n,TaskMode:r,AttributeType:o,ObjectType:i,ObjectShape:s,VisibleState:a,LogType:{pasteObject:0,changeAttribute:1,dragObject:2,deleteObject:3,pressShortcut:4,resizeObject:5,sendLogs:6,saveJob:7,jumpFrame:8,drawObject:9,changeLabel:10,sendTaskInfo:11,loadJob:12,moveImage:13,zoomImage:14,lockObject:15,mergeObjects:16,copyObject:17,propagateObject:18,undoAction:19,redoAction:20,sendUserActivity:21,sendException:22,changeFrame:23,debugInfo:24,fitImage:25,rotateImage:26}}})()},function(t,e){t.exports=function(t,e){return{enumerable:!(1&t),configurable:!(2&t),writable:!(4&t),value:e}}},function(t,e){t.exports=function(t){if(null==t)throw TypeError("Can't call method on "+t);return t}},function(t,e){t.exports=!1},function(t,e,n){var r=n(14).f,o=n(7),i=n(1)("toStringTag");t.exports=function(t,e,n){t&&!o(t=n?t:t.prototype,i)&&r(t,i,{configurable:!0,value:e})}},function(t,e){t.exports=function(t){if("function"!=typeof t)throw TypeError(String(t)+" is not a function");return t}},function(t,e){t.exports={}},function(t,e,n){n(109),n(4),n(9),n(8),(()=>{const{PluginError:e}=n(5),r=[];class o{static async apiWrapper(t,...n){const r=await o.list();for(const o of r){const r=o.functions.filter(e=>e.callback===t)[0];if(r&&r.enter)try{await r.enter.call(this,o,...n)}catch(t){throw t instanceof e?t:new e(`Exception in plugin ${o.name}: ${t.toString()}`)}}let i=await t.implementation.call(this,...n);for(const o of r){const r=o.functions.filter(e=>e.callback===t)[0];if(r&&r.leave)try{i=await r.leave.call(this,o,i,...n)}catch(t){throw t instanceof e?t:new e(`Exception in plugin ${o.name}: ${t.toString()}`)}}return i}static async register(t){const n=[];if("object"!=typeof t)throw new e(`Plugin should be an object, but got "${typeof t}"`);if(!("name"in t)||"string"!=typeof t.name)throw new e('Plugin must contain a "name" field and it must be a string');if(!("description"in t)||"string"!=typeof t.description)throw new e('Plugin must contain a "description" field and it must be a string');if("functions"in t)throw new e('Plugin must not contain a "functions" field');!function t(e,r){const o={};for(const n in e)Object.prototype.hasOwnProperty.call(e,n)&&("object"==typeof e[n]?Object.prototype.hasOwnProperty.call(r,n)&&t(e[n],r[n]):["enter","leave"].includes(n)&&"function"==typeof r&&(e[n],1)&&(o.callback=r,o[n]=e[n]));Object.keys(o).length&&n.push(o)}(t,{cvat:this}),Object.defineProperty(t,"functions",{value:n,writable:!1}),r.push(t)}static async list(){return r}}t.exports=o})()},function(t,e,n){var r=n(23);t.exports=function(t){return Object(r(t))}},function(t,e){var n;n=function(){return this}();try{n=n||new Function("return this")()}catch(t){"object"==typeof window&&(n=window)}t.exports=n},function(t,e,n){var r=n(57),o=n(23);t.exports=function(t){return r(o(t))}},function(t,e,n){var r=n(24),o=n(91);(t.exports=function(t,e){return o[t]||(o[t]=void 0!==e?e:{})})("versions",[]).push({version:"3.4.0",mode:r?"pure":"global",copyright:"© 2019 Denis Pushkarev (zloirock.ru)"})},function(t,e,n){var r=n(34),o=Math.min;t.exports=function(t){return t>0?o(r(t),9007199254740991):0}},function(t,e){var n=Math.ceil,r=Math.floor;t.exports=function(t){return isNaN(t=+t)?0:(t>0?r:n)(t)}},function(t,e,n){var r=n(26);t.exports=function(t,e,n){if(r(t),void 0===e)return t;switch(n){case 0:return function(){return t.call(e)};case 1:return function(n){return t.call(e,n)};case 2:return function(n,r){return t.call(e,n,r)};case 3:return function(n,r,o){return t.call(e,n,r,o)}}return function(){return t.apply(e,arguments)}}},function(t,e,n){var r=n(67),o=n(27),i=n(1)("iterator");t.exports=function(t){if(null!=t)return t[i]||t["@@iterator"]||o[r(t)]}},function(t,e,n){n(4),n(9),n(154),n(8),n(55),(()=>{const e=n(28),r=n(19),{getFrame:o,getPreview:i}=n(157),{ArgumentError:s}=n(5),{TaskStatus:a}=n(21),{Label:c}=n(38),u=n(53);function l(t){Object.defineProperties(t,{annotations:Object.freeze({value:{async upload(n,r){return await e.apiWrapper.call(this,t.annotations.upload,n,r)},async save(){return await e.apiWrapper.call(this,t.annotations.save)},async clear(n=!1){return await e.apiWrapper.call(this,t.annotations.clear,n)},async dump(n,r){return await e.apiWrapper.call(this,t.annotations.dump,n,r)},async statistics(){return await e.apiWrapper.call(this,t.annotations.statistics)},async put(n=[]){return await e.apiWrapper.call(this,t.annotations.put,n)},async get(n,r={}){return await e.apiWrapper.call(this,t.annotations.get,n,r)},async search(n,r,o){return await e.apiWrapper.call(this,t.annotations.search,n,r,o)},async select(n,r,o){return await e.apiWrapper.call(this,t.annotations.select,n,r,o)},async hasUnsavedChanges(){return await e.apiWrapper.call(this,t.annotations.hasUnsavedChanges)},async merge(n){return await e.apiWrapper.call(this,t.annotations.merge,n)},async split(n,r){return await e.apiWrapper.call(this,t.annotations.split,n,r)},async group(n,r=!1){return await e.apiWrapper.call(this,t.annotations.group,n,r)},async exportDataset(n){return await e.apiWrapper.call(this,t.annotations.exportDataset,n)}},writable:!0}),frames:Object.freeze({value:{async get(n){return await e.apiWrapper.call(this,t.frames.get,n)},async preview(){return await e.apiWrapper.call(this,t.frames.preview)}},writable:!0}),logs:Object.freeze({value:{async put(n,r){return await e.apiWrapper.call(this,t.logs.put,n,r)},async save(n){return await e.apiWrapper.call(this,t.logs.save,n)}},writable:!0}),actions:Object.freeze({value:{async undo(n){return await e.apiWrapper.call(this,t.actions.undo,n)},async redo(n){return await e.apiWrapper.call(this,t.actions.redo,n)},async clear(){return await e.apiWrapper.call(this,t.actions.clear)}},writable:!0}),events:Object.freeze({value:{async subscribe(n,r){return await e.apiWrapper.call(this,t.events.subscribe,n,r)},async unsubscribe(n,r=null){return await e.apiWrapper.call(this,t.events.unsubscribe,n,r)}},writable:!0})})}class f{constructor(){}}class p extends f{constructor(t){super();const e={id:void 0,assignee:void 0,status:void 0,start_frame:void 0,stop_frame:void 0,task:void 0};for(const n in e)if(Object.prototype.hasOwnProperty.call(e,n)&&(n in t&&(e[n]=t[n]),void 0===e[n]))throw new s(`Job field "${n}" was not initialized`);Object.defineProperties(this,Object.freeze({id:{get:()=>e.id},assignee:{get:()=>e.assignee,set:t=>{if(null!==t&&!(t instanceof u))throw new s("Value must be a user instance");e.assignee=t}},status:{get:()=>e.status,set:t=>{const n=a;let r=!1;for(const e in n)if(n[e]===t){r=!0;break}if(!r)throw new s("Value must be a value from the enumeration cvat.enums.TaskStatus");e.status=t}},startFrame:{get:()=>e.start_frame},stopFrame:{get:()=>e.stop_frame},task:{get:()=>e.task}})),this.annotations={get:Object.getPrototypeOf(this).annotations.get.bind(this),put:Object.getPrototypeOf(this).annotations.put.bind(this),save:Object.getPrototypeOf(this).annotations.save.bind(this),dump:Object.getPrototypeOf(this).annotations.dump.bind(this),merge:Object.getPrototypeOf(this).annotations.merge.bind(this),split:Object.getPrototypeOf(this).annotations.split.bind(this),group:Object.getPrototypeOf(this).annotations.group.bind(this),clear:Object.getPrototypeOf(this).annotations.clear.bind(this),upload:Object.getPrototypeOf(this).annotations.upload.bind(this),select:Object.getPrototypeOf(this).annotations.select.bind(this),statistics:Object.getPrototypeOf(this).annotations.statistics.bind(this),hasUnsavedChanges:Object.getPrototypeOf(this).annotations.hasUnsavedChanges.bind(this)},this.frames={get:Object.getPrototypeOf(this).frames.get.bind(this),preview:Object.getPrototypeOf(this).frames.preview.bind(this)}}async save(){return await e.apiWrapper.call(this,p.prototype.save)}}class h extends f{constructor(t){super();const e={id:void 0,name:void 0,status:void 0,size:void 0,mode:void 0,owner:void 0,assignee:void 0,created_date:void 0,updated_date:void 0,bug_tracker:void 0,overlap:void 0,segment_size:void 0,z_order:void 0,image_quality:void 0,start_frame:void 0,stop_frame:void 0,frame_filter:void 0};for(const n in e)Object.prototype.hasOwnProperty.call(e,n)&&n in t&&(e[n]=t[n]);if(e.labels=[],e.jobs=[],e.files=Object.freeze({server_files:[],client_files:[],remote_files:[]}),Array.isArray(t.segments))for(const n of t.segments)if(Array.isArray(n.jobs))for(const t of n.jobs){const r=new p({url:t.url,id:t.id,assignee:t.assignee,status:t.status,start_frame:n.start_frame,stop_frame:n.stop_frame,task:this});e.jobs.push(r)}if(Array.isArray(t.labels))for(const n of t.labels){const t=new c(n);e.labels.push(t)}Object.defineProperties(this,Object.freeze({id:{get:()=>e.id},name:{get:()=>e.name,set:t=>{if(!t.trim().length)throw new s("Value must not be empty");e.name=t}},status:{get:()=>e.status},size:{get:()=>e.size},mode:{get:()=>e.mode},owner:{get:()=>e.owner},assignee:{get:()=>e.assignee,set:t=>{if(null!==t&&!(t instanceof u))throw new s("Value must be a user instance");e.assignee=t}},createdDate:{get:()=>e.created_date},updatedDate:{get:()=>e.updated_date},bugTracker:{get:()=>e.bug_tracker,set:t=>{e.bug_tracker=t}},overlap:{get:()=>e.overlap,set:t=>{if(!Number.isInteger(t)||t<0)throw new s("Value must be a non negative integer");e.overlap=t}},segmentSize:{get:()=>e.segment_size,set:t=>{if(!Number.isInteger(t)||t<0)throw new s("Value must be a positive integer");e.segment_size=t}},zOrder:{get:()=>e.z_order,set:t=>{if("boolean"!=typeof t)throw new s("Value must be a boolean");e.z_order=t}},imageQuality:{get:()=>e.image_quality,set:t=>{if(!Number.isInteger(t)||t<0)throw new s("Value must be a positive integer");e.image_quality=t}},labels:{get:()=>[...e.labels],set:t=>{if(!Array.isArray(t))throw new s("Value must be an array of Labels");for(const e of t)if(!(e instanceof c))throw new s("Each array value must be an instance of Label. "+`${typeof e} was found`);e.labels=[...t]}},jobs:{get:()=>[...e.jobs]},serverFiles:{get:()=>[...e.files.server_files],set:t=>{if(!Array.isArray(t))throw new s(`Value must be an array. But ${typeof t} has been got.`);for(const e of t)if("string"!=typeof e)throw new s(`Array values must be a string. But ${typeof e} has been got.`);Array.prototype.push.apply(e.files.server_files,t)}},clientFiles:{get:()=>[...e.files.client_files],set:t=>{if(!Array.isArray(t))throw new s(`Value must be an array. But ${typeof t} has been got.`);for(const e of t)if(!(e instanceof File))throw new s(`Array values must be a File. But ${e.constructor.name} has been got.`);Array.prototype.push.apply(e.files.client_files,t)}},remoteFiles:{get:()=>[...e.files.remote_files],set:t=>{if(!Array.isArray(t))throw new s(`Value must be an array. But ${typeof t} has been got.`);for(const e of t)if("string"!=typeof e)throw new s(`Array values must be a string. But ${typeof e} has been got.`);Array.prototype.push.apply(e.files.remote_files,t)}},startFrame:{get:()=>e.start_frame,set:t=>{if(!Number.isInteger(t)||t<0)throw new s("Value must be a not negative integer");e.start_frame=t}},stopFrame:{get:()=>e.stop_frame,set:t=>{if(!Number.isInteger(t)||t<0)throw new s("Value must be a not negative integer");e.stop_frame=t}},frameFilter:{get:()=>e.frame_filter,set:t=>{if("string"!=typeof t)throw new s(`Filter value must be a string. But ${typeof t} has been got.`);e.frame_filter=t}}})),this.annotations={get:Object.getPrototypeOf(this).annotations.get.bind(this),put:Object.getPrototypeOf(this).annotations.put.bind(this),save:Object.getPrototypeOf(this).annotations.save.bind(this),dump:Object.getPrototypeOf(this).annotations.dump.bind(this),merge:Object.getPrototypeOf(this).annotations.merge.bind(this),split:Object.getPrototypeOf(this).annotations.split.bind(this),group:Object.getPrototypeOf(this).annotations.group.bind(this),clear:Object.getPrototypeOf(this).annotations.clear.bind(this),upload:Object.getPrototypeOf(this).annotations.upload.bind(this),select:Object.getPrototypeOf(this).annotations.select.bind(this),statistics:Object.getPrototypeOf(this).annotations.statistics.bind(this),hasUnsavedChanges:Object.getPrototypeOf(this).annotations.hasUnsavedChanges.bind(this),exportDataset:Object.getPrototypeOf(this).annotations.exportDataset.bind(this)},this.frames={get:Object.getPrototypeOf(this).frames.get.bind(this),preview:Object.getPrototypeOf(this).frames.preview.bind(this)}}async save(t=(()=>{})){return await e.apiWrapper.call(this,h.prototype.save,t)}async delete(){return await e.apiWrapper.call(this,h.prototype.delete)}}t.exports={Job:p,Task:h};const{getAnnotations:d,putAnnotations:b,saveAnnotations:g,hasUnsavedChanges:m,mergeAnnotations:y,splitAnnotations:v,groupAnnotations:w,clearAnnotations:O,selectObject:x,annotationsStatistics:j,uploadAnnotations:k,dumpAnnotations:S,exportDataset:A}=n(159);l(p.prototype),l(h.prototype),p.prototype.save.implementation=async function(){if(this.id){const t={status:this.status,assignee:this.assignee?this.assignee.id:null};return await r.jobs.saveJob(this.id,t),this}throw new s("Can not save job without and id")},p.prototype.frames.get.implementation=async function(t){if(!Number.isInteger(t)||t<0)throw new s(`Frame must be a positive integer. Got: "${t}"`);if(tthis.stopFrame)throw new s(`The frame with number ${t} is out of the job`);return await o(this.task.id,this.task.mode,t)},p.prototype.frames.preview.implementation=async function(){return await i(this.task.id)},p.prototype.annotations.get.implementation=async function(t,e){if(tthis.stopFrame)throw new s(`Frame ${t} does not exist in the job`);return await d(this,t,e)},p.prototype.annotations.save.implementation=async function(t){return await g(this,t)},p.prototype.annotations.merge.implementation=async function(t){return await y(this,t)},p.prototype.annotations.split.implementation=async function(t,e){return await v(this,t,e)},p.prototype.annotations.group.implementation=async function(t,e){return await w(this,t,e)},p.prototype.annotations.hasUnsavedChanges.implementation=function(){return m(this)},p.prototype.annotations.clear.implementation=async function(t){return await O(this,t)},p.prototype.annotations.select.implementation=function(t,e,n){return x(this,t,e,n)},p.prototype.annotations.statistics.implementation=function(){return j(this)},p.prototype.annotations.put.implementation=function(t){return b(this,t)},p.prototype.annotations.upload.implementation=async function(t,e){return await k(this,t,e)},p.prototype.annotations.dump.implementation=async function(t,e){return await S(this,t,e)},h.prototype.save.implementation=async function(t){if(void 0!==this.id){const t={assignee:this.assignee?this.assignee.id:null,name:this.name,bug_tracker:this.bugTracker,z_order:this.zOrder,labels:[...this.labels.map(t=>t.toJSON())]};return await r.tasks.saveTask(this.id,t),this}const e={name:this.name,labels:this.labels.map(t=>t.toJSON()),image_quality:this.imageQuality,z_order:Boolean(this.zOrder)};void 0!==this.bugTracker&&(e.bug_tracker=this.bugTracker),void 0!==this.segmentSize&&(e.segment_size=this.segmentSize),void 0!==this.overlap&&(e.overlap=this.overlap),void 0!==this.startFrame&&(e.start_frame=this.startFrame),void 0!==this.stopFrame&&(e.stop_frame=this.stopFrame),void 0!==this.frameFilter&&(e.frame_filter=this.frameFilter);const n={client_files:this.clientFiles,server_files:this.serverFiles,remote_files:this.remoteFiles},o=await r.tasks.createTask(e,n,t);return new h(o)},h.prototype.delete.implementation=async function(){return await r.tasks.deleteTask(this.id)},h.prototype.frames.get.implementation=async function(t){if(!Number.isInteger(t)||t<0)throw new s(`Frame must be a positive integer. Got: "${t}"`);if(t>=this.size)throw new s(`The frame with number ${t} is out of the task`);return await o(this.id,this.mode,t)},h.prototype.frames.preview.implementation=async function(){return await i(this.id)},h.prototype.annotations.get.implementation=async function(t,e){if(!Number.isInteger(t)||t<0)throw new s(`Frame must be a positive integer. Got: "${t}"`);if(t>=this.size)throw new s(`Frame ${t} does not exist in the task`);return await d(this,t,e)},h.prototype.annotations.save.implementation=async function(t){return await g(this,t)},h.prototype.annotations.merge.implementation=async function(t){return await y(this,t)},h.prototype.annotations.split.implementation=async function(t,e){return await v(this,t,e)},h.prototype.annotations.group.implementation=async function(t,e){return await w(this,t,e)},h.prototype.annotations.hasUnsavedChanges.implementation=function(){return m(this)},h.prototype.annotations.clear.implementation=async function(t){return await O(this,t)},h.prototype.annotations.select.implementation=function(t,e,n){return x(this,t,e,n)},h.prototype.annotations.statistics.implementation=function(){return j(this)},h.prototype.annotations.put.implementation=function(t){return b(this,t)},h.prototype.annotations.upload.implementation=async function(t,e){return await k(this,t,e)},h.prototype.annotations.dump.implementation=async function(t,e){return await S(this,t,e)},h.prototype.annotations.exportDataset.implementation=async function(t){return await A(this,t)}})()},function(t,e,n){n(4),n(8),n(55),(()=>{const{AttributeType:e}=n(21),{ArgumentError:r}=n(5);class o{constructor(t){const n={id:void 0,default_value:void 0,input_type:void 0,mutable:void 0,name:void 0,values:void 0};for(const e in n)Object.prototype.hasOwnProperty.call(n,e)&&Object.prototype.hasOwnProperty.call(t,e)&&(Array.isArray(t[e])?n[e]=[...t[e]]:n[e]=t[e]);if(!Object.values(e).includes(n.input_type))throw new r(`Got invalid attribute type ${n.input_type}`);Object.defineProperties(this,Object.freeze({id:{get:()=>n.id},defaultValue:{get:()=>n.default_value},inputType:{get:()=>n.input_type},mutable:{get:()=>n.mutable},name:{get:()=>n.name},values:{get:()=>[...n.values]}}))}toJSON(){const t={name:this.name,mutable:this.mutable,input_type:this.inputType,default_value:this.defaultValue,values:this.values};return void 0!==this.id&&(t.id=this.id),t}}t.exports={Attribute:o,Label:class{constructor(t){const e={id:void 0,name:void 0};for(const n in e)Object.prototype.hasOwnProperty.call(e,n)&&Object.prototype.hasOwnProperty.call(t,n)&&(e[n]=t[n]);if(e.attributes=[],Object.prototype.hasOwnProperty.call(t,"attributes")&&Array.isArray(t.attributes))for(const n of t.attributes)e.attributes.push(new o(n));Object.defineProperties(this,Object.freeze({id:{get:()=>e.id},name:{get:()=>e.name},attributes:{get:()=>[...e.attributes]}}))}toJSON(){const t={name:this.name,attributes:[...this.attributes.map(t=>t.toJSON())]};return void 0!==this.id&&(t.id=this.id),t}}}})()},function(t,e,n){(()=>{const{ArgumentError:e}=n(5);t.exports={isBoolean:function(t){return"boolean"==typeof t},isInteger:function(t){return"number"==typeof t&&Number.isInteger(t)},isEnum:function(t){for(const e in this)if(Object.prototype.hasOwnProperty.call(this,e)&&this[e]===t)return!0;return!1},isString:function(t){return"string"==typeof t},checkFilter:function(t,n){for(const r in t)if(Object.prototype.hasOwnProperty.call(t,r)){if(!(r in n))throw new e(`Unsupported filter property has been recieved: "${r}"`);if(!n[r](t[r]))throw new e(`Received filter property "${r}" is not satisfied for checker`)}},checkObjectType:function(t,n,r,o){if(r){if(typeof n!==r){if("integer"===r&&Number.isInteger(n))return;throw new e(`"${t}" is expected to be "${r}", but "${typeof n}" has been got.`)}}else if(o&&!(n instanceof o)){if(void 0!==n)throw new e(`"${t}" is expected to be ${o.name}, but `+`"${n.constructor.name}" has been got`);throw new e(`"${t}" is expected to be ${o.name}, but "undefined" has been got.`)}}}})()},function(t,e,n){var r=n(10),o=n(56),i=n(22),s=n(31),a=n(41),c=n(7),u=n(58),l=Object.getOwnPropertyDescriptor;e.f=r?l:function(t,e){if(t=s(t),e=a(e,!0),u)try{return l(t,e)}catch(t){}if(c(t,e))return i(!o.f.call(t,e),t[e])}},function(t,e,n){var r=n(11);t.exports=function(t,e){if(!r(t))return t;var n,o;if(e&&"function"==typeof(n=t.toString)&&!r(o=n.call(t)))return o;if("function"==typeof(n=t.valueOf)&&!r(o=n.call(t)))return o;if(!e&&"function"==typeof(n=t.toString)&&!r(o=n.call(t)))return o;throw TypeError("Can't convert object to primitive value")}},function(t,e,n){var r=n(0),o=n(11),i=r.document,s=o(i)&&o(i.createElement);t.exports=function(t){return s?i.createElement(t):{}}},function(t,e,n){var r=n(0),o=n(12);t.exports=function(t,e){try{o(r,t,e)}catch(n){r[t]=e}return e}},function(t,e,n){var r=n(32),o=n(60),i=r("keys");t.exports=function(t){return i[t]||(i[t]=o(t))}},function(t,e){t.exports={}},function(t,e){t.exports=["constructor","hasOwnProperty","isPrototypeOf","propertyIsEnumerable","toLocaleString","toString","valueOf"]},function(t,e){t.exports=function(t,e,n){if(!(t instanceof e))throw TypeError("Incorrect "+(n?n+" ":"")+"invocation");return t}},function(t,e,n){var r=n(18);t.exports=r("navigator","userAgent")||""},function(t,e,n){var r=n(3),o=n(72),i=n(46),s=n(45),a=n(70),c=n(42),u=n(44)("IE_PROTO"),l=function(){},f=function(){var t,e=c("iframe"),n=i.length;for(e.style.display="none",a.appendChild(e),e.src=String("javascript:"),(t=e.contentWindow.document).open(),t.write(" + {% for js_file in js_3rdparty %} {% endfor %} @@ -80,6 +81,7 @@ + diff --git a/cvat/apps/engine/tests/test_model.py b/cvat/apps/engine/tests/test_model.py deleted file mode 100644 index 34454c0b..00000000 --- a/cvat/apps/engine/tests/test_model.py +++ /dev/null @@ -1,25 +0,0 @@ -# Copyright (C) 2018 Intel Corporation -# -# SPDX-License-Identifier: MIT - -import os.path as osp - -from django.test import TestCase -from cvat.apps.engine.models import Task - - -class TaskModelTest(TestCase): - def test_frame_id_path_conversions(self): - task_id = 1 - task = Task(task_id) - - for i in [10 ** p for p in range(6)]: - src_path_expected = osp.join( - str(i // 10000), str(i // 100), '%s.jpg' % i) - src_path = task.get_frame_path(i) - - dst_frame = task.get_image_frame(src_path) - - self.assertTrue(src_path.endswith(src_path_expected), - '%s vs. %s' % (src_path, src_path_expected)) - self.assertEqual(i, dst_frame) diff --git a/cvat/apps/engine/tests/test_rest_api.py b/cvat/apps/engine/tests/test_rest_api.py index f3da0410..1c2f7a87 100644 --- a/cvat/apps/engine/tests/test_rest_api.py +++ b/cvat/apps/engine/tests/test_rest_api.py @@ -6,14 +6,14 @@ import os import shutil from PIL import Image from io import BytesIO +from enum import Enum import random from rest_framework.test import APITestCase, APIClient from rest_framework import status from django.conf import settings from django.contrib.auth.models import User, Group from cvat.apps.engine.models import (Task, Segment, Job, StatusChoice, - AttributeType, Project) -from cvat.apps.annotation.models import AnnotationFormat + AttributeType, Project, Data) from unittest import mock import io import xml.etree.ElementTree as ET @@ -21,6 +21,8 @@ from collections import defaultdict import zipfile from pycocotools import coco as coco_loader import tempfile +import av +import numpy as np def create_db_users(cls): (group_admin, _) = Group.objects.get_or_create(name="admin") @@ -50,14 +52,27 @@ def create_db_users(cls): cls.user = cls.user5 = user_dummy def create_db_task(data): + data_settings = { + "size": data.pop("size"), + "image_quality": data.pop("image_quality"), + } + + db_data = Data.objects.create(**data_settings) + shutil.rmtree(db_data.get_data_dirname(), ignore_errors=True) + os.makedirs(db_data.get_data_dirname()) + os.makedirs(db_data.get_upload_dirname()) + db_task = Task.objects.create(**data) shutil.rmtree(db_task.get_task_dirname(), ignore_errors=True) - os.makedirs(db_task.get_upload_dirname()) - os.makedirs(db_task.get_data_dirname()) + os.makedirs(db_task.get_task_dirname()) + os.makedirs(db_task.get_task_logs_dirname()) + os.makedirs(db_task.get_task_artifacts_dirname()) + db_task.data = db_data + db_task.save() - for x in range(0, db_task.size, db_task.segment_size): + for x in range(0, db_task.data.size, db_task.segment_size): start_frame = x - stop_frame = min(x + db_task.segment_size - 1, db_task.size - 1) + stop_frame = min(x + db_task.segment_size - 1, db_task.data.size - 1) db_segment = Segment() db_segment.task = db_task @@ -1051,7 +1066,7 @@ class TaskGetAPITestCase(APITestCase): def _check_response(self, response, db_task): self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(response.data["name"], db_task.name) - self.assertEqual(response.data["size"], db_task.size) + self.assertEqual(response.data["size"], db_task.data.size) self.assertEqual(response.data["mode"], db_task.mode) owner = db_task.owner.id if db_task.owner else None self.assertEqual(response.data["owner"], owner) @@ -1060,7 +1075,7 @@ class TaskGetAPITestCase(APITestCase): self.assertEqual(response.data["overlap"], db_task.overlap) self.assertEqual(response.data["segment_size"], db_task.segment_size) self.assertEqual(response.data["z_order"], db_task.z_order) - self.assertEqual(response.data["image_quality"], db_task.image_quality) + self.assertEqual(response.data["image_quality"], db_task.data.image_quality) self.assertEqual(response.data["status"], db_task.status) self.assertListEqual( [label.name for label in db_task.label_set.all()], @@ -1146,7 +1161,7 @@ class TaskUpdateAPITestCase(APITestCase): self.assertEqual(response.status_code, status.HTTP_200_OK) name = data.get("name", db_task.name) self.assertEqual(response.data["name"], name) - self.assertEqual(response.data["size"], db_task.size) + self.assertEqual(response.data["size"], db_task.data.size) mode = data.get("mode", db_task.mode) self.assertEqual(response.data["mode"], mode) owner = db_task.owner.id if db_task.owner else None @@ -1159,7 +1174,7 @@ class TaskUpdateAPITestCase(APITestCase): self.assertEqual(response.data["segment_size"], db_task.segment_size) z_order = data.get("z_order", db_task.z_order) self.assertEqual(response.data["z_order"], z_order) - image_quality = data.get("image_quality", db_task.image_quality) + image_quality = data.get("image_quality", db_task.data.image_quality) self.assertEqual(response.data["image_quality"], image_quality) self.assertEqual(response.data["status"], db_task.status) if data.get("labels"): @@ -1187,7 +1202,6 @@ class TaskUpdateAPITestCase(APITestCase): data = { "name": "new name for the task", "owner": self.owner.id, - "image_quality": 60, "labels": [{ "name": "non-vehicle", "attributes": [{ @@ -1204,7 +1218,6 @@ class TaskUpdateAPITestCase(APITestCase): data = { "name": "new name for the task", "owner": self.assignee.id, - "image_quality": 63, "labels": [{ "name": "car", "attributes": [{ @@ -1221,7 +1234,6 @@ class TaskUpdateAPITestCase(APITestCase): def test_api_v1_tasks_id_observer(self): data = { "name": "new name for the task", - "image_quality": 61, "labels": [{ "name": "test", }] @@ -1231,7 +1243,6 @@ class TaskUpdateAPITestCase(APITestCase): def test_api_v1_tasks_id_no_auth(self): data = { "name": "new name for the task", - "image_quality": 59, "labels": [{ "name": "test", }] @@ -1315,7 +1326,6 @@ class TaskCreateAPITestCase(APITestCase): def _check_response(self, response, user, data): self.assertEqual(response.status_code, status.HTTP_201_CREATED) self.assertEqual(response.data["name"], data["name"]) - self.assertEqual(response.data["size"], 0) self.assertEqual(response.data["mode"], "") self.assertEqual(response.data["owner"], data.get("owner", user.id)) self.assertEqual(response.data["assignee"], data.get("assignee")) @@ -1323,7 +1333,6 @@ class TaskCreateAPITestCase(APITestCase): self.assertEqual(response.data["overlap"], data.get("overlap", None)) self.assertEqual(response.data["segment_size"], data.get("segment_size", 0)) self.assertEqual(response.data["z_order"], data.get("z_order", False)) - self.assertEqual(response.data["image_quality"], data.get("image_quality", 50)) self.assertEqual(response.data["status"], StatusChoice.ANNOTATION) self.assertListEqual( [label["name"] for label in data.get("labels")], @@ -1342,7 +1351,6 @@ class TaskCreateAPITestCase(APITestCase): def test_api_v1_tasks_admin(self): data = { "name": "new name for the task", - "image_quality": 60, "labels": [{ "name": "non-vehicle", "attributes": [{ @@ -1359,7 +1367,6 @@ class TaskCreateAPITestCase(APITestCase): data = { "name": "new name for the task", "owner": self.assignee.id, - "image_quality": 63, "labels": [{ "name": "car", "attributes": [{ @@ -1376,7 +1383,6 @@ class TaskCreateAPITestCase(APITestCase): def test_api_v1_tasks_observer(self): data = { "name": "new name for the task", - "image_quality": 61, "labels": [{ "name": "test", }] @@ -1386,7 +1392,6 @@ class TaskCreateAPITestCase(APITestCase): def test_api_v1_tasks_no_auth(self): data = { "name": "new name for the task", - "image_quality": 59, "labels": [{ "name": "test", }] @@ -1402,9 +1407,76 @@ def generate_image_file(filename): f.name = filename f.seek(0) - return f + return (width, height), f + +def generate_image_files(*args): + images = [] + image_sizes = [] + for image_name in args: + img_size, image = generate_image_file(image_name) + image_sizes.append(img_size) + images.append(image) + + return image_sizes, images + +def generate_video_file(filename, width=1920, height=1080, duration=1, fps=25): + f = BytesIO() + total_frames = duration * fps + container = av.open(f, mode='w', format='mp4') + + stream = container.add_stream('mpeg4', rate=fps) + stream.width = width + stream.height = height + stream.pix_fmt = 'yuv420p' + + for frame_i in range(total_frames): + img = np.empty((stream.width, stream.height, 3)) + img[:, :, 0] = 0.5 + 0.5 * np.sin(2 * np.pi * (0 / 3 + frame_i / total_frames)) + img[:, :, 1] = 0.5 + 0.5 * np.sin(2 * np.pi * (1 / 3 + frame_i / total_frames)) + img[:, :, 2] = 0.5 + 0.5 * np.sin(2 * np.pi * (2 / 3 + frame_i / total_frames)) + + img = np.round(255 * img).astype(np.uint8) + img = np.clip(img, 0, 255) + + frame = av.VideoFrame.from_ndarray(img, format='rgb24') + for packet in stream.encode(frame): + container.mux(packet) + + # Flush stream + for packet in stream.encode(): + container.mux(packet) + + # Close the file + container.close() + f.name = filename + f.seek(0) + + return [(width, height)] * total_frames, f + +def generate_zip_archive_file(filename, count): + image_sizes = [] + zip_buf = BytesIO() + with zipfile.ZipFile(zip_buf, 'w') as zip_chunk: + for idx in range(count): + image_name = "image_{:6d}.jpg".format(idx) + size, image_buf = generate_image_file(image_name) + image_sizes.append(size) + zip_chunk.writestr(image_name, image_buf.getvalue()) + + zip_buf.name = filename + zip_buf.seek(0) + return image_sizes, zip_buf class TaskDataAPITestCase(APITestCase): + _image_sizes = {} + + class ChunkType(str, Enum): + IMAGESET = 'imageset' + VIDEO = 'video' + + def __str__(self): + return self.value + def setUp(self): self.client = APIClient() @@ -1415,27 +1487,56 @@ class TaskDataAPITestCase(APITestCase): @classmethod def setUpClass(cls): super().setUpClass() - path = os.path.join(settings.SHARE_ROOT, "test_1.jpg") - data = generate_image_file("test_1.jpg") - with open(path, 'wb') as image: + filename = "test_1.jpg" + path = os.path.join(settings.SHARE_ROOT, filename) + img_size, data = generate_image_file(filename) + with open(path, "wb") as image: image.write(data.read()) + cls._image_sizes[filename] = img_size - path = os.path.join(settings.SHARE_ROOT, "test_2.jpg") - data = generate_image_file("test_2.jpg") - with open(path, 'wb') as image: + filename = "test_2.jpg" + path = os.path.join(settings.SHARE_ROOT, filename) + img_size, data = generate_image_file(filename) + with open(path, "wb") as image: image.write(data.read()) + cls._image_sizes[filename] = img_size - path = os.path.join(settings.SHARE_ROOT, "test_3.jpg") - data = generate_image_file("test_3.jpg") - with open(path, 'wb') as image: + filename = "test_3.jpg" + path = os.path.join(settings.SHARE_ROOT, filename) + img_size, data = generate_image_file(filename) + with open(path, "wb") as image: image.write(data.read()) + cls._image_sizes[filename] = img_size - path = os.path.join(settings.SHARE_ROOT, "data", "test_3.jpg") + filename = os.path.join("data", "test_3.jpg") + path = os.path.join(settings.SHARE_ROOT, filename) os.makedirs(os.path.dirname(path)) - data = generate_image_file("test_3.jpg") - with open(path, 'wb') as image: + img_size, data = generate_image_file(filename) + with open(path, "wb") as image: image.write(data.read()) + cls._image_sizes[filename] = img_size + filename = "test_video_1.mp4" + path = os.path.join(settings.SHARE_ROOT, filename) + img_sizes, data = generate_video_file(filename, width=1280, height=720) + with open(path, "wb") as video: + video.write(data.read()) + cls._image_sizes[filename] = img_sizes + + filename = os.path.join("videos", "test_video_1.mp4") + path = os.path.join(settings.SHARE_ROOT, filename) + os.makedirs(os.path.dirname(path)) + img_sizes, data = generate_video_file(filename, width=1280, height=720) + with open(path, "wb") as video: + video.write(data.read()) + cls._image_sizes[filename] = img_sizes + + filename = os.path.join("test_archive_1.zip") + path = os.path.join(settings.SHARE_ROOT, filename) + img_sizes, data = generate_zip_archive_file(filename, count=5) + with open(path, "wb") as zip_archive: + zip_archive.write(data.read()) + cls._image_sizes[filename] = img_sizes @classmethod def tearDownClass(cls): @@ -1452,8 +1553,14 @@ class TaskDataAPITestCase(APITestCase): path = os.path.join(settings.SHARE_ROOT, "data", "test_3.jpg") os.remove(path) + path = os.path.join(settings.SHARE_ROOT, "test_video_1.mp4") + os.remove(path) + + path = os.path.join(settings.SHARE_ROOT, "videos", "test_video_1.mp4") + os.remove(path) - def _run_api_v1_tasks_id_data(self, tid, user, data): + + def _run_api_v1_tasks_id_data_post(self, tid, user, data): with ForceLogin(user, self.client): response = self.client.post('/api/v1/tasks/{}/data'.format(tid), data=data) @@ -1463,59 +1570,285 @@ class TaskDataAPITestCase(APITestCase): def _create_task(self, user, data): with ForceLogin(user, self.client): response = self.client.post('/api/v1/tasks', data=data, format="json") - return response + def _get_task(self, user, tid): + with ForceLogin(user, self.client): + return self.client.get("/api/v1/tasks/{}".format(tid)) + + def _run_api_v1_task_id_data_get(self, tid, user, data_type, data_quality=None, data_number=None): + url = '/api/v1/tasks/{}/data?type={}'.format(tid, data_type) + if data_quality is not None: + url += '&quality={}'.format(data_quality) + if data_number is not None: + url += '&number={}'.format(data_number) + with ForceLogin(user, self.client): + return self.client.get(url) + + def _get_preview(self, tid, user): + return self._run_api_v1_task_id_data_get(tid, user, "preview") + + def _get_compressed_chunk(self, tid, user, number): + return self._run_api_v1_task_id_data_get(tid, user, "chunk", "compressed", number) + + def _get_original_chunk(self, tid, user, number): + return self._run_api_v1_task_id_data_get(tid, user, "chunk", "original", number) + + def _get_compressed_frame(self, tid, user, number): + return self._run_api_v1_task_id_data_get(tid, user, "frame", "compressed", number) + + def _get_original_frame(self, tid, user, number): + return self._run_api_v1_task_id_data_get(tid, user, "frame", "original", number) + + @staticmethod + def _extract_zip_chunk(chunk_buffer): + chunk = zipfile.ZipFile(chunk_buffer, mode='r') + return [Image.open(BytesIO(chunk.read(f))) for f in sorted(chunk.namelist())] + + @staticmethod + def _extract_video_chunk(chunk_buffer): + container = av.open(chunk_buffer) + stream = container.streams.video[0] + return [f.to_image() for f in container.decode(stream)] + + def _test_api_v1_tasks_id_data_spec(self, user, spec, data, expected_compressed_type, expected_original_type, image_sizes): + # create task + response = self._create_task(user, spec) + self.assertEqual(response.status_code, status.HTTP_201_CREATED) + + task_id = response.data["id"] + + # post data for the task + response = self._run_api_v1_tasks_id_data_post(task_id, user, data) + self.assertEqual(response.status_code, status.HTTP_202_ACCEPTED) + + response = self._get_task(user, task_id) + + expected_status_code = status.HTTP_200_OK + if user == self.user and "owner" in spec and spec["owner"] != user.id and \ + "assignee" in spec and spec["assignee"] != user.id: + expected_status_code = status.HTTP_403_FORBIDDEN + self.assertEqual(response.status_code, expected_status_code) + + if expected_status_code == status.HTTP_200_OK: + task = response.json() + self.assertEqual(expected_compressed_type, task["data_compressed_chunk_type"]) + self.assertEqual(expected_original_type, task["data_original_chunk_type"]) + self.assertEqual(len(image_sizes), task["size"]) + + # check preview + response = self._get_preview(task_id, user) + self.assertEqual(response.status_code, expected_status_code) + if expected_status_code == status.HTTP_200_OK: + preview = Image.open(io.BytesIO(b"".join(response.streaming_content))) + self.assertEqual(preview.size, image_sizes[0]) + + # check compressed chunk + response = self._get_compressed_chunk(task_id, user, 0) + self.assertEqual(response.status_code, expected_status_code) + if expected_status_code == status.HTTP_200_OK: + compressed_chunk = io.BytesIO(b"".join(response.streaming_content)) + if task["data_compressed_chunk_type"] == self.ChunkType.IMAGESET: + images = self._extract_zip_chunk(compressed_chunk) + else: + images = self._extract_video_chunk(compressed_chunk) + + self.assertEqual(len(images), min(task["data_chunk_size"], len(image_sizes))) + + for image_idx, image in enumerate(images): + self.assertEqual(image.size, image_sizes[image_idx]) + + # check original chunk + response = self._get_original_chunk(task_id, user, 0) + self.assertEqual(response.status_code, expected_status_code) + if expected_status_code == status.HTTP_200_OK: + original_chunk = io.BytesIO(b"".join(response.streaming_content)) + if task["data_original_chunk_type"] == self.ChunkType.IMAGESET: + images = self._extract_zip_chunk(original_chunk) + else: + images = self._extract_video_chunk(original_chunk) + + for image_idx, image in enumerate(images): + self.assertEqual(image.size, image_sizes[image_idx]) + + self.assertEqual(len(images), min(task["data_chunk_size"], len(image_sizes))) + + if task["data_original_chunk_type"] == self.ChunkType.IMAGESET: + server_files = [img for key, img in data.items() if key.startswith("server_files")] + client_files = [img for key, img in data.items() if key.startswith("client_files")] + + if server_files: + source_files = [os.path.join(settings.SHARE_ROOT, f) for f in sorted(server_files)] + else: + source_files = [f for f in sorted(client_files, key=lambda e: e.name)] + + source_images = [] + for f in source_files: + if zipfile.is_zipfile(f): + source_images.extend(self._extract_zip_chunk(f)) + else: + source_images.append(Image.open(f)) + + for img_idx, image in enumerate(images): + server_image = np.array(image) + source_image = np.array(source_images[img_idx]) + self.assertTrue(np.array_equal(source_image, server_image)) + def _test_api_v1_tasks_id_data(self, user): - data = { + task_spec = { "name": "my task #1", "owner": self.owner.id, "assignee": self.assignee.id, "overlap": 0, "segment_size": 100, "z_order": False, - "image_quality": 75, "labels": [ {"name": "car"}, {"name": "person"}, ] } - response = self._create_task(user, data) - self.assertEqual(response.status_code, status.HTTP_201_CREATED) - task_id = response.data["id"] - data = { - "client_files[0]": generate_image_file("test_1.jpg"), - "client_files[1]": generate_image_file("test_2.jpg"), - "client_files[2]": generate_image_file("test_3.jpg"), + image_sizes, images = generate_image_files("test_1.jpg", "test_2.jpg", "test_3.jpg") + task_data = { + "client_files[0]": images[0], + "client_files[1]": images[1], + "client_files[2]": images[2], + "image_quality": 75, } - response = self._run_api_v1_tasks_id_data(task_id, user, data) - self.assertEqual(response.status_code, status.HTTP_202_ACCEPTED) + self._test_api_v1_tasks_id_data_spec(user, task_spec, task_data, self.ChunkType.IMAGESET, self.ChunkType.IMAGESET, image_sizes) - data = { + task_spec = { "name": "my task #2", "overlap": 0, "segment_size": 0, - "image_quality": 75, "labels": [ {"name": "car"}, {"name": "person"}, ] } - response = self._create_task(user, data) - self.assertEqual(response.status_code, status.HTTP_201_CREATED) - task_id = response.data["id"] - data = { + task_data = { "server_files[0]": "test_1.jpg", "server_files[1]": "test_2.jpg", "server_files[2]": "test_3.jpg", - "server_files[3]": "data/test_3.jpg", + "server_files[3]": os.path.join("data", "test_3.jpg"), + "image_quality": 75, } + image_sizes = [ + self._image_sizes[task_data["server_files[3]"]], + self._image_sizes[task_data["server_files[0]"]], + self._image_sizes[task_data["server_files[1]"]], + self._image_sizes[task_data["server_files[2]"]], + ] - response = self._run_api_v1_tasks_id_data(task_id, user, data) - self.assertEqual(response.status_code, status.HTTP_202_ACCEPTED) + self._test_api_v1_tasks_id_data_spec(user, task_spec, task_data, self.ChunkType.IMAGESET, self.ChunkType.IMAGESET, image_sizes) + + task_spec = { + "name": "my video task #1", + "overlap": 0, + "segment_size": 100, + "z_order": False, + "labels": [ + {"name": "car"}, + {"name": "person"}, + ] + } + image_sizes, video = generate_video_file(filename="test_video_1.mp4", width=1280, height=720) + task_data = { + "client_files[0]": video, + "image_quality": 43, + } + + self._test_api_v1_tasks_id_data_spec(user, task_spec, task_data, self.ChunkType.VIDEO, self.ChunkType.VIDEO, image_sizes) + + task_spec = { + "name": "my video task #2", + "overlap": 0, + "segment_size": 5, + "labels": [ + {"name": "car"}, + {"name": "person"}, + ] + } + + task_data = { + "server_files[0]": "test_video_1.mp4", + "image_quality": 57, + } + image_sizes = self._image_sizes[task_data["server_files[0]"]] + + self._test_api_v1_tasks_id_data_spec(user, task_spec, task_data, self.ChunkType.VIDEO, self.ChunkType.VIDEO, image_sizes) + + task_spec = { + "name": "my video task #3", + "overlap": 0, + "segment_size": 0, + "labels": [ + {"name": "car"}, + {"name": "person"}, + ] + } + task_data = { + "server_files[0]": os.path.join("videos", "test_video_1.mp4"), + "image_quality": 57, + } + image_sizes = self._image_sizes[task_data["server_files[0]"]] + + self._test_api_v1_tasks_id_data_spec(user, task_spec, task_data, self.ChunkType.VIDEO, self.ChunkType.VIDEO, image_sizes) + + task_spec = { + "name": "my video task #4", + "overlap": 0, + "segment_size": 5, + "labels": [ + {"name": "car"}, + {"name": "person"}, + ] + } + + task_data = { + "server_files[0]": "test_video_1.mp4", + "image_quality": 12, + "use_zip_chunks": True, + } + image_sizes = self._image_sizes[task_data["server_files[0]"]] + + self._test_api_v1_tasks_id_data_spec(user, task_spec, task_data, self.ChunkType.IMAGESET, self.ChunkType.VIDEO, image_sizes) + + task_spec = { + "name": "my archive task #6", + "overlap": 0, + "segment_size": 0, + "labels": [ + {"name": "car"}, + {"name": "person"}, + ] + } + task_data = { + "server_files[0]": "test_archive_1.zip", + "image_quality": 88, + } + image_sizes = self._image_sizes[task_data["server_files[0]"]] + + self._test_api_v1_tasks_id_data_spec(user, task_spec, task_data, self.ChunkType.IMAGESET, self.ChunkType.IMAGESET, image_sizes) + + task_spec = { + "name": "my archive task #7", + "overlap": 0, + "segment_size": 0, + "labels": [ + {"name": "car"}, + {"name": "person"}, + ] + } + image_sizes, archive = generate_zip_archive_file("test_archive_2.zip", 7) + task_data = { + "client_files[0]": archive, + "image_quality": 100, + } + + self._test_api_v1_tasks_id_data_spec(user, task_spec, task_data, self.ChunkType.IMAGESET, self.ChunkType.IMAGESET, image_sizes) def test_api_v1_tasks_id_data_admin(self): self._test_api_v1_tasks_id_data(self.admin) @@ -1534,7 +1867,6 @@ class TaskDataAPITestCase(APITestCase): "overlap": 0, "segment_size": 100, "z_order": False, - "image_quality": 75, "labels": [ {"name": "car"}, {"name": "person"}, @@ -1577,7 +1909,6 @@ class JobAnnotationAPITestCase(APITestCase): "overlap": 0, "segment_size": 100, "z_order": False, - "image_quality": 75, "labels": [ { "name": "car", @@ -1607,9 +1938,10 @@ class JobAnnotationAPITestCase(APITestCase): tid = response.data["id"] images = { - "client_files[0]": generate_image_file("test_1.jpg"), - "client_files[1]": generate_image_file("test_2.jpg"), - "client_files[2]": generate_image_file("test_3.jpg"), + "client_files[0]": generate_image_file("test_1.jpg")[1], + "client_files[1]": generate_image_file("test_2.jpg")[1], + "client_files[2]": generate_image_file("test_3.jpg")[1], + "image_quality": 75, } response = self.client.post("/api/v1/tasks/{}/data".format(tid), data=images) assert response.status_code == status.HTTP_202_ACCEPTED @@ -2731,7 +3063,6 @@ class TaskAnnotationAPITestCase(JobAnnotationAPITestCase): response = self._get_annotation_formats(annotator) self.assertEqual(response.status_code, HTTP_200_OK) - if annotator is not None: supported_formats = response.data else: diff --git a/cvat/apps/engine/views.py b/cvat/apps/engine/views.py index 8536f21a..fb590b69 100644 --- a/cvat/apps/engine/views.py +++ b/cvat/apps/engine/views.py @@ -6,13 +6,12 @@ import os import os.path as osp import re import traceback -from ast import literal_eval import shutil from datetime import datetime from tempfile import mkstemp from django.views.generic import RedirectView -from django.http import HttpResponseBadRequest, HttpResponseNotFound +from django.http import HttpResponse, HttpResponseNotFound from django.shortcuts import render from django.conf import settings from sendfile import sendfile @@ -24,6 +23,7 @@ from rest_framework import viewsets from rest_framework import serializers from rest_framework.decorators import action from rest_framework import mixins +from rest_framework.exceptions import APIException from django_filters import rest_framework as filters import django_rq from django.db import IntegrityError @@ -36,8 +36,8 @@ from cvat.apps.authentication.decorators import login_required from .log import slogger, clogger from cvat.apps.engine.models import StatusChoice, Task, Job, Plugin from cvat.apps.engine.serializers import (TaskSerializer, UserSerializer, - ExceptionSerializer, AboutSerializer, JobSerializer, ImageMetaSerializer, - RqStatusSerializer, TaskDataSerializer, LabeledDataSerializer, + ExceptionSerializer, AboutSerializer, JobSerializer, DataMetaSerializer, + RqStatusSerializer, DataSerializer, LabeledDataSerializer, PluginSerializer, FileInfoSerializer, LogEventSerializer, ProjectSerializer, BasicUserSerializer) from cvat.apps.annotation.serializers import AnnotationFileSerializer, AnnotationFormatSerializer @@ -47,6 +47,7 @@ from cvat.apps.authentication import auth from rest_framework.permissions import SAFE_METHODS from cvat.apps.annotation.models import AnnotationDumper, AnnotationLoader from cvat.apps.annotation.format import get_annotation_formats +from cvat.apps.engine.frame_provider import FrameProvider import cvat.apps.dataset_manager.task as DatumaroTask from drf_yasg.utils import swagger_auto_schema @@ -375,6 +376,9 @@ class TaskViewSet(auth.TaskGetQuerySetMixin, viewsets.ModelViewSet): task_dirname = instance.get_task_dirname() super().perform_destroy(instance) shutil.rmtree(task_dirname, ignore_errors=True) + if instance.data and not instance.data.tasks.all(): + shutil.rmtree(instance.data.get_data_dirname(), ignore_errors=True) + instance.data.delete() @swagger_auto_schema(method='get', operation_summary='Returns a list of jobs for a specific task', responses={'200': JobSerializer(many=True)}) @@ -388,17 +392,79 @@ class TaskViewSet(auth.TaskGetQuerySetMixin, viewsets.ModelViewSet): return Response(serializer.data) @swagger_auto_schema(method='post', operation_summary='Method permanently attaches images or video to a task') - @action(detail=True, methods=['POST'], serializer_class=TaskDataSerializer) + @swagger_auto_schema(method='get', operation_summary='Method returns data for a specific task', + manual_parameters=[ + openapi.Parameter('type', in_=openapi.IN_QUERY, required=True, type=openapi.TYPE_STRING, + enum=['chunk', 'frame', 'preview'], + description="Specifies the type of the requested data"), + openapi.Parameter('quality', in_=openapi.IN_QUERY, required=True, type=openapi.TYPE_STRING, + enum=['compressed', 'original'], + description="Specifies the quality level of the requested data, doesn't matter for 'preview' type"), + openapi.Parameter('number', in_=openapi.IN_QUERY, required=True, type=openapi.TYPE_NUMBER, + description="A unique number value identifying chunk or frame, doesn't matter for 'preview' type"), + ] + ) + @action(detail=True, methods=['POST', 'GET']) def data(self, request, pk): - """ - These data cannot be changed later - """ - db_task = self.get_object() # call check_object_permissions as well - serializer = TaskDataSerializer(db_task, data=request.data) - if serializer.is_valid(raise_exception=True): - serializer.save() - task.create(db_task.id, serializer.data) + if request.method == 'POST': + db_task = self.get_object() # call check_object_permissions as well + serializer = DataSerializer(data=request.data) + serializer.is_valid(raise_exception=True) + db_data = serializer.save() + db_task.data = db_data + db_task.save() + data = {k:v for k, v in serializer.data.items()} + data['use_zip_chunks'] = serializer.validated_data['use_zip_chunks'] + task.create(db_task.id, data) return Response(serializer.data, status=status.HTTP_202_ACCEPTED) + else: + data_type = request.query_params.get('type', None) + data_id = request.query_params.get('number', None) + data_quality = request.query_params.get('quality', 'compressed') + + possible_data_type_values = ('chunk', 'frame', 'preview') + possible_quality_values = ('compressed', 'original') + + if not data_type or data_type not in possible_data_type_values: + return Response(data='data type not specified or has wrong value', status=status.HTTP_400_BAD_REQUEST) + elif data_type == 'chunk' or data_type == 'frame': + if not data_id: + return Response(data='number not specified', status=status.HTTP_400_BAD_REQUEST) + elif data_quality not in possible_quality_values: + return Response(data='wrong quality value', status=status.HTTP_400_BAD_REQUEST) + + try: + db_task = self.get_object() + frame_provider = FrameProvider(db_task.data) + + if data_type == 'chunk': + data_id = int(data_id) + data_quality = FrameProvider.Quality.COMPRESSED \ + if data_quality == 'compressed' else FrameProvider.Quality.ORIGINAL + path = os.path.realpath(frame_provider.get_chunk(data_id, data_quality)) + + # Follow symbol links if the chunk is a link on a real image otherwise + # mimetype detection inside sendfile will work incorrectly. + return sendfile(request, path) + + elif data_type == 'frame': + data_id = int(data_id) + data_quality = FrameProvider.Quality.COMPRESSED \ + if data_quality == 'compressed' else FrameProvider.Quality.ORIGINAL + buf, mime = frame_provider.get_frame(data_id, data_quality) + + return HttpResponse(buf.getvalue(), content_type=mime) + + elif data_type == 'preview': + return sendfile(request, frame_provider.get_preview()) + else: + return Response(data='unknown data type {}.'.format(data_type), status=status.HTTP_400_BAD_REQUEST) + except APIException as e: + return Response(data=e.default_detail, status=e.status_code) + except Exception as e: + msg = 'cannot get requested data type: {}, number: {}, quality: {}'.format(data_type, data_id, data_quality) + slogger.task[pk].error(msg, exc_info=True) + return Response(data=msg + '\n' + str(e), status=status.HTTP_400_BAD_REQUEST) @swagger_auto_schema(method='get', operation_summary='Method returns annotations for a specific task') @swagger_auto_schema(method='put', operation_summary='Method performs an update of all annotations in a specific task') @@ -477,7 +543,7 @@ class TaskViewSet(auth.TaskGetQuerySetMixin, viewsets.ModelViewSet): raise serializers.ValidationError( "Please specify a correct 'format' parameter for the request") - file_path = os.path.join(db_task.get_task_dirname(), + file_path = os.path.join(db_task.get_task_artifacts_dirname(), "{}.{}.{}.{}".format(filename, username, timestamp, db_dumper.format.lower())) queue = django_rq.get_queue("default") @@ -548,40 +614,30 @@ class TaskViewSet(auth.TaskGetQuerySetMixin, viewsets.ModelViewSet): return response - @swagger_auto_schema(method='get', operation_summary='Method provides a list of sizes (width, height) of media files which are related with the task', - responses={'200': ImageMetaSerializer(many=True)}) - @action(detail=True, methods=['GET'], serializer_class=ImageMetaSerializer, - url_path='frames/meta') - def data_info(self, request, pk): - try: - db_task = self.get_object() # call check_object_permissions as well - meta_cache_file = open(db_task.get_image_meta_cache_path()) - except OSError: - task.make_image_meta_cache(db_task) - meta_cache_file = open(db_task.get_image_meta_cache_path()) + @staticmethod + @swagger_auto_schema(method='get', operation_summary='Method provides a meta information about media files which are related with the task', + responses={'200': DataMetaSerializer()}) + @action(detail=True, methods=['GET'], serializer_class=DataMetaSerializer, + url_path='data/meta') + def data_info(request, pk): + db_task = models.Task.objects.prefetch_related('data__images').select_related('data__video').get(pk=pk) + + if hasattr(db_task.data, 'video'): + media = [db_task.data.video] + else: + media = list(db_task.data.images.order_by('frame')) - data = literal_eval(meta_cache_file.read()) - serializer = ImageMetaSerializer(many=True, data=data['original_size']) - if serializer.is_valid(raise_exception=True): - return Response(serializer.data) + frame_meta = [{ + 'width': item.width, + 'height': item.height, + 'name': item.path, + } for item in media] - @swagger_auto_schema(method='get', manual_parameters=[openapi.Parameter('frame', openapi.IN_PATH, required=True, - description="A unique integer value identifying this frame", type=openapi.TYPE_INTEGER)], - operation_summary='Method returns a specific frame for a specific task', - responses={'200': openapi.Response(description='frame')}) - @action(detail=True, methods=['GET'], serializer_class=None, - url_path='frames/(?P