diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 095a9f5a26c3792637f994f3ad29d7a7e40090f3..a235b5650da38e148988d6b74c862064ddf1a48e 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -82,12 +82,10 @@ build_test_image: - docker login -u gitlab-ci-token -p $CI_JOB_TOKEN $CI_REGISTRY - docker pull $DEV_IMAGE_BASE || true - docker build --network=host --cache-from $DEV_IMAGE_BASE -t $DEV_IMAGE_BASE --target node . - - docker push $DEV_IMAGE_BASE - - docker image prune --filter label=stage=intermediate - docker pull $DEV_IMAGE || true - docker build --network=host --cache-from $DEV_IMAGE --cache-from $DEV_IMAGE_BASE -t $DEV_IMAGE . + - docker push $DEV_IMAGE_BASE - docker push $DEV_IMAGE - - docker image prune --filter label=stage=intermediate tags: - docker interruptible: true diff --git a/frontend/package.json b/frontend/package.json index ef5d5cd8cd797de59f7d2b5158f54fb520f416c4..6ed231a385aa98dae3d39974ca4d24efde8d638c 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -13,7 +13,6 @@ "axios": "^0.18.0", "file-saver": "^2.0.2", "highlight.js": "^9.12.0", - "marked": "^4.0.18", "v-clipboard": "^2.0.1", "vue": "^2.6.12", "vue-class-component": "^6.0.0", diff --git a/frontend/src/components/submission_notes/CorrectionHelpCard.vue b/frontend/src/components/submission_notes/CorrectionHelpCard.vue index 21783f536885221e46cc0489a9024377d9156458..0be45efe97d30fbbf616c525fd13d473644894fd 100644 --- a/frontend/src/components/submission_notes/CorrectionHelpCard.vue +++ b/frontend/src/components/submission_notes/CorrectionHelpCard.vue @@ -5,13 +5,6 @@ <h3>Tips on using the correction interface</h3> </v-card-title> <v-card-text> - Markdown is rendered by default. <br> - Select the math button to choose to have math rendered or not. <br> - In case you need the un-rendered markdown, click the "Copy to Clipboard" button. <br> - Cick on the individual line numbers in order to add comments for a specific line. <br> - After adding feedback to a line, clicking the "Hide feedback" button will hide it or show it. <br> - When feedback is hidden, the lines that contain feedback will be highlighted in red. <br> - <!-- ------THE OLD FLAVOR TEXT, SAVED IN CASE IT IS NEEDED FOR SOME REASON ------- Never trade an ale. The sea-dog leads with yellow fever, crush the captain's quarters until it waves.<br> Ho-ho-ho! malaria of life.<br> @@ -26,7 +19,7 @@ The scallywag loots with passion, crush the bikini atoll before it falls.<br> The sea leads with treasure, ransack the brig until it dies.<br> The parrot robs with desolation, view the seychelles before it screams.<br> - The warm anchor quirky blows the landlubber.<br> --> + The warm anchor quirky blows the landlubber.<br> </v-card-text> </v-card> </template> diff --git a/frontend/src/components/submission_notes/base/SubmissionLine.vue b/frontend/src/components/submission_notes/base/SubmissionLine.vue index 48d25b9f75e6c879fe397c4da6339f12e7ab1ee2..ee5537965cae1ba4517b851a916e0173e81643e2 100644 --- a/frontend/src/components/submission_notes/base/SubmissionLine.vue +++ b/frontend/src/components/submission_notes/base/SubmissionLine.vue @@ -16,12 +16,7 @@ </td> <td class="code-cell-content pl-2"> <!-- eslint-disable-next-line --> - <span - :key="key" - class="code-line" - v-html="html" - /> - + <span class="code-line" :key="key" v-html="code"/> <slot /> </td> </div> @@ -51,9 +46,7 @@ export default { }, data () { return { - key: 0, - html: '', - markdowned: true + key: 0 } }, computed: { @@ -65,10 +58,6 @@ export default { subNotesEventBus.$on('resetSubmission', () => { this.key++ }) - const { marked } = require('marked') - this.html = marked.parse(this.code) - - }, methods: { toggleEditor () { @@ -88,7 +77,7 @@ export default { } .code-line { - white-space: normal; + white-space: pre-wrap; font-family: monospace; } diff --git a/frontend/src/components/submission_notes/toolbars/AnnotatedSubmissionTopToolbar.vue b/frontend/src/components/submission_notes/toolbars/AnnotatedSubmissionTopToolbar.vue index c576b0f0e97b4b193b1a87c89cff0ac34f9e5428..4f42298d67716667d7f9c13158e575d2527e1511 100644 --- a/frontend/src/components/submission_notes/toolbars/AnnotatedSubmissionTopToolbar.vue +++ b/frontend/src/components/submission_notes/toolbars/AnnotatedSubmissionTopToolbar.vue @@ -24,32 +24,11 @@ <v-spacer /> <toggle-feedback-visibility-button /> <div v-if="isMarkdown"> - <v-btn - v-if="mathIsRendered" - large - text - color="info" - title="Math is being rendered" - :style="{backgroundColor: '#cce7ff'}" - @click="$emit('input', !mathIsRendered)" - > - <v-icon> - functions - </v-icon> - </v-btn> - <v-btn - v-else - large - text - color="grey" - title="Math is not being rendered" - @click="$emit('input', !mathIsRendered)" - > - <v-icon> - functions - </v-icon> + <v-btn @click="$emit('input', !mathIsRendered)"> + {{ mathIsRendered ? 'Reset Math' : 'Render Math' }} </v-btn> </div> + <v-spacer /> <v-tooltip v-if="sourceCodeAvailable" top @@ -80,7 +59,6 @@ <v-btn v-if="showClipboard" icon - text v-on="on" @click="copyToClipboard" > diff --git a/frontend/src/components/submission_notes/toolbars/ToggleFeedbackVisibilityButton.vue b/frontend/src/components/submission_notes/toolbars/ToggleFeedbackVisibilityButton.vue index 05b5587a95c0d8674edd35450294f24f798cae3d..453a5ea8ca702d9ee9cea16587d01650da2f1992 100644 --- a/frontend/src/components/submission_notes/toolbars/ToggleFeedbackVisibilityButton.vue +++ b/frontend/src/components/submission_notes/toolbars/ToggleFeedbackVisibilityButton.vue @@ -1,32 +1,16 @@ <template> <v-btn - v-if="showFeedback" id="feedback-visibility-toggle" - class="me-3" text color="info" - large - title="Feedback is on" - :style="{backgroundColor: '#cce7ff'}" @click="showFeedback = !showFeedback" > - <v-icon> - rate_review - </v-icon> - </v-btn> - <v-btn - v-else - id="feedback-visibility-toggle" - class="me-3" - text - large - color="grey" - title="Feedback is off" - @click="showFeedback = !showFeedback" - > - <v-icon> - rate_review - </v-icon> + <div v-if="showFeedback"> + Hide Feedback + </div> + <div v-else> + Show Feedback + </div> </v-btn> </template> diff --git a/frontend/yarn.lock b/frontend/yarn.lock index 9e0f0a76c89279e26bba304d30081566ed59f25d..f13a22aaa8371dfae0b9d57a0026cc1740f52280 100644 --- a/frontend/yarn.lock +++ b/frontend/yarn.lock @@ -2416,7 +2416,7 @@ domain-browser@^1.1.1: resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-1.2.0.tgz#3d31f50191a6749dd1375a7f522e823d42e54eda" integrity sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA== -domelementtype@1: +domelementtype@1, domelementtype@^1.3.1: version "1.3.1" resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-1.3.1.tgz#d048c44b37b0d10a7f2a3d5fee3f4333d790481f" integrity sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w== @@ -2569,6 +2569,26 @@ entities@^2.0.0: resolved "https://registry.yarnpkg.com/entities/-/entities-2.2.0.tgz#098dc90ebb83d8dffa089d55256b351d34c4da55" integrity sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A== +entities@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/entities/-/entities-2.2.0.tgz#098dc90ebb83d8dffa089d55256b351d34c4da55" + integrity sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A== + +entities@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/entities/-/entities-2.2.0.tgz#098dc90ebb83d8dffa089d55256b351d34c4da55" + integrity sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A== + +entities@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/entities/-/entities-2.2.0.tgz#098dc90ebb83d8dffa089d55256b351d34c4da55" + integrity sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A== + +entities@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/entities/-/entities-2.2.0.tgz#098dc90ebb83d8dffa089d55256b351d34c4da55" + integrity sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A== + errno@^0.1.3, errno@~0.1.7: version "0.1.8" resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.8.tgz#8bb3e9c7d463be4976ff888f76b4809ebc2e811f" @@ -4278,6 +4298,48 @@ is-negative-zero@^2.0.1: resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.1.tgz#3de746c18dda2319241a53675908d8f766f11c24" integrity sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w== +is-number-object@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/is-number-object/-/is-number-object-1.0.6.tgz#6a7aaf838c7f0686a50b4553f7e54a96494e89f0" + integrity sha512-bEVOqiRcvo3zO1+G2lVMy+gkkEm9Yh7cDMRusKKu5ZJKPUYSJwICTKZrNKHA2EbSP0Tu0+6B/emsYNHZyn6K8g== + dependencies: + has-tostringtag "^1.0.0" + +is-negative-zero@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.1.tgz#3de746c18dda2319241a53675908d8f766f11c24" + integrity sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w== + +is-number-object@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-number-object/-/is-number-object-1.0.4.tgz#36ac95e741cf18b283fc1ddf5e83da798e3ec197" + integrity sha512-zohwelOAur+5uXtk8O3GPQ1eAcu4ZX3UwxQhUlfFFMNpUd83gXgjbhJh6HmB6LUNV/ieOLQuDwJO3dWJosUeMw== + +is-negative-zero@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.1.tgz#3de746c18dda2319241a53675908d8f766f11c24" + integrity sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w== + +is-number-object@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-number-object/-/is-number-object-1.0.4.tgz#36ac95e741cf18b283fc1ddf5e83da798e3ec197" + integrity sha512-zohwelOAur+5uXtk8O3GPQ1eAcu4ZX3UwxQhUlfFFMNpUd83gXgjbhJh6HmB6LUNV/ieOLQuDwJO3dWJosUeMw== + +is-negative-zero@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.1.tgz#3de746c18dda2319241a53675908d8f766f11c24" + integrity sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w== + +is-number-object@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-number-object/-/is-number-object-1.0.4.tgz#36ac95e741cf18b283fc1ddf5e83da798e3ec197" + integrity sha512-zohwelOAur+5uXtk8O3GPQ1eAcu4ZX3UwxQhUlfFFMNpUd83gXgjbhJh6HmB6LUNV/ieOLQuDwJO3dWJosUeMw== + +is-negative-zero@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.1.tgz#3de746c18dda2319241a53675908d8f766f11c24" + integrity sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w== + is-number-object@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/is-number-object/-/is-number-object-1.0.4.tgz#36ac95e741cf18b283fc1ddf5e83da798e3ec197" @@ -4772,11 +4834,6 @@ map-visit@^1.0.0: dependencies: object-visit "^1.0.0" -marked@^4.0.18: - version "4.0.18" - resolved "https://registry.yarnpkg.com/marked/-/marked-4.0.18.tgz#cd0ac54b2e5610cfb90e8fd46ccaa8292c9ed569" - integrity sha512-wbLDJ7Zh0sqA0Vdg6aqlbT+yPxqLblpAZh1mK2+AO2twQkPywvvqQNfEPVwSSRjZ7dZcdeVBIAgiO7MMp3Dszw== - md5.js@^1.3.4: version "1.3.5" resolved "https://registry.yarnpkg.com/md5.js/-/md5.js-1.3.5.tgz#b5d07b8e3216e3e27cd728d72f70d1e6a342005f" diff --git a/grady/.coveragerc b/grady/.coveragerc deleted file mode 100644 index f578fcfa0b500bed801d7aa3717a1036d669f5f2..0000000000000000000000000000000000000000 --- a/grady/.coveragerc +++ /dev/null @@ -1,14 +0,0 @@ -[run] -branch = True -source = core,util.factories -omit = - core/migrations/* - core/apps.py - core/admin.py - core/tests/* - -[report] -ignore_errors = False - -[html] -directory = public diff --git a/grady/.dockerignore b/grady/.dockerignore deleted file mode 100644 index 41a3cce3c4dc84f2dcf53a19643d92bddfb742e3..0000000000000000000000000000000000000000 --- a/grady/.dockerignore +++ /dev/null @@ -1,30 +0,0 @@ -# Common -.git -Dockerfile - -# Django -*/db.sqlite3 -*/__pycache__* -*.pyc -*.pyo -*.pyd -*/env* -.venv -.ipynb_checkpoints -pip-log.txt -pip-delete-this-directory.txt -.tox -.coverage -.coverage.* -.cache -coverage.xml -*,cover -*.log -static/ -public/ - - -# node -*/node_modules -*/npm-debug.log -*/dist diff --git a/grady/.editorconfig b/grady/.editorconfig deleted file mode 100644 index 73622a70e09e90a96b57cc57fa3ef406dab8b43e..0000000000000000000000000000000000000000 --- a/grady/.editorconfig +++ /dev/null @@ -1,37 +0,0 @@ - -# top-most EditorConfig file -root = true - -# Unix-style newlines with a newline ending every file -[*] -end_of_line = lf -insert_final_newline = true -trim_trailing_whitespace = true - -# Python specific settigs -[*.py] -indent_style = space -indent_size = 4 -charset = utf-8 - -# html specific settigs -[*.html] -indent_style = space -indent_size = 2 -charset = utf-8 - -# Tab indentation (no size specified) -[Makefile] -indent_style = tab - -# Matches the exact files either package.json or .travis.yml -[{package.json,.travis.yml}] -indent_style = space -indent_size = 2 - -# Frontend -[*.{js,jsx,ts,tsx,vue}] -indent_style = space -indent_size = 2 -trim_trailing_whitespace = true -insert_final_newline = true diff --git a/grady/.gitignore b/grady/.gitignore deleted file mode 100644 index efc87898c8babf7ed30fac01246d073e1d921bc1..0000000000000000000000000000000000000000 --- a/grady/.gitignore +++ /dev/null @@ -1,47 +0,0 @@ -# python specific -*.DS_Store -*.egg-info -*.pot -*.py[co] -.tox/ -*.ipynb -.ipynb_checkpoints/ -__pycache__ -MANIFEST -.coverage -cache/ -.mypy_cache/ - -# Django specific -dist/ -docs/_build/ -docs/locale/ -tests/coverage_html/ -tests/.coverage -build/ -tests/report/ -*.sqlite3 -static/ - -# project specific -env-grady/ -env/ -.venv/ -scripts/ -coverage_html/ -.public/ -*.csv -.importer* -*.sublime-* -.idea/ -.vscode/ -anon-export/ -public/ -geckodriver.log -.screenshots - -# node -node_modules -secret -dump.sql -.pytest_cache/ diff --git a/grady/.gitlab-ci.yml b/grady/.gitlab-ci.yml deleted file mode 100644 index a235b5650da38e148988d6b74c862064ddf1a48e..0000000000000000000000000000000000000000 --- a/grady/.gitlab-ci.yml +++ /dev/null @@ -1,240 +0,0 @@ -stages: - - build - - test - - build_image - - pages - - staging - -variables: - WORKON_HOME: .pipenv/venvs - PIP_CACHE_DIR: .pipenv/pipcache - DEV_IMAGE: $CI_REGISTRY_IMAGE/dev-image - DEV_IMAGE_BASE: $CI_REGISTRY_IMAGE/dev-image-base - RELEASE_IMAGE: $CI_REGISTRY_IMAGE:$CI_COMMIT_TAG - DOCKER_DRIVER: overlay2 - DOCKER_TLS_CERTDIR: "" - POSTGRES_DB: $CI_POSTGRES_DB - POSTGRES_USER: $CI_POSTGRES_USER - POSTGRES_PASSWORD: $CI_POSTGRES_PASSWORD - -include: - template: Dependency-Scanning.gitlab-ci.yml - -cache: - key: "pip-cache" - paths: - - "$PIP_CACHE_DIR" - - # ========================== Build Testing section =========================== # -build_test_env: - image: python:3.8 - stage: build - script: - - pip install pipenv - - pipenv install --dev - artifacts: - paths: - - .pipenv - expire_in: 1 day - cache: - key: "$CI_PIPELINE_ID" - paths: - - "$WORKON_HOME" - tags: - - docker - interruptible: true - - -build_frontend: - image: node:fermium - stage: build - variables: - VUE_APP_CI: 'true' - script: - - cd frontend - - yarn - - yarn build - artifacts: - paths: - - frontend/dist - - frontend/node_modules/ - expire_in: 1 days - cache: - key: "$CI_PIPELINE_ID" - paths: - - frontend/dist - - frontend/node_modules/ - tags: - - docker - interruptible: true - -build_test_image: - image: docker:latest - stage: build - only: - - branches - services: - - docker:dind - variables: - DOCKER_HOST: tcp://docker:2375/ - DOCKER_DRIVER: overlay2 - script: - - docker login -u gitlab-ci-token -p $CI_JOB_TOKEN $CI_REGISTRY - - docker pull $DEV_IMAGE_BASE || true - - docker build --network=host --cache-from $DEV_IMAGE_BASE -t $DEV_IMAGE_BASE --target node . - - docker pull $DEV_IMAGE || true - - docker build --network=host --cache-from $DEV_IMAGE --cache-from $DEV_IMAGE_BASE -t $DEV_IMAGE . - - docker push $DEV_IMAGE_BASE - - docker push $DEV_IMAGE - tags: - - docker - interruptible: true - -# ============================== Testing section ============================= # -# ----------------------------- Backend subsection --------------------------- # -.test_template_virtualenv: &test_definition_virtualenv - image: python:3.8 - before_script: - - pip install pipenv - - VENV=$(pipenv --venv) - - source $VENV/bin/activate - dependencies: - - build_test_env - cache: - key: "$CI_PIPELINE_ID" - tags: - - docker - interruptible: true - needs: - - build_test_env - -test_pytest: - <<: *test_definition_virtualenv - stage: test - services: - - postgres:13 - script: - - pytest --cov --ds=grady.settings.test core/tests - artifacts: - paths: - - .coverage - cache: - key: "$CI_JOB_NAME" - paths: - - .coverage - -test_flake8: - <<: *test_definition_virtualenv - stage: test - script: - - flake8 --exclude=migrations core util functional_tests - -# ----------------------------- Frontend subsection -------------------------- # -.test_template_frontend: &test_definition_frontend - image: docker.gitlab.gwdg.de/grady-corp/python-geckodriver:master - before_script: - - pip install pipenv - - VENV=$(pipenv --venv) - - source $VENV/bin/activate - dependencies: - - build_test_env - - build_frontend - cache: - key: "$CI_PIPELINE_ID" - tags: - - docker - interruptible: true - needs: - - build_frontend - - build_test_env - -test_frontend: - <<: *test_definition_frontend - stage: test - services: - - postgres:13 - script: - - cp frontend/dist/index.html core/templates - - python util/format_index.py - - python manage.py collectstatic --no-input - - HEADLESS_TESTS=True pytest --ds=grady.settings.test functional_tests - artifacts: - paths: - - functional_tests/screenshots/ - when: on_failure - expire_in: 30 days - retry: 2 - -# =========================== Build Image section ============================ # - -build_release_image: - image: docker:latest - stage: build_image - only: - - tags - services: - - docker:dind - variables: - DOCKER_HOST: tcp://docker:2375/ - DOCKER_DRIVER: overlay2 - script: - - docker login -u gitlab-ci-token -p $CI_JOB_TOKEN $CI_REGISTRY - - docker pull $DEV_IMAGE_BASE || true - - docker pull $DEV_IMAGE || true - - docker build --cache-from $DEV_IMAGE --cache-from $DEV_IMAGE_BASE -t $RELEASE_IMAGE . - - docker push $RELEASE_IMAGE - tags: - - docker - -# =========================== Gitlab pages section =========================== # -pages: - <<: *test_definition_virtualenv - stage: - pages - script: - - coverage html -d public - dependencies: - - test_pytest - - build_test_env - artifacts: - paths: - - public - only: - - master - interruptible: true - needs: - - test_pytest - - build_test_env - -# ============================== Staging section ============================= # -.staging_template: &staging_definition - stage: staging - image: docker:latest - only: - - master - when: manual - before_script: - - apk add --update py-pip && pip install docker-compose - tags: - - grady-staging - -staging: - <<: *staging_definition - environment: - name: review/$CI_COMMIT_REF_NAME - url: https://staging.grady.janmax.org - on_stop: staging_stop - script: - - docker login -u gitlab-ci-token -p $CI_JOB_TOKEN $CI_REGISTRY - - docker-compose stop - - docker-compose pull - - docker-compose up -d --force-recreate - -staging_stop: - <<: *staging_definition - script: - - docker-compose rm --force --stop - when: manual - environment: - name: review/$CI_COMMIT_REF_NAME - action: stop diff --git a/grady/.gitlab/issue_templates/Bug.md b/grady/.gitlab/issue_templates/Bug.md deleted file mode 100644 index 34f76c3af7951ad09f051c581c53b8b0ec4a5153..0000000000000000000000000000000000000000 --- a/grady/.gitlab/issue_templates/Bug.md +++ /dev/null @@ -1,28 +0,0 @@ -#### Summary - - - -#### Steps to reproduce - - - -#### Example Project - - - -#### What is the current bug behavior? - - - -#### What is the expected correct behavior? - - - -#### Relevant logs and/or screenshots - - - -#### Possible fixes - -/label Bug -/label ~"Needs assignment" diff --git a/grady/.gitlab/issue_templates/Feature.md b/grady/.gitlab/issue_templates/Feature.md deleted file mode 100644 index 000831fe742facde606dfdcaf66d5b338ba584eb..0000000000000000000000000000000000000000 --- a/grady/.gitlab/issue_templates/Feature.md +++ /dev/null @@ -1,14 +0,0 @@ -### Description / Overview - -### Use cases - -(Who is this for?) - -### Links / references - -### Feature checklist - -(Make sure these are completed before closing the issue, with a link to the -relevant commit.) - -/label ~"Feature proposal" diff --git a/grady/.pre-commit-config.yaml b/grady/.pre-commit-config.yaml deleted file mode 100644 index 16e0bdac36a17b5fc891f58014a69c40d24ba469..0000000000000000000000000000000000000000 --- a/grady/.pre-commit-config.yaml +++ /dev/null @@ -1,10 +0,0 @@ -- repo: git@github.com:pre-commit/pre-commit-hooks - sha: v1.1.1 - hooks: - - id: trailing-whitespace - - id: end-of-file-fixer - - id: debug-statements - - id: flake8 - args: - - --exclude=*/migrations/*,docs/*,grady/* - - id: check-added-large-files diff --git a/grady/.pylintrc b/grady/.pylintrc deleted file mode 100644 index 2bfbcef12a25402143b5aa779e21246a103e01b2..0000000000000000000000000000000000000000 --- a/grady/.pylintrc +++ /dev/null @@ -1,20 +0,0 @@ -[MASTER] - -# Add files or directories to the blacklist. They should be base names, not -# paths. -ignore=CVS, migrations, static, env, docs, manage.py - -# Use multiple processes to speed up Pylint. -jobs=4 - -# Pickle collected data for later comparisons. -persistent=yes - -# When enabled, pylint would attempt to guess common misconfiguration and emit -# user-friendly hints instead of false-positive error messages -suggestion-mode=yes - -# List of plugins (as comma separated values of python modules names) to load, -# usually to register additional checkers. -load-plugins=pylint_django - diff --git a/grady/Dockerfile b/grady/Dockerfile deleted file mode 100644 index 36d0e47d267c769dd815e56b554e878b77ca9d2f..0000000000000000000000000000000000000000 --- a/grady/Dockerfile +++ /dev/null @@ -1,41 +0,0 @@ -FROM node:fermium as node - -WORKDIR /app/ -COPY frontend/package.json . -COPY frontend/yarn.lock . -RUN yarn - -# CACHED -COPY frontend/ . -RUN yarn build - -FROM alpine:edge - -WORKDIR /code - -# This set is needed otherwise the postgres driver wont work -RUN apk update \ - && apk add build-base gcc curl libzmq musl-dev zeromq-dev python3 python3-dev py3-pip \ - && apk add --no-cache postgresql-dev git - -# Create symlink for python -RUN ln -sf python3 /usr/bin/python - -RUN pip install pipenv -COPY Pipfile . -COPY Pipfile.lock . -RUN pipenv install --system --deploy && rm -rf /root/.cache - -# CACHED -COPY . . -COPY --from=node /app/dist /code/frontend/dist -COPY --from=node /app/dist/index.html /code/core/templates/index.html - -ENV PYTHONUNBUFFERED 1 -RUN python util/format_index.py -RUN python manage.py collectstatic --noinput - -# Reduces image size -RUN apk del build-base musl-dev python3-dev zeromq-dev - -CMD ["./deploy.sh"] diff --git a/grady/LICENSE b/grady/LICENSE deleted file mode 100644 index 9b744fc0bcb3e5eae009fb8e074e663c2a2d3b51..0000000000000000000000000000000000000000 --- a/grady/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2017 Jan Maximilian Michal - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/grady/Makefile b/grady/Makefile deleted file mode 100644 index ba608333ff68b97571ce7ab8eb343c68006ee55e..0000000000000000000000000000000000000000 --- a/grady/Makefile +++ /dev/null @@ -1,43 +0,0 @@ -APP_LIST ?= core grady util -DB_NAME = postgres - -.ONESHELL: - -.PHONY: run install migrations-check isort isort-check test teste2e - -run: - python manage.py runserver 0.0.0.0:8000 - -migrations-check: - python manage.py makemigrations --check --dry-run - -isort: - isort -rc $(APP_LIST) - -isort-check: - isort -c -rc $(APP_LIST) - -migrate: - python manage.py migrate - -test: - pytest --ds=grady.settings core/tests - -frontend/dist: $(shell find frontend/src -type f) - yarn --cwd frontend build - -teste2e: frontend/dist - set -e - cp frontend/dist/index.html core/templates - trap "git checkout core/templates/index.html" EXIT - python util/format_index.py - python manage.py collectstatic --no-input - HEADLESS_TESTS=$(headless) pytest --ds=grady.settings $(path) - -coverage: - set -e - DJANGO_SETTINGS_MODULE=grady.settings pytest --cov - coverage html - -db: - docker run -d --name $(DB_NAME) -p 5432:5432 -e POSTGRES_PASSWORD=postgres postgres:13 diff --git a/grady/Pipfile b/grady/Pipfile deleted file mode 100644 index cf502961b585db85bb245c9f3ce2fe0d577c3a77..0000000000000000000000000000000000000000 --- a/grady/Pipfile +++ /dev/null @@ -1,40 +0,0 @@ -[[source]] -name = "pypi" -url = "https://pypi.org/simple" -verify_ssl = true - -[dev-packages] -flake8 = "~=3.9.0" -pre-commit = "~=1.13.0" -pytest = "~=6.1.0" -pytest-cov = "~=2.10.1" -pytest-xdist = "~=2.1.0" -pytest-django = "~=3.10.0" -selenium = "~=3.141.0" -factory-boy = "~=3.0.1" -Faker = "~=4.1.3" - -[packages] -pyzmq = "~=22.3.0" -django-cors-headers = "~=3.5.0" -django-extensions = "~=3.0.9" -djangorestframework-jwt = "~=1.11.0" -djangorestframework = "~=3.11.0" -django-silk = "~=4.1.0" -djangorestframework-camel-case = {git = "https://gitlab.gwdg.de/grady-corp/djangorestframework-camel-case.git"} -drf-yasg = "~=1.17.1" -gunicorn = "~=20.0.4" -psycopg2-binary = "~=2.8.6" -whitenoise = "~=5.2.0" -xlrd = "~=1.2.0" -JSON-log-formatter = "~=0.3.0" -xkcdpass = "~=1.17.3" -django-constance = {extras = ["database"],version = "~=2.7.0"} -semver = "~=2.10.2" -Django = "~=3.1.1" -nbformat = "~=5.0.7" -nbconvert = "~=6.4.5" - - -[requires] -python_version = "3.8" diff --git a/grady/Pipfile.lock b/grady/Pipfile.lock deleted file mode 100644 index 90161f5372f92fb5b2b54a0dde3483c2a3043329..0000000000000000000000000000000000000000 --- a/grady/Pipfile.lock +++ /dev/null @@ -1,1129 +0,0 @@ -{ - "_meta": { - "hash": { - "sha256": "29b8205fd2ddf3d002a61251a9f6750cc38666561e5cbf5350ff9f3403079c7d" - }, - "pipfile-spec": 6, - "requires": { - "python_version": "3.8" - }, - "sources": [ - { - "name": "pypi", - "url": "https://pypi.org/simple", - "verify_ssl": true - } - ] - }, - "default": { - "asgiref": { - "hashes": [ - "sha256:45a429524fba18aba9d512498b19d220c4d628e75b40cf5c627524dbaebc5cc1", - "sha256:fddeea3c53fa99d0cdb613c3941cc6e52d822491fc2753fba25768fb5bf4e865" - ], - "markers": "python_version >= '3.7'", - "version": "==3.5.1" - }, - "attrs": { - "hashes": [ - "sha256:2d27e3784d7a565d36ab851fe94887c5eccd6a463168875832a1be79c82828b4", - "sha256:626ba8234211db98e869df76230a137c4c40a12d72445c45d5f5b716f076e2fd" - ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", - "version": "==21.4.0" - }, - "autopep8": { - "hashes": [ - "sha256:44f0932855039d2c15c4510d6df665e4730f2b8582704fa48f9c55bd3e17d979", - "sha256:ed77137193bbac52d029a52c59bec1b0629b5a186c495f1eb21b126ac466083f" - ], - "version": "==1.6.0" - }, - "beautifulsoup4": { - "hashes": [ - "sha256:58d5c3d29f5a36ffeb94f02f0d786cd53014cf9b3b3951d42e0080d8a9498d30", - "sha256:ad9aa55b65ef2808eb405f46cf74df7fcb7044d5cbc26487f96eb2ef2e436693" - ], - "markers": "python_version >= '3.6'", - "version": "==4.11.1" - }, - "bleach": { - "hashes": [ - "sha256:08a1fe86d253b5c88c92cc3d810fd8048a16d15762e1e5b74d502256e5926aa1", - "sha256:c6d6cc054bdc9c83b48b8083e236e5f00f238428666d2ce2e083eaa5fd568565" - ], - "markers": "python_version >= '3.7'", - "version": "==5.0.0" - }, - "certifi": { - "hashes": [ - "sha256:78884e7c1d4b00ce3cea67b44566851c4343c120abd683433ce934a68ea58872", - "sha256:d62a0163eb4c2344ac042ab2bdf75399a71a2d8c7d47eac2e2ee91b9d6339569" - ], - "version": "==2021.10.8" - }, - "charset-normalizer": { - "hashes": [ - "sha256:2857e29ff0d34db842cd7ca3230549d1a697f96ee6d3fb071cfa6c7393832597", - "sha256:6881edbebdb17b39b4eaaa821b438bf6eddffb4468cf344f09f89def34a8b1df" - ], - "markers": "python_version >= '3'", - "version": "==2.0.12" - }, - "coreapi": { - "hashes": [ - "sha256:46145fcc1f7017c076a2ef684969b641d18a2991051fddec9458ad3f78ffc1cb", - "sha256:bf39d118d6d3e171f10df9ede5666f63ad80bba9a29a8ec17726a66cf52ee6f3" - ], - "version": "==2.3.3" - }, - "coreschema": { - "hashes": [ - "sha256:5e6ef7bf38c1525d5e55a895934ab4273548629f16aed5c0a6caa74ebf45551f", - "sha256:9503506007d482ab0867ba14724b93c18a33b22b6d19fb419ef2d239dd4a1607" - ], - "version": "==0.0.4" - }, - "defusedxml": { - "hashes": [ - "sha256:1bb3032db185915b62d7c6209c5a8792be6a32ab2fedacc84e01b52c51aa3e69", - "sha256:a352e7e428770286cc899e2542b6cdaedb2b4953ff269a210103ec58f6198a61" - ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", - "version": "==0.7.1" - }, - "django": { - "hashes": [ - "sha256:0fabc786489af16ad87a8c170ba9d42bfd23f7b699bd5ef05675864e8d012859", - "sha256:72a4a5a136a214c39cf016ccdd6b69e2aa08c7479c66d93f3a9b5e4bb9d8a347" - ], - "index": "pypi", - "version": "==3.1.14" - }, - "django-constance": { - "extras": [ - "database" - ], - "hashes": [ - "sha256:62bdb1a3aef20d80e18d832b30ffcc6626762c538817a5a3571bcefa5a55c849", - "sha256:866a7356d3f8ee08374285e97c1edae70edaa3df6eaf7b2e9699f7cde8a88f3b" - ], - "index": "pypi", - "version": "==2.7.0" - }, - "django-cors-headers": { - "hashes": [ - "sha256:9322255c296d5f75089571f29e520c83ff9693df17aa3cf9f6a4bea7c6740169", - "sha256:db82b2840f667d47872ae3e4a4e0a0d72fbecb42779b8aa233fa8bb965f7836a" - ], - "index": "pypi", - "version": "==3.5.0" - }, - "django-extensions": { - "hashes": [ - "sha256:6809c89ca952f0e08d4e0766bc0101dfaf508d7649aced1180c091d737046ea7", - "sha256:dc663652ac9460fd06580a973576820430c6d428720e874ae46b041fa63e0efa" - ], - "index": "pypi", - "version": "==3.0.9" - }, - "django-picklefield": { - "hashes": [ - "sha256:15ccba592ca953b9edf9532e64640329cd47b136b7f8f10f2939caa5f9ce4287", - "sha256:3c702a54fde2d322fe5b2f39b8f78d9f655b8f77944ab26f703be6c0ed335a35" - ], - "version": "==3.0.1" - }, - "django-silk": { - "hashes": [ - "sha256:a331e55618fa62eaf3cf5a63f31bc1e91205efbeeca5e587c577498b0e251ed8" - ], - "index": "pypi", - "version": "==4.1.0" - }, - "djangorestframework": { - "hashes": [ - "sha256:5cc724dc4b076463497837269107e1995b1fbc917468d1b92d188fd1af9ea789", - "sha256:a5967b68a04e0d97d10f4df228e30f5a2d82ba63b9d03e1759f84993b7bf1b53" - ], - "index": "pypi", - "version": "==3.11.2" - }, - "djangorestframework-camel-case": { - "git": "https://gitlab.gwdg.de/grady-corp/djangorestframework-camel-case.git", - "ref": "39ae6bbde19d3fadc5b60505395c51f44b22a069" - }, - "djangorestframework-jwt": { - "hashes": [ - "sha256:5efe33032f3a4518a300dc51a51c92145ad95fb6f4b272e5aa24701db67936a7", - "sha256:ab15dfbbe535eede8e2e53adaf52ef0cf018ee27dbfad10cbc4cbec2ab63d38c" - ], - "index": "pypi", - "version": "==1.11.0" - }, - "drf-yasg": { - "hashes": [ - "sha256:5572e9d5baab9f6b49318169df9789f7399d0e3c7bdac8fdb8dfccf1d5d2b1ca", - "sha256:7d7af27ad16e18507e9392b2afd6b218fbffc432ec8dbea053099a2241e184ff" - ], - "index": "pypi", - "version": "==1.17.1" - }, - "entrypoints": { - "hashes": [ - "sha256:b706eddaa9218a19ebcd67b56818f05bb27589b1ca9e8d797b74affad4ccacd4", - "sha256:f174b5ff827504fd3cd97cc3f8649f3693f51538c7e4bdf3ef002c8429d42f9f" - ], - "markers": "python_version >= '3.6'", - "version": "==0.4" - }, - "gprof2dot": { - "hashes": [ - "sha256:1223189383b53dcc8ecfd45787ac48c0ed7b4dbc16ee8b88695d053eea1acabf" - ], - "version": "==2021.2.21" - }, - "gunicorn": { - "hashes": [ - "sha256:1904bb2b8a43658807108d59c3f3d56c2b6121a701161de0ddf9ad140073c626", - "sha256:cd4a810dd51bf497552cf3f863b575dabd73d6ad6a91075b65936b151cbf4f9c" - ], - "index": "pypi", - "version": "==20.0.4" - }, - "idna": { - "hashes": [ - "sha256:84d9dd047ffa80596e0f246e2eab0b391788b0503584e8945f2368256d2735ff", - "sha256:9d643ff0a55b762d5cdb124b8eaa99c66322e2157b69160bc32796e824360e6d" - ], - "markers": "python_version >= '3'", - "version": "==3.3" - }, - "importlib-resources": { - "hashes": [ - "sha256:b6062987dfc51f0fcb809187cffbd60f35df7acb4589091f154214af6d0d49d3", - "sha256:e447dc01619b1e951286f3929be820029d48c75eb25d265c28b92a16548212b8" - ], - "markers": "python_version < '3.9'", - "version": "==5.7.1" - }, - "inflection": { - "hashes": [ - "sha256:1a29730d366e996aaacffb2f1f1cb9593dc38e2ddd30c91250c6dde09ea9b417", - "sha256:f38b2b640938a4f35ade69ac3d053042959b62a0f1076a5bbaa1b9526605a8a2" - ], - "markers": "python_version >= '3.5'", - "version": "==0.5.1" - }, - "ipython-genutils": { - "hashes": [ - "sha256:72dd37233799e619666c9f639a9da83c34013a73e8bbc79a7a6348d93c61fab8", - "sha256:eb2e116e75ecef9d4d228fdc66af54269afa26ab4463042e33785b887c628ba8" - ], - "version": "==0.2.0" - }, - "itypes": { - "hashes": [ - "sha256:03da6872ca89d29aef62773672b2d408f490f80db48b23079a4b194c86dd04c6", - "sha256:af886f129dea4a2a1e3d36595a2d139589e4dd287f5cab0b40e799ee81570ff1" - ], - "version": "==1.2.0" - }, - "jinja2": { - "hashes": [ - "sha256:31351a702a408a9e7595a8fc6150fc3f43bb6bf7e319770cbc0db9df9437e852", - "sha256:6088930bfe239f0e6710546ab9c19c9ef35e29792895fed6e6e31a023a182a61" - ], - "markers": "python_version >= '3.7'", - "version": "==3.1.2" - }, - "json-log-formatter": { - "hashes": [ - "sha256:03029bddba697d2f6c81419a80f1c58d3a89ae715336c6a88b370e7d2c983198" - ], - "index": "pypi", - "version": "==0.3.1" - }, - "jsonschema": { - "hashes": [ - "sha256:71b5e39324422543546572954ce71c67728922c104902cb7ce252e522235b33f", - "sha256:7c6d882619340c3347a1bf7315e147e6d3dae439033ae6383d6acb908c101dfc" - ], - "markers": "python_version >= '3.7'", - "version": "==4.5.1" - }, - "jupyter-client": { - "hashes": [ - "sha256:05d4ff6a0ade25138c6bb0fbeac7ddc26b5fe835e7dd816b64b4a45b931bdc0b", - "sha256:404abe552540aff3527e66e16beb114b6b4ff58479d51a301f4eb9701e4f52ef" - ], - "markers": "python_version >= '3.7'", - "version": "==7.3.1" - }, - "jupyter-core": { - "hashes": [ - "sha256:a6de44b16b7b31d7271130c71a6792c4040f077011961138afed5e5e73181aec", - "sha256:e7f5212177af7ab34179690140f188aa9bf3d322d8155ed972cbded19f55b6f3" - ], - "markers": "python_version >= '3.7'", - "version": "==4.10.0" - }, - "jupyterlab-pygments": { - "hashes": [ - "sha256:2405800db07c9f770863bcf8049a529c3dd4d3e28536638bd7c1c01d2748309f", - "sha256:7405d7fde60819d905a9fa8ce89e4cd830e318cdad22a0030f7a901da705585d" - ], - "markers": "python_version >= '3.7'", - "version": "==0.2.2" - }, - "markupsafe": { - "hashes": [ - "sha256:0212a68688482dc52b2d45013df70d169f542b7394fc744c02a57374a4207003", - "sha256:089cf3dbf0cd6c100f02945abeb18484bd1ee57a079aefd52cffd17fba910b88", - "sha256:10c1bfff05d95783da83491be968e8fe789263689c02724e0c691933c52994f5", - "sha256:33b74d289bd2f5e527beadcaa3f401e0df0a89927c1559c8566c066fa4248ab7", - "sha256:3799351e2336dc91ea70b034983ee71cf2f9533cdff7c14c90ea126bfd95d65a", - "sha256:3ce11ee3f23f79dbd06fb3d63e2f6af7b12db1d46932fe7bd8afa259a5996603", - "sha256:421be9fbf0ffe9ffd7a378aafebbf6f4602d564d34be190fc19a193232fd12b1", - "sha256:43093fb83d8343aac0b1baa75516da6092f58f41200907ef92448ecab8825135", - "sha256:46d00d6cfecdde84d40e572d63735ef81423ad31184100411e6e3388d405e247", - "sha256:4a33dea2b688b3190ee12bd7cfa29d39c9ed176bda40bfa11099a3ce5d3a7ac6", - "sha256:4b9fe39a2ccc108a4accc2676e77da025ce383c108593d65cc909add5c3bd601", - "sha256:56442863ed2b06d19c37f94d999035e15ee982988920e12a5b4ba29b62ad1f77", - "sha256:671cd1187ed5e62818414afe79ed29da836dde67166a9fac6d435873c44fdd02", - "sha256:694deca8d702d5db21ec83983ce0bb4b26a578e71fbdbd4fdcd387daa90e4d5e", - "sha256:6a074d34ee7a5ce3effbc526b7083ec9731bb3cbf921bbe1d3005d4d2bdb3a63", - "sha256:6d0072fea50feec76a4c418096652f2c3238eaa014b2f94aeb1d56a66b41403f", - "sha256:6fbf47b5d3728c6aea2abb0589b5d30459e369baa772e0f37a0320185e87c980", - "sha256:7f91197cc9e48f989d12e4e6fbc46495c446636dfc81b9ccf50bb0ec74b91d4b", - "sha256:86b1f75c4e7c2ac2ccdaec2b9022845dbb81880ca318bb7a0a01fbf7813e3812", - "sha256:8dc1c72a69aa7e082593c4a203dcf94ddb74bb5c8a731e4e1eb68d031e8498ff", - "sha256:8e3dcf21f367459434c18e71b2a9532d96547aef8a871872a5bd69a715c15f96", - "sha256:8e576a51ad59e4bfaac456023a78f6b5e6e7651dcd383bcc3e18d06f9b55d6d1", - "sha256:96e37a3dc86e80bf81758c152fe66dbf60ed5eca3d26305edf01892257049925", - "sha256:97a68e6ada378df82bc9f16b800ab77cbf4b2fada0081794318520138c088e4a", - "sha256:99a2a507ed3ac881b975a2976d59f38c19386d128e7a9a18b7df6fff1fd4c1d6", - "sha256:a49907dd8420c5685cfa064a1335b6754b74541bbb3706c259c02ed65b644b3e", - "sha256:b09bf97215625a311f669476f44b8b318b075847b49316d3e28c08e41a7a573f", - "sha256:b7bd98b796e2b6553da7225aeb61f447f80a1ca64f41d83612e6139ca5213aa4", - "sha256:b87db4360013327109564f0e591bd2a3b318547bcef31b468a92ee504d07ae4f", - "sha256:bcb3ed405ed3222f9904899563d6fc492ff75cce56cba05e32eff40e6acbeaa3", - "sha256:d4306c36ca495956b6d568d276ac11fdd9c30a36f1b6eb928070dc5360b22e1c", - "sha256:d5ee4f386140395a2c818d149221149c54849dfcfcb9f1debfe07a8b8bd63f9a", - "sha256:dda30ba7e87fbbb7eab1ec9f58678558fd9a6b8b853530e176eabd064da81417", - "sha256:e04e26803c9c3851c931eac40c695602c6295b8d432cbe78609649ad9bd2da8a", - "sha256:e1c0b87e09fa55a220f058d1d49d3fb8df88fbfab58558f1198e08c1e1de842a", - "sha256:e72591e9ecd94d7feb70c1cbd7be7b3ebea3f548870aa91e2732960fa4d57a37", - "sha256:e8c843bbcda3a2f1e3c2ab25913c80a3c5376cd00c6e8c4a86a89a28c8dc5452", - "sha256:efc1913fd2ca4f334418481c7e595c00aad186563bbc1ec76067848c7ca0a933", - "sha256:f121a1420d4e173a5d96e47e9a0c0dcff965afdf1626d28de1460815f7c4ee7a", - "sha256:fc7b548b17d238737688817ab67deebb30e8073c95749d55538ed473130ec0c7" - ], - "markers": "python_version >= '3.7'", - "version": "==2.1.1" - }, - "mistune": { - "hashes": [ - "sha256:59a3429db53c50b5c6bcc8a07f8848cb00d7dc8bdb431a4ab41920d201d4756e", - "sha256:88a1051873018da288eee8538d476dffe1262495144b33ecb586c4ab266bb8d4" - ], - "version": "==0.8.4" - }, - "nbclient": { - "hashes": [ - "sha256:40c52c9b5e3c31faecaee69f202b3f53e38d7c1c563de0fadde9d7eda0fdafe8", - "sha256:47ac905af59379913c1f8f541098d2550153cf8dc58553cbe18c702b181518b0" - ], - "markers": "python_version >= '3.7'", - "version": "==0.5.13" - }, - "nbconvert": { - "hashes": [ - "sha256:21163a8e2073c07109ca8f398836e45efdba2aacea68d6f75a8a545fef070d4e", - "sha256:e01d219f55cc79f9701c834d605e8aa3acf35725345d3942e3983937f368ce14" - ], - "index": "pypi", - "version": "==6.4.5" - }, - "nbformat": { - "hashes": [ - "sha256:aa9450c16d29286dc69b92ea4913c1bffe86488f90184445996ccc03a2f60382", - "sha256:f545b22138865bfbcc6b1ffe89ed5a2b8e2dc5d4fe876f2ca60d8e6f702a30f8" - ], - "index": "pypi", - "version": "==5.0.8" - }, - "nest-asyncio": { - "hashes": [ - "sha256:b98e3ec1b246135e4642eceffa5a6c23a3ab12c82ff816a92c612d68205813b2", - "sha256:e442291cd942698be619823a17a86a5759eabe1f8613084790de189fe9e16d65" - ], - "markers": "python_version >= '3.5'", - "version": "==1.5.5" - }, - "packaging": { - "hashes": [ - "sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb", - "sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522" - ], - "markers": "python_version >= '3.6'", - "version": "==21.3" - }, - "pandocfilters": { - "hashes": [ - "sha256:0b679503337d233b4339a817bfc8c50064e2eff681314376a47cb582305a7a38", - "sha256:33aae3f25fd1a026079f5d27bdd52496f0e0803b3469282162bafdcbdf6ef14f" - ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==1.5.0" - }, - "psycopg2-binary": { - "hashes": [ - "sha256:0deac2af1a587ae12836aa07970f5cb91964f05a7c6cdb69d8425ff4c15d4e2c", - "sha256:0e4dc3d5996760104746e6cfcdb519d9d2cd27c738296525d5867ea695774e67", - "sha256:11b9c0ebce097180129e422379b824ae21c8f2a6596b159c7659e2e5a00e1aa0", - "sha256:15978a1fbd225583dd8cdaf37e67ccc278b5abecb4caf6b2d6b8e2b948e953f6", - "sha256:1fabed9ea2acc4efe4671b92c669a213db744d2af8a9fc5d69a8e9bc14b7a9db", - "sha256:2dac98e85565d5688e8ab7bdea5446674a83a3945a8f416ad0110018d1501b94", - "sha256:42ec1035841b389e8cc3692277a0bd81cdfe0b65d575a2c8862cec7a80e62e52", - "sha256:6422f2ff0919fd720195f64ffd8f924c1395d30f9a495f31e2392c2efafb5056", - "sha256:6a32f3a4cb2f6e1a0b15215f448e8ce2da192fd4ff35084d80d5e39da683e79b", - "sha256:7312e931b90fe14f925729cde58022f5d034241918a5c4f9797cac62f6b3a9dd", - "sha256:7d92a09b788cbb1aec325af5fcba9fed7203897bbd9269d5691bb1e3bce29550", - "sha256:833709a5c66ca52f1d21d41865a637223b368c0ee76ea54ca5bad6f2526c7679", - "sha256:89705f45ce07b2dfa806ee84439ec67c5d9a0ef20154e0e475e2b2ed392a5b83", - "sha256:8cd0fb36c7412996859cb4606a35969dd01f4ea34d9812a141cd920c3b18be77", - "sha256:950bc22bb56ee6ff142a2cb9ee980b571dd0912b0334aa3fe0fe3788d860bea2", - "sha256:a0c50db33c32594305b0ef9abc0cb7db13de7621d2cadf8392a1d9b3c437ef77", - "sha256:a0eb43a07386c3f1f1ebb4dc7aafb13f67188eab896e7397aa1ee95a9c884eb2", - "sha256:aaa4213c862f0ef00022751161df35804127b78adf4a2755b9f991a507e425fd", - "sha256:ac0c682111fbf404525dfc0f18a8b5f11be52657d4f96e9fcb75daf4f3984859", - "sha256:ad20d2eb875aaa1ea6d0f2916949f5c08a19c74d05b16ce6ebf6d24f2c9f75d1", - "sha256:b4afc542c0ac0db720cf516dd20c0846f71c248d2b3d21013aa0d4ef9c71ca25", - "sha256:b8a3715b3c4e604bcc94c90a825cd7f5635417453b253499664f784fc4da0152", - "sha256:ba28584e6bca48c59eecbf7efb1576ca214b47f05194646b081717fa628dfddf", - "sha256:ba381aec3a5dc29634f20692349d73f2d21f17653bda1decf0b52b11d694541f", - "sha256:bd1be66dde2b82f80afb9459fc618216753f67109b859a361cf7def5c7968729", - "sha256:c2507d796fca339c8fb03216364cca68d87e037c1f774977c8fc377627d01c71", - "sha256:cec7e622ebc545dbb4564e483dd20e4e404da17ae07e06f3e780b2dacd5cee66", - "sha256:d14b140a4439d816e3b1229a4a525df917d6ea22a0771a2a78332273fd9528a4", - "sha256:d1b4ab59e02d9008efe10ceabd0b31e79519da6fb67f7d8e8977118832d0f449", - "sha256:d5227b229005a696cc67676e24c214740efd90b148de5733419ac9aaba3773da", - "sha256:e1f57aa70d3f7cc6947fd88636a481638263ba04a742b4a37dd25c373e41491a", - "sha256:e74a55f6bad0e7d3968399deb50f61f4db1926acf4a6d83beaaa7df986f48b1c", - "sha256:e82aba2188b9ba309fd8e271702bd0d0fc9148ae3150532bbb474f4590039ffb", - "sha256:ee69dad2c7155756ad114c02db06002f4cded41132cc51378e57aad79cc8e4f4", - "sha256:f5ab93a2cb2d8338b1674be43b442a7f544a0971da062a5da774ed40587f18f5" - ], - "index": "pypi", - "version": "==2.8.6" - }, - "pycodestyle": { - "hashes": [ - "sha256:720f8b39dde8b293825e7ff02c475f3077124006db4f440dcbc9a20b76548a20", - "sha256:eddd5847ef438ea1c7870ca7eb78a9d47ce0cdb4851a5523949f2601d0cbbe7f" - ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", - "version": "==2.8.0" - }, - "pygments": { - "hashes": [ - "sha256:5eb116118f9612ff1ee89ac96437bb6b49e8f04d8a13b514ba26f620208e26eb", - "sha256:dc9c10fb40944260f6ed4c688ece0cd2048414940f1cea51b8b226318411c519" - ], - "markers": "python_version >= '3.6'", - "version": "==2.12.0" - }, - "pyjwt": { - "hashes": [ - "sha256:5c6eca3c2940464d106b99ba83b00c6add741c9becaec087fb7ccdefea71350e", - "sha256:8d59a976fb773f3e6a39c85636357c4f0e242707394cadadd9814f5cbaa20e96" - ], - "version": "==1.7.1" - }, - "pyparsing": { - "hashes": [ - "sha256:2b020ecf7d21b687f219b71ecad3631f644a47f01403fa1d1036b0c6416d70fb", - "sha256:5026bae9a10eeaefb61dab2f09052b9f4307d44aee4eda64b309723d8d206bbc" - ], - "markers": "python_full_version >= '3.6.8'", - "version": "==3.0.9" - }, - "pyrsistent": { - "hashes": [ - "sha256:0e3e1fcc45199df76053026a51cc59ab2ea3fc7c094c6627e93b7b44cdae2c8c", - "sha256:1b34eedd6812bf4d33814fca1b66005805d3640ce53140ab8bbb1e2651b0d9bc", - "sha256:4ed6784ceac462a7d6fcb7e9b663e93b9a6fb373b7f43594f9ff68875788e01e", - "sha256:5d45866ececf4a5fff8742c25722da6d4c9e180daa7b405dc0a2a2790d668c26", - "sha256:636ce2dc235046ccd3d8c56a7ad54e99d5c1cd0ef07d9ae847306c91d11b5fec", - "sha256:6455fc599df93d1f60e1c5c4fe471499f08d190d57eca040c0ea182301321286", - "sha256:6bc66318fb7ee012071b2792024564973ecc80e9522842eb4e17743604b5e045", - "sha256:7bfe2388663fd18bd8ce7db2c91c7400bf3e1a9e8bd7d63bf7e77d39051b85ec", - "sha256:7ec335fc998faa4febe75cc5268a9eac0478b3f681602c1f27befaf2a1abe1d8", - "sha256:914474c9f1d93080338ace89cb2acee74f4f666fb0424896fcfb8d86058bf17c", - "sha256:b568f35ad53a7b07ed9b1b2bae09eb15cdd671a5ba5d2c66caee40dbf91c68ca", - "sha256:cdfd2c361b8a8e5d9499b9082b501c452ade8bbf42aef97ea04854f4a3f43b22", - "sha256:d1b96547410f76078eaf66d282ddca2e4baae8964364abb4f4dcdde855cd123a", - "sha256:d4d61f8b993a7255ba714df3aca52700f8125289f84f704cf80916517c46eb96", - "sha256:d7a096646eab884bf8bed965bad63ea327e0d0c38989fc83c5ea7b8a87037bfc", - "sha256:df46c854f490f81210870e509818b729db4488e1f30f2a1ce1698b2295a878d1", - "sha256:e24a828f57e0c337c8d8bb9f6b12f09dfdf0273da25fda9e314f0b684b415a07", - "sha256:e4f3149fd5eb9b285d6bfb54d2e5173f6a116fe19172686797c056672689daf6", - "sha256:e92a52c166426efbe0d1ec1332ee9119b6d32fc1f0bbfd55d5c1088070e7fc1b", - "sha256:f87cc2863ef33c709e237d4b5f4502a62a00fab450c9e020892e8e2ede5847f5", - "sha256:fd8da6d0124efa2f67d86fa70c851022f87c98e205f0594e1fae044e7119a5a6" - ], - "markers": "python_version >= '3.7'", - "version": "==0.18.1" - }, - "python-dateutil": { - "hashes": [ - "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86", - "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9" - ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==2.8.2" - }, - "pytz": { - "hashes": [ - "sha256:1e760e2fe6a8163bc0b3d9a19c4f84342afa0a2affebfaa84b01b978a02ecaa7", - "sha256:e68985985296d9a66a881eb3193b0906246245294a881e7c8afe623866ac6a5c" - ], - "version": "==2022.1" - }, - "pyzmq": { - "hashes": [ - "sha256:08c4e315a76ef26eb833511ebf3fa87d182152adf43dedee8d79f998a2162a0b", - "sha256:0ca6cd58f62a2751728016d40082008d3b3412a7f28ddfb4a2f0d3c130f69e74", - "sha256:1621e7a2af72cced1f6ec8ca8ca91d0f76ac236ab2e8828ac8fe909512d566cb", - "sha256:18cd854b423fce44951c3a4d3e686bac8f1243d954f579e120a1714096637cc0", - "sha256:2841997a0d85b998cbafecb4183caf51fd19c4357075dfd33eb7efea57e4c149", - "sha256:2b97502c16a5ec611cd52410bdfaab264997c627a46b0f98d3f666227fd1ea2d", - "sha256:3a4c9886d61d386b2b493377d980f502186cd71d501fffdba52bd2a0880cef4f", - "sha256:3c1895c95be92600233e476fe283f042e71cf8f0b938aabf21b7aafa62a8dac9", - "sha256:42abddebe2c6a35180ca549fadc7228d23c1e1f76167c5ebc8a936b5804ea2df", - "sha256:468bd59a588e276961a918a3060948ae68f6ff5a7fa10bb2f9160c18fe341067", - "sha256:480b9931bfb08bf8b094edd4836271d4d6b44150da051547d8c7113bf947a8b0", - "sha256:53f4fd13976789ffafedd4d46f954c7bb01146121812b72b4ddca286034df966", - "sha256:62bcade20813796c426409a3e7423862d50ff0639f5a2a95be4b85b09a618666", - "sha256:67db33bea0a29d03e6eeec55a8190e033318cee3cbc732ba8fd939617cbf762d", - "sha256:6b217b8f9dfb6628f74b94bdaf9f7408708cb02167d644edca33f38746ca12dd", - "sha256:7661fc1d5cb73481cf710a1418a4e1e301ed7d5d924f91c67ba84b2a1b89defd", - "sha256:76c532fd68b93998aab92356be280deec5de8f8fe59cd28763d2cc8a58747b7f", - "sha256:79244b9e97948eaf38695f4b8e6fc63b14b78cc37f403c6642ba555517ac1268", - "sha256:7c58f598d9fcc52772b89a92d72bf8829c12d09746a6d2c724c5b30076c1f11d", - "sha256:7dc09198e4073e6015d9a8ea093fc348d4e59de49382476940c3dd9ae156fba8", - "sha256:80e043a89c6cadefd3a0712f8a1322038e819ebe9dbac7eca3bce1721bcb63bf", - "sha256:851977788b9caa8ed011f5f643d3ee8653af02c5fc723fa350db5125abf2be7b", - "sha256:8eddc033e716f8c91c6a2112f0a8ebc5e00532b4a6ae1eb0ccc48e027f9c671c", - "sha256:902319cfe23366595d3fa769b5b751e6ee6750a0a64c5d9f757d624b2ac3519e", - "sha256:954e73c9cd4d6ae319f1c936ad159072b6d356a92dcbbabfd6e6204b9a79d356", - "sha256:ab888624ed68930442a3f3b0b921ad7439c51ba122dbc8c386e6487a658e4a4e", - "sha256:acebba1a23fb9d72b42471c3771b6f2f18dcd46df77482612054bd45c07dfa36", - "sha256:b4ebed0977f92320f6686c96e9e8dd29eed199eb8d066936bac991afc37cbb70", - "sha256:badb868fff14cfd0e200eaa845887b1011146a7d26d579aaa7f966c203736b92", - "sha256:be4e0f229cf3a71f9ecd633566bd6f80d9fa6afaaff5489492be63fe459ef98c", - "sha256:c0f84360dcca3481e8674393bdf931f9f10470988f87311b19d23cda869bb6b7", - "sha256:c1e41b32d6f7f9c26bc731a8b529ff592f31fc8b6ef2be9fa74abd05c8a342d7", - "sha256:c88fa7410e9fc471e0858638f403739ee869924dd8e4ae26748496466e27ac59", - "sha256:cf98fd7a6c8aaa08dbc699ffae33fd71175696d78028281bc7b832b26f00ca57", - "sha256:d072f7dfbdb184f0786d63bda26e8a0882041b1e393fbe98940395f7fab4c5e2", - "sha256:d1b5d457acbadcf8b27561deeaa386b0217f47626b29672fa7bd31deb6e91e1b", - "sha256:d3dcb5548ead4f1123851a5ced467791f6986d68c656bc63bfff1bf9e36671e2", - "sha256:d6157793719de168b199194f6b6173f0ccd3bf3499e6870fac17086072e39115", - "sha256:d728b08448e5ac3e4d886b165385a262883c34b84a7fe1166277fe675e1c197a", - "sha256:de8df0684398bd74ad160afdc2a118ca28384ac6f5e234eb0508858d8d2d9364", - "sha256:e6a02cf7271ee94674a44f4e62aa061d2d049001c844657740e156596298b70b", - "sha256:ea12133df25e3a6918718fbb9a510c6ee5d3fdd5a346320421aac3882f4feeea", - "sha256:ea5a79e808baef98c48c884effce05c31a0698c1057de8fc1c688891043c1ce1", - "sha256:f43b4a2e6218371dd4f41e547bd919ceeb6ebf4abf31a7a0669cd11cd91ea973", - "sha256:f762442bab706fd874064ca218b33a1d8e40d4938e96c24dafd9b12e28017f45", - "sha256:f89468059ebc519a7acde1ee50b779019535db8dcf9b8c162ef669257fef7a93", - "sha256:f907c7359ce8bf7f7e63c82f75ad0223384105f5126f313400b7e8004d9b33c3" - ], - "index": "pypi", - "version": "==22.3.0" - }, - "requests": { - "hashes": [ - "sha256:68d7c56fd5a8999887728ef304a6d12edc7be74f1cfa47714fc8b414525c9a61", - "sha256:f22fa1e554c9ddfd16e6e41ac79759e17be9e492b3587efa038054674760e72d" - ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5'", - "version": "==2.27.1" - }, - "ruamel.yaml": { - "hashes": [ - "sha256:742b35d3d665023981bd6d16b3d24248ce5df75fdb4e2924e93a05c1f8b61ca7", - "sha256:8b7ce697a2f212752a35c1ac414471dc16c424c9573be4926b56ff3f5d23b7af" - ], - "markers": "python_version >= '3'", - "version": "==0.17.21" - }, - "ruamel.yaml.clib": { - "hashes": [ - "sha256:0847201b767447fc33b9c235780d3aa90357d20dd6108b92be544427bea197dd", - "sha256:1070ba9dd7f9370d0513d649420c3b362ac2d687fe78c6e888f5b12bf8bc7bee", - "sha256:1866cf2c284a03b9524a5cc00daca56d80057c5ce3cdc86a52020f4c720856f0", - "sha256:221eca6f35076c6ae472a531afa1c223b9c29377e62936f61bc8e6e8bdc5f9e7", - "sha256:31ea73e564a7b5fbbe8188ab8b334393e06d997914a4e184975348f204790277", - "sha256:3fb9575a5acd13031c57a62cc7823e5d2ff8bc3835ba4d94b921b4e6ee664104", - "sha256:4ff604ce439abb20794f05613c374759ce10e3595d1867764dd1ae675b85acbd", - "sha256:6e7be2c5bcb297f5b82fee9c665eb2eb7001d1050deaba8471842979293a80b0", - "sha256:72a2b8b2ff0a627496aad76f37a652bcef400fd861721744201ef1b45199ab78", - "sha256:77df077d32921ad46f34816a9a16e6356d8100374579bc35e15bab5d4e9377de", - "sha256:78988ed190206672da0f5d50c61afef8f67daa718d614377dcd5e3ed85ab4a99", - "sha256:7b2927e92feb51d830f531de4ccb11b320255ee95e791022555971c466af4527", - "sha256:7f7ecb53ae6848f959db6ae93bdff1740e651809780822270eab111500842a84", - "sha256:825d5fccef6da42f3c8eccd4281af399f21c02b32d98e113dbc631ea6a6ecbc7", - "sha256:846fc8336443106fe23f9b6d6b8c14a53d38cef9a375149d61f99d78782ea468", - "sha256:89221ec6d6026f8ae859c09b9718799fea22c0e8da8b766b0b2c9a9ba2db326b", - "sha256:9efef4aab5353387b07f6b22ace0867032b900d8e91674b5d8ea9150db5cae94", - "sha256:a32f8d81ea0c6173ab1b3da956869114cae53ba1e9f72374032e33ba3118c233", - "sha256:a49e0161897901d1ac9c4a79984b8410f450565bbad64dbfcbf76152743a0cdb", - "sha256:ada3f400d9923a190ea8b59c8f60680c4ef8a4b0dfae134d2f2ff68429adfab5", - "sha256:bf75d28fa071645c529b5474a550a44686821decebdd00e21127ef1fd566eabe", - "sha256:cfdb9389d888c5b74af297e51ce357b800dd844898af9d4a547ffc143fa56751", - "sha256:d67f273097c368265a7b81e152e07fb90ed395df6e552b9fa858c6d2c9f42502", - "sha256:dc6a613d6c74eef5a14a214d433d06291526145431c3b964f5e16529b1842bed", - "sha256:de9c6b8a1ba52919ae919f3ae96abb72b994dd0350226e28f3686cb4f142165c" - ], - "markers": "python_version < '3.11' and platform_python_implementation == 'CPython'", - "version": "==0.2.6" - }, - "semver": { - "hashes": [ - "sha256:21e80ca738975ed513cba859db0a0d2faca2380aef1962f48272ebf9a8a44bd4", - "sha256:c0a4a9d1e45557297a722ee9bac3de2ec2ea79016b6ffcaca609b0bc62cf4276" - ], - "index": "pypi", - "version": "==2.10.2" - }, - "setuptools": { - "hashes": [ - "sha256:5534570b9980fc650d45c62877ff603c7aaaf24893371708736cc016bd221c3c", - "sha256:ca6ba73b7fd5f734ae70ece8c4c1f7062b07f3352f6428f6277e27c8f5c64237" - ], - "markers": "python_version >= '3.7'", - "version": "==62.2.0" - }, - "six": { - "hashes": [ - "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926", - "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254" - ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==1.16.0" - }, - "soupsieve": { - "hashes": [ - "sha256:3b2503d3c7084a42b1ebd08116e5f81aadfaea95863628c80a3b774a11b7c759", - "sha256:fc53893b3da2c33de295667a0e19f078c14bf86544af307354de5fcf12a3f30d" - ], - "markers": "python_version >= '3.6'", - "version": "==2.3.2.post1" - }, - "sqlparse": { - "hashes": [ - "sha256:0c00730c74263a94e5a9919ade150dfc3b19c574389985446148402998287dae", - "sha256:48719e356bb8b42991bdbb1e8b83223757b93789c00910a616a071910ca4a64d" - ], - "markers": "python_version >= '3.5'", - "version": "==0.4.2" - }, - "testpath": { - "hashes": [ - "sha256:2f1b97e6442c02681ebe01bd84f531028a7caea1af3825000f52345c30285e0f", - "sha256:8ada9f80a2ac6fb0391aa7cdb1a7d11cfa8429f693eda83f74dde570fe6fa639" - ], - "markers": "python_version >= '3.5'", - "version": "==0.6.0" - }, - "toml": { - "hashes": [ - "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b", - "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f" - ], - "markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==0.10.2" - }, - "tornado": { - "hashes": [ - "sha256:0a00ff4561e2929a2c37ce706cb8233b7907e0cdc22eab98888aca5dd3775feb", - "sha256:0d321a39c36e5f2c4ff12b4ed58d41390460f798422c4504e09eb5678e09998c", - "sha256:1e8225a1070cd8eec59a996c43229fe8f95689cb16e552d130b9793cb570a288", - "sha256:20241b3cb4f425e971cb0a8e4ffc9b0a861530ae3c52f2b0434e6c1b57e9fd95", - "sha256:25ad220258349a12ae87ede08a7b04aca51237721f63b1808d39bdb4b2164558", - "sha256:33892118b165401f291070100d6d09359ca74addda679b60390b09f8ef325ffe", - "sha256:33c6e81d7bd55b468d2e793517c909b139960b6c790a60b7991b9b6b76fb9791", - "sha256:3447475585bae2e77ecb832fc0300c3695516a47d46cefa0528181a34c5b9d3d", - "sha256:34ca2dac9e4d7afb0bed4677512e36a52f09caa6fded70b4e3e1c89dbd92c326", - "sha256:3e63498f680547ed24d2c71e6497f24bca791aca2fe116dbc2bd0ac7f191691b", - "sha256:548430be2740e327b3fe0201abe471f314741efcb0067ec4f2d7dcfb4825f3e4", - "sha256:6196a5c39286cc37c024cd78834fb9345e464525d8991c21e908cc046d1cc02c", - "sha256:61b32d06ae8a036a6607805e6720ef00a3c98207038444ba7fd3d169cd998910", - "sha256:6286efab1ed6e74b7028327365cf7346b1d777d63ab30e21a0f4d5b275fc17d5", - "sha256:65d98939f1a2e74b58839f8c4dab3b6b3c1ce84972ae712be02845e65391ac7c", - "sha256:66324e4e1beede9ac79e60f88de548da58b1f8ab4b2f1354d8375774f997e6c0", - "sha256:6c77c9937962577a6a76917845d06af6ab9197702a42e1346d8ae2e76b5e3675", - "sha256:70dec29e8ac485dbf57481baee40781c63e381bebea080991893cd297742b8fd", - "sha256:7250a3fa399f08ec9cb3f7b1b987955d17e044f1ade821b32e5f435130250d7f", - "sha256:748290bf9112b581c525e6e6d3820621ff020ed95af6f17fedef416b27ed564c", - "sha256:7da13da6f985aab7f6f28debab00c67ff9cbacd588e8477034c0652ac141feea", - "sha256:8f959b26f2634a091bb42241c3ed8d3cedb506e7c27b8dd5c7b9f745318ddbb6", - "sha256:9de9e5188a782be6b1ce866e8a51bc76a0fbaa0e16613823fc38e4fc2556ad05", - "sha256:a48900ecea1cbb71b8c71c620dee15b62f85f7c14189bdeee54966fbd9a0c5bd", - "sha256:b87936fd2c317b6ee08a5741ea06b9d11a6074ef4cc42e031bc6403f82a32575", - "sha256:c77da1263aa361938476f04c4b6c8916001b90b2c2fdd92d8d535e1af48fba5a", - "sha256:cb5ec8eead331e3bb4ce8066cf06d2dfef1bfb1b2a73082dfe8a161301b76e37", - "sha256:cc0ee35043162abbf717b7df924597ade8e5395e7b66d18270116f8745ceb795", - "sha256:d14d30e7f46a0476efb0deb5b61343b1526f73ebb5ed84f23dc794bdb88f9d9f", - "sha256:d371e811d6b156d82aa5f9a4e08b58debf97c302a35714f6f45e35139c332e32", - "sha256:d3d20ea5782ba63ed13bc2b8c291a053c8d807a8fa927d941bd718468f7b950c", - "sha256:d3f7594930c423fd9f5d1a76bee85a2c36fd8b4b16921cae7e965f22575e9c01", - "sha256:dcef026f608f678c118779cd6591c8af6e9b4155c44e0d1bc0c87c036fb8c8c4", - "sha256:e0791ac58d91ac58f694d8d2957884df8e4e2f6687cdf367ef7eb7497f79eaa2", - "sha256:e385b637ac3acaae8022e7e47dfa7b83d3620e432e3ecb9a3f7f58f150e50921", - "sha256:e519d64089b0876c7b467274468709dadf11e41d65f63bba207e04217f47c085", - "sha256:e7229e60ac41a1202444497ddde70a48d33909e484f96eb0da9baf8dc68541df", - "sha256:ed3ad863b1b40cd1d4bd21e7498329ccaece75db5a5bf58cd3c9f130843e7102", - "sha256:f0ba29bafd8e7e22920567ce0d232c26d4d47c8b5cf4ed7b562b5db39fa199c5", - "sha256:fa2ba70284fa42c2a5ecb35e322e68823288a4251f9ba9cc77be04ae15eada68", - "sha256:fba85b6cd9c39be262fcd23865652920832b61583de2a2ca907dbd8e8a8c81e5" - ], - "markers": "python_version >= '3.5'", - "version": "==6.1" - }, - "traitlets": { - "hashes": [ - "sha256:60474f39bf1d39a11e0233090b99af3acee93bbc2281777e61dd8c87da8a0014", - "sha256:9dd4025123fbe018a2092b2ad6984792f53ea3362c698f37473258b1fa97b0bc" - ], - "markers": "python_version >= '3.7'", - "version": "==5.2.0" - }, - "uritemplate": { - "hashes": [ - "sha256:4346edfc5c3b79f694bccd6d6099a322bbeb628dbf2cd86eea55a456ce5124f0", - "sha256:830c08b8d99bdd312ea4ead05994a38e8936266f84b9a7878232db50b044e02e" - ], - "markers": "python_version >= '3.6'", - "version": "==4.1.1" - }, - "urllib3": { - "hashes": [ - "sha256:44ece4d53fb1706f667c9bd1c648f5469a2ec925fcf3a776667042d645472c14", - "sha256:aabaf16477806a5e1dd19aa41f8c2b7950dd3c746362d7e3223dbe6de6ac448e" - ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' and python_version < '4'", - "version": "==1.26.9" - }, - "webencodings": { - "hashes": [ - "sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78", - "sha256:b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923" - ], - "version": "==0.5.1" - }, - "whitenoise": { - "hashes": [ - "sha256:05ce0be39ad85740a78750c86a93485c40f08ad8c62a6006de0233765996e5c7", - "sha256:05d00198c777028d72d8b0bbd234db605ef6d60e9410125124002518a48e515d" - ], - "index": "pypi", - "version": "==5.2.0" - }, - "xkcdpass": { - "hashes": [ - "sha256:9e89291c927671ef5616a9c9ebaa118b7b1b844e188474d53529d1be8a961a3e" - ], - "index": "pypi", - "version": "==1.17.6" - }, - "xlrd": { - "hashes": [ - "sha256:546eb36cee8db40c3eaa46c351e67ffee6eeb5fa2650b71bc4c758a29a1b29b2", - "sha256:e551fb498759fa3a5384a94ccd4c3c02eb7c00ea424426e212ac0c57be9dfbde" - ], - "index": "pypi", - "version": "==1.2.0" - }, - "zipp": { - "hashes": [ - "sha256:56bf8aadb83c24db6c4b577e13de374ccfb67da2078beba1d037c17980bf43ad", - "sha256:c4f6e5bbf48e74f7a38e7cc5b0480ff42b0ae5178957d564d18932525d5cf099" - ], - "markers": "python_version < '3.10'", - "version": "==3.8.0" - } - }, - "develop": { - "aspy.yaml": { - "hashes": [ - "sha256:463372c043f70160a9ec950c3f1e4c3a82db5fca01d334b6bc89c7164d744bdc", - "sha256:e7c742382eff2caed61f87a39d13f99109088e5e93f04d76eb8d4b28aa143f45" - ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==1.3.0" - }, - "attrs": { - "hashes": [ - "sha256:2d27e3784d7a565d36ab851fe94887c5eccd6a463168875832a1be79c82828b4", - "sha256:626ba8234211db98e869df76230a137c4c40a12d72445c45d5f5b716f076e2fd" - ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", - "version": "==21.4.0" - }, - "cached-property": { - "hashes": [ - "sha256:9fa5755838eecbb2d234c3aa390bd80fbd3ac6b6869109bfc1b499f7bd89a130", - "sha256:df4f613cf7ad9a588cc381aaf4a512d26265ecebd5eb9e1ba12f1319eb85a6a0" - ], - "version": "==1.5.2" - }, - "cfgv": { - "hashes": [ - "sha256:c6a0883f3917a037485059700b9e75da2464e6c27051014ad85ba6aaa5884426", - "sha256:f5a830efb9ce7a445376bb66ec94c638a9787422f96264c98edc6bdeed8ab736" - ], - "markers": "python_full_version >= '3.6.1'", - "version": "==3.3.1" - }, - "coverage": { - "hashes": [ - "sha256:03e2a7826086b91ef345ff18742ee9fc47a6839ccd517061ef8fa1976e652ce9", - "sha256:07e6db90cd9686c767dcc593dff16c8c09f9814f5e9c51034066cad3373b914d", - "sha256:18d520c6860515a771708937d2f78f63cc47ab3b80cb78e86573b0a760161faf", - "sha256:1ebf730d2381158ecf3dfd4453fbca0613e16eaa547b4170e2450c9707665ce7", - "sha256:21b7745788866028adeb1e0eca3bf1101109e2dc58456cb49d2d9b99a8c516e6", - "sha256:26e2deacd414fc2f97dd9f7676ee3eaecd299ca751412d89f40bc01557a6b1b4", - "sha256:2c6dbb42f3ad25760010c45191e9757e7dce981cbfb90e42feef301d71540059", - "sha256:2fea046bfb455510e05be95e879f0e768d45c10c11509e20e06d8fcaa31d9e39", - "sha256:34626a7eee2a3da12af0507780bb51eb52dca0e1751fd1471d0810539cefb536", - "sha256:37d1141ad6b2466a7b53a22e08fe76994c2d35a5b6b469590424a9953155afac", - "sha256:46191097ebc381fbf89bdce207a6c107ac4ec0890d8d20f3360345ff5976155c", - "sha256:4dd8bafa458b5c7d061540f1ee9f18025a68e2d8471b3e858a9dad47c8d41903", - "sha256:4e21876082ed887baed0146fe222f861b5815455ada3b33b890f4105d806128d", - "sha256:58303469e9a272b4abdb9e302a780072c0633cdcc0165db7eec0f9e32f901e05", - "sha256:5ca5aeb4344b30d0bec47481536b8ba1181d50dbe783b0e4ad03c95dc1296684", - "sha256:68353fe7cdf91f109fc7d474461b46e7f1f14e533e911a2a2cbb8b0fc8613cf1", - "sha256:6f89d05e028d274ce4fa1a86887b071ae1755082ef94a6740238cd7a8178804f", - "sha256:7a15dc0a14008f1da3d1ebd44bdda3e357dbabdf5a0b5034d38fcde0b5c234b7", - "sha256:8bdde1177f2311ee552f47ae6e5aa7750c0e3291ca6b75f71f7ffe1f1dab3dca", - "sha256:8ce257cac556cb03be4a248d92ed36904a59a4a5ff55a994e92214cde15c5bad", - "sha256:8cf5cfcb1521dc3255d845d9dca3ff204b3229401994ef8d1984b32746bb45ca", - "sha256:8fbbdc8d55990eac1b0919ca69eb5a988a802b854488c34b8f37f3e2025fa90d", - "sha256:9548f10d8be799551eb3a9c74bbf2b4934ddb330e08a73320123c07f95cc2d92", - "sha256:96f8a1cb43ca1422f36492bebe63312d396491a9165ed3b9231e778d43a7fca4", - "sha256:9b27d894748475fa858f9597c0ee1d4829f44683f3813633aaf94b19cb5453cf", - "sha256:9baff2a45ae1f17c8078452e9e5962e518eab705e50a0aa8083733ea7d45f3a6", - "sha256:a2a8b8bcc399edb4347a5ca8b9b87e7524c0967b335fbb08a83c8421489ddee1", - "sha256:acf53bc2cf7282ab9b8ba346746afe703474004d9e566ad164c91a7a59f188a4", - "sha256:b0be84e5a6209858a1d3e8d1806c46214e867ce1b0fd32e4ea03f4bd8b2e3359", - "sha256:b31651d018b23ec463e95cf10070d0b2c548aa950a03d0b559eaa11c7e5a6fa3", - "sha256:b78e5afb39941572209f71866aa0b206c12f0109835aa0d601e41552f9b3e620", - "sha256:c76aeef1b95aff3905fb2ae2d96e319caca5b76fa41d3470b19d4e4a3a313512", - "sha256:dd035edafefee4d573140a76fdc785dc38829fe5a455c4bb12bac8c20cfc3d69", - "sha256:dd6fe30bd519694b356cbfcaca9bd5c1737cddd20778c6a581ae20dc8c04def2", - "sha256:e5f4e1edcf57ce94e5475fe09e5afa3e3145081318e5fd1a43a6b4539a97e518", - "sha256:ec6bc7fe73a938933d4178c9b23c4e0568e43e220aef9472c4f6044bfc6dd0f0", - "sha256:f1555ea6d6da108e1999b2463ea1003fe03f29213e459145e70edbaf3e004aaa", - "sha256:f5fa5803f47e095d7ad8443d28b01d48c0359484fec1b9d8606d0e3282084bc4", - "sha256:f7331dbf301b7289013175087636bbaf5b2405e57259dd2c42fdcc9fcc47325e", - "sha256:f9987b0354b06d4df0f4d3e0ec1ae76d7ce7cbca9a2f98c25041eb79eec766f1", - "sha256:fd9e830e9d8d89b20ab1e5af09b32d33e1a08ef4c4e14411e559556fd788e6b2" - ], - "markers": "python_version >= '3.7'", - "version": "==6.3.2" - }, - "distlib": { - "hashes": [ - "sha256:6564fe0a8f51e734df6333d08b8b94d4ea8ee6b99b5ed50613f731fd4089f34b", - "sha256:e4b58818180336dc9c529bfb9a0b58728ffc09ad92027a3f30b7cd91e3458579" - ], - "version": "==0.3.4" - }, - "execnet": { - "hashes": [ - "sha256:8f694f3ba9cc92cab508b152dcfe322153975c29bda272e2fd7f3f00f36e47c5", - "sha256:a295f7cc774947aac58dde7fdc85f4aa00c42adf5d8f5468fc630c1acf30a142" - ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", - "version": "==1.9.0" - }, - "factory-boy": { - "hashes": [ - "sha256:2ce2f665045d9f15145a6310565fcb8255d52fc6fd867f3b783b3ac3de6cf10e" - ], - "index": "pypi", - "version": "==3.0.1" - }, - "faker": { - "hashes": [ - "sha256:179418909da04b04000eab5463c403895faed2849d36ef8d9cbda72cc44797a0", - "sha256:edffca9d8106fffc23ccef15797665fa8aebec4c0eeb3fd6d43cd23540978d5b" - ], - "index": "pypi", - "version": "==4.1.8" - }, - "filelock": { - "hashes": [ - "sha256:9cd540a9352e432c7246a48fe4e8712b10acb1df2ad1f30e8c070b82ae1fed85", - "sha256:f8314284bfffbdcfa0ff3d7992b023d4c628ced6feb957351d4c48d059f56bc0" - ], - "markers": "python_version >= '3.7'", - "version": "==3.6.0" - }, - "flake8": { - "hashes": [ - "sha256:07528381786f2a6237b061f6e96610a4167b226cb926e2aa2b6b1d78057c576b", - "sha256:bf8fd333346d844f616e8d47905ef3a3384edae6b4e9beb0c5101e25e3110907" - ], - "index": "pypi", - "version": "==3.9.2" - }, - "identify": { - "hashes": [ - "sha256:3acfe15a96e4272b4ec5662ee3e231ceba976ef63fd9980ed2ce9cc415df393f", - "sha256:c83af514ea50bf2be2c4a3f2fb349442b59dc87284558ae9ff54191bff3541d2" - ], - "markers": "python_version >= '3.7'", - "version": "==2.5.0" - }, - "importlib-metadata": { - "hashes": [ - "sha256:1208431ca90a8cca1a6b8af391bb53c1a2db74e5d1cef6ddced95d4b2062edc6", - "sha256:ea4c597ebf37142f827b8f39299579e31685c31d3a438b59f469406afd0f2539" - ], - "markers": "python_version >= '3.7'", - "version": "==4.11.3" - }, - "iniconfig": { - "hashes": [ - "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3", - "sha256:bc3af051d7d14b2ee5ef9969666def0cd1a000e121eaea580d4a313df4b37f32" - ], - "version": "==1.1.1" - }, - "mccabe": { - "hashes": [ - "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42", - "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f" - ], - "version": "==0.6.1" - }, - "nodeenv": { - "hashes": [ - "sha256:3ef13ff90291ba2a4a7a4ff9a979b63ffdd00a464dbe04acf0ea6471517a4c2b", - "sha256:621e6b7076565ddcacd2db0294c0381e01fd28945ab36bcf00f41c5daf63bef7" - ], - "version": "==1.6.0" - }, - "packaging": { - "hashes": [ - "sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb", - "sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522" - ], - "markers": "python_version >= '3.6'", - "version": "==21.3" - }, - "platformdirs": { - "hashes": [ - "sha256:027d8e83a2d7de06bbac4e5ef7e023c02b863d7ea5d079477e722bb41ab25788", - "sha256:58c8abb07dcb441e6ee4b11d8df0ac856038f944ab98b7be6b27b2a3c7feef19" - ], - "markers": "python_version >= '3.7'", - "version": "==2.5.2" - }, - "pluggy": { - "hashes": [ - "sha256:15b2acde666561e1298d71b523007ed7364de07029219b604cf808bfa1c765b0", - "sha256:966c145cd83c96502c3c3868f50408687b38434af77734af1e9ca461a4081d2d" - ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==0.13.1" - }, - "pre-commit": { - "hashes": [ - "sha256:33bb9bf599c334d458fa9e311bde54e0c306a651473b6a36fdb36a61c8605c89", - "sha256:e233f5cf3230ae9ed9ada132e9cf6890e18cc937adc669353fb64394f6e80c17" - ], - "index": "pypi", - "version": "==1.13.0" - }, - "py": { - "hashes": [ - "sha256:51c75c4126074b472f746a24399ad32f6053d1b34b68d2fa41e558e6f4a98719", - "sha256:607c53218732647dff4acdfcd50cb62615cedf612e72d1724fb1a0cc6405b378" - ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", - "version": "==1.11.0" - }, - "pycodestyle": { - "hashes": [ - "sha256:720f8b39dde8b293825e7ff02c475f3077124006db4f440dcbc9a20b76548a20", - "sha256:eddd5847ef438ea1c7870ca7eb78a9d47ce0cdb4851a5523949f2601d0cbbe7f" - ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", - "version": "==2.8.0" - }, - "pyflakes": { - "hashes": [ - "sha256:7893783d01b8a89811dd72d7dfd4d84ff098e5eed95cfa8905b22bbffe52efc3", - "sha256:f5bc8ecabc05bb9d291eb5203d6810b49040f6ff446a756326104746cc00c1db" - ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==2.3.1" - }, - "pyparsing": { - "hashes": [ - "sha256:2b020ecf7d21b687f219b71ecad3631f644a47f01403fa1d1036b0c6416d70fb", - "sha256:5026bae9a10eeaefb61dab2f09052b9f4307d44aee4eda64b309723d8d206bbc" - ], - "markers": "python_full_version >= '3.6.8'", - "version": "==3.0.9" - }, - "pytest": { - "hashes": [ - "sha256:4288fed0d9153d9646bfcdf0c0428197dba1ecb27a33bb6e031d002fa88653fe", - "sha256:c0a7e94a8cdbc5422a51ccdad8e6f1024795939cc89159a0ae7f0b316ad3823e" - ], - "index": "pypi", - "version": "==6.1.2" - }, - "pytest-cov": { - "hashes": [ - "sha256:45ec2d5182f89a81fc3eb29e3d1ed3113b9e9a873bcddb2a71faaab066110191", - "sha256:47bd0ce14056fdd79f93e1713f88fad7bdcc583dcd7783da86ef2f085a0bb88e" - ], - "index": "pypi", - "version": "==2.10.1" - }, - "pytest-django": { - "hashes": [ - "sha256:4de6dbd077ed8606616958f77655fed0d5e3ee45159475671c7fa67596c6dba6", - "sha256:c33e3d3da14d8409b125d825d4e74da17bb252191bf6fc3da6856e27a8b73ea4" - ], - "index": "pypi", - "version": "==3.10.0" - }, - "pytest-forked": { - "hashes": [ - "sha256:8b67587c8f98cbbadfdd804539ed5455b6ed03802203485dd2f53c1422d7440e", - "sha256:bbbb6717efc886b9d64537b41fb1497cfaf3c9601276be8da2cccfea5a3c8ad8" - ], - "markers": "python_version >= '3.6'", - "version": "==1.4.0" - }, - "pytest-xdist": { - "hashes": [ - "sha256:7c629016b3bb006b88ac68e2b31551e7becf173c76b977768848e2bbed594d90", - "sha256:82d938f1a24186520e2d9d3a64ef7d9ac7ecdf1a0659e095d18e596b8cbd0672" - ], - "index": "pypi", - "version": "==2.1.0" - }, - "python-dateutil": { - "hashes": [ - "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86", - "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9" - ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==2.8.2" - }, - "pyyaml": { - "hashes": [ - "sha256:0283c35a6a9fbf047493e3a0ce8d79ef5030852c51e9d911a27badfde0605293", - "sha256:055d937d65826939cb044fc8c9b08889e8c743fdc6a32b33e2390f66013e449b", - "sha256:07751360502caac1c067a8132d150cf3d61339af5691fe9e87803040dbc5db57", - "sha256:0b4624f379dab24d3725ffde76559cff63d9ec94e1736b556dacdfebe5ab6d4b", - "sha256:0ce82d761c532fe4ec3f87fc45688bdd3a4c1dc5e0b4a19814b9009a29baefd4", - "sha256:1e4747bc279b4f613a09eb64bba2ba602d8a6664c6ce6396a4d0cd413a50ce07", - "sha256:213c60cd50106436cc818accf5baa1aba61c0189ff610f64f4a3e8c6726218ba", - "sha256:231710d57adfd809ef5d34183b8ed1eeae3f76459c18fb4a0b373ad56bedcdd9", - "sha256:277a0ef2981ca40581a47093e9e2d13b3f1fbbeffae064c1d21bfceba2030287", - "sha256:2cd5df3de48857ed0544b34e2d40e9fac445930039f3cfe4bcc592a1f836d513", - "sha256:40527857252b61eacd1d9af500c3337ba8deb8fc298940291486c465c8b46ec0", - "sha256:473f9edb243cb1935ab5a084eb238d842fb8f404ed2193a915d1784b5a6b5fc0", - "sha256:48c346915c114f5fdb3ead70312bd042a953a8ce5c7106d5bfb1a5254e47da92", - "sha256:50602afada6d6cbfad699b0c7bb50d5ccffa7e46a3d738092afddc1f9758427f", - "sha256:68fb519c14306fec9720a2a5b45bc9f0c8d1b9c72adf45c37baedfcd949c35a2", - "sha256:77f396e6ef4c73fdc33a9157446466f1cff553d979bd00ecb64385760c6babdc", - "sha256:819b3830a1543db06c4d4b865e70ded25be52a2e0631ccd2f6a47a2822f2fd7c", - "sha256:897b80890765f037df3403d22bab41627ca8811ae55e9a722fd0392850ec4d86", - "sha256:98c4d36e99714e55cfbaaee6dd5badbc9a1ec339ebfc3b1f52e293aee6bb71a4", - "sha256:9df7ed3b3d2e0ecfe09e14741b857df43adb5a3ddadc919a2d94fbdf78fea53c", - "sha256:9fa600030013c4de8165339db93d182b9431076eb98eb40ee068700c9c813e34", - "sha256:a80a78046a72361de73f8f395f1f1e49f956c6be882eed58505a15f3e430962b", - "sha256:b3d267842bf12586ba6c734f89d1f5b871df0273157918b0ccefa29deb05c21c", - "sha256:b5b9eccad747aabaaffbc6064800670f0c297e52c12754eb1d976c57e4f74dcb", - "sha256:c5687b8d43cf58545ade1fe3e055f70eac7a5a1a0bf42824308d868289a95737", - "sha256:cba8c411ef271aa037d7357a2bc8f9ee8b58b9965831d9e51baf703280dc73d3", - "sha256:d15a181d1ecd0d4270dc32edb46f7cb7733c7c508857278d3d378d14d606db2d", - "sha256:d4db7c7aef085872ef65a8fd7d6d09a14ae91f691dec3e87ee5ee0539d516f53", - "sha256:d4eccecf9adf6fbcc6861a38015c2a64f38b9d94838ac1810a9023a0609e1b78", - "sha256:d67d839ede4ed1b28a4e8909735fc992a923cdb84e618544973d7dfc71540803", - "sha256:daf496c58a8c52083df09b80c860005194014c3698698d1a57cbcfa182142a3a", - "sha256:e61ceaab6f49fb8bdfaa0f92c4b57bcfbea54c09277b1b4f7ac376bfb7a7c174", - "sha256:f84fbc98b019fef2ee9a1cb3ce93e3187a6df0b2538a651bfb890254ba9f90b5" - ], - "markers": "python_version >= '3.6'", - "version": "==6.0" - }, - "selenium": { - "hashes": [ - "sha256:2d7131d7bc5a5b99a2d9b04aaf2612c411b03b8ca1b1ee8d3de5845a9be2cb3c", - "sha256:deaf32b60ad91a4611b98d8002757f29e6f2c2d5fcaf202e1c9ad06d6772300d" - ], - "index": "pypi", - "version": "==3.141.0" - }, - "six": { - "hashes": [ - "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926", - "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254" - ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==1.16.0" - }, - "text-unidecode": { - "hashes": [ - "sha256:1311f10e8b895935241623731c2ba64f4c455287888b18189350b67134a822e8", - "sha256:bad6603bb14d279193107714b288be206cac565dfa49aa5b105294dd5c4aab93" - ], - "version": "==1.3" - }, - "toml": { - "hashes": [ - "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b", - "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f" - ], - "markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==0.10.2" - }, - "urllib3": { - "hashes": [ - "sha256:44ece4d53fb1706f667c9bd1c648f5469a2ec925fcf3a776667042d645472c14", - "sha256:aabaf16477806a5e1dd19aa41f8c2b7950dd3c746362d7e3223dbe6de6ac448e" - ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' and python_version < '4'", - "version": "==1.26.9" - }, - "virtualenv": { - "hashes": [ - "sha256:e617f16e25b42eb4f6e74096b9c9e37713cf10bf30168fb4a739f3fa8f898a3a", - "sha256:ef589a79795589aada0c1c5b319486797c03b67ac3984c48c669c0e4f50df3a5" - ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", - "version": "==20.14.1" - }, - "zipp": { - "hashes": [ - "sha256:56bf8aadb83c24db6c4b577e13de374ccfb67da2078beba1d037c17980bf43ad", - "sha256:c4f6e5bbf48e74f7a38e7cc5b0480ff42b0ae5178957d564d18932525d5cf099" - ], - "markers": "python_version < '3.10'", - "version": "==3.8.0" - } - } -} diff --git a/grady/README.md b/grady/README.md deleted file mode 100644 index b9db2c139060fbc9956d01c87c795b63a6871b64..0000000000000000000000000000000000000000 --- a/grady/README.md +++ /dev/null @@ -1,247 +0,0 @@ -![](frontend/src/assets/brand.svg) - -# Grady - will correct you! - - -The intention of this tool is to simplify the exam correcting process at the -University of Goettingen. It is deployed as a web application consisting -of a Django-Rest backend and a Vue.js frontend. - -[![pipeline status](https://gitlab.gwdg.de/j.michal/grady/badges/master/pipeline.svg)](https://gitlab.gwdg.de/j.michal/grady/commits/master) [![coverage report](https://gitlab.gwdg.de/j.michal/grady/badges/master/coverage.svg)](https://gitlab.gwdg.de/j.michal/grady/commits/master) - -## Overview - -Grady has three basic functions for the three types of users - -* Reviewers can - * edit feedback that has been provided by tutors - * mark feedback as final if it should not be modified (only final feedback is - shown to students) - * delete feedback (submission will be reassigned) -* Tutors can - * request a submission that they have to correct and submit feedback for it - * delete their own feedback - * review feedback of other tutors - * they do not see which student submitted the solution -* Students can - * review their final feedback and score in the post exam review - -An overview over the database can be found in the docs folder. - - -## Contributing - - -Feature proposals are welcome! If you experienced any bugs or otherwise -unexpected behavior please submit an issue using the issue templates. - -It is of course possible to contribute but currently there is no standardized -way since the project is in a very early stage and fairly small. If you feel the -need to help us out anyway, please contact us via our university email -addresses. - - -## Development - -### Dependencies - - -Make sure the following packages and tools are installed: - -- Python 3.8 -- [Pipenv](https://docs.pipenv.org/en/latest/) -- [Docker](https://www.docker.com/) or a local installation of [Postgres](https://www.postgresql.org/) -- `npm` or `yarn` (you can use `npm` to install `yarn`) -- `make` - -These are required to set up the project. All other application dependencies are -listed in the `Pipfile` files. These will be -installed automatically during the installation process. - -### Installing - -To set up a new development instance perform the following steps: - -1. Create a virtual environment with a Python3.6 interpreter and install -all relevant dependencies: - -```shell script -pipenv install --dev -``` - -2. Set the environment variable `DJANGO_DEV` to `True` like this: -```shell script -export DJANGO_DEV=True -``` - -3. Enter a shell in the virtual environment: -```shell script -pipenv shell -``` - -4. Set up a Postgres 9.5 database. If you have docker installed the - easiest way is to just run it in a docker container, like this: -```shell script - docker run -d --rm --name postgres -p 5432:5432 postgres:13 - -``` - -Alternatively, take a look at the Makefile targets that should make your -life easier, e.g `make db`. - -And apply database migrations once the database is up: -```shell script -python manage.py migrate -``` - -5. Create a superuser if necessary: -```shell script -python manage.py createsuperuser -``` -More users can be added in the admin interface. You should be able -to reach it via <http://localhost:8000/admin>. - -7. Everything is set. You can start the development server with: -```shell script -python manage.py runserver -``` - -8. Congratulations! Your backend should now be up an running. To setup the frontend - see the README in the `frontend` folder. - -### Testing - -> "Code without tests is broken by design." -- (Jacob Kaplan-Moss, Django core developer) - -Well, currently this repository lacks tests, thats true. But that will change as -this work until now is merely a prototype that will be developed further. However, -the few existing tests can be seen as examples and can be found in the `tests.py` -file of each app (currently only `core`). You can run those tests with -```shell script -make test -``` -or if you want a coverage report as well you can run: -```shell script -make coverage -``` - -If you'd like to run the functional tests, simply run: -```shell script -make teste2e path=functional_tests -``` - -or -```shell script -make teste2e path=functional_tests headless=True -``` -for headless mode (Note: You might need to install additional dependencies). - - make teste2e - -Notice that this will always issue a complete rebuild of the frontend. If you want to run tests without building the -frontend anew, use - - make teste2e-nc - - -## Production - -In order to run the app in production, a server with -[Docker](https://www.docker.com/) is needed. To make routing to the -respective instances easier, we recommend running [traefik](https://traefik.io/) -as a reverse proxy on the server. For easier configuration of the containers -we recommend using `docker-compose`. The following guide will assume both these -dependencies are available. - -### Setting up a new instance -Simply copy the following `docker-compose.yml` onto your production server: -```yaml -version: "3" - -services: - - postgres: - image: postgres:13 - labels: - traefik.enable: "false" - networks: - - internal - volumes: - - ./database:/var/lib/postgresql/data - - grady: - image: docker.gitlab.gwdg.de/j.michal/grady:master - restart: always - entrypoint: - - ./deploy.sh - volumes: - - ./secret:/code/secret - environment: - GRADY_INSTANCE: ${INSTANCE} - SCRIPT_NAME: ${URLPATH} - networks: - - internal - - proxy - labels: - traefik.backend: ${INSTANCE} - traefik.enable: "true" - traefik.frontend.rule: Host:${GRADY_HOST};PathPrefix:${URLPATH} - traefik.docker.network: proxy - traefik.port: "8000" - depends_on: - - postgres - -networks: - proxy: - external: true - internal: - external: false -``` - -and set the `INSTANCE`, `URLPATH`, `GRADY_HOST` variables either directly in the -compose file or within an `.env` file in the same directory as the `docker-compose.yml` -(it will be automatically loaded by `docker-compose`). -Login to gwdg gitlab docker registry by entering: -```commandline -docker login docker.gitlab.gwdg.de -``` -Running -```commandline -docker-compose pull -docker-compose up -d -``` -will download the latest postgres and grady images and run them in the background. - -### Importing exam data -#### Exam data structure -In order to import the exam data it must be in a specific format. -You need the following: - -1. A .json file file containing the output of the converted ILIAS export which is - generated by [hektor](https://gitlab.gwdg.de/j.michal/hektor) -2. A plain text file containing one username per line. A new **reviewer** account - will be created with the corresponding username and a randomly - generated password. The passwords are written to a `.importer_passwords` file. - This step should not be skipped because a reviewer account is necessary in order - to activate the tutor accounts. - - -#### Importing exam data -In order to create reviewer accounts, open an interactive shell session in the running container: -```commandline -$ docker exec -it <container_id> /bin/sh -``` - -While in the shell, create a new file containing one username per line: -```commandline -$ echo "user1\nuser2" > reviewers -``` - -After creating the file, call the importer script: -```commandline -$ python manage.py importer -``` - -Keep in mind that you can import exam data in two ways. You can either import the .json file using the importer or you can use the frontend to import data in a more user-friendly way. In either case, you will have to use the importer in order to create the reviewer accounts. - -When logging in to an instance that has no data imported you will automatically be prompted to import some data. If you are on an instance that already has data, you can find the import dialog in the dropdown menu next to the logout button. In the import dialog, simply select the .json file and upload it. This procedure may take a while depending on the file size. diff --git a/grady/core/__init__.py b/grady/core/__init__.py deleted file mode 100644 index 17acc4cd4393f0d1b62100ecfb5ed2a5db34e814..0000000000000000000000000000000000000000 --- a/grady/core/__init__.py +++ /dev/null @@ -1 +0,0 @@ -default_app_config = 'core.apps.CoreConfig' diff --git a/grady/core/admin.py b/grady/core/admin.py deleted file mode 100644 index 79001a88ee94f003a380a2964ed9369290d2b476..0000000000000000000000000000000000000000 --- a/grady/core/admin.py +++ /dev/null @@ -1,17 +0,0 @@ -from django.contrib import admin -from django.contrib.auth.models import Group - -from core.models import (ExamType, Feedback, StudentInfo, Submission, - SubmissionType, Test, UserAccount) - -# Stuff we needwant -admin.site.register(UserAccount) -admin.site.register(SubmissionType) -admin.site.register(Feedback) -admin.site.register(Test) -admin.site.register(ExamType) -admin.site.register(Submission) -admin.site.register(StudentInfo) - -# ... and stuff we don't needwant -admin.site.unregister(Group) diff --git a/grady/core/apps.py b/grady/core/apps.py deleted file mode 100644 index 17b1806403fee0526e8813617a9516177c496d20..0000000000000000000000000000000000000000 --- a/grady/core/apps.py +++ /dev/null @@ -1,9 +0,0 @@ -from django.apps import AppConfig - - -class CoreConfig(AppConfig): - name = 'core' - verbose_name = 'where everything comes together' - - def ready(self): - import core.signals # noqa diff --git a/grady/core/management/commands/extractsubmissions.py b/grady/core/management/commands/extractsubmissions.py deleted file mode 100644 index 1e25c4ca4b01970928f13f9e9a8332c007f7e36a..0000000000000000000000000000000000000000 --- a/grady/core/management/commands/extractsubmissions.py +++ /dev/null @@ -1,13 +0,0 @@ -from django.core.management.base import BaseCommand - -from core import models - - -class Command(BaseCommand): - help = 'Extract all submissions from this instance' - - def handle(self, *args, **kwargs): - for submission in models.Submission.objects.filter( - feedback__isnull=False).order_by('type'): - print(submission.feedback.score, repr(submission.text), - file=open(str(submission.type).replace(' ', '_'), 'a')) diff --git a/grady/core/management/commands/importer.py b/grady/core/management/commands/importer.py deleted file mode 100644 index 1d0bd87c6116a3de726ff1926fd146c4629f76df..0000000000000000000000000000000000000000 --- a/grady/core/management/commands/importer.py +++ /dev/null @@ -1,10 +0,0 @@ -from django.core.management.base import BaseCommand - -import util.importer - - -class Command(BaseCommand): - help = 'Start the Grady command line importer' - - def handle(self, *args, **kwargs): - util.importer.start() diff --git a/grady/core/management/commands/maketestdata.py b/grady/core/management/commands/maketestdata.py deleted file mode 100644 index 075cf243e320592e0db25ca78afd82af8cf72c76..0000000000000000000000000000000000000000 --- a/grady/core/management/commands/maketestdata.py +++ /dev/null @@ -1,10 +0,0 @@ -from django.core.management.base import BaseCommand - -from util.factories import init_test_instance - - -class Command(BaseCommand): - help = 'Creates some initial test data for the application' - - def handle(self, *args, **options): - init_test_instance() diff --git a/grady/core/management/commands/replaceusernames.py b/grady/core/management/commands/replaceusernames.py deleted file mode 100644 index cf1fe74d161ff6355e62f1a3e903de81e44b0676..0000000000000000000000000000000000000000 --- a/grady/core/management/commands/replaceusernames.py +++ /dev/null @@ -1,30 +0,0 @@ -import argparse -import json -import sys - -from django.contrib.auth import get_user_model -from django.core.management.base import BaseCommand - - -class Command(BaseCommand): - help = ('replaces all usernames based on a ' - 'matrikel_no -> new_name dict (input should be JSON)') - - def add_arguments(self, parser): - parser.add_argument( - 'matno2username_dict', - help='the mapping as a JSON file', - default=sys.stdin, - type=argparse.FileType('r') - ) - - def _handle(self, matno2username_dict, **kwargs): - matno2username = json.JSONDecoder().decode(matno2username_dict.read()) - for student in get_user_model().get_students(): - if student.student.matrikel_no in matno2username: - new_name = matno2username[student.student.matrikel_no] - student.username = new_name - student.save() - - def handle(self, *args, **options): - self._handle(*args, **options) diff --git a/grady/core/management/commands/setstudentpasswords.py b/grady/core/management/commands/setstudentpasswords.py deleted file mode 100644 index 1fe569165ef151ac7ab37707488942085fbe48cf..0000000000000000000000000000000000000000 --- a/grady/core/management/commands/setstudentpasswords.py +++ /dev/null @@ -1,44 +0,0 @@ -import csv -import re -import secrets -import sys - -from django.contrib.auth import get_user_model -from django.core.management.base import BaseCommand - - -class Command(BaseCommand): - help = ('All student passwords will be changed' - 'and a list of these password will be printed') - - def add_arguments(self, parser): - parser.add_argument( - 'instance', - help="Name of the instance that generated the passwords" - ) - - def _handle(self, *args, output=sys.stdout, instance="", **kwargs): - with open('/usr/share/dict/words') as f: - # strip punctuation - words = set(re.sub(r"[^a-z]", "\n", f.read().lower()).split('\n')) - choose_from = list({word.strip().lower() - for word in words if 5 < len(word) < 8}) - - writer = csv.writer(output) - writer.writerow( - ['Name', 'Matrikel', 'Username', 'password', 'instance']) - - for student in get_user_model().get_students(): - password = '-'.join(secrets.choice(choose_from) for _ in range(3)) - - student.set_password(password) - student.save() - - if not student.fullname: - student.fullname = '__no_name__' - - writer.writerow([student.fullname, student.student.matrikel_no, - student.username, password, instance]) - - def handle(self, *args, **options): - self._handle(*args, **options) diff --git a/grady/core/management/commands/usermod.py b/grady/core/management/commands/usermod.py deleted file mode 100644 index 14a95621055783ba33c2b392f5857a5487b4dad4..0000000000000000000000000000000000000000 --- a/grady/core/management/commands/usermod.py +++ /dev/null @@ -1,37 +0,0 @@ -from django.contrib.auth import get_user_model -from django.core.management.base import BaseCommand - - -class Command(BaseCommand): - help = 'All user accounts will be disabled' - - def add_arguments(self, parser): - parser.add_argument( - 'switch', - choices=('enable', 'disable'), - default='enable', - help='enable all users (enable) or disable all (disable)' - ) - filter_group = parser.add_mutually_exclusive_group() - filter_group.add_argument( - '--exclude', - default=(), - nargs='+', - help='Provide all users you want to exclude from the operation' - ) - filter_group.add_argument( - '--include', - help=('Provide users you want to operate on' - 'Everything else is untouched'), - nargs='+', - default=()) - - def handle(self, switch, exclude=None, include=None, *args, **kwargs): - if include: - for user in get_user_model().objects.filter(username__in=include): - user.is_active = switch == 'enable' - user.save() - else: # this includes nothing set - for user in get_user_model().objects.exclude(username__in=exclude): - user.is_active = switch == 'enable' - user.save() diff --git a/grady/core/migrations/0001_initial.py b/grady/core/migrations/0001_initial.py deleted file mode 100644 index 3624c16e6e5350129516765df98880b8b850273d..0000000000000000000000000000000000000000 --- a/grady/core/migrations/0001_initial.py +++ /dev/null @@ -1,261 +0,0 @@ -# Generated by Django 2.1.11 on 2019-12-01 16:48 - -import core.models.student_info -import core.models.user_account -from django.conf import settings -import django.contrib.auth.models -import django.contrib.auth.validators -import django.core.validators -from django.db import migrations, models -import django.db.models.deletion -import django.utils.timezone -import uuid - - -class Migration(migrations.Migration): - - initial = True - - dependencies = [ - ('auth', '0009_alter_user_last_name_max_length'), - ] - - operations = [ - migrations.CreateModel( - name='UserAccount', - fields=[ - ('password', models.CharField(max_length=128, verbose_name='password')), - ('last_login', models.DateTimeField(blank=True, null=True, verbose_name='last login')), - ('is_superuser', models.BooleanField(default=False, help_text='Designates that this user has all permissions without explicitly assigning them.', verbose_name='superuser status')), - ('username', models.CharField(error_messages={'unique': 'A user with that username already exists.'}, help_text='Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.', max_length=150, unique=True, validators=[django.contrib.auth.validators.UnicodeUsernameValidator()], verbose_name='username')), - ('first_name', models.CharField(blank=True, max_length=30, verbose_name='first name')), - ('last_name', models.CharField(blank=True, max_length=150, verbose_name='last name')), - ('email', models.EmailField(blank=True, max_length=254, verbose_name='email address')), - ('is_staff', models.BooleanField(default=False, help_text='Designates whether the user can log into this admin site.', verbose_name='staff status')), - ('is_active', models.BooleanField(default=True, help_text='Designates whether this user should be treated as active. Unselect this instead of deleting accounts.', verbose_name='active')), - ('date_joined', models.DateTimeField(default=django.utils.timezone.now, verbose_name='date joined')), - ('role', models.CharField(choices=[('Student', 'student'), ('Tutor', 'tutor'), ('Reviewer', 'reviewer')], max_length=50)), - ('user_id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)), - ('fullname', models.CharField(blank=True, max_length=70, verbose_name='full name')), - ('is_admin', models.BooleanField(default=False)), - ], - options={ - 'verbose_name': 'user', - 'verbose_name_plural': 'users', - 'abstract': False, - }, - managers=[ - ('objects', django.contrib.auth.models.UserManager()), - ('corrector', core.models.user_account.TutorReviewerManager()), - ], - ), - migrations.CreateModel( - name='ExamType', - fields=[ - ('exam_type_id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)), - ('module_reference', models.CharField(max_length=50, unique=True)), - ('total_score', models.PositiveIntegerField()), - ('pass_score', models.PositiveIntegerField()), - ('pass_only', models.BooleanField(default=False)), - ], - options={ - 'verbose_name': 'ExamType', - 'verbose_name_plural': 'ExamTypes', - }, - ), - migrations.CreateModel( - name='Feedback', - fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('score', models.DecimalField(decimal_places=2, default=0, max_digits=5)), - ('created', models.DateTimeField(auto_now_add=True)), - ('is_final', models.BooleanField(default=False)), - ('final_by_reviewer', models.BooleanField(default=False)), - ], - options={ - 'verbose_name': 'Feedback', - 'verbose_name_plural': 'Feedback Set', - }, - ), - migrations.CreateModel( - name='FeedbackComment', - fields=[ - ('comment_id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)), - ('text', models.TextField(blank=True)), - ('created', models.DateTimeField(auto_now_add=True)), - ('modified', models.DateTimeField(auto_now=True)), - ('visible_to_student', models.BooleanField(default=True)), - ('of_line', models.PositiveIntegerField(default=0)), - ('of_feedback', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='feedback_lines', to='core.Feedback')), - ('of_tutor', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='comment_list', to=settings.AUTH_USER_MODEL)), - ], - options={ - 'verbose_name': 'Feedback Comment', - 'verbose_name_plural': 'Feedback Comments', - 'ordering': ('created',), - }, - ), - migrations.CreateModel( - name='FeedbackLabel', - fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('name', models.CharField(max_length=50, unique=True)), - ('description', models.TextField()), - ('colour', models.CharField(default='#b0b0b0', max_length=7, validators=[django.core.validators.RegexValidator(code='nomatch', message='Colour must be in format: #[0-9A-F]{7}', regex='^#[0-9A-F]{6}$')])), - ('feedback', models.ManyToManyField(related_name='labels', to='core.Feedback')), - ('feedback_comments', models.ManyToManyField(related_name='labels', to='core.FeedbackComment')), - ], - ), - migrations.CreateModel( - name='Group', - fields=[ - ('group_id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)), - ('name', models.CharField(max_length=120)), - ], - ), - migrations.CreateModel( - name='MetaSubmission', - fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('done_assignments', models.PositiveIntegerField(default=0)), - ('has_active_assignment', models.BooleanField(default=False)), - ('has_feedback', models.BooleanField(default=False)), - ('has_final_feedback', models.BooleanField(default=False)), - ('feedback_authors', models.ManyToManyField(to=settings.AUTH_USER_MODEL)), - ], - ), - migrations.CreateModel( - name='SolutionComment', - fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('text', models.TextField()), - ('created', models.DateTimeField(auto_now_add=True)), - ('modified', models.DateTimeField(auto_now=True)), - ('of_line', models.PositiveIntegerField()), - ], - ), - migrations.CreateModel( - name='StudentInfo', - fields=[ - ('student_id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)), - ('has_logged_in', models.BooleanField(default=False)), - ('matrikel_no', models.CharField(default=core.models.student_info.random_matrikel_no, max_length=30, unique=True)), - ('total_score', models.PositiveIntegerField(default=0)), - ('passes_exam', models.BooleanField(default=False)), - ('exam', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='students', to='core.ExamType')), - ('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='student', to=settings.AUTH_USER_MODEL)), - ], - options={ - 'verbose_name': 'Student', - 'verbose_name_plural': 'Student Set', - }, - ), - migrations.CreateModel( - name='Submission', - fields=[ - ('submission_id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)), - ('seen_by_student', models.BooleanField(default=False)), - ('text', models.TextField(blank=True)), - ('source_code', models.TextField(blank=True, editable=False, null=True)), - ('source_code_available', models.BooleanField(default=False, editable=False)), - ('student', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='submissions', to='core.StudentInfo')), - ], - options={ - 'verbose_name': 'Submission', - 'verbose_name_plural': 'Submission Set', - 'ordering': ('type__name',), - }, - ), - migrations.CreateModel( - name='SubmissionType', - fields=[ - ('submission_type_id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)), - ('name', models.CharField(max_length=100, unique=True)), - ('full_score', models.PositiveIntegerField(default=0)), - ('description', models.TextField()), - ('solution', models.TextField()), - ('programming_language', models.CharField(choices=[('c', 'C syntax highlighting'), ('java', 'Java syntax highlighting'), ('mipsasm', 'Mips syntax highlighting'), ('haskell', 'Haskell syntax highlighting'), ('python', 'Python syntax highlighting'), ('plaintext', 'No syntax highlighting')], default='c', max_length=25)), - ], - options={ - 'verbose_name': 'SubmissionType', - 'verbose_name_plural': 'SubmissionType Set', - }, - ), - migrations.CreateModel( - name='Test', - fields=[ - ('test_id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)), - ('name', models.CharField(max_length=30)), - ('label', models.CharField(max_length=50)), - ('annotation', models.TextField()), - ('submission', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='tests', to='core.Submission')), - ], - options={ - 'verbose_name': 'Test', - 'verbose_name_plural': 'Tests', - }, - ), - migrations.CreateModel( - name='TutorSubmissionAssignment', - fields=[ - ('assignment_id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)), - ('stage', models.CharField(choices=[('feedback-creation', 'No feedback was ever assigned'), ('feedback-validation', 'Feedback exists but is not validated'), ('feedback-review', 'Review by exam reviewer required')], default='feedback-creation', max_length=60)), - ('is_done', models.BooleanField(default=False)), - ('created', models.DateTimeField(auto_now_add=True)), - ('owner', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='assignments', to=settings.AUTH_USER_MODEL)), - ('submission', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='assignments', to='core.Submission')), - ], - ), - migrations.AddField( - model_name='submission', - name='type', - field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='submissions', to='core.SubmissionType'), - ), - migrations.AddField( - model_name='solutioncomment', - name='of_submission_type', - field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='solution_comments', to='core.SubmissionType'), - ), - migrations.AddField( - model_name='solutioncomment', - name='of_user', - field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='solution_comments', to=settings.AUTH_USER_MODEL), - ), - migrations.AddField( - model_name='metasubmission', - name='submission', - field=models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='meta', to='core.Submission'), - ), - migrations.AddField( - model_name='feedback', - name='of_submission', - field=models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='feedback', to='core.Submission'), - ), - migrations.AddField( - model_name='useraccount', - name='group', - field=models.ManyToManyField(blank=True, related_name='group', to='core.Group'), - ), - migrations.AddField( - model_name='useraccount', - name='groups', - field=models.ManyToManyField(blank=True, help_text='The groups this user belongs to. A user will get all permissions granted to each of their groups.', related_name='user_set', related_query_name='user', to='auth.Group', verbose_name='groups'), - ), - migrations.AddField( - model_name='useraccount', - name='user_permissions', - field=models.ManyToManyField(blank=True, help_text='Specific permissions for this user.', related_name='user_set', related_query_name='user', to='auth.Permission', verbose_name='user permissions'), - ), - migrations.AlterUniqueTogether( - name='test', - unique_together={('submission', 'name')}, - ), - migrations.AlterUniqueTogether( - name='submission', - unique_together={('type', 'student')}, - ), - migrations.AlterUniqueTogether( - name='feedbackcomment', - unique_together={('of_line', 'of_tutor', 'of_feedback')}, - ), - ] diff --git a/grady/core/migrations/0002_auto_20191202_1018.py b/grady/core/migrations/0002_auto_20191202_1018.py deleted file mode 100644 index 07cfd2d188c9282a7a55918d9aea885848028594..0000000000000000000000000000000000000000 --- a/grady/core/migrations/0002_auto_20191202_1018.py +++ /dev/null @@ -1,22 +0,0 @@ -# Generated by Django 2.1.11 on 2019-12-02 10:18 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('core', '0001_initial'), - ] - - operations = [ - migrations.RemoveField( - model_name='useraccount', - name='group', - ), - migrations.AddField( - model_name='useraccount', - name='exercise_groups', - field=models.ManyToManyField(blank=True, related_name='users', to='core.Group'), - ), - ] diff --git a/grady/core/migrations/0003_auto_20191203_1445.py b/grady/core/migrations/0003_auto_20191203_1445.py deleted file mode 100644 index 5abadff66e86c918e3b366633dbe45996241f997..0000000000000000000000000000000000000000 --- a/grady/core/migrations/0003_auto_20191203_1445.py +++ /dev/null @@ -1,18 +0,0 @@ -# Generated by Django 2.1.11 on 2019-12-03 14:45 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('core', '0002_auto_20191202_1018'), - ] - - operations = [ - migrations.AlterField( - model_name='submissiontype', - name='programming_language', - field=models.CharField(choices=[('c', 'C syntax highlighting'), ('java', 'Java syntax highlighting'), ('mipsasm', 'Mips syntax highlighting'), ('haskell', 'Haskell syntax highlighting'), ('python', 'Python syntax highlighting'), ('markdown', 'Markdown syntax highlighting with asciimath rendering'), ('plaintext', 'No syntax highlighting')], default='c', max_length=25), - ), - ] diff --git a/grady/core/migrations/0004_feedback_modified.py b/grady/core/migrations/0004_feedback_modified.py deleted file mode 100644 index 0364705d092669fa5e151147cc1e7d5243747937..0000000000000000000000000000000000000000 --- a/grady/core/migrations/0004_feedback_modified.py +++ /dev/null @@ -1,18 +0,0 @@ -# Generated by Django 2.1.14 on 2020-04-14 18:38 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('core', '0003_auto_20191203_1445'), - ] - - operations = [ - migrations.AddField( - model_name='feedback', - name='modified', - field=models.DateTimeField(auto_now=True), - ), - ] diff --git a/grady/core/migrations/0005_auto_20200707_1456.py b/grady/core/migrations/0005_auto_20200707_1456.py deleted file mode 100644 index 63d03d4431f1f74298e4d3ea2183d2d22dd4eb71..0000000000000000000000000000000000000000 --- a/grady/core/migrations/0005_auto_20200707_1456.py +++ /dev/null @@ -1,47 +0,0 @@ -# Generated by Django 2.2.12 on 2020-07-07 14:56 - -import core.models.user_account -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - dependencies = [ - ('core', '0004_feedback_modified'), - ] - - operations = [ - migrations.RemoveField( - model_name='studentinfo', - name='exam', - ), - migrations.RemoveField( - model_name='studentinfo', - name='passes_exam', - ), - migrations.RemoveField( - model_name='studentinfo', - name='total_score', - ), - migrations.AlterField( - model_name='useraccount', - name='exercise_groups', - field=models.ManyToManyField(blank=True, default=core.models.user_account.group_default, related_name='users', to='core.Group'), - ), - migrations.CreateModel( - name='StudentsExam', - fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('total_score', models.PositiveIntegerField(default=0)), - ('passes_exam', models.BooleanField(default=False)), - ('exam', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='exam', to='core.ExamType')), - ('student', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='students', to='core.StudentInfo')), - ], - ), - migrations.AddField( - model_name='studentinfo', - name='exams', - field=models.ManyToManyField(blank=True, related_name='exams', to='core.StudentsExam'), - ), - ] diff --git a/grady/core/migrations/0005_auto_20200929_1202.py b/grady/core/migrations/0005_auto_20200929_1202.py deleted file mode 100644 index a4dab173b0c6c7566760be6a65fd77e7cc5b630f..0000000000000000000000000000000000000000 --- a/grady/core/migrations/0005_auto_20200929_1202.py +++ /dev/null @@ -1,19 +0,0 @@ -# Generated by Django 2.2.16 on 2020-09-29 12:02 - -import core.models.user_account -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('core', '0004_feedback_modified'), - ] - - operations = [ - migrations.AlterField( - model_name='useraccount', - name='exercise_groups', - field=models.ManyToManyField(blank=True, default=core.models.user_account.group_default, related_name='users', to='core.Group'), - ), - ] diff --git a/grady/core/migrations/0006_auto_20200810_1115.py b/grady/core/migrations/0006_auto_20200810_1115.py deleted file mode 100644 index e9d7d8d17dbfdb3430fc801b84ca52ea734fac65..0000000000000000000000000000000000000000 --- a/grady/core/migrations/0006_auto_20200810_1115.py +++ /dev/null @@ -1,17 +0,0 @@ -# Generated by Django 2.2.12 on 2020-08-10 11:15 - -from django.db import migrations - - -class Migration(migrations.Migration): - - dependencies = [ - ('core', '0005_auto_20200707_1456'), - ] - - operations = [ - migrations.RenameModel( - old_name='StudentsExam', - new_name='ExamInfo', - ), - ] diff --git a/grady/core/migrations/0006_auto_20201027_1234.py b/grady/core/migrations/0006_auto_20201027_1234.py deleted file mode 100644 index b3cb85eaa430bb482880ad340a1813195f676da9..0000000000000000000000000000000000000000 --- a/grady/core/migrations/0006_auto_20201027_1234.py +++ /dev/null @@ -1,18 +0,0 @@ -# Generated by Django 3.1.2 on 2020-10-27 12:34 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('core', '0005_auto_20200929_1202'), - ] - - operations = [ - migrations.AlterField( - model_name='useraccount', - name='first_name', - field=models.CharField(blank=True, max_length=150, verbose_name='first name'), - ), - ] diff --git a/grady/core/migrations/0007_auto_20200922_1026.py b/grady/core/migrations/0007_auto_20200922_1026.py deleted file mode 100644 index a077aaa5d6709744d10a420986355c601108c997..0000000000000000000000000000000000000000 --- a/grady/core/migrations/0007_auto_20200922_1026.py +++ /dev/null @@ -1,23 +0,0 @@ -# Generated by Django 2.2.12 on 2020-09-22 10:26 - -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - dependencies = [ - ('core', '0006_auto_20200810_1115'), - ] - - operations = [ - migrations.RemoveField( - model_name='studentinfo', - name='exams', - ), - migrations.AlterField( - model_name='examinfo', - name='student', - field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='exams', to='core.StudentInfo'), - ), - ] diff --git a/grady/core/migrations/0008_auto_20200922_1148.py b/grady/core/migrations/0008_auto_20200922_1148.py deleted file mode 100644 index 7426432e672356d72067d4d79d3c8ebd99d33796..0000000000000000000000000000000000000000 --- a/grady/core/migrations/0008_auto_20200922_1148.py +++ /dev/null @@ -1,19 +0,0 @@ -# Generated by Django 2.2.12 on 2020-09-22 11:48 - -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - dependencies = [ - ('core', '0007_auto_20200922_1026'), - ] - - operations = [ - migrations.AlterField( - model_name='examinfo', - name='exam', - field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='exam_infos', to='core.ExamType'), - ), - ] diff --git a/grady/core/migrations/0009_submissiontype_exam_type.py b/grady/core/migrations/0009_submissiontype_exam_type.py deleted file mode 100644 index eaa876ff06dbd1bae88397ef7514b52a0c8d3121..0000000000000000000000000000000000000000 --- a/grady/core/migrations/0009_submissiontype_exam_type.py +++ /dev/null @@ -1,19 +0,0 @@ -# Generated by Django 2.2.16 on 2020-10-22 11:57 - -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - dependencies = [ - ('core', '0008_auto_20200922_1148'), - ] - - operations = [ - migrations.AddField( - model_name='submissiontype', - name='exam_type', - field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='submission_types', to='core.ExamType'), - ), - ] diff --git a/grady/core/migrations/0010_group_examtype.py b/grady/core/migrations/0010_group_examtype.py deleted file mode 100644 index 1c9e45fff8ee132a60ef9be0b7d8fd5af54faa22..0000000000000000000000000000000000000000 --- a/grady/core/migrations/0010_group_examtype.py +++ /dev/null @@ -1,19 +0,0 @@ -# Generated by Django 2.2.16 on 2020-11-03 11:54 - -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - dependencies = [ - ('core', '0009_submissiontype_exam_type'), - ] - - operations = [ - migrations.AddField( - model_name='group', - name='examType', - field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='groups', to='core.ExamType'), - ), - ] diff --git a/grady/core/migrations/0011_auto_20201103_1211.py b/grady/core/migrations/0011_auto_20201103_1211.py deleted file mode 100644 index 5a42817f9395b8a4c5c78125261e5c574ed84c43..0000000000000000000000000000000000000000 --- a/grady/core/migrations/0011_auto_20201103_1211.py +++ /dev/null @@ -1,18 +0,0 @@ -# Generated by Django 2.2.16 on 2020-11-03 12:11 - -from django.db import migrations - - -class Migration(migrations.Migration): - - dependencies = [ - ('core', '0010_group_examtype'), - ] - - operations = [ - migrations.RenameField( - model_name='group', - old_name='examType', - new_name='exam_type', - ), - ] diff --git a/grady/core/migrations/0012_auto_20201103_1228.py b/grady/core/migrations/0012_auto_20201103_1228.py deleted file mode 100644 index 6de5b38584bd13ce32d853c845844c59bc97c66c..0000000000000000000000000000000000000000 --- a/grady/core/migrations/0012_auto_20201103_1228.py +++ /dev/null @@ -1,17 +0,0 @@ -# Generated by Django 2.2.16 on 2020-11-03 12:28 - -from django.db import migrations - - -class Migration(migrations.Migration): - - dependencies = [ - ('core', '0011_auto_20201103_1211'), - ] - - operations = [ - migrations.AlterModelOptions( - name='group', - options={'verbose_name': 'Group', 'verbose_name_plural': 'Groups'}, - ), - ] diff --git a/grady/core/migrations/0013_auto_20201103_1248.py b/grady/core/migrations/0013_auto_20201103_1248.py deleted file mode 100644 index 8e36cd62370435053a161e3097dc761fd9c49f9d..0000000000000000000000000000000000000000 --- a/grady/core/migrations/0013_auto_20201103_1248.py +++ /dev/null @@ -1,21 +0,0 @@ -# Generated by Django 2.2.16 on 2020-11-03 12:48 - -from django.db import migrations - - -class Migration(migrations.Migration): - - dependencies = [ - ('core', '0012_auto_20201103_1228'), - ] - - operations = [ - migrations.AlterModelOptions( - name='group', - options={}, - ), - migrations.RemoveField( - model_name='group', - name='exam_type', - ), - ] diff --git a/grady/core/migrations/0014_merge_20201123_1252.py b/grady/core/migrations/0014_merge_20201123_1252.py deleted file mode 100644 index e89e1ffce9f80c0e4caa0972750916c239f4dd2c..0000000000000000000000000000000000000000 --- a/grady/core/migrations/0014_merge_20201123_1252.py +++ /dev/null @@ -1,14 +0,0 @@ -# Generated by Django 3.1.3 on 2020-11-23 12:52 - -from django.db import migrations - - -class Migration(migrations.Migration): - - dependencies = [ - ('core', '0013_auto_20201103_1248'), - ('core', '0006_auto_20201027_1234'), - ] - - operations = [ - ] diff --git a/grady/core/migrations/0015_group_exam_type.py b/grady/core/migrations/0015_group_exam_type.py deleted file mode 100644 index 87662145d085a6b4d7198da982cb8c6ea372e54c..0000000000000000000000000000000000000000 --- a/grady/core/migrations/0015_group_exam_type.py +++ /dev/null @@ -1,19 +0,0 @@ -# Generated by Django 3.1.7 on 2021-09-02 11:36 - -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - dependencies = [ - ('core', '0014_merge_20201123_1252'), - ] - - operations = [ - migrations.AddField( - model_name='group', - name='exam_type', - field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='groups', to='core.examtype'), - ), - ] diff --git a/grady/core/migrations/0016_auto_20210902_1140.py b/grady/core/migrations/0016_auto_20210902_1140.py deleted file mode 100644 index 4f975a5518a9d0ee46018a1dd5b6813f211f99be..0000000000000000000000000000000000000000 --- a/grady/core/migrations/0016_auto_20210902_1140.py +++ /dev/null @@ -1,18 +0,0 @@ -# Generated by Django 3.1.7 on 2021-09-02 11:40 - -from django.db import migrations - - -class Migration(migrations.Migration): - - dependencies = [ - ('core', '0015_group_exam_type'), - ] - - operations = [ - migrations.RenameField( - model_name='group', - old_name='exam_type', - new_name='exam', - ), - ] diff --git a/grady/core/migrations/__init__.py b/grady/core/migrations/__init__.py deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/grady/core/models/__init__.py b/grady/core/models/__init__.py deleted file mode 100644 index 432bbb04b58960821b295e512876e2d174129c7d..0000000000000000000000000000000000000000 --- a/grady/core/models/__init__.py +++ /dev/null @@ -1,13 +0,0 @@ -from .group import Group # noqa -from .exam_type import ExamType # noqa -from .submission_type import SubmissionType, SolutionComment # noqa -from .user_account import UserAccount, TutorReviewerManager # noqa -from .user_account import UserAccount, TutorReviewerManager # noqa -from .student_info import StudentInfo, random_matrikel_no, ExamInfo # noqa -from .test import Test # noqa -from .submission import Submission, MetaSubmission # noqa -from .feedback import Feedback, FeedbackComment # noqa -from .assignment import (DeletionOfDoneAssignmentsNotPermitted, TutorSubmissionAssignment, # noqa - CanOnlyCallFinishOnUnfinishedAssignments, SubmissionTypeDepleted, # noqa - NotMoreThanTwoOpenAssignmentsAllowed) # noqa -from .label import FeedbackLabel # noqa diff --git a/grady/core/models/assignment.py b/grady/core/models/assignment.py deleted file mode 100644 index 8936bf9ab84473704401416279d02a232f2e4765..0000000000000000000000000000000000000000 --- a/grady/core/models/assignment.py +++ /dev/null @@ -1,111 +0,0 @@ -import logging -import uuid - -import constance -from django.db import models - -from core.models import Submission, UserAccount, MetaSubmission - -log = logging.getLogger(__name__) -config = constance.config - - -class DeletionOfDoneAssignmentsNotPermitted(Exception): - pass - - -class CanOnlyCallFinishOnUnfinishedAssignments(Exception): - pass - - -class SubmissionTypeDepleted(Exception): - pass - - -class NotMoreThanTwoOpenAssignmentsAllowed(Exception): - pass - - -class TutorSubmissionAssignmentManager(models.Manager): - - @staticmethod - def available_assignments(create_assignment_options): - stage = create_assignment_options['stage'] - owner = create_assignment_options['owner'] - submission_type = create_assignment_options['submission_type'] - group = create_assignment_options.get('group') - - stage = TutorSubmissionAssignment.assignment_count_on_stage[stage] - candidates = MetaSubmission.objects.filter( - submission__type__pk=submission_type, - done_assignments=stage, - has_final_feedback=False, - has_active_assignment=False, - ).exclude( - feedback_authors=owner - ) - if group is not None: - candidates = candidates.filter( - submission__student__user__exercise_groups__pk=group - ) - return candidates - - -class TutorSubmissionAssignment(models.Model): - objects = TutorSubmissionAssignmentManager() - - FEEDBACK_CREATION = 'feedback-creation' - FEEDBACK_VALIDATION = 'feedback-validation' - FEEDBACK_REVIEW = 'feedback-review' - - stages = ( - (FEEDBACK_CREATION, 'No feedback was ever assigned'), - (FEEDBACK_VALIDATION, 'Feedback exists but is not validated'), - (FEEDBACK_REVIEW, 'Review by exam reviewer required'), - ) - - assignment_count_on_stage = { - FEEDBACK_CREATION: 0, - FEEDBACK_VALIDATION: 1, - FEEDBACK_REVIEW: 2, - } - - owner = models.ForeignKey(UserAccount, - on_delete=models.CASCADE, - related_name='assignments') - - assignment_id = models.UUIDField(primary_key=True, - default=uuid.uuid4, - editable=False) - submission = models.ForeignKey(Submission, - on_delete=models.CASCADE, - related_name='assignments') - - stage = models.CharField(choices=stages, - max_length=60, - default=FEEDBACK_CREATION) - - is_done = models.BooleanField(default=False) - created = models.DateTimeField(auto_now_add=True) - - def __str__(self): - return (f'{self.owner} assigned to {self.submission}' - f' (done={self.is_done})') - - def finish(self): - self.refresh_from_db() - if self.is_done: - raise CanOnlyCallFinishOnUnfinishedAssignments() - - meta = self.submission.meta - meta.feedback_authors.add(self.owner) - meta.done_assignments += 1 - meta.has_active_assignment = False - self.is_done = True - self.save() - meta.save() - - def delete(self, *args, **kwargs): - if self.is_done: - raise DeletionOfDoneAssignmentsNotPermitted() - super().delete(*args, **kwargs) diff --git a/grady/core/models/exam_type.py b/grady/core/models/exam_type.py deleted file mode 100644 index bf9ab0a79d752fb9d59597510c37fe9ddc5141d5..0000000000000000000000000000000000000000 --- a/grady/core/models/exam_type.py +++ /dev/null @@ -1,44 +0,0 @@ - -import logging -import uuid - -import constance -from django.db import models - -log = logging.getLogger(__name__) -config = constance.config - - -class ExamType(models.Model): - """A model that contains information about the module a submission can - belong to. The information is not needed and is currently, just used to - detect if students already have enough points to pass an exam. - - It is NOT intended to use this for including different exams regarding - submissions types. - - Attributes - ---------- - module_reference : CharField - a unique reference that identifies a module within the university - pass_only : BooleanField - True if no grade is given - pass_score : PositiveIntegerField - minimum score for (just) passing - total_score : PositiveIntegerField - maximum score for the exam (currently never used anywhere) - """ - class Meta: - verbose_name = "ExamType" - verbose_name_plural = "ExamTypes" - - def __str__(self) -> str: - return self.module_reference - - exam_type_id = models.UUIDField(primary_key=True, - default=uuid.uuid4, - editable=False) - module_reference = models.CharField(max_length=50, unique=True) - total_score = models.PositiveIntegerField() - pass_score = models.PositiveIntegerField() - pass_only = models.BooleanField(default=False) diff --git a/grady/core/models/feedback.py b/grady/core/models/feedback.py deleted file mode 100644 index 6a83bbe98e6c9e524204835cfb1763826902e778..0000000000000000000000000000000000000000 --- a/grady/core/models/feedback.py +++ /dev/null @@ -1,94 +0,0 @@ -import logging -import uuid - -import constance -from django.contrib.auth import get_user_model -from django.db import models - -from core.models.submission import Submission - -log = logging.getLogger(__name__) -config = constance.config - - -class Feedback(models.Model): - """ - Attributes - ---------- - score : PositiveIntegerField - A score that has been assigned to he submission. Is final if it was - accepted. - created : DateTimeField - When the feedback was initially created - modified: DateTimeField - Timestamp indicating the last time the feedback was saved - of_submission : OneToOneField - The submission this feedback belongs to. It finally determines how many - points a student receives for his submission. - origin : IntegerField - Of whom was this feedback originally created. She below for the choices - final_by_reviewer: BooleanField - Whether or not this feedback was set to final by a reviewer once - """ - score = models.DecimalField(max_digits=5, decimal_places=2, default=0) - created = models.DateTimeField(auto_now_add=True) - modified = models.DateTimeField(auto_now=True) - is_final = models.BooleanField(default=False) - final_by_reviewer = models.BooleanField(default=False) - - of_submission = models.OneToOneField( - Submission, - on_delete=models.CASCADE, - related_name='feedback') - - # the denominators that are allowed for the decimal score interpreted as a fraction - ALLOWED_DENOMINATORS = [1, 2] - - class Meta: - verbose_name = "Feedback" - verbose_name_plural = "Feedback Set" - - def __str__(self) -> str: - return 'Feedback for {}'.format(self.of_submission) - - def is_full_score(self) -> bool: - return self.of_submission.type.full_score == self.score - - def get_full_score(self) -> int: - return self.of_submission.type.full_score - - -class FeedbackComment(models.Model): - """ This Class contains the Feedback for a specific line of a Submission""" - comment_id = models.UUIDField(primary_key=True, - default=uuid.uuid4, - editable=False) - text = models.TextField(blank=True) - created = models.DateTimeField(auto_now_add=True) - modified = models.DateTimeField(auto_now=True) - - visible_to_student = models.BooleanField(default=True) - - of_line = models.PositiveIntegerField(default=0) - of_tutor = models.ForeignKey( - get_user_model(), - related_name="comment_list", - on_delete=models.PROTECT - ) - of_feedback = models.ForeignKey( - Feedback, - related_name="feedback_lines", - on_delete=models.CASCADE, - null=True - ) - - class Meta: - verbose_name = "Feedback Comment" - verbose_name_plural = "Feedback Comments" - ordering = ('created',) - unique_together = ('of_line', 'of_tutor', 'of_feedback') - - def __str__(self): - return 'Comment on line {} of tutor {}: "{}"'.format(self.of_line, - self.of_tutor, - self.text) diff --git a/grady/core/models/group.py b/grady/core/models/group.py deleted file mode 100644 index f03b8181c048855576b48ed1271aa40a7f5e4713..0000000000000000000000000000000000000000 --- a/grady/core/models/group.py +++ /dev/null @@ -1,14 +0,0 @@ -from django.db import models -from core.models.exam_type import ExamType -import uuid - - -class Group(models.Model): - group_id = models.UUIDField(primary_key=True, - default=uuid.uuid4, - editable=False) - name = models.CharField(max_length=120) - exam = models.ForeignKey(ExamType, - on_delete=models.CASCADE, - related_name='groups', - null=True) diff --git a/grady/core/models/label.py b/grady/core/models/label.py deleted file mode 100644 index 731b241b9577f87bcccccc3ec95e4272962de87a..0000000000000000000000000000000000000000 --- a/grady/core/models/label.py +++ /dev/null @@ -1,21 +0,0 @@ -import logging - -from django.core.validators import RegexValidator -from django.db import models - -from core.models.feedback import Feedback, FeedbackComment - -log = logging.getLogger(__name__) - -HexColourValidator = RegexValidator( - regex='^#[0-9A-F]{6}$', - message='Colour must be in format: #[0-9A-F]{7}', - code='nomatch') - - -class FeedbackLabel(models.Model): - name = models.CharField(max_length=50, unique=True) - description = models.TextField() - colour = models.CharField(validators=[HexColourValidator], max_length=7, default='#b0b0b0') - feedback = models.ManyToManyField(Feedback, related_name='labels') - feedback_comments = models.ManyToManyField(FeedbackComment, related_name='labels') diff --git a/grady/core/models/student_info.py b/grady/core/models/student_info.py deleted file mode 100644 index 1b57910dc702c677cfa29ffa88af0d500aec79b8..0000000000000000000000000000000000000000 --- a/grady/core/models/student_info.py +++ /dev/null @@ -1,140 +0,0 @@ -import logging -import uuid -from collections import OrderedDict -from random import randrange -from typing import Dict - -import constance -from django.contrib.auth import get_user_model -from django.db import models -from django.db.models import BooleanField, F, When, Sum, QuerySet, Value, Case -from django.db.models.functions import Coalesce - -from core.models.submission_type import SubmissionType -from core.models.exam_type import ExamType - -log = logging.getLogger(__name__) -config = constance.config - - -def random_matrikel_no() -> str: - """Use as a default value for student's matriculation number. - - Returns: - str: an eight digit number - """ - return str(10_000_000 + randrange(90_000_000)) - - -class ExamInfo(models.Model): - exam = models.ForeignKey(ExamType, - on_delete=models.CASCADE, - related_name='exam_infos', - null=False) - - student = models.ForeignKey('StudentInfo', - on_delete=models.CASCADE, - related_name='exams', - null=False) - - total_score = models.PositiveIntegerField(default=0) - passes_exam = models.BooleanField(default=False) - - def update_total_score(self): - ''' This helper is invoked after feedback changes ''' - self.total_score = self.student.submissions.aggregate( - Sum('feedback__score'))['feedback__score__sum'] or 0 - if self.exam is not None: - self.passes_exam = self.total_score >= self.exam.pass_score - self.save() - - def score_per_submission(self) -> Dict[str, int]: - """ TODO: get rid of it and use an annotation. """ - if self.student.submissions.all(): - return OrderedDict({ - s.type.name: s.feedback.score if hasattr(s, 'feedback') else 0 - for s in self.student.submissions.filter(type__exam_type=self.exam) - .order_by('type__name') - }) - - return OrderedDict({ - t.name: 0 for t in SubmissionType.objects.all() - }) - - -class StudentInfo(models.Model): - """ - The StudentInfo model includes all information of a student, that we got - from the E-Learning output, along with some useful classmethods that - provide specially annotated QuerySets. - - Information like email (if given), and the username are stored in the - associated user model. - - Attributes: - exams (ManyToManyField): - Module the student wants te be graded in, or different exercise - assignments for one module. - - has_logged_in (BooleanField): - Login is permitted once. If this is set the user can not log in. - - matrikel_no (CharField): - The matriculation number of the student - """ - student_id = models.UUIDField(primary_key=True, - default=uuid.uuid4, - editable=False) - has_logged_in = models.BooleanField(default=False) - matrikel_no = models.CharField(unique=True, - max_length=30, - default=random_matrikel_no) - - user = models.OneToOneField(get_user_model(), - on_delete=models.CASCADE, - related_name='student') - - def add_exam(self, exam): - exam_info = ExamInfo(exam=exam, student=self) - exam_info.save() - self.exams.add(exam_info) - - @classmethod - def get_annotated_score_submission_list(cls) -> QuerySet: - """Can be used to quickly annotate a user with the necessary - information on the overall score of a student and if he does not need - any more correction. - - A student is done if - * module type was pass_only and student has enough points - * every submission got accepted feedback - - Returns - ------- - QuerySet - the annotated QuerySet as described above. - """ - return cls.objects.annotate( - overall_score=Coalesce(Sum('submissions__feedback__score'), - Value(0)), - ).annotate( - done=Case( - When(exam__pass_score__lt=F('overall_score'), then=Value(1)), - default=Value(0), - output_field=BooleanField() - ) - ).order_by('user__username') - - def disable(self): - """The student won't be able to login in anymore, but his current - session can be continued until s/he logs out. - """ - self.has_logged_in = True - self.save() - - def __str__(self) -> str: - return self.user.username - - class Meta: - verbose_name = "Student" - verbose_name_plural = "Student Set" diff --git a/grady/core/models/submission.py b/grady/core/models/submission.py deleted file mode 100644 index f2f98dfef048193e685b1afb2659a93a24afbb30..0000000000000000000000000000000000000000 --- a/grady/core/models/submission.py +++ /dev/null @@ -1,89 +0,0 @@ -import logging -import uuid - -import constance -from django.contrib.auth import get_user_model -from django.db import models - -from core.models.submission_type import SubmissionType - -log = logging.getLogger(__name__) -config = constance.config - - -class Submission(models.Model): - """The answer of a student to a specific question. Holds the answer and - very often serves as ForeignKey. - - With the method assign_tutor feedback for a submission can be created and a - tutor will be assigned to this feedback permanently (unless deleted by a - reviewer or if it gets reassigned). There cannot be more than ONE feedback - per Submission. - - Attributes - ---------- - seen_by_student : BooleanField - True if the student saw his accepted feedback. - student : ForgeignKey - The student how cause all of this - text : TextField - The code/text submitted by the student - source_code : TextField - If the original "source code" is not easily displayable (like Jupyter Notebooks), - it's converted to readable source code and the original is saved in this field - source_code_available : BooleanField - Whether there is original source code available under `source_code` or not - type : OneToOneField - Relation to the type containing meta information - """ - submission_id = models.UUIDField(primary_key=True, - default=uuid.uuid4, - editable=False) - seen_by_student = models.BooleanField(default=False) - text = models.TextField(blank=True) - source_code = models.TextField(null=True, blank=True, editable=False) - source_code_available = models.BooleanField(default=False, editable=False) - type = models.ForeignKey( - SubmissionType, - on_delete=models.PROTECT, - related_name='submissions') - student = models.ForeignKey( - 'StudentInfo', - on_delete=models.CASCADE, - related_name='submissions') - - class Meta: - verbose_name = "Submission" - verbose_name_plural = "Submission Set" - unique_together = (('type', 'student'),) - ordering = ('type__name',) - - def __str__(self) -> str: - return "Submission {}".format(self.pk) - - -class MetaSubmission(models.Model): - - submission = models.OneToOneField('submission', - related_name='meta', - on_delete=models.CASCADE) - done_assignments = models.PositiveIntegerField(default=0) - has_active_assignment = models.BooleanField(default=False) - - # Managed by signal! - has_feedback = models.BooleanField(default=False) - # Managed by signal! - has_final_feedback = models.BooleanField(default=False) - - feedback_authors = models.ManyToManyField(get_user_model()) - - def __str__(self): - return f''' Submission Meta of {self.submission} - - done_assignments = {self.done_assignments} - has_active_assignment = {self.has_active_assignment} - has_feedback = {self.has_feedback} - has_final_feedback = {self.has_final_feedback} - feedback_authors = {self.feedback_authors.values_list('username', - flat=True)} - ''' diff --git a/grady/core/models/submission_type.py b/grady/core/models/submission_type.py deleted file mode 100644 index c37cbfa8d884d8a4c0862afe4055575756a9ca55..0000000000000000000000000000000000000000 --- a/grady/core/models/submission_type.py +++ /dev/null @@ -1,128 +0,0 @@ -import logging -import uuid - -import constance -from django.db import models -from django.db.models import (Case, Count, IntegerField, Q, - Value, When) -from django.db.models.query import QuerySet -from core.models.exam_type import ExamType - - -log = logging.getLogger(__name__) -config = constance.config - - -class SubmissionType(models.Model): - """This model mostly holds meta information about the kind of task that was - presented to the student. It serves as a foreign key for the submissions - that are of this type. This model is currently NOT exposed directly in a - view. - - Attributes - ---------- - description : TextField - The task description the student had to fulfill. The content may be - HTML formatted. - full_score : PositiveIntegerField - Maximum score one can get on that one - name : CharField - The original title of the exam. This is wildly used as an identifier by - the preprocessing scripts. - solution : TextField - A sample solution or a correction guideline - """ - - C = 'c' - JAVA = 'java' - MIPS = 'mipsasm' - HASKELL = 'haskell' - TEXT = 'plaintext' - PYTHON = 'python' - MARKDOWN = 'markdown' - - LANGUAGE_CHOICES = ( - (C, 'C syntax highlighting'), - (JAVA, 'Java syntax highlighting'), - (MIPS, 'Mips syntax highlighting'), - (HASKELL, 'Haskell syntax highlighting'), - (PYTHON, 'Python syntax highlighting'), - (MARKDOWN, 'Markdown syntax highlighting with asciimath rendering'), - (TEXT, 'No syntax highlighting'), - ) - - submission_type_id = models.UUIDField(primary_key=True, - default=uuid.uuid4, - editable=False) - name = models.CharField(max_length=100, unique=True) - full_score = models.PositiveIntegerField(default=0) - description = models.TextField() - solution = models.TextField() - exam_type = models.ForeignKey(ExamType, - on_delete=models.CASCADE, - related_name='submission_types', - null=True) - programming_language = models.CharField(max_length=25, - choices=LANGUAGE_CHOICES, - default=C) - - def __str__(self) -> str: - return self.name - - class Meta: - verbose_name = "SubmissionType" - verbose_name_plural = "SubmissionType Set" - - @classmethod - def get_annotated_feedback_count(cls) -> QuerySet: - """ Annotates submission lists with counts - - The following fields are annotated: - * number of submissions per submission type - * count of received *accepted* feedback per submission type - * and finally the progress on each submission type as percentage - - The QuerySet that is return is ordered by name lexicographically. - - Returns: - The annotated QuerySet as described above - """ - return cls.objects\ - .annotate( # to display only manual - feedback_final=Count( - Case(When( - Q(submissions__meta__has_final_feedback=True), - then=Value(1)), output_field=IntegerField()) - ), - feedback_in_validation=Count( - Case(When( - Q(submissions__meta__done_assignments=1) & - Q(submissions__meta__has_final_feedback=False), - then=Value(1)), output_field=IntegerField()) - ), - feedback_in_conflict=Count( - Case(When( - Q(submissions__meta__done_assignments=2) & - Q(submissions__meta__has_final_feedback=False), - then=Value(1)), output_field=IntegerField()) - ), - submission_count=Count('submissions'), - ).order_by('name') - - -class SolutionComment(models.Model): - text = models.TextField() - created = models.DateTimeField(auto_now_add=True) - modified = models.DateTimeField(auto_now=True) - - of_line = models.PositiveIntegerField() - of_user = models.ForeignKey( - 'UserAccount', - related_name="solution_comments", - on_delete=models.PROTECT - ) - of_submission_type = models.ForeignKey( - SubmissionType, - related_name="solution_comments", - on_delete=models.PROTECT, - ) diff --git a/grady/core/models/test.py b/grady/core/models/test.py deleted file mode 100644 index b43d3b2cd2469d175809c94f5c8972751c864eea..0000000000000000000000000000000000000000 --- a/grady/core/models/test.py +++ /dev/null @@ -1,44 +0,0 @@ -import logging -import uuid - -import constance -from django.db import models - -log = logging.getLogger(__name__) -config = constance.config - - -class Test(models.Model): - """Tests contain information that has been unapproved by automated tests, - and directly belongs to a submission. Often certain Feedback was already - given by information provided by these tests. - - Attributes - ---------- - annotation : TextField - All the output of the test (e.g. compiler output) - label : CharField - Indicates SUCCES or FAILURE - name : CharField - The name of the test that was performed - submission : ForeignKey - The submission the tests where unapproved on - """ - test_id = models.UUIDField(primary_key=True, - default=uuid.uuid4, - editable=False) - - name = models.CharField(max_length=30) - label = models.CharField(max_length=50) - annotation = models.TextField() - submission = models.ForeignKey('submission', - related_name='tests', - on_delete=models.CASCADE,) - - class Meta: - verbose_name = "Test" - verbose_name_plural = "Tests" - unique_together = (('submission', 'name'),) - - def __str__(self) -> str: - return f'{self.name} {self.label}' diff --git a/grady/core/models/user_account.py b/grady/core/models/user_account.py deleted file mode 100644 index 281d1747a35984f2be8cb7afd0961e3b347dd53b..0000000000000000000000000000000000000000 --- a/grady/core/models/user_account.py +++ /dev/null @@ -1,109 +0,0 @@ -import logging -import uuid - -import constance -from django.contrib.auth.models import AbstractUser, UserManager -from django.db import models -from django.db.models import (Case, Count, IntegerField, Q, - Value, When) -from django.apps import apps - -from core.models import Group - -log = logging.getLogger(__name__) -config = constance.config - - -class TutorReviewerManager(UserManager): - - def get_queryset(self): - return super().get_queryset().filter( - Q(role=UserAccount.TUTOR) | Q(role=UserAccount.REVIEWER)) - - def with_feedback_count(self): - def _get_counter(stage): - return Count(Case( - When( - Q(assignments__stage=stage) & - Q(assignments__is_done=True), - then=Value(1))), - output_field=IntegerField()) - - assignment_model = apps.get_model('core', 'TutorSubmissionAssignment') # noqa - - return self.get_queryset() \ - .annotate(feedback_created=_get_counter( - assignment_model.FEEDBACK_CREATION)) \ - .annotate(feedback_validated=_get_counter( - assignment_model.FEEDBACK_VALIDATION)) - - -def group_default(): - return [Group.objects.get_or_create(name="Default Group")[0].pk] - - -class UserAccount(AbstractUser): - """ - An abstract base class implementing a fully featured User model with - admin-compliant permissions. - - Username and password are required. Other fields are optional. - """ - - STUDENT = 'Student' - TUTOR = 'Tutor' - REVIEWER = 'Reviewer' - - ROLE_CHOICES = ( - (STUDENT, 'student'), - (TUTOR, 'tutor'), - (REVIEWER, 'reviewer') - ) - - # Fields - role = models.CharField(max_length=50, choices=ROLE_CHOICES) - user_id = models.UUIDField(primary_key=True, - default=uuid.uuid4, - editable=False) - - exercise_groups = models.ManyToManyField(Group, - blank=True, - related_name='users', - default=group_default) - - fullname = models.CharField('full name', max_length=70, blank=True) - is_admin = models.BooleanField(default=False) - - # Managers - objects = UserManager() - corrector = TutorReviewerManager() - - # Helper methods - def is_student(self): - return self.role == 'Student' - - def is_tutor(self): - return self.role == 'Tutor' - - def is_reviewer(self): - return self.role == 'Reviewer' - - def set_groups(self, groups): - if groups == [] or groups is None: - self.exercise_groups.set(group_default()) - else: - self.exercise_groups.set(groups) - - # All of these methods are deprecated and should be replaced by custom - # Managers (see tutor manager) - @classmethod - def get_students(cls): - return cls.objects.filter(role=cls.STUDENT) - - @classmethod - def get_tutors(cls): - return cls.objects.filter(role=cls.TUTOR) - - @classmethod - def get_reviewers(cls): - return cls.objects.filter(role=cls.REVIEWER) diff --git a/grady/core/permissions.py b/grady/core/permissions.py deleted file mode 100644 index af557db0869393568168591fb6ed5d805773832c..0000000000000000000000000000000000000000 --- a/grady/core/permissions.py +++ /dev/null @@ -1,62 +0,0 @@ -import logging - -import constance -from django.http import HttpRequest -from django.views import View -from rest_framework import permissions - -log = logging.getLogger(__name__) -config = constance.config - - -class IsUserRoleGenericPermission(permissions.BasePermission): - """ Generic class that encapsulates how to identify someone - as a member of a user Group """ - - def has_permission(self, request: HttpRequest, view: View) -> bool: - """ required by BasePermission. Check if user is instance of any - of the models provided in class' models attribute """ - assert self.roles is not None, ( - "'%s' has to include a `roles` attribute" - % self.__class__.__name__ - ) - - user = request.user - is_authorized = user.is_superuser or (user.is_authenticated and - user.role in self.roles) - - return is_authorized - - -class IsStudent(IsUserRoleGenericPermission): - """ Has student permissions """ - roles = ('Student', ) - - -class IsReviewer(IsUserRoleGenericPermission): - """ Has reviewer permissions """ - roles = ('Reviewer', ) - - -class IsTutor(IsUserRoleGenericPermission): - """ Has tutor permissions """ - roles = ('Tutor', ) - - -class IsTutorOrReviewer(IsUserRoleGenericPermission): - """ Has tutor or reviewer permissions """ - roles = ('Tutor', 'Reviewer') - - -class GenericIsConfigEnabled(permissions.BasePermission): - """ - Generic class that encapsulates how to check if a runtime config is set. - """ - def has_permission(self, request, view) -> bool: - assert self.required_configs is not None, "Need to include at least one config attribute" - - return all(getattr(config, cfg) for cfg in self.required_configs) - - -class SolutionsEnabledToStudents(GenericIsConfigEnabled): - required_configs = ["SHOW_SOLUTION_TO_STUDENTS"] diff --git a/grady/core/serializers/__init__.py b/grady/core/serializers/__init__.py deleted file mode 100644 index a607259eae60ae3d4dafa55d0def10d5b91631a9..0000000000000000000000000000000000000000 --- a/grady/core/serializers/__init__.py +++ /dev/null @@ -1,11 +0,0 @@ -from .common_serializers import * # noqa -from .submission_type import (SubmissionTypeListSerializer, SubmissionTypeSerializer, # noqa - SolutionCommentSerializer) # noqa -from .feedback import (FeedbackSerializer, FeedbackWithStudentSerializer, # noqa - FeedbackCommentSerializer, # noqa - VisibleCommentFeedbackSerializer) # noqa -from .assignment import * # noqa -from .student import * # noqa -from .submission import * # noqa -from .tutor import CorrectorSerializer # noqa -from .label import LabelSerializer # noqa diff --git a/grady/core/serializers/assignment.py b/grady/core/serializers/assignment.py deleted file mode 100644 index 02c3c0a698eb2113af75fa06fc5e813f6d402f2b..0000000000000000000000000000000000000000 --- a/grady/core/serializers/assignment.py +++ /dev/null @@ -1,73 +0,0 @@ -import secrets - -from rest_framework import serializers - -from core import models -from core.models import (Submission, TutorSubmissionAssignment) -from core.serializers import (DynamicFieldsModelSerializer, FeedbackSerializer, - TestSerializer) - - -class SubmissionAssignmentSerializer(DynamicFieldsModelSerializer): - full_score = serializers.ReadOnlyField(source='type.full_score') - tests = TestSerializer(many=True, read_only=True) - - class Meta: - model = Submission - fields = ('pk', 'type', 'text', 'full_score', 'tests', 'source_code_available') - read_only_fields = ('text', 'type') - - -class AssignmentSerializer(DynamicFieldsModelSerializer): - of_tutor = serializers.CharField(source='owner.username') - - class Meta: - model = TutorSubmissionAssignment - fields = ('pk', 'submission', 'is_done', 'owner', 'stage', 'of_tutor') - read_only_fields = ('is_done', 'submission', 'owner') - - -class AssignmentDetailSerializer(AssignmentSerializer): - feedback = FeedbackSerializer(source='submission.feedback', read_only=True) - submission = SubmissionAssignmentSerializer(read_only=True) - submission_type = serializers.UUIDField(write_only=True) - group = serializers.UUIDField(write_only=True, required=False) - - class Meta: - model = TutorSubmissionAssignment - fields = ('pk', 'submission', 'feedback', 'is_done', - 'owner', 'stage', 'submission_type', 'group') - read_only_fields = ('is_done', 'submission', 'owner') - - def create(self, validated_data): - owner = self.context['request'].user - - open_assignments = TutorSubmissionAssignment.objects.filter( - owner=owner, - is_done=False, - ) - - if len(open_assignments) > 2: - raise models.NotMoreThanTwoOpenAssignmentsAllowed( - 'Not more than two active assignments allowed' - ) - - candidates = TutorSubmissionAssignment.objects.available_assignments({ - **validated_data, - 'owner': owner - }) - - length = len(candidates) - - if length == 0: - raise models.SubmissionTypeDepleted( - 'There are no submissions left for the given criteria' - ) - - index = secrets.choice(range(length)) - - return TutorSubmissionAssignment.objects.create( - submission=candidates[index].submission, - owner=owner, - stage=validated_data.get('stage') - ) diff --git a/grady/core/serializers/common_serializers.py b/grady/core/serializers/common_serializers.py deleted file mode 100644 index c70c51168ad5ef431b1397b65e4fa3a65590b8e6..0000000000000000000000000000000000000000 --- a/grady/core/serializers/common_serializers.py +++ /dev/null @@ -1,104 +0,0 @@ -import logging -from collections import defaultdict - -import django.contrib.auth.password_validation as validators -from django.core import exceptions -from django.db.models.manager import Manager -from rest_framework import serializers -from rest_framework.utils import html - -from core import models - -from .generic import DynamicFieldsModelSerializer - -log = logging.getLogger(__name__) - - -class ExamSerializer(DynamicFieldsModelSerializer): - - class Meta: - model = models.ExamType - fields = ('pk', 'module_reference', 'total_score', - 'pass_score', 'pass_only',) - - -class GroupSerializer(serializers.ModelSerializer): - exam = ExamSerializer(many=False) - - class Meta: - model = models.Group - fields = ('pk', 'name', 'exam') - - -class TestSerializer(DynamicFieldsModelSerializer): - - class Meta: - model = models.Test - fields = ('pk', 'name', 'label', 'annotation') - - -class UserAccountSerializer(DynamicFieldsModelSerializer): - exercise_groups = GroupSerializer(many=True) - - def validate(self, data): - password = data.get('password') - - try: - if password is not None: - validators.validate_password(password=password, - user=self.instance) - except exceptions.ValidationError as err: - raise serializers.ValidationError({'password': list(err.messages)}) - return data - - class Meta: - model = models.UserAccount - fields = ('pk', 'username', 'role', 'is_admin', 'password', 'exercise_groups') - read_only_fields = ('pk', 'username', 'role', 'is_admin', 'exercise_groups') - extra_kwargs = {'password': {'write_only': True}} - - -class CommentDictionarySerializer(serializers.ListSerializer): - - def to_internal_value(self, comment_dict): - """ Converts a line_no -> comment list dictionary back to a list - of comments. Currently we do not have any information about the - feedback since it is not available in this scope. Feedback is - responsible to add it later on update/creation """ - if html.is_html_input(comment_dict): - comment_dict = html.parse_html_list(comment_dict) - - if not isinstance(comment_dict, dict): - raise serializers.ValidationError( - 'Comments have to be provided as a dict' - 'with: line -> list of comments' - ) - - ret = [] - errors = [] - - for line, comment in comment_dict.items(): - try: - comment['of_line'] = line - validated = self.child.run_validation(comment) - except serializers.ValidationError as err: - errors.append(err.detail) - else: - ret.append(validated) - errors.append({}) - - if any(errors): - raise serializers.ValidationError(errors) - - return ret - - def to_representation(self, comments): - """ Provides a dict where all the keys correspond to lines and contain - a list of comments on that line. """ - if isinstance(comments, Manager): - comments = comments.all() - - ret = defaultdict(list) - for comment in comments: - ret[comment.of_line].append(self.child.to_representation(comment)) - return ret diff --git a/grady/core/serializers/feedback.py b/grady/core/serializers/feedback.py deleted file mode 100644 index d67db180658730793553c0755a5d0c2bb28c12b2..0000000000000000000000000000000000000000 --- a/grady/core/serializers/feedback.py +++ /dev/null @@ -1,252 +0,0 @@ -import logging - -import constance -from django.db import transaction -from rest_framework import serializers - -from core import models -from core.models import Feedback, UserAccount -from core.serializers import CommentDictionarySerializer -from util.factories import GradyUserFactory - -from .generic import DynamicFieldsModelSerializer - -config = constance.config -log = logging.getLogger(__name__) -user_factory = GradyUserFactory() - - -class FeedbackCommentSerializer(DynamicFieldsModelSerializer): - of_tutor = serializers.StringRelatedField(source='of_tutor.username') - labels = serializers.PrimaryKeyRelatedField(many=True, required=False, - queryset=models.FeedbackLabel.objects.all()) - - class Meta: - model = models.FeedbackComment - fields = ('pk', - 'text', - 'created', - 'modified', - 'of_tutor', - 'of_line', - 'labels', - 'visible_to_student') - # visible_to_student is kept in sync with modified, such that the latest modified - # comment is the one that is visible - read_only_fields = ('created', 'of_tutor', 'visible_to_student') - extra_kwargs = { - 'of_feedback': {'write_only': True}, - 'of_line': {'write_only': True}, - } - list_serializer_class = CommentDictionarySerializer - - -class FeedbackSerializer(DynamicFieldsModelSerializer): - feedback_lines = FeedbackCommentSerializer(many=True, required=False) - of_submission_type = serializers.ReadOnlyField( - source='of_submission.type.pk') - feedback_stage_for_user = serializers.SerializerMethodField() - labels = serializers.PrimaryKeyRelatedField(many=True, required=False, - queryset=models.FeedbackLabel.objects.all()) - - def get_feedback_stage_for_user(self, obj): - """ Search for the assignment of this feedback and report in which - stage the tutor has worked on it. - - TODO Note: This method is unorthodox since it mingles the rather dump - feedback object with assignment logic. The reverse lookups in the - method are not pre-fetched. Remove if possible. """ - if 'request' not in self.context: - return - - # This is only required for tutors - user = self.context['request'].user - if user.role == models.UserAccount.REVIEWER: - return None - - assignments = obj.of_submission.assignments.filter(owner=user) - - if assignments.count() == 0: - return None - - return assignments[0].stage - - @transaction.atomic - def create(self, validated_data) -> Feedback: - submission = validated_data.pop('of_submission') - feedback_lines = validated_data.pop('feedback_lines', []) - labels = validated_data.pop('labels', []) - user = self.context['request'].user - if config.SINGLE_CORRECTION: - is_final = True - validated_data.pop('is_final') - else: - is_final = validated_data.pop('is_final', False) - final_by_reviewer = is_final and \ - user.role == UserAccount.REVIEWER - feedback = Feedback.objects.create(of_submission=submission, - is_final=is_final, - final_by_reviewer=final_by_reviewer, - **validated_data) - for label in labels: - feedback.labels.add(label) - - submission.meta.feedback_authors.add(self.context['request'].user) - - for comment in feedback_lines: - labels = comment.pop('labels', []) - comment_instance = models.FeedbackComment.objects.create( - of_feedback=feedback, - of_tutor=self.context['request'].user, - **comment - ) - comment_instance.labels.set(labels) - - return feedback - - @transaction.atomic - def update(self, feedback, validated_data): - user = self.context['request'].user - - if user.role == UserAccount.REVIEWER: - feedback.final_by_reviewer = self.context['request'].data['is_final'] - - for comment in validated_data.pop('feedback_lines', []): - labels = comment.pop('labels', None) - comment_instance, _ = models.FeedbackComment.objects.update_or_create( - of_feedback=feedback, - of_tutor=self.context['request'].user, - of_line=comment.get('of_line'), - defaults={'text': comment.get('text')}) - - if labels is not None: - comment_instance.labels.set(labels) - - # Set all feedback final for when single correction is active - if config.SINGLE_CORRECTION: - feedback.is_final = True - validated_data['is_final'] = True - - return super().update(feedback, validated_data) - - def validate_of_submission(self, submission): - feedback = self.instance - if feedback is not None and feedback.of_submission.pk != submission.pk: - raise serializers.ValidationError( - 'It is not allowed to update this field.') - - return submission - - def validate_is_final(self, is_final): - feedback = self.instance - if feedback is None: - return is_final - - user = self.context['request'].user - meta = feedback.of_submission.meta - user_in_authors = meta.feedback_authors.filter(user_id=user.user_id).exists() - allowed_assignment_count = 3 if user_in_authors else 2 - if meta.done_assignments >= allowed_assignment_count and not is_final: - raise serializers.ValidationError( - 'Conflict resolutions must be final' - ) - - return is_final - - def validate(self, data): - if self.instance: - score = data.get('score', self.instance.score) - submission = data.get('of_submission', self.instance.of_submission) - else: - try: - score = data.get('score') - submission = data.get('of_submission') - except KeyError: - raise serializers.ValidationError( - 'You need a score and a submission.') - - if not 0 <= score <= submission.type.full_score: - raise serializers.ValidationError( - f'Score has to be in range [0..{submission.type.full_score}].') - - if score.as_integer_ratio()[1] not in Feedback.ALLOWED_DENOMINATORS: - raise serializers.ValidationError( - f'For fractional scores, the denominator must be one of ' - f'{Feedback.ALLOWED_DENOMINATORS}' - ) - - has_full_score = score == submission.type.full_score - has_feedback_lines = ('feedback_lines' in data and - len(data['feedback_lines']) > 0 or - self.instance is not None and - self.instance.feedback_lines.count() > 0) - - has_label_attached = ('labels' in data and len(data['labels']) > 0 or - self.instance is not None and - self.instance.labels.count() > 0) - - labels_get_deleted = 'labels' in data and len(data['labels']) == 0 - - # a non-full scored feedback is considered valid if there is - # at least one comment line or a label attached to the feedback - if not (has_full_score or has_feedback_lines or - (has_label_attached and not labels_get_deleted)): - raise serializers.ValidationError( - 'Sorry, you have to explain why this does not get full score') - - if hasattr(submission, 'feedback') and not self.instance: - raise serializers.ValidationError( - 'Feedback for this submission already exists') - - for comment in data.get('feedback_lines', {}): - lines_in_submission = len(submission.text.split('\n')) - - if comment['text'] == '' and 'labels' not in comment: - raise serializers.ValidationError( - "Cannot create feedback with an empty comment attached to it" - ) - if not 0 < comment['of_line'] <= lines_in_submission: - raise serializers.ValidationError( - "Cannot comment line number %d of %d" % ( - comment['of_line'], lines_in_submission)) - - return data - - class Meta: - model = Feedback - fields = ('pk', 'of_submission', 'is_final', 'score', 'feedback_lines', - 'created', 'modified', 'of_submission_type', 'feedback_stage_for_user', 'labels') - - -class FeedbackWithStudentSerializer(FeedbackSerializer): - of_student = serializers.ReadOnlyField(source='of_submission.student.user.fullname') - - class Meta: - model = Feedback - fields = ('pk', 'of_submission', 'is_final', 'score', 'feedback_lines', 'of_student', - 'created', 'modified', 'of_submission_type', 'feedback_stage_for_user', 'labels') - - -class VisibleCommentFeedbackSerializer(FeedbackSerializer): - feedback_lines = serializers.SerializerMethodField() - of_submission_type = serializers.ReadOnlyField( - source='of_submission.type.pk') - - def get_feedback_lines(self, feedback): - comments = feedback.feedback_lines.filter(visible_to_student=True) - serializer = FeedbackCommentSerializer( - comments, - many=True, - fields=('pk', 'text', 'created', 'modified', 'of_line', 'labels') - ) - # this is a weird hack because, for some reason, serializer.data - # just won't contain the correct data. Instead .data returns a list - # containing just the `of_line` attr of the serialized comments - # after long debugging i found that for inexplicable reasons - # `data.serializer._data` contains the correct data. No clue why. - return serializer.data.serializer._data - - class Meta: - model = Feedback - fields = ('pk', 'of_submission', 'is_final', 'score', 'feedback_lines', - 'created', 'of_submission_type', 'labels') diff --git a/grady/core/serializers/generic.py b/grady/core/serializers/generic.py deleted file mode 100644 index 944c7a301c62c772bf1f6d42e96a118d2f21302b..0000000000000000000000000000000000000000 --- a/grady/core/serializers/generic.py +++ /dev/null @@ -1,18 +0,0 @@ -from rest_framework import serializers - - -class DynamicFieldsModelSerializer(serializers.ModelSerializer): - - def __init__(self, *args, **kwargs): - # Don't pass the 'fields' arg up to the superclass - fields = kwargs.pop('fields', None) - - # Instantiate the superclass normally - super(DynamicFieldsModelSerializer, self).__init__(*args, **kwargs) - - if fields is not None: - # Drop any fields that are not specified in the `fields` argument. - allowed = set(fields) - existing = set(self.fields) - for field_name in existing - allowed: - self.fields.pop(field_name) diff --git a/grady/core/serializers/label.py b/grady/core/serializers/label.py deleted file mode 100644 index 9aad4762e61e86f641e3a7eac3cdbc0ab94b1e39..0000000000000000000000000000000000000000 --- a/grady/core/serializers/label.py +++ /dev/null @@ -1,14 +0,0 @@ -from rest_framework import serializers - -from core.models import FeedbackLabel - - -class LabelSerializer(serializers.ModelSerializer): - class Meta: - model = FeedbackLabel - fields = ( - 'pk', - 'name', - 'description', - 'colour' - ) diff --git a/grady/core/serializers/student.py b/grady/core/serializers/student.py deleted file mode 100644 index 54a234a4afa8beebfbe605f355c3bf8fd9c05e56..0000000000000000000000000000000000000000 --- a/grady/core/serializers/student.py +++ /dev/null @@ -1,81 +0,0 @@ -from rest_framework import serializers - -from core.models import StudentInfo, ExamInfo -from core.serializers import DynamicFieldsModelSerializer, ExamSerializer -from core.serializers.submission import (SubmissionListSerializer, - SubmissionNoTextFieldsSerializer, - SubmissionNoTypeSerializer) - - -class ExamInfoListSerializer(DynamicFieldsModelSerializer): - - class Meta: - model = ExamInfo - fields = ('exam', 'student', 'total_score', 'passes_exam') - - -class StudentInfoSerializer(DynamicFieldsModelSerializer): - name = serializers.ReadOnlyField(source='user.fullname') - matrikel_no = serializers.ReadOnlyField(source='user.matrikel_no') - exams = ExamInfoListSerializer(many=True) - submissions = SubmissionListSerializer(many=True) - - class Meta: - model = StudentInfo - fields = ('pk', - 'name', - 'user', - 'matrikel_no', - 'submissions', - 'exams') - - -class StudentInfoForListViewSerializer(DynamicFieldsModelSerializer): - name = serializers.ReadOnlyField(source='user.fullname') - user = serializers.ReadOnlyField(source='user.username') - user_pk = serializers.ReadOnlyField(source='user.pk') - exams = serializers.ReadOnlyField(source='exams.module_reference') - submissions = SubmissionNoTextFieldsSerializer(many=True) - is_active = serializers.BooleanField(source='user.is_active') - - class Meta: - model = StudentInfo - fields = ('pk', - 'name', - 'user', - 'user_pk', - 'exams', - 'submissions', - 'matrikel_no', - 'is_active') - - -class StudentExportSerializer(DynamicFieldsModelSerializer): - name = serializers.ReadOnlyField(source='user.fullname') - user = serializers.ReadOnlyField(source='user.username') - user_pk = serializers.ReadOnlyField(source='user.pk') - exams = ExamInfoListSerializer(many=True) - email = serializers.ReadOnlyField(source='user.email') - is_active = serializers.BooleanField(source='user.is_active') - submissions = SubmissionNoTypeSerializer(many=True) - - class Meta: - model = StudentInfo - fields = ('pk', - 'name', - 'user', - 'user_pk', - 'exams', - 'email', - 'submissions', - 'matrikel_no', - 'is_active') - - -class ExamInfoSerializer(DynamicFieldsModelSerializer): - exam = ExamSerializer() - student = StudentInfoSerializer() - - class Meta: - model = ExamInfo - fields = ('exam', 'student', 'total_score', 'passes_exam') diff --git a/grady/core/serializers/submission.py b/grady/core/serializers/submission.py deleted file mode 100644 index b7b789d2c77e0de52d205f5a11ceba38ca9b4b2f..0000000000000000000000000000000000000000 --- a/grady/core/serializers/submission.py +++ /dev/null @@ -1,69 +0,0 @@ -from rest_framework import serializers - -from core.models import Submission -from core.serializers import (DynamicFieldsModelSerializer, FeedbackSerializer, - SubmissionTypeListSerializer, - SubmissionTypeSerializer, TestSerializer, - VisibleCommentFeedbackSerializer) - - -class SubmissionNoTextFieldsSerializer(DynamicFieldsModelSerializer): - score = serializers.ReadOnlyField(source='feedback.score') - final = serializers.ReadOnlyField(source='feedback.is_final') - full_score = serializers.ReadOnlyField(source='type.full_score') - - class Meta: - model = Submission - fields = ('pk', 'type', 'score', 'final', 'full_score') - - -class StudentSubmissionSerializer(DynamicFieldsModelSerializer): - type = SubmissionTypeSerializer( - # exclude solution from Type information - fields=(('pk', - 'name', - 'full_score', - 'description', - 'programming_language'))) - feedback = VisibleCommentFeedbackSerializer() - tests = TestSerializer(many=True) - - class Meta: - model = Submission - fields = ('pk', 'type', 'text', 'feedback', 'tests', 'source_code_available') - - -class StudentSubmissionWithSolutionSerializer(StudentSubmissionSerializer): - type = SubmissionTypeSerializer() - - class Meta: - model = Submission - fields = ('pk', 'type', 'text', 'feedback', 'tests', 'source_code_available') - - -class SubmissionNoTypeSerializer(DynamicFieldsModelSerializer): - feedback = FeedbackSerializer() - full_score = serializers.ReadOnlyField(source='type.full_score') - tests = TestSerializer(many=True) - - class Meta: - model = Submission - fields = ('pk', 'type', 'full_score', 'text', 'feedback', 'tests', 'source_code_available') - - -class SubmissionNoTypeWithStudentSerializer(SubmissionNoTypeSerializer): - of_student = serializers.ReadOnlyField(source='student.user.fullname') - - class Meta: - model = Submission - fields = ('pk', 'type', 'full_score', 'text', 'feedback', - 'tests', 'of_student', 'source_code_available') - - -class SubmissionListSerializer(DynamicFieldsModelSerializer): - type = SubmissionTypeListSerializer(fields=('pk', 'name', 'full_score')) - feedback = FeedbackSerializer() - - class Meta: - model = Submission - fields = ('pk', 'type', 'feedback') diff --git a/grady/core/serializers/submission_type.py b/grady/core/serializers/submission_type.py deleted file mode 100644 index d60e44fbb0a31cb35373f2a7ac77ba40aac90e9c..0000000000000000000000000000000000000000 --- a/grady/core/serializers/submission_type.py +++ /dev/null @@ -1,68 +0,0 @@ -import logging - -from rest_framework import serializers -from rest_framework.exceptions import ValidationError - -from core import models -from core.serializers import (DynamicFieldsModelSerializer, CommentDictionarySerializer, - ExamSerializer) - -log = logging.getLogger(__name__) - - -class SolutionCommentSerializer(DynamicFieldsModelSerializer): - of_user = serializers.StringRelatedField(source='of_user.username') - - def validate(self, attrs): - super().validate(attrs) - submission_type = attrs.get('of_submission_type') - of_line = attrs.get('of_line') - if self.instance: - submission_type = self.instance.of_submission_type - of_line = self.instance.of_line - - max_line_number = len(submission_type.solution.split('\n')) - - if not (0 < of_line <= max_line_number): - raise ValidationError('Invalid line number for comment') - return attrs - - def create(self, validated_data): - validated_data['of_user'] = self.context['request'].user - return super().create(validated_data) - - class Meta: - model = models.SolutionComment - fields = ( - 'pk', - 'text', - 'created', - 'of_user', - 'of_line', - 'of_submission_type' - ) - read_only_fields = ('pk', 'created', 'of_user') - list_serializer_class = CommentDictionarySerializer - - -class SubmissionTypeListSerializer(DynamicFieldsModelSerializer): - - class Meta: - model = models.SubmissionType - fields = ('pk', 'name', 'full_score') - - -class SubmissionTypeSerializer(DynamicFieldsModelSerializer): - solution_comments = SolutionCommentSerializer(many=True, required=False) - exam_type = ExamSerializer() - - class Meta: - model = models.SubmissionType - fields = ('pk', - 'name', - 'exam_type', - 'full_score', - 'description', - 'solution', - 'programming_language', - 'solution_comments') diff --git a/grady/core/serializers/tutor.py b/grady/core/serializers/tutor.py deleted file mode 100644 index b2eff1e8829433b1806e14b00cbece143231f5e4..0000000000000000000000000000000000000000 --- a/grady/core/serializers/tutor.py +++ /dev/null @@ -1,63 +0,0 @@ -import logging - -import django.contrib.auth.password_validation as validators -from django.core import exceptions -from rest_framework import serializers - -from core import models -from util.factories import GradyUserFactory - -from .generic import DynamicFieldsModelSerializer - -log = logging.getLogger(__name__) -user_factory = GradyUserFactory() - - -class CorrectorSerializer(DynamicFieldsModelSerializer): - feedback_created = serializers.SerializerMethodField() - feedback_validated = serializers.SerializerMethodField() - password = serializers.CharField( - style={'input_type': 'password'}, - write_only=True, - required=False - ) - role = serializers.CharField(read_only=True) - - def get_feedback_created(self, t): - ''' It is required that this field was previously annotated ''' - return t.feedback_created if hasattr(t, 'feedback_created') else 0 - - def get_feedback_validated(self, t): - ''' It is required that this field was previously annotated ''' - return t.feedback_validated if hasattr(t, 'feedback_validated') else 0 - - def create(self, validated_data) -> models.UserAccount: - log_validated_data = dict(validated_data) - log_validated_data['password'] = '******' - log.info("Crating tutor from data %s", log_validated_data) - return user_factory.make_tutor( - username=validated_data['username'], - password=validated_data.get('password'), - is_active=validated_data.get('is_active', False)) - - def validate(self, data): - user = models.UserAccount(**data) - password = data.get('password') - - try: - if password is not None: - validators.validate_password(password=password, user=user) - except exceptions.ValidationError as err: - raise serializers.ValidationError({'password': list(err.messages)}) - return data - - class Meta: - model = models.UserAccount - fields = ('pk', - 'password', - 'is_active', - 'username', - 'feedback_created', - 'feedback_validated', - 'exercise_groups', - 'role') diff --git a/grady/core/signals.py b/grady/core/signals.py deleted file mode 100644 index b857cb0b491b69ae9576cdd9799cd167918c8d1d..0000000000000000000000000000000000000000 --- a/grady/core/signals.py +++ /dev/null @@ -1,73 +0,0 @@ -import logging - -from django.db.models.signals import post_save, pre_delete, pre_save -from django.dispatch import receiver - -from core import models -from core.models import (Feedback, FeedbackComment, MetaSubmission, Submission, - TutorSubmissionAssignment) - -log = logging.getLogger(__name__) - - -@receiver(post_save, sender=Submission) -def create_meta_after_submission_create(sender, instance, created, **kwargs): - log.debug('SIGNAL -- create_meta_after_submission_create') - if created: - MetaSubmission.objects.create(submission=instance) - - -@receiver(post_save, sender=TutorSubmissionAssignment) -def update_active_after_assignment_save(sender, instance, created, **kwargs): - """ Assignments are created undone therefore save that no other - should use it. If it is already set to done it is not active. - """ - log.debug('SIGNAL -- update_active_after_assignment_save') - meta = instance.submission.meta - meta.has_active_assignment = created and not instance.is_done - meta.save() - - -@receiver(pre_delete, sender=TutorSubmissionAssignment) -def remove_active_assignment_on_delete(sender, instance, **kwargs): - log.debug('SIGNAL -- remove_active_assignment_on_delete') - if instance.is_done: - raise models.DeletionOfDoneAssignmentsNotPermitted() - meta = instance.submission.meta - meta.has_active_assignment = False - meta.save() - - -@receiver(post_save, sender=Feedback) -def update_after_feedback_save(sender, instance, created, **kwargs): - """ Do the following steps when feedback is saved: - - - set that feedback exists - - copy the final status of the feedback - - set all assignments of the submission done and remove active status - """ - log.debug('SIGNAL -- update_after_feedback_save') - meta = instance.of_submission.meta - meta.has_feedback = True - meta.has_final_feedback = instance.is_final or instance.final_by_reviewer - meta.save() - - -@receiver(post_save, sender=Feedback) -def update_student_score(sender, instance, **kwargs): - student = instance.of_submission.student - - for exam_info in student.exams.all(): - exam_info.update_total_score() - log.debug('SIGNAL -- Scores of student %s were updated)', student) - - -@receiver(pre_save, sender=FeedbackComment) -def set_comment_visibility_after_conflict(sender, instance, **kwargs): - log.debug('SIGNAL -- set_comment_visibility_after_conflict') - comments_on_the_same_line = FeedbackComment.objects.filter( - of_line=instance.of_line, - of_feedback=instance.of_feedback, - ) - comments_on_the_same_line.update(visible_to_student=False) - instance.visible_to_student = True diff --git a/grady/core/templates/index.html b/grady/core/templates/index.html deleted file mode 100644 index c94bda457fa57278eee5cf88c0c9c6c9482bbc37..0000000000000000000000000000000000000000 --- a/grady/core/templates/index.html +++ /dev/null @@ -1,18 +0,0 @@ -{% load static %} -<!DOCTYPE html><html><head><meta charset=utf-8><meta http-equiv=X-UA-Compatible content="IE=edge"><meta name=viewport content="width=device-width,initial-scale=1"><title>Grady</title><script>MathJax = { - loader: {load: ['input/asciimath', 'output/chtml', 'input/tex']}, - asciimath: { - delimiters: [['$', '$']] - }, - options: { - skipHtmlTags: [// HTML tags that won't be searched for math - 'script', 'noscript', 'style', 'textarea', 'pre', - 'code', 'annotation', 'annotation-xml' - ], - includeHtmlTags: { // HTML tags that can appear within math - br: '\n', wbr: '', '#comment': '' - }, - ignoreHtmlClass: 'tex2jax_ignore', // class that marks tags not to search - processHtmlClass: 'latex', // class that marks tags that should be searched - } - };</script><script id=MathJax-script async src=https://grady.informatik.uni-goettingen.de/static/mathjax/es5/startup.js></script><link href={% static 'css/app.456a8c3b.css' %} rel=preload as=style><link href={% static 'css/chunk-vendors.7792972f.css' %} rel=preload as=style><link href={% static 'js/app.fa6788ea.js' %} rel=preload as=script><link href={% static 'js/chunk-vendors.a2099867.js' %} rel=preload as=script><link href={% static 'css/chunk-vendors.7792972f.css' %} rel=stylesheet><link href={% static 'css/app.456a8c3b.css' %} rel=stylesheet></head><body class=tex2jax_ignore><noscript><strong>We're sorry but frontend doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id=app></div><script src={% static 'js/chunk-vendors.a2099867.js' %}></script><script src={% static 'js/app.fa6788ea.js' %}></script></body></html> \ No newline at end of file diff --git a/grady/core/tests/__init__.py b/grady/core/tests/__init__.py deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/grady/core/tests/test_access_rights.py b/grady/core/tests/test_access_rights.py deleted file mode 100644 index 4fbe8575379b8935e12a59cd2bfb000368a04b23..0000000000000000000000000000000000000000 --- a/grady/core/tests/test_access_rights.py +++ /dev/null @@ -1,163 +0,0 @@ -from django.urls import reverse -from rest_framework import status -from rest_framework.test import (APIRequestFactory, APITestCase, - force_authenticate) - -from core.views import (ExamApiViewSet, StudentReviewerApiViewSet, - StudentSelfApiView, CorrectorApiViewSet) -from util.factories import GradyUserFactory, make_exams - - -class AccessRightsOfStudentAPIViewTests(APITestCase): - """ All tests that ensure that only students can see what students - should see belong here """ - - @classmethod - def setUpTestData(cls): - cls.factory = APIRequestFactory() - cls.user_factory = GradyUserFactory() - - def setUp(self): - self.exam = make_exams(exams=[{ - 'module_reference': 'Test Exam 01', - 'total_score': 100, - 'pass_score': 60, - }])[0] - self.student = self.user_factory.make_student(exam=self.exam) - self.tutor = self.user_factory.make_tutor(exam=self.exam) - self.reviewer = self.user_factory.make_reviewer(exam=self.exam) - self.request = self.factory.get(reverse('student-page')) - self.view = StudentSelfApiView.as_view() - - def test_unauthenticated_access_denied(self): - response = self.view(self.request) - self.assertEqual(status.HTTP_401_UNAUTHORIZED, response.status_code) - - def test_tutor_has_no_access(self): - force_authenticate(self.request, user=self.tutor) - response = self.view(self.request) - self.assertEqual(status.HTTP_403_FORBIDDEN, response.status_code) - - def test_reviewer_has_no_access(self): - force_authenticate(self.request, user=self.reviewer) - response = self.view(self.request) - self.assertEqual(status.HTTP_403_FORBIDDEN, response.status_code) - - def test_student_is_authorized(self): - force_authenticate(self.request, user=self.student) - response = self.view(self.request) - self.assertEqual(status.HTTP_200_OK, response.status_code) - - -class AccessRightsOfTutorAPIViewTests(APITestCase): - """ Tests to ensure that only Reviewers have access to the TutorList - information """ - @classmethod - def setUpTestData(cls): - cls.factory = APIRequestFactory() - cls.user_factory = GradyUserFactory() - - def setUp(self): - self.exam = make_exams(exams=[{ - 'module_reference': 'Test Exam 01', - 'total_score': 100, - 'pass_score': 60, - }])[0] - self.student = self.user_factory.make_student(exam=self.exam) - self.tutor = self.user_factory.make_tutor(exam=self.exam) - self.reviewer = self.user_factory.make_reviewer(exam=self.exam) - self.request = self.factory.get(reverse('corrector-list')) - self.view = CorrectorApiViewSet.as_view({'get': 'list'}) - - def test_unauthenticated_access_denied(self): - response = self.view(self.request) - self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED) - - def test_student_has_no_access(self): - force_authenticate(self.request, user=self.student) - response = self.view(self.request) - self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) - - def test_tutor_has_no_access(self): - force_authenticate(self.request, user=self.tutor) - response = self.view(self.request) - self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) - - def test_reviewer_has_access(self): - force_authenticate(self.request, user=self.reviewer) - response = self.view(self.request) - self.assertEqual(response.status_code, status.HTTP_200_OK) - - -class AccessRightsOfStudentReviewerAPIViewTest(APITestCase): - """ Tests to ensure that only Reviewers have access to the - StudentReviewerApi endpoint information""" - - @classmethod - def setUpTestData(cls): - cls.factory = APIRequestFactory() - cls.user_factory = GradyUserFactory() - - def setUp(self): - self.exam = make_exams(exams=[{ - 'module_reference': 'Test Exam 01', - 'total_score': 100, - 'pass_score': 60, - }])[0] - self.student = self.user_factory.make_student(exam=self.exam) - self.tutor = self.user_factory.make_tutor(exam=self.exam) - self.reviewer = self.user_factory.make_reviewer(exam=self.exam) - self.request = self.factory.get(reverse('student-list')) - self.view = StudentReviewerApiViewSet.as_view({'get': 'list'}) - - def test_unauthenticated_access_denied(self): - response = self.view(self.request) - self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED) - - def test_student_has_no_access(self): - force_authenticate(self.request, user=self.student) - response = self.view(self.request) - self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) - - def test_reviewer_has_access(self): - force_authenticate(self.request, user=self.reviewer) - response = self.view(self.request) - self.assertEqual(response.status_code, status.HTTP_200_OK) - - -class AccessRightsOfExamTypeAPIViewTest(APITestCase): - """ In older versions students had no access rights, but since multiple exams can now be - imported and the examselection page is necessary, everyone needs access.""" - - @classmethod - def setUpTestData(cls): - cls.factory = APIRequestFactory() - cls.user_factory = GradyUserFactory() - - def setUp(self): - self.exam = make_exams(exams=[{ - 'module_reference': 'Test Exam 01', - 'total_score': 100, - 'pass_score': 60, - }])[0] - self.student = self.user_factory.make_student(exam=self.exam) - self.tutor = self.user_factory.make_tutor(exam=self.exam) - self.reviewer = self.user_factory.make_reviewer(exam=self.exam) - self.request = self.factory.get(reverse('examtype-list')) - self.view = ExamApiViewSet.as_view({'get': 'list'}) - - def test_student_has_access(self): - force_authenticate(self.request, user=self.student) - response = self.view(self.request) - self.assertEqual(response.status_code, status.HTTP_200_OK) - - # TODO see issue #90 for details - # def test_tutor_has_no_access(self): - # force_authenticate(self.request, user=self.tutor) - # response = self.view(self.request) - # self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) - - def test_reviewer_has_access(self): - force_authenticate(self.request, user=self.reviewer) - response = self.view(self.request) - self.assertEqual(response.status_code, status.HTTP_200_OK) diff --git a/grady/core/tests/test_assignment_views.py b/grady/core/tests/test_assignment_views.py deleted file mode 100644 index a205d97cca75e59c4aa39d40b35cbf83b1bf4e4b..0000000000000000000000000000000000000000 --- a/grady/core/tests/test_assignment_views.py +++ /dev/null @@ -1,317 +0,0 @@ -from rest_framework import status -from rest_framework.test import APIClient, APITestCase - -from core import models -from core.models import (TutorSubmissionAssignment) -from util.factories import make_test_data, make_exams - - -class TestApiEndpoints(APITestCase): - - @classmethod - def setUpTestData(cls): - exams = make_exams([{ - 'module_reference': 'Test Exam 01', - 'total_score': 100, - 'pass_score': 60, - }] - ) - cls.data = make_test_data(data_dict={ - 'exams': [{ - 'module_reference': 'Test Exam 01', - 'total_score': 100, - 'pass_score': 60, - 'exam_type_id': exams[0].exam_type_id - }], - 'submission_types': [ - { - 'name': '01. Sort this or that', - 'full_score': 35, - 'description': 'Very complicated', - 'solution': 'Trivial!', - 'exam_type': exams[0] - }, - { - 'name': '02. Merge this or that or maybe even this', - 'full_score': 35, - 'description': 'Very complicated', - 'solution': 'Trivial!', - 'exam_type': exams[0] - } - ], - 'students': [ - { - 'username': 'student01', - 'password': 'p', - 'exam': 'Test Exam 01' - }, - { - 'username': 'student02', - 'password': 'p', - 'exam': 'Test Exam 01' - } - ], - 'tutors': [ - {'username': 'tutor01', 'password': 'p'}, - {'username': 'tutor02', 'password': 'p'} - ], - 'reviewers': [ - {'username': 'reviewer', 'password': 'p'} - ], - 'submissions': [ - { - 'text': 'function blabl\n' - ' on multi lines\n' - ' for blabla in bla:\n' - ' lorem ipsum und so\n', - 'type': '01. Sort this or that', - 'user': 'student01', - 'feedback': { - 'score': 5, - 'is_final': True, - 'feedback_lines': { - '1': [{ - 'text': 'This is very bad!', - 'of_tutor': 'tutor01' - }], - } - - } - }, - { - 'text': 'function blabl\n' - ' asasxasx\n' - ' lorem ipsum und so\n', - 'type': '02. Merge this or that or maybe even this', - 'user': 'student01' - }, - { - 'text': 'function blabl\n' - ' on multi lines\n' - ' asasxasx\n' - ' lorem ipsum und so\n', - 'type': '01. Sort this or that', - 'user': 'student02' - }, - { - 'text': 'function lorem ipsum etc\n', - 'type': '02. Merge this or that or maybe even this', - 'user': 'student02' - }, - ]} - ) - - def setUp(self): - self.client = APIClient() - - def test_tutor_gets_an_assignment(self): - self.client.force_authenticate(user=self.data['tutors'][0]) - - response = self.client.post('/api/assignment/', { - "submission_type": self.data['submission_types'][0].pk, - "stage": "feedback-creation", - }) - self.assertEqual(status.HTTP_201_CREATED, response.status_code) - - # we should simply test if any newly created assignment is unfinished - def test_first_work_assignment_was_created_unfinished(self): - self.client.force_authenticate(user=self.data['tutors'][0]) - - self.client.post('/api/assignment/', { - "submission_type": self.data['submission_types'][0].pk, - "stage": "feedback-creation", - }) - self.assertFalse(TutorSubmissionAssignment.objects.first().is_done) - - def test_assignment_raises_error_when_depleted(self): - self.data['submissions'][0].delete() - self.data['submissions'][2].delete() - - self.client.force_authenticate(user=self.data['tutors'][0]) - - response = self.client.post('/api/assignment/', { - "submission_type": self.data['submission_types'][0].pk, - "stage": "feedback-creation", - }) - self.assertEqual(status.HTTP_404_NOT_FOUND, response.status_code) - - def test_assignment_delete_of_done_not_permitted(self): - self.client.force_authenticate(user=self.data['tutors'][0]) - - self.client.post('/api/assignment/', { - "submission_type": self.data['submission_types'][0].pk, - "stage": "feedback-creation", - }) - first = TutorSubmissionAssignment.objects.first() - first.is_done = True - first.save() - - self.assertRaises(models.DeletionOfDoneAssignmentsNotPermitted, - first.delete) - - def test_assignment_delete_undone_permitted(self): - self.client.force_authenticate(user=self.data['tutors'][0]) - - self.client.post('/api/assignment/', { - "submission_type": self.data['submission_types'][0].pk, - "stage": "feedback-creation", - }) - first = TutorSubmissionAssignment.objects.first() - first.delete() - - self.assertEqual(0, TutorSubmissionAssignment.objects.all().count()) - - def tutor_can_release_own_unfinished_assignments(self): - self.client.force_authenticate(user=self.data['tutors'][0]) - - response = self.client.post('/api/assignment/', { - "submission_type": self.data['submission_types'][0].pk, - "stage": "feedback-creation", - }) - self.assertEqual(status.HTTP_201_CREATED, response.status_code) - - response = self.client.post('/api/assignment/', { - "submission_type": self.data['submission_types'][0].pk, - "stage": "feedback-creation", - }) - self.assertEqual(status.HTTP_201_CREATED, response.status_code) - self.client.post( - f'/api/assignment/{response.data["pk"]}/finish/', { - "score": 23, - "of_submission": response.data['submission']['pk'], - "feedback_lines": { - 1: {"text": "< some string >", "labels": []}, - 2: {"text": "< some string >", "labels": []} - }, - "labels": [], - } - ) - self.assertEqual(2, TutorSubmissionAssignment.objects.all().count()) - self.assertEqual(1, TutorSubmissionAssignment.objects.filter(is_done=True).count()) - - self.client.force_authenticate(user=self.data['tutors'][1]) - - response = self.client.post('/api/assignment/', { - "submission_type": self.data['submission_types'][0].pk, - "stage": "feedback-creation", - }) - self.assertEqual(status.HTTP_201_CREATED, response.status_code) - - response = self.client.delete('/api/assignment/') - self.assertEqual(status.HTTP_204_NO_CONTENT, response.status_code) - self.assertEqual(2, TutorSubmissionAssignment.objects.all().count()) - - def test_two_tutors_cant_have_assignments_for_same_submission(self): - self.client.force_authenticate(user=self.data['tutors'][0]) - - assignment_fst_tutor = self.client.post('/api/assignment/', { - "submission_type": self.data['submission_types'][1].pk, - "stage": "feedback-creation", - }).data - - self.client.force_authenticate(user=self.data['tutors'][1]) - - assignment_snd_tutor = self.client.post('/api/assignment/', { - "submission_type": self.data['submission_types'][1].pk, - "stage": "feedback-creation", - }).data - - self.assertNotEqual(assignment_fst_tutor['submission']['pk'], - assignment_snd_tutor['submission']['pk']) - - def test_reviewer_can_get_active_assignments(self): - self.client.force_authenticate(user=self.data['tutors'][0]) - - assignment = self.client.post('/api/assignment/', { - "submission_type": self.data['submission_types'][0].pk, - "stage": "feedback-creation", - }).data - - # tutors shouldn't have access - res = self.client.get('/api/assignment/active/') - self.assertEqual(status.HTTP_403_FORBIDDEN, res.status_code) - - self.client.force_authenticate(user=self.data['reviewers'][0]) - - active_assignments = self.client.get('/api/assignment/active/').data - self.assertIn(assignment['pk'], [assignment['pk'] for assignment in active_assignments]) - - def test_reviewer_can_delete_active_assignments(self): - self.client.force_authenticate(user=self.data['tutors'][0]) - - assignment = self.client.post('/api/assignment/', { - "submission_type": self.data['submission_types'][0].pk, - "stage": "feedback-creation", - }).data - - # tutors shouldn't have access - res = self.client.delete('/api/assignment/active/') - self.assertEqual(status.HTTP_403_FORBIDDEN, res.status_code) - - self.client.force_authenticate(user=self.data['reviewers'][0]) - - res = self.client.delete('/api/assignment/active/') - self.assertEqual(status.HTTP_204_NO_CONTENT, res.status_code) - self.assertNotIn( - assignment['pk'], - [assignment.pk for assignment - in TutorSubmissionAssignment.objects.filter(is_done=False)] - ) - - def test_all_stages_of_the_subscription(self): - self.client.force_authenticate(user=self.data['tutors'][0]) - - response = self.client.post('/api/assignment/', { - "submission_type": self.data['submission_types'][0].pk, - "stage": "feedback-creation", - }) - self.assertEqual(status.HTTP_201_CREATED, response.status_code) - response = self.client.post( - f'/api/assignment/{response.data["pk"]}/finish/', { - "score": 23, - "of_submission": response.data['submission']['pk'], - "feedback_lines": { - 1: {"text": "< some string >", "labels": []}, - 2: {"text": "< some string >", "labels": []} - }, - "labels": [], - } - ) - self.assertEqual(status.HTTP_201_CREATED, response.status_code) - - # some other tutor reviews it - self.client.force_authenticate(user=self.data['tutors'][1]) - - response = self.client.post('/api/assignment/', { - "submission_type": self.data['submission_types'][0].pk, - "stage": "feedback-validation", - }) - - self.assertEqual(status.HTTP_201_CREATED, response.status_code) - submission_id_in_database = models.Feedback.objects.filter( - is_final=False).first().of_submission.submission_id - submission_id_in_response = response.data['submission']['pk'] - - self.assertEqual( - str(submission_id_in_database), - submission_id_in_response) - - assignment = models.TutorSubmissionAssignment.objects.get(pk=response.data['pk']) - self.assertFalse(assignment.is_done) - response = self.client.post( - f'/api/assignment/{assignment.pk}/finish/', { - "score": 20, - "is_final": True, - "feedback_lines": { - 2: {"text": "< some addition by second tutor>"}, - } - } - ) - - assignment.refresh_from_db() - meta = assignment.submission.meta - self.assertEqual(status.HTTP_200_OK, response.status_code) - self.assertEqual(2, len(response.data['feedback_lines'][2])) - self.assertTrue(assignment.is_done) - self.assertIn(self.data['tutors'][0], meta.feedback_authors.all()) - self.assertIn(self.data['tutors'][1], meta.feedback_authors.all()) diff --git a/grady/core/tests/test_auth.py b/grady/core/tests/test_auth.py deleted file mode 100644 index 38780f25f40c0c939e45ef74531f15c0706e8acd..0000000000000000000000000000000000000000 --- a/grady/core/tests/test_auth.py +++ /dev/null @@ -1,71 +0,0 @@ -import pytest -import os - -from rest_framework.test import APIClient, APITestCase -from constance.test import override_config -from core.models import UserAccount - - -class AuthTests(APITestCase): - - @classmethod - def setUpTestData(cls): - cls.credentials = {'username': 'user', 'password': 'p'} - cls.user = UserAccount.objects.create( - username=cls.credentials['username']) - cls.user.set_password(cls.credentials['password']) - cls.user.save() - cls.client = APIClient() - - def test_get_token(self): - response = self.client.post('/api/get-token/', self.credentials) - self.assertContains(response, 'token') - - def test_refresh_token(self): - token = self.client.post('/api/get-token/', self.credentials).data - response = self.client.post('/api/refresh-token/', token) - self.assertContains(response, 'token') - - @override_config(REGISTRATION_PASSWORD='pw') - def test_registration_correct_password(self): - credentials = { - 'username': 'john-doe', - 'password': 'safeandsound', - 'registration_password': 'pw', - } - response = self.client.post('/api/corrector/register/', credentials) - self.assertEqual(201, response.status_code) - - @override_config(REGISTRATION_PASSWORD='wrong_pw') - def test_registration_wrong_password(self): - credentials = { - 'username': 'john-doe', - 'password': 'safeandsound', - 'registration_password': 'pw', - } - response = self.client.post('/api/corrector/register/', credentials) - self.assertEqual(403, response.status_code) - - @pytest.mark.skipif(os.environ.get('DJANGO_DEV', False), - reason="No password strengths checks in dev") - @override_config(REGISTRATION_PASSWORD='pw') - def test_password_is_strong_enough(self): - response = self.client.post('/api/corrector/register/', { - 'username': 'hans', - 'password': 'weak', - 'registration_password': 'pw', - }) - - self.assertEqual(400, response.status_code) - self.assertIn('password', response.data) - - @override_config(REGISTRATION_PASSWORD='pw') - def test_cannot_register_active(self): - response = self.client.post('/api/corrector/register/', { - 'username': 'hans', - 'password': 'safeandsound', - 'registration_password': 'pw', - 'is_active': True - }) - - self.assertEqual(403, response.status_code) diff --git a/grady/core/tests/test_commands.py b/grady/core/tests/test_commands.py deleted file mode 100644 index e313c5a3c96d84f3d66a3b8feb2137cda48e9bb0..0000000000000000000000000000000000000000 --- a/grady/core/tests/test_commands.py +++ /dev/null @@ -1,39 +0,0 @@ -import json -import tempfile - -from django.contrib.auth import get_user_model -from django.core.management import call_command -from django.test import TestCase - -from util.factories import GradyUserFactory, make_exams - - -class CommandsTestCase(TestCase): - - factory = GradyUserFactory() - - def test_usermod(self): - self.factory.make_tutor(username='otto') - args = ['disable'] - opts = {'include': ('otto',)} - call_command('usermod', *args, **opts) - - someone = get_user_model().objects.get(username='otto') - self.assertFalse(someone.is_active) - - def test_replaceusernames(self): - self.exam = make_exams(exams=[{ - 'module_reference': 'Test Exam 01', - 'total_score': 100, - 'pass_score': 60, - }])[0] - self.factory.make_student(identifier=88884444, username='before', exam=self.exam) - - with tempfile.NamedTemporaryFile() as matno2username: - matno2username.write(json.dumps({'88884444': 'after'}).encode()) - matno2username.flush() - args = [matno2username.name] - call_command('replaceusernames', *args, **{}) - - student = get_user_model().objects.get(student__matrikel_no=88884444) - self.assertEqual('after', student.username) diff --git a/grady/core/tests/test_configuration_viewset.py b/grady/core/tests/test_configuration_viewset.py deleted file mode 100644 index 23cc354bac3e45ecd28740b6f755409cf9175581..0000000000000000000000000000000000000000 --- a/grady/core/tests/test_configuration_viewset.py +++ /dev/null @@ -1,58 +0,0 @@ -import constance - -from rest_framework import status -from rest_framework.test import APITestCase -from util.factories import GradyUserFactory, make_exams - -config = constance.config - - -class ConfigurationViewTestCase(APITestCase): - factory = GradyUserFactory() - - @classmethod - def setUpTestData(cls): - cls.exam = make_exams(exams=[{ - 'module_reference': 'Test Exam 01', - 'total_score': 100, - 'pass_score': 60, - }])[0] - cls.student = cls.factory.make_student(exam=cls.exam) - cls.reviewer = cls.factory.make_reviewer(exam=cls.exam) - - def setUp(self): - self.client.force_authenticate(user=self.reviewer) - self.rev_list_response = self.client.get('/api/config/') - - self.client.force_authenticate(user=self.student) - self.stud_list_response = self.client.get('/api/config/') - - stud_patch_data = { - "singleCorrection": True, - } - - rev_patch_data = { - "exerciseMode": True, - "showSolutionToStudents": False - } - - self.client.force_authenticate(user=self.reviewer) - self.rev_patch_response = self.client.patch('/api/config/change_config/', rev_patch_data) - - self.client.force_authenticate(user=self.student) - self.stud_patch_response = self.client.patch('/api/config/change_config/', stud_patch_data) - - def test_student_can_access(self): - self.assertEqual(status.HTTP_200_OK, self.stud_list_response.status_code) - - def test_reviewer_can_access(self): - self.assertEqual(status.HTTP_200_OK, self.rev_list_response.status_code) - - def test_student_can_not_patch_config(self): - self.assertEqual(status.HTTP_403_FORBIDDEN, self.stud_patch_response.status_code) - self.assertEqual(False, config.SINGLE_CORRECTION) - - def test_reviewers_can_patch_config(self): - self.assertEqual(status.HTTP_206_PARTIAL_CONTENT, self.rev_patch_response.status_code) - self.assertEqual(True, config.EXERCISE_MODE) - self.assertEqual(False, config.SHOW_SOLUTION_TO_STUDENTS) diff --git a/grady/core/tests/test_examlist.py b/grady/core/tests/test_examlist.py deleted file mode 100644 index b5be17ccb0f15831591d7f0619fc13973648b2d6..0000000000000000000000000000000000000000 --- a/grady/core/tests/test_examlist.py +++ /dev/null @@ -1,49 +0,0 @@ -""" Tests that we can receive information about what exams where written """ - -from django.urls import reverse -from rest_framework import status -from rest_framework.test import (APIRequestFactory, APITestCase, - force_authenticate) - -from core.models import ExamType -from core.views import ExamApiViewSet -from util.factories import GradyUserFactory - - -class ExamListTest(APITestCase): - """ briefly tests if we are able to retrieve data, and get correct fields - """ - @classmethod - def setUpTestData(cls): - cls.factory = APIRequestFactory() - cls.user_factory = GradyUserFactory() - - def setUp(self): - self.request = self.factory.get(reverse('examtype-list')) - self.examtype = ExamType.objects.create(module_reference='B.Inf.9000', - total_score=90, - pass_score=45) - force_authenticate(self.request, - self.user_factory.make_reviewer()) - self.view = ExamApiViewSet.as_view({'get': 'list'}) - self.response = self.view(self.request) - - def test_can_access_when_authenticated(self): - self.assertEqual(self.response.status_code, status.HTTP_200_OK) - - def test_getting_all_available_exams(self): - self.assertEqual(1, len(self.response.data)) - - # Tests concerning exam data - def test_exam_data_contains_module_reference(self): - self.assertEqual('B.Inf.9000', - self.response.data[0]["module_reference"]) - - def test_exam_data_contains_total_score(self): - self.assertEqual(90, self.response.data[0]["total_score"]) - - def test_exam_data_contains_pass_score(self): - self.assertEqual(45, self.response.data[0]["pass_score"]) - - def test_exam_data_contains_pass_only_field(self): - self.assertEqual(False, self.response.data[0]["pass_only"]) diff --git a/grady/core/tests/test_export.py b/grady/core/tests/test_export.py deleted file mode 100644 index 3768a277374187657e9e0e5d940753baca660270..0000000000000000000000000000000000000000 --- a/grady/core/tests/test_export.py +++ /dev/null @@ -1,238 +0,0 @@ -from rest_framework import status -from rest_framework.test import APIClient, APITestCase - -from util.factories import make_test_data, make_exams - - -def make_data(): - exams = make_exams([{ - 'module_reference': 'Test Exam 01', - 'total_score': 100, - 'pass_score': 60, - 'pass_only': True - }] - ) - return make_test_data(data_dict={ - 'exams': [{ - 'module_reference': 'Test Exam 01', - 'total_score': 100, - 'pass_score': 60, - 'pass_only': True, - 'exam_type_id': exams[0].exam_type_id - }], - 'submission_types': [ - { - 'name': '01. Sort', - 'full_score': 35, - 'description': 'Very complicated', - 'solution': 'Trivial!', - 'programming_language': 'Haskell', - 'exam_type': exams[0] - }, - { - 'name': '02. Shuffle', - 'full_score': 35, - 'description': 'Very complicated', - 'solution': 'Trivial!', - 'exam_type': exams[0] - } - ], - 'students': [ - {'username': 'student01', 'exam': 'Test Exam 01'}, - {'username': 'student02', 'exam': 'Test Exam 01'} - ], - 'tutors': [{ - 'username': 'tutor01' - }], - 'reviewers': [ - {'username': 'reviewer'} - ], - 'submissions': [ - { - 'text': 'function blabl\n' - ' on multi lines\n' - ' for blabla in bla:\n' - ' lorem ipsum und so\n', - 'type': '01. Sort', - 'user': 'student01', - 'feedback': { - 'score': 5, - 'is_final': True, - 'feedback_lines': { - '1': [{ - 'text': 'This is very bad!', - 'of_tutor': 'reviewer' - }], - } - - } - }, - { - 'text': 'not much', - 'type': '02. Shuffle', - 'user': 'student01' - }, - { - 'text': 'function blabl\n' - ' asasxasx\n' - ' lorem ipsum und so\n', - 'type': '01. Sort', - 'user': 'student02' - }, - { - 'text': 'not much to see here', - 'type': '02. Shuffle', - 'user': 'student02' - } - ]} - ) - - -class ExportInstanceTest(APITestCase): - @classmethod - def setUpTestData(cls): - cls.data = make_data() - - def setUp(self): - self.client = APIClient() - self.client.force_login(user=self.data['reviewers'][0]) - self.response = self.client.get('/api/instance/export/') - - def test_can_access(self): - self.assertEqual(status.HTTP_200_OK, self.response.status_code) - - def test_data_is_correct(self): - instance = self.response.json() - - # examTypes fields - self.assertIn('examTypes', instance) - self.assertIn('pk', instance['examTypes'][0]) - self.assertEqual('Test Exam 01', instance['examTypes'][0]['moduleReference']) - self.assertEqual(100, instance['examTypes'][0]['totalScore']) - self.assertEqual(60, instance['examTypes'][0]['passScore']) - self.assertEqual(True, instance['examTypes'][0]['passOnly']) - - # submissionTypes fields - self.assertIn('submissionTypes', instance) - self.assertEqual(2, len(instance['submissionTypes'])) - self.assertIn('pk', instance['submissionTypes'][0]) - self.assertEqual('01. Sort', instance['submissionTypes'][0]['name']) - self.assertEqual(35, instance['submissionTypes'][0]['fullScore']) - self.assertEqual('Very complicated', instance['submissionTypes'][0]['description']) - self.assertEqual('Trivial!', instance['submissionTypes'][0]['solution']) - self.assertEqual('Haskell', instance['submissionTypes'][0]['programmingLanguage']) - - # students fields - self.assertIn('students', instance) - self.assertEqual(2, len(instance['students'])) - self.assertIn('pk', instance['students'][0]) - self.assertIn('userPk', instance['students'][0]) - self.assertIn('exams', instance['students'][0]) - student_users = [s['user'] for s in instance['students']] - self.assertIn('student01', student_users) - self.assertIn('student02', student_users) - self.assertLess(0, len(instance['students'][1]['submissions'])) - - # students[submissions] nested - self.assertIn('submissions', instance['students'][1]) - self.assertLess(0, len(instance['students'][1]['submissions'])) - self.assertIn('pk', instance['students'][1]['submissions'][0]) - self.assertIn('function blabl', instance['students'][1]['submissions'][0]['text']) - self.assertIn('type', instance['students'][1]['submissions'][0]) - self.assertIn('tests', instance['students'][1]['submissions'][0]) - - # students[submissions][feedback] nested - submissions = instance['students'][0]['submissions'] - self.assertIn('feedback', submissions[0]) - self.assertLess(0, len(submissions[0]['feedback'])) - self.assertEqual(5, submissions[0]['feedback']['score']) - self.assertEqual(True, submissions[0]['feedback']['isFinal']) - self.assertIn('created', submissions[0]['feedback']) - - # students[submissions][feedback][feedbackLines] nested - feedback = instance['students'][0]['submissions'][0]['feedback'] - self.assertIn('feedbackLines', feedback) - self.assertLess(0, len(feedback['feedbackLines'])) - self.assertIn('1', feedback['feedbackLines']) - self.assertIn('pk', feedback['feedbackLines']['1'][0]) - self.assertEqual('This is very bad!', feedback['feedbackLines']['1'][0]['text']) - self.assertEqual('reviewer', feedback['feedbackLines']['1'][0]['ofTutor']) - - # reviewers fields - self.assertIn('reviewers', instance) - self.assertLess(0, len(instance['reviewers'])) - self.assertIn('pk', instance['reviewers'][0]) - self.assertEqual('reviewer', instance['reviewers'][0]['username']) - - # tutors fields - self.assertIn('tutors', instance) - self.assertLess(0, len(instance['tutors'])) - tutor_names = [t['username'] for t in instance['tutors']] - self.assertIn('tutor01', tutor_names) - self.assertIn('reviewer', tutor_names) - - -class ExportJSONTest(APITestCase): - @classmethod - def setUpTestData(cls): - cls.data = make_data() - - def setUp(self): - self.client = APIClient() - self.client.force_login(user=self.data['reviewers'][0]) - self.response = self.client.post('/api/export/json/') - - def test_can_access(self): - self.assertEqual(status.HTTP_200_OK, self.response.status_code) - - def test_data_is_correct(self): - # due to using the client, we need to parse the json - student1, student2 = self.response.data - self.assertIn('Matrikel', student1) - self.assertIn('Matrikel', student2) - - self.assertEqual('', student1['Name']) - self.assertEqual('', student2['Name']) - - self.assertEqual('Test Exam 01', student1['Exams'][0]['exam']['module_reference']) - self.assertEqual('Test Exam 01', student2['Exams'][0]['exam']['module_reference']) - - self.assertEqual('student01', student1['Username']) - self.assertEqual('student02', student2['Username']) - - self.assertEqual('********', student2['Password']) - self.assertEqual('********', student1['Password']) - - self.assertEqual('01. Sort', student1['Scores'][0]['submissions'][0]['type']) - self.assertEqual('01. Sort', student2['Scores'][0]['submissions'][0]['type']) - - self.assertEqual('02. Shuffle', student1['Scores'][0]['submissions'][1]['type']) - self.assertEqual('02. Shuffle', student2['Scores'][0]['submissions'][1]['type']) - - self.assertEqual(5, student1['Scores'][0]['submissions'][0]['score']) - self.assertEqual(0, student2['Scores'][0]['submissions'][0]['score']) - - self.assertEqual(0, student2['Scores'][0]['submissions'][1]['score']) - self.assertEqual(0, student2['Scores'][0]['submissions'][1]['score']) - - -class ExportJSONAndSetPasswordsTest(APITestCase): - @classmethod - def setUpTestData(cls): - cls.data = make_data() - - def setUp(self): - self.client = APIClient() - self.client.force_login(user=self.data['reviewers'][0]) - self.response = self.client.post('/api/export/json/', - data={'setPasswords': True}) - - def test_can_access(self): - self.assertEqual(status.HTTP_200_OK, self.response.status_code) - - def test_data_contains_correct_password(self): - student1, student2 = self.response.data - ret = self.client.login(username=student1['Username'], password=student1['Password']) - self.assertTrue(ret) - ret = self.client.login(username=student2['Username'], password=student2['Password']) - self.assertTrue(ret) diff --git a/grady/core/tests/test_factory.py b/grady/core/tests/test_factory.py deleted file mode 100644 index c32ae5aa1e12a7dec5b99716016b074c8e280f43..0000000000000000000000000000000000000000 --- a/grady/core/tests/test_factory.py +++ /dev/null @@ -1,52 +0,0 @@ -from django.test import TestCase - -from core import models -from core.models import StudentInfo -from util.factories import GradyUserFactory, make_exams - - -class FactoryTestCase(TestCase): - - factory = GradyUserFactory() - - def test_make_student(self): - self.exam = make_exams(exams=[{ - 'module_reference': 'Test Exam 01', - 'total_score': 100, - 'pass_score': 60, - }])[0] - user = self.factory.make_student(exam=self.exam) - - self.assertEqual(StudentInfo.objects.count(), 1) - self.assertEqual(user.student.exams.first().exam.module_reference, "Test Exam 01") - self.assertEqual(len(str(user.student.matrikel_no)), 8) - - def test_can_create_reviewer(self): - self.assertTrue(isinstance(self.factory.make_reviewer(), - models.UserAccount)) - - def test_reviewer_appears_in_query_set(self): - self.assertIn(self.factory.make_reviewer(), - models.UserAccount.objects.all()) - - def test_can_create_tutor(self): - self.assertIn(self.factory.make_tutor(), - models.UserAccount.objects.all()) - - def test_can_create_student_user(self): - self.exam = make_exams(exams=[{ - 'module_reference': 'Test Exam 01', - 'total_score': 100, - 'pass_score': 60, - }])[0] - self.assertIn(self.factory.make_student(exam=self.exam), - models.UserAccount.objects.all()) - - def test_can_create_student_info(self): - self.exam = make_exams(exams=[{ - 'module_reference': 'Test Exam 01', - 'total_score': 100, - 'pass_score': 60, - }])[0] - self.assertIn(self.factory.make_student(exam=self.exam).student, - StudentInfo.objects.all()) diff --git a/grady/core/tests/test_feedback.py b/grady/core/tests/test_feedback.py deleted file mode 100644 index 7148854d4f17ce9b7357482f3449c4926525b7fe..0000000000000000000000000000000000000000 --- a/grady/core/tests/test_feedback.py +++ /dev/null @@ -1,703 +0,0 @@ -import unittest - -from constance.test import override_config -from rest_framework import status -from rest_framework.test import APIRequestFactory, APITestCase - -from core.models import (Feedback, FeedbackComment, - Submission, SubmissionType, - FeedbackLabel, TutorSubmissionAssignment, MetaSubmission) -from util.factories import GradyUserFactory, make_test_data, make_exams - - -class FeedbackRetrieveTestCase(APITestCase): - - factory = GradyUserFactory() - EXPECTED_SCORE = 23 - - @classmethod - def setUpTestData(cls): - cls.score = 23 - cls.tutor = cls.factory.make_tutor() - cls.exam = make_exams(exams=[{ - 'module_reference': 'Test Exam 01', - 'total_score': 100, - 'pass_score': 60, - }])[0] - cls.student = cls.factory.make_student(exam=cls.exam) - cls.reviewer = cls.factory.make_reviewer() - cls.tutors = [cls.tutor, cls.reviewer] - cls.request_factory = APIRequestFactory() - cls.submission_type = SubmissionType.objects.create( - name='Cooking some crystal with Jesse') - cls.sub = Submission.objects.create(student=cls.student.student, - type=cls.submission_type) - cls.feedback = Feedback.objects.create(score=23, is_final=False, - of_submission=cls.sub) - - for line in range(1, 3): - for tutor in cls.tutors: - FeedbackComment.objects.create(text='fortytwo', - of_feedback=cls.feedback, - of_tutor=tutor, - of_line=line) - - def setUp(self): - self.client.force_authenticate(user=self.reviewer) - self.response = self.client.get(f'/api/feedback/{self.sub.pk}/') - self.data = self.response.data - - def test_only_one_final_comment_per_line(self): - comments_on_first_line = FeedbackComment.objects.filter(of_line=1) - self.assertEqual(2, comments_on_first_line.count()) - final_comments = [comment for comment in comments_on_first_line.all() - if comment.visible_to_student] - self.assertEqual(1, len(final_comments)) - - def test_can_retrieve_feedback_via_endpoint(self): - self.assertEqual(self.response.status_code, status.HTTP_200_OK) - - def test_if_feedback_contains_correct_score(self): - self.assertIn('score', self.data) - self.assertEqual(self.data.get('score'), self.EXPECTED_SCORE) - - def test_if_feedback_contains_linekeys(self): - self.assertIn('feedback_lines', self.data) - self.assertIn(1, self.data['feedback_lines']) - self.assertIn(2, self.data['feedback_lines']) - - def test_if_feedback_contains_final(self): - self.assertIn('is_final', self.data) - self.assertIsNotNone(self.data['is_final']) - - def test_if_comment_contains_text(self): - self.assertIn('text', self.data['feedback_lines'][1][0]) - self.assertEqual( - 'fortytwo', self.data['feedback_lines'][1][0]['text']) - - def test_if_comment_contains_created(self): - self.assertIn('created', self.data['feedback_lines'][1][0]) - self.assertIsNotNone(self.data['feedback_lines'][1][0]['created']) - - def test_if_comment_has_tutor(self): - self.assertIn('of_tutor', self.data['feedback_lines'][1][0]) - self.assertEqual( - self.tutor.username, - self.data['feedback_lines'][1][0]['of_tutor']) - - def test_if_comment_has_final(self): - self.assertIn('visible_to_student', self.data['feedback_lines'][1][0]) - self.assertIsNotNone( - self.data['feedback_lines'][1][0]['visible_to_student']) - - -class FeedbackCreateTestCase(APITestCase): - - @classmethod - def setUpTestData(cls): - cls.url = lambda self: f'/api/assignment/{self.assignment.pk}/finish/' - cls.user_factory = GradyUserFactory() - cls.tutor = cls.user_factory.make_tutor(password='p') - cls.reviewer = cls.user_factory.make_reviewer(password='p') - cls.exam = make_exams(exams=[{ - 'module_reference': 'Test Exam 01', - 'total_score': 100, - 'pass_score': 60, - }])[0] - cls.student = cls.user_factory.make_student(exam=cls.exam) - cls.submission_type = SubmissionType.objects.create( - name='Cooking some crystal with Jesse', - full_score=100 - ) - text = ''' First line of defense - We do not have a second line - security via obscurity - is very bad. ''' - cls.sub = Submission.objects.create(student=cls.student.student, - type=cls.submission_type, - text=text) - cls.fst_label = FeedbackLabel.objects.create(name='Label1', description='Bla') - cls.snd_label = FeedbackLabel.objects.create(name='Label2', description='Bla') - - def setUp(self): - self.sub.refresh_from_db() - self.fst_label.refresh_from_db() - self.snd_label.refresh_from_db() - self.client.force_authenticate(user=self.tutor) - self.assignment = TutorSubmissionAssignment.objects.create( - submission=Submission.objects.first(), - owner=self.tutor, - ) - - def test_cannot_create_feedback_without_feedback_lines(self): - # TODO this test has to be adapted to test the various constraints - # e.g. feedback without lines can only be given if the score is equal - # to the max Score for this submission - data = { - 'score': 10, - 'is_final': False, - 'of_submission': self.assignment.submission.pk - - } - self.assertEqual(Feedback.objects.count(), 0) - response = self.client.post(self.url(), data, format='json') - self.assertEqual(status.HTTP_400_BAD_REQUEST, response.status_code) - self.assertEqual(Feedback.objects.count(), 0) - - def test_cannot_create_feedback_with_score_higher_than_max(self): - data = { - 'score': 101, - 'is_final': False, - 'of_submission': self.assignment.submission.pk - } - self.assertEqual(Feedback.objects.count(), 0) - response = self.client.post(self.url(), data, format='json') - self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) - self.assertEqual(Feedback.objects.count(), 0) - - def test_tutor_cannot_set_feedback_final_on_creation(self): - data = { - 'score': 100, - 'is_final': True, - 'of_submission': self.assignment.submission.pk - } - response = self.client.post(self.url(), data, format='json') - self.assertEqual(status.HTTP_403_FORBIDDEN, response.status_code) - self.assertEqual(Feedback.objects.count(), 0) - - @override_config(SINGLE_CORRECTION=True) - def test_tutor_can_set_feedback_final_on_creation_with_single_correction_enabled(self): - data = { - 'score': 100, - 'is_final': True, - 'of_submission': self.assignment.submission.pk - } - response = self.client.post(self.url(), data, format='json') - self.assertEqual(status.HTTP_201_CREATED, response.status_code) - self.assertEqual(Feedback.objects.count(), 1) - - def test_tutor_has_to_write_a_line_if_score_is_not_100_percent(self): - data = { - 'score': 50, - 'is_final': False, - 'of_submission': self.assignment.submission.pk - } - response = self.client.post(self.url(), data, format='json') - self.assertEqual(status.HTTP_400_BAD_REQUEST, response.status_code) - self.assertEqual(Feedback.objects.count(), 0) - - def test_cannot_create_feedback_with_score_less_than_zero(self): - data = { - 'score': -1, - 'is_final': False, - 'of_submission': self.assignment.submission.pk - } - self.assertEqual(Feedback.objects.count(), 0) - response = self.client.post(self.url(), data, format='json') - self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) - self.assertEqual(Feedback.objects.count(), 0) - - def test_cannot_create_feedback_with_score_with_invalid_fractional_denominator(self): - data = { - 'score': 1.500000001, - 'is_final': False, - 'of_submission': self.assignment.submission.pk - } - self.assertEqual(Feedback.objects.count(), 0) - response = self.client.post(self.url(), data, format='json') - self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) - self.assertEqual(Feedback.objects.count(), 0) - - def test_can_create_with_labels(self): - data = { - 'score': 0, - 'is_final': False, - 'of_submission': self.assignment.submission.pk, - 'labels': [self.fst_label.pk, self.snd_label.pk], - 'feedback_lines': { - '2': { - 'text': 'Why you no learn how to code, man?', - 'labels': [] - } - } - } - self.assertEqual(self.fst_label.feedback.count(), 0) - response = self.client.post(self.url(), data, format='json') - self.assertEqual(response.status_code, status.HTTP_201_CREATED) - self.fst_label.refresh_from_db() - self.snd_label.refresh_from_db() - self.assertEqual(self.fst_label.feedback.count(), 1) - self.assertEqual(self.snd_label.feedback.count(), 1) - self.assertEqual(Feedback.objects.first().labels.count(), 2) - - def test_can_create_feedback_with_half_points(self): - data = { - 'score': 0.5, - 'is_final': False, - 'of_submission': self.assignment.submission.pk, - 'feedback_lines': { - '2': { - 'text': 'Why you no learn how to code, man?', - 'labels': [] - } - } - } - self.client.post(self.url(), data, format='json') - object_score = self.sub.feedback.score - self.assertEqual(object_score, 0.5) - - def test_check_score_is_set_accordingly(self): - data = { - 'score': 5, - 'is_final': False, - 'of_submission': self.assignment.submission.pk, - 'feedback_lines': { - '4': { - 'text': 'Why you no learn how to code, man?', - 'labels': [] - } - } - } - self.client.post(self.url(), data, format='json') - object_score = self.sub.feedback.score - self.assertEqual(object_score, 5) - - def test_can_create_feedback_with_comment(self): - data = { - 'score': 0, - 'is_final': False, - 'of_submission': self.assignment.submission.pk, - 'feedback_lines': { - '3': { - 'text': 'Nice meth!', - 'labels': [] - } - } - } - self.assertEqual(FeedbackComment.objects.count(), 0) - response = self.client.post(self.url(), data, format='json') - self.assertEqual(response.status_code, status.HTTP_201_CREATED) - self.assertEqual(FeedbackComment.objects.count(), 1) - - def test_feedback_comment_is_created_correctly(self): - data = { - 'score': 0, - 'is_final': False, - 'of_submission': self.assignment.submission.pk, - 'feedback_lines': { - '3': { - 'text': 'Nice meth!', - 'labels': [] - } - } - } - self.client.post(self.url(), data, format='json') - comment = FeedbackComment.objects.first() - self.assertEqual(comment.of_tutor, self.tutor) - self.assertEqual(comment.text, 'Nice meth!') - self.assertIsNotNone(comment.created) - self.assertEqual(comment.of_line, 3) - self.assertTrue(comment.visible_to_student) - - def test_tutor_cannot_create_without_assignment(self): - data = { - 'score': 0, - 'of_submission': self.assignment.submission.pk, - 'feedback_lines': { - '2': { - 'text': 'Well, at least you tried.', - 'labels': [] - }, - } - } - self.assignment.delete() - response = self.client.post(self.url(), data, format='json') - self.assertEqual(status.HTTP_404_NOT_FOUND, response.status_code) - - def test_reviewer_can_create_without_assignment(self): - data = { - 'score': 0, - 'of_submission': self.assignment.submission.pk, - 'feedback_lines': { - '2': { - 'text': 'This is not particularly good...', - 'labels': [] - }, - } - } - self.assignment.delete() - self.client.force_authenticate(user=self.reviewer) - response = self.client.post('/api/feedback/', data, format='json') - self.assertEqual(status.HTTP_201_CREATED, response.status_code) - - @override_config(EXERCISE_MODE=True) - def test_tutor_can_create_without_assignment_in_exercise_mode(self): - data = { - 'score': 0, - 'of_submission': self.assignment.submission.pk, - 'feedback_lines': { - '2': { - 'text': 'You have failed!1!!11', - 'labels': [] - }, - } - } - self.assignment.delete() - response = self.client.post('/api/feedback/', data, format='json') - self.assertEqual(status.HTTP_201_CREATED, response.status_code) - - def test_cannot_create_with_someoneelses_assignment(self): - data = { - 'score': 0, - 'of_submission': self.assignment.submission.pk, - 'feedback_lines': { - '1': { - 'text': 'Well, at least you tried.', - 'labels': [] - }, - } - } - other_tutor = self.user_factory.make_tutor('Berta') - self.client.force_authenticate(other_tutor) - response = self.client.post(self.url(), data, format='json') - # returns 404 since the other users assignment is not visible to this one - self.assertEqual(status.HTTP_404_NOT_FOUND, response.status_code) - - def test_can_create_multiple_feedback_comments(self): - data = { - 'score': 0, - 'is_final': False, - 'of_submission': self.assignment.submission.pk, - 'feedback_lines': { - '1': { - 'text': 'Nice meth!', - 'labels': [] - }, - '3': { - 'text': 'Good one!', - 'labels': [] - } - } - } - self.client.post(self.url(), data, format='json') - first_comment = FeedbackComment.objects.get(text='Nice meth!') - self.assertEqual(first_comment.of_tutor, self.tutor) - self.assertIsNotNone(first_comment.created) - self.assertEqual(first_comment.of_line, 1) - self.assertTrue(first_comment.visible_to_student) - - second_comment = FeedbackComment.objects.get(text='Good one!') - self.assertEqual(second_comment.of_tutor, self.tutor) - self.assertIsNotNone(second_comment.created) - self.assertEqual(second_comment.of_line, 3) - self.assertTrue(second_comment.visible_to_student) - - -class FeedbackPatchTestCase(APITestCase): - - @classmethod - def setUpTestData(cls): - cls.burl = '/api/feedback/' - cls.finish_url = lambda self: f'/api/assignment/{self.assignment.pk}/finish/' - exams = make_exams([{ - 'module_reference': 'Test Exam 01', - 'total_score': 100, - 'pass_score': 60, - }] - ) - cls.data = make_test_data({ - 'exams': [{ - 'module_reference': 'Test Exam 01', - 'total_score': 100, - 'pass_score': 60, - 'exam_type': exams[0].exam_type_id - }], - 'submission_types': [ - { - 'name': '01. Sort this or that', - 'full_score': 35, - 'description': 'Very complicated', - 'solution': 'Trivial!', - 'exam_type': exams[0] - }], - 'students': [ - { - 'username': 'student01', - 'exam': 'Test Exam 01' - }, - { - 'username': 'student02', - 'exam': 'Test Exam 01', - } - ], - 'tutors': [ - {'username': 'tutor01'}, - {'username': 'tutor02'} - ], - 'reviewers': [{ - 'username': 'reviewer01', - }], - 'submissions': [ - { - 'text': 'function blabl\n' - ' on multi lines\n' - ' for blabla in bla:\n', - 'type': '01. Sort this or that', - 'user': 'student01' - }, - { - 'text': 'conflict test', - 'type': '01. Sort this or that', - 'user': 'student02' - }, - ] - }) - - cls.fst_label = FeedbackLabel.objects.create(name='Label1', description='Bla') - cls.snd_label = FeedbackLabel.objects.create(name='Label2', description='Bla') - - # construct submission that has conflicting feedback - cls.conflict_submission = Submission.objects.get(student__user=cls.data['students'][1]) - conflict_meta = MetaSubmission.objects.get( - submission__submission_id=cls.conflict_submission.submission_id - ) - conflict_meta.done_assignments = 2 - conflict_meta.has_final_feedback = False - conflict_meta.has_active_assignment = False - conflict_meta.has_feedback = True - conflict_meta.save() - - Feedback.objects.create(**{ - "score": 0, - "is_final": False, - "final_by_reviewer": False, - "of_submission": cls.conflict_submission - }) - - def setUp(self): - self.tutor01 = self.data['tutors'][0] - self.tutor02 = self.data['tutors'][1] - self.reviewer = self.data['reviewers'][0] - self.client.force_authenticate(user=self.tutor01) - self.assignment = TutorSubmissionAssignment.objects.create( - submission=Submission.objects.get(student__user=self.data['students'][0]), - owner=self.tutor01, - ) - data = { - 'score': 35, - 'is_final': False, - 'of_submission': self.assignment.submission.pk, - 'feedback_lines': { - '2': { - 'text': 'Very good.', - 'labels': [] - }, - } - } - response = self.client.post(self.finish_url(), data, format='json') - self.feedback = Feedback.objects.get( - of_submission=response.data['of_submission']) - self.url = f'{self.burl}{self.feedback.of_submission.submission_id}/' - - self.fst_label.refresh_from_db() - self.snd_label.refresh_from_db() - - def test_can_patch_onto_the_own_feedback(self): - data = { - 'feedback_lines': { - '1': { - 'text': 'Spam spam spam', - 'labels': [] - }, - } - } - response = self.client.patch(self.url, data, format='json') - self.assertEqual(status.HTTP_200_OK, response.status_code) - self.assertEqual( - 'Spam spam spam', - response.data['feedback_lines'][1][0]['text'] - ) - self.assertEqual( - 'Very good.', - response.data['feedback_lines'][2][0]['text'] - ) - - def test_can_update_a_single_line(self): - data = { - 'feedback_lines': { - '2': { - 'text': 'Turns out this is rather bad.', - 'labels': [] - }, - } - } - - response = self.client.patch(self.url, data, format='json') - self.assertEqual(status.HTTP_200_OK, response.status_code) - - @unittest.expectedFailure - def test_tutor_can_not_update_when_there_is_a_new_assignment(self): - # Step 1 - Create a new assignment for Tutor 2 - TutorSubmissionAssignment.objects.create( - submission=Submission.objects.last(), - owner=self.tutor02, - stage='feedback-validation', - ) - - # Step 2 - Tutor 1 tries to patch - data = { - 'feedback_lines': { - '2': {'text': 'Turns out this is rather bad.', 'labels': []}, - } - } - - response = self.client.patch(self.url, data, format='json') - self.assertEqual(status.HTTP_403_FORBIDDEN, response.status_code) - - def test_cannot_patch_first_feedback_final(self): - data = { - 'feedback_lines': { - '2': {'text': 'Turns out this is rather bad.', 'labels': []}, - }, - 'is_final': True - } - - response = self.client.patch(self.url, data, format='json') - self.assertEqual(status.HTTP_403_FORBIDDEN, response.status_code) - - def test_reviewer_can_patch_first_feedback_final(self): - data = { - 'feedback_lines': { - '2': {'text': 'Turns out this is rather bad.', 'labels': []}, - }, - 'is_final': True - } - - self.client.force_authenticate(user=self.reviewer) - response = self.client.patch(self.url, data, format='json') - self.assertEqual(status.HTTP_200_OK, response.status_code) - - def test_cannot_unset_final_on_third_feedback(self): - data = { - 'feedback_lines': { - '2': {'text': 'this is good.', 'labels': []}, - }, - 'is_final': False - } - - url = f'{self.burl}{self.conflict_submission.submission_id}/' - self.client.force_authenticate(user=self.reviewer) - response = self.client.patch(url, data, format='json') - self.assertEqual(status.HTTP_400_BAD_REQUEST, response.status_code) - - def tutor_can_patch_labels(self): - data = { - 'feedback_lines': { - '2': { - 'text': 'Turns out this is rather bad.', - 'labels': [self.fst_label.pk, self.snd_label.pk] - }, - } - } - - self.assertEqual(FeedbackComment.objects.first().labels.count(), 0) - response = self.client.patch(self.url, data, format='json') - self.assertEqual(status.HTTP_200_OK, response.status_code) - self.assertEqual(FeedbackComment.objects.first().labels.count(), 2) - - -class FeedbackCommentApiEndpointTest(APITestCase): - - @classmethod - def setUpTestData(cls): - cls.burl = '/api/feedback/' - exams = make_exams([{ - 'module_reference': 'Test Exam 01', - 'total_score': 100, - 'pass_score': 60, - }] - ) - cls.data = make_test_data({ - 'exams': [{ - 'module_reference': 'Test Exam 01', - 'total_score': 100, - 'pass_score': 60, - 'exam_type': exams[0].exam_type_id - }], - 'submission_types': [ - { - 'name': '01. Sort this or that', - 'full_score': 35, - 'description': 'Very complicated', - 'solution': 'Trivial!', - 'exam_type': exams[0] - }], - 'students': [ - { - 'username': 'student01', - 'exam': 'Test Exam 01' - } - ], - 'tutors': [ - {'username': 'tutor01'}, - {'username': 'tutor02'}, - ], - 'reviewers': [ - {'username': 'reviewer01'}, - ], - 'submissions': [{ - 'text': 'function blabl\n' - ' on multi lines\n' - ' for blabla in bla:\n', - 'type': '01. Sort this or that', - 'user': 'student01', - 'feedback': { - 'score': 5, - 'is_final': True, - 'feedback_lines': { - '1': [{'text': 'This is very bad!', - 'of_tutor': 'tutor01'}], - '2': [{'text': 'And this is even worse!', - 'of_tutor': 'tutor02'}], - } - } - }] - }) - - def setUp(self): - self.url = '/api/feedback-comment/%s/' - self.tutor01 = self.data['tutors'][0] - self.tutor02 = self.data['tutors'][1] - - def test_tutor_can_delete_own_comment(self): - self.client.force_authenticate(user=self.tutor01) - comment = FeedbackComment.objects.get(of_tutor=self.tutor01) - response = self.client.delete(self.url % comment.pk) - self.assertEqual(status.HTTP_204_NO_CONTENT, response.status_code) - - def test_tutor_cannot_delete_foreign_comment(self): - self.client.force_authenticate(user=self.tutor02) - comment = FeedbackComment.objects.get(of_tutor=self.tutor02) - self.client.force_authenticate(self.tutor01) - response = self.client.delete(self.url % comment.pk) - self.assertEqual(status.HTTP_404_NOT_FOUND, response.status_code) - - def test_reviewer_can_delete_other_users_comments(self): - reviewer = self.data['reviewers'][0] - self.client.force_authenticate(user=reviewer) - comment01 = FeedbackComment.objects.get(of_tutor=self.tutor01) - comment02 = FeedbackComment.objects.get(of_tutor=self.tutor02) - - response = self.client.delete(self.url % comment01.pk) - self.assertEqual(status.HTTP_204_NO_CONTENT, response.status_code) - - response = self.client.delete(self.url % comment02.pk) - self.assertEqual(status.HTTP_403_FORBIDDEN, response.status_code) - self.assertTrue(FeedbackComment.objects.filter(of_tutor=self.tutor02).exists(), - msg='Second comment should not be deleted for feedback with not full score') - try: - FeedbackComment.objects.get(of_tutor=self.tutor01) - except FeedbackComment.DoesNotExist: - pass - else: - self.fail('No exception raised') diff --git a/grady/core/tests/test_functional_views.py b/grady/core/tests/test_functional_views.py deleted file mode 100644 index 5f72f1980c96cdc077d3ac74260373a59f2bf588..0000000000000000000000000000000000000000 --- a/grady/core/tests/test_functional_views.py +++ /dev/null @@ -1 +0,0 @@ -# TODO test the config view diff --git a/grady/core/tests/test_import_views.py b/grady/core/tests/test_import_views.py deleted file mode 100644 index 52ec4eb0c867cbdd4bfc6f3c2480bafce78abca0..0000000000000000000000000000000000000000 --- a/grady/core/tests/test_import_views.py +++ /dev/null @@ -1,82 +0,0 @@ -from rest_framework import status -from rest_framework.test import APIClient, APITestCase -from core.models import UserAccount, SubmissionType - -from util.factories import GradyUserFactory - -test_data = { - "meta": { - "version": "6.0.0" - }, - "data": { - "module": { - "module_reference": "test", - "pass_only": True, - "pass_score": 1, - "total_score": 99 - }, - "students": [ - { - "fullname": "test", - "identifier": "test-test", - "submissions": [ - { - "code": "some messy, perhaps incorrect stuff", - "tests": [], - "type": "[a0] coding stuff" - }, - { - "code": "i don't know man", - "tests": [], - "type": "[a1] improvise" - } - ], - } - ], - "submission_types": [ - { - "description": "code some 1337 stuff", - "full_score": 99, - "name": "[a0] coding stuff", - "programming_language": "c", - "solution": "how dare u" - }, - { - "description": "now this one's hard", - "full_score": 1, - "name": "[a1] improvise", - "programming_language": "haskell", - "solution": "nope" - }, - ] - } -} - - -class ImportViewTest(APITestCase): - - factory = GradyUserFactory() - - def setUp(self): - self.url = '/api/import/' - self.client = APIClient() - self.client.force_login(user=self.factory.make_reviewer()) - - def test_can_not_submit_nothing(self): - res = self.client.post(self.url) - self.assertEqual(status.HTTP_400_BAD_REQUEST, res.status_code) - - def test_will_fail_on_wrong_importer_version(self): - data = {"meta": {"version": "0.0.0"}} - res = self.client.post(self.url, data) - self.assertEqual(status.HTTP_409_CONFLICT, res.status_code) - - def test_data_is_imported_correctly(self): - res = self.client.post(self.url, test_data) - - sub_types = SubmissionType.objects.all() - students = UserAccount.objects.all().filter(role='Student') - - self.assertEqual(2, len(sub_types)) - self.assertEqual(1, len(students)) - self.assertEqual(status.HTTP_201_CREATED, res.status_code) diff --git a/grady/core/tests/test_labels.py b/grady/core/tests/test_labels.py deleted file mode 100644 index 99760fd986333c84b45302d7bfcfdffa6b83f920..0000000000000000000000000000000000000000 --- a/grady/core/tests/test_labels.py +++ /dev/null @@ -1,48 +0,0 @@ -from rest_framework import status -from rest_framework.test import APITestCase - -from core.models import FeedbackLabel -from util.factories import GradyUserFactory, make_exams - - -class LabelsTestCases(APITestCase): - @classmethod - def setUpTestData(cls) -> None: - cls.factory = GradyUserFactory() - cls.exam = make_exams(exams=[{ - 'module_reference': 'Test Exam 01', - 'total_score': 100, - 'pass_score': 60, - }])[0] - cls.student = cls.factory.make_student(exam=cls.exam) - cls.tutor = cls.factory.make_tutor(exam=cls.exam) - cls.reviewer = cls.factory.make_reviewer(exam=cls.exam) - cls.label_post_data = { - 'name': 'A label', - 'description': 'with a description...' - } - cls.label_url = '/api/label/' - - def test_student_can_read_labels(self): - self.client.force_authenticate(user=self.student) - response = self.client.get(self.label_url) - self.assertEqual(response.status_code, status.HTTP_200_OK) - self.assertEqual(FeedbackLabel.objects.count(), 0) - - def test_student_can_not_write_labels(self): - self.client.force_authenticate(user=self.student) - response = self.client.post(self.label_url, data=self.label_post_data) - self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) - self.assertEqual(FeedbackLabel.objects.count(), 0) - - def test_tutor_can_create_label(self): - self.client.force_authenticate(user=self.tutor) - response = self.client.post(self.label_url, data=self.label_post_data) - self.assertEqual(response.status_code, status.HTTP_201_CREATED) - self.assertEqual(FeedbackLabel.objects.count(), 1) - - def test_reviewer_can_create_label(self): - self.client.force_authenticate(user=self.reviewer) - response = self.client.post(self.label_url, data=self.label_post_data) - self.assertEqual(response.status_code, status.HTTP_201_CREATED) - self.assertEqual(FeedbackLabel.objects.count(), 1) diff --git a/grady/core/tests/test_student_page.py b/grady/core/tests/test_student_page.py deleted file mode 100644 index 3fdb139d214c35dc319e29461c2b7cdcd41f9cf7..0000000000000000000000000000000000000000 --- a/grady/core/tests/test_student_page.py +++ /dev/null @@ -1,264 +0,0 @@ -from django.urls import reverse -from rest_framework.test import (APIRequestFactory, APITestCase, - force_authenticate) - -from core.models import SubmissionType, ExamType -from core.views import StudentSelfApiView, StudentSelfSubmissionsApiView -from util.factories import make_test_data, make_exams - - -class StudentPageTests(APITestCase): - - @classmethod - def setUpTestData(cls): - cls.factory = APIRequestFactory() - - def setUp(self): - exams = make_exams([{ - 'module_reference': 'TestExam B.Inf.0042', - 'total_score': 42, - 'pass_score': 21, - }] - ) - self.test_data = make_test_data(data_dict={ - 'exams': [{ - 'module_reference': 'TestExam B.Inf.0042', - 'total_score': 42, - 'pass_score': 21, - 'exam_type': exams[0].exam_type_id - }], - 'submission_types': [{ - 'name': 'problem01', - 'full_score': 10, - 'description': 'Very hard', - 'solution': 'Impossible!', - 'exam_type': exams[0] - }], - 'students': [{ - 'username': 'user01', - 'fullname': 'us er01', - 'exam': 'TestExam B.Inf.0042' - }], - 'tutors': [{ - 'username': 'tutor01' - }], - 'reviewers': [{ - 'username': 'reviewer' - }], - 'submissions': [{ - 'user': 'user01', - 'type': 'problem01', - 'text': 'Too hard for me ;-(', - 'feedback': { - 'text': 'Very bad!', - 'score': 3, - 'feedback_lines': { - '1': [{ - 'text': 'This is very bad!', - 'of_tutor': 'tutor01' - }], - } - } - }] - }) - - self.student = self.test_data['students'][0] - self.student_info = self.student.student - self.tutor = self.test_data['tutors'][0] - self.reviewer = self.test_data['reviewers'][0] - self.submission = self.test_data['submissions'][0] - self.feedback = self.submission.feedback - - self.request = self.factory.get(reverse('student-page')) - self.view = StudentSelfApiView.as_view() - force_authenticate(self.request, user=self.student) - self.response = self.view(self.request) - - self.exam_info_id = self.response.data['exams'][0]['exam'] - self.exam_obj = ExamType.objects.get(exam_type_id=self.exam_info_id) - self.submission_list = self.response.data['submissions'] - self.submission_list_first_entry = self.submission_list[0] - - def test_student_information_contains_name(self): - self.assertEqual( - self.response.data['name'], self.student.fullname) - - def test_all_student_submissions_are_loded(self): - self.assertEqual(len(self.submission_list), - SubmissionType.objects.count()) - - # Tests concerning exam data - def test_exam_data_contains_module_reference(self): - self.assertEqual( - self.exam_obj.module_reference, - self.student_info.exams.first().exam.module_reference) - - def test_exam_data_contains_total_score(self): - self.assertEqual( - self.exam_obj.total_score, self.student_info.exams.first().exam.total_score) - - def test_exam_data_contains_pass_score(self): - self.assertEqual( - self.exam_obj.pass_score, self.student_info.exams.first().exam.pass_score) - - def test_exam_data_contains_pass_only_field(self): - self.assertEqual( - self.exam_obj.pass_only, self.student_info.exams.first().exam.pass_only) - - # Tests concerning submission data - def test_a_student_submissions_contains_type_name(self): - self.assertEqual( - self.submission_list_first_entry['type']['name'], - self.student_info.submissions.first().type.name) - - def test_a_student_submissions_contains_type_id(self): - self.assertEqual( - self.submission_list_first_entry['type']['pk'], - str(self.student_info.submissions.first().type.pk)) - - def test_submission_data_contains_full_score(self): - self.assertEqual( - self.submission_list_first_entry['type']['full_score'], - self.student_info.submissions.first().type.full_score) - - def test_submission_data_contains_feedback_score(self): - self.assertEqual( - self.submission_list_first_entry['feedback']['score'], - self.student_info.submissions.first().feedback.score) - - # We don't want a matriculation number here - def test_matriculation_number_is_not_send(self): - self.assertNotIn('matrikel_no', self.submission_list_first_entry) - - -class StudentSelfSubmissionsTests(APITestCase): - - @classmethod - def setUpTestData(cls): - cls.factory = APIRequestFactory() - - def setUp(self): - exams = make_exams([{ - 'module_reference': 'Test Exam 01', - 'total_score': 100, - 'pass_score': 60, - }] - ) - self.test_data = make_test_data(data_dict={ - 'exams': [{ - 'module_reference': 'Test Exam 01', - 'total_score': 100, - 'pass_score': 60, - 'exam_type': exams[0].exam_type_id - }], - 'submission_types': [{ - 'name': 'problem01', - 'full_score': 10, - 'description': 'Very hard', - 'solution': 'Impossible!', - 'exam_type': exams[0] - }], - 'students': [{ - 'username': 'user01', - 'exam': 'Test Exam 01' - }], - 'tutors': [ - { - 'username': 'tutor01' - }, - { - 'username': 'tutor02' - } - ], - 'submissions': [{ - 'user': 'user01', - 'type': 'problem01', - 'text': 'Too hard for me ;-(', - 'feedback': { - 'text': 'Very bad!', - 'score': 3, - 'feedback_lines': { - '1': [ - { - 'text': 'This is very bad!', - 'of_tutor': 'tutor01', - # explicitness to required - # will also be set automatically - 'visible_to_student': False - }, - { - 'text': 'This is good!', - 'of_tutor': 'tutor02' - } - ], - } - } - }] - }) - - self.student = self.test_data['students'][0] - self.student_info = self.student.student - self.tutor = self.test_data['tutors'][0] - self.submission = self.test_data['submissions'][0] - self.feedback = self.submission.feedback - - self.request = self.factory.get(reverse('student-submissions')) - self.view = StudentSelfSubmissionsApiView.as_view() - - force_authenticate(self.request, user=self.student) - self.response = self.view(self.request) - - self.submission_list = self.response.data - self.submission_list_first_entry = self.submission_list[0] - - # Tests concerning submission data - def test_a_student_submissions_contains_type_name(self): - self.assertEqual( - self.submission_list_first_entry['type']['name'], - self.student_info.submissions.first().type.name) - - def test_a_student_submissions_contains_type_id(self): - self.assertEqual( - self.submission_list_first_entry['type']['pk'], - str(self.student_info.submissions.first().type.pk)) - - def test_submission_data_contains_full_score(self): - self.assertEqual( - self.submission_list_first_entry['type']['full_score'], - self.student_info.submissions.first().type.full_score) - - def test_submission_data_contains_description(self): - self.assertEqual( - self.submission_list_first_entry['type']['description'], - self.student_info.submissions.first().type.description) - - def test_submission_data_not_contains_solution(self): - self.assertNotIn('solution', self.submission_list_first_entry['type']) - - def test_submission_data_contains_final_status(self): - self.assertEqual( - self.submission_list_first_entry['feedback']['is_final'], - self.student_info.submissions.first().feedback.is_final) - - def test_submission_data_contains_feedback_score(self): - self.assertEqual( - self.submission_list_first_entry['feedback']['score'], - self.student_info.submissions.first().feedback.score) - - def test_submission_feedback_contains_submission_lines(self): - self.assertIn( - 'feedback_lines', - self.submission_list_first_entry['feedback'] - ) - - def test_feedback_contains_one_comment_per_line(self): - lines = self.submission_list_first_entry['feedback']['feedback_lines'] - self.assertEqual(len(lines[1]), 1) - - def test_feedback_comment_does_not_contain_tutor(self): - lines = self.submission_list_first_entry['feedback']['feedback_lines'] - self.assertNotIn('of_tutor', lines[1][0]) - - # We don't want a matriculation number here - def test_matriculation_number_is_not_send(self): - self.assertNotIn('matrikel_no', self.submission_list_first_entry) diff --git a/grady/core/tests/test_student_reviewer_viewset.py b/grady/core/tests/test_student_reviewer_viewset.py deleted file mode 100644 index 8cb650e754d335f552bcbe7e245cf84e81e60b30..0000000000000000000000000000000000000000 --- a/grady/core/tests/test_student_reviewer_viewset.py +++ /dev/null @@ -1,156 +0,0 @@ -from django.urls import reverse -from rest_framework import status -from rest_framework.test import (APIRequestFactory, APITestCase, - force_authenticate) - -from core import models -from core.views import StudentReviewerApiViewSet -from util.factories import make_test_data, make_exams, make_groups - - -class StudentPageTests(APITestCase): - - @classmethod - def setUpTestData(cls): - cls.factory = APIRequestFactory() - - def setUp(self): - exams = make_exams([{ - 'module_reference': 'TestExam B.Inf.0042', - 'total_score': 42, - 'pass_score': 21, - }]) - groups = make_groups([{ - 'name': 'Group 01', - 'exam': exams[0] - }, - { - 'name': 'Group 02', - 'exam': exams[0] - }]) - self.test_data = make_test_data(data_dict={ - 'exams': [{ - 'module_reference': 'TestExam B.Inf.0042', - 'total_score': 42, - 'pass_score': 21, - 'exam_type': exams[0].exam_type_id - }], - 'submission_types': [{ - 'name': 'problem01', - 'full_score': 10, - 'description': 'Very hard', - 'solution': 'Impossible!', - 'exam_type': exams[0] - }], - 'students': [ - { - 'username': 'user01', - 'exam': 'TestExam B.Inf.0042', - 'exercise_groups': [groups[0]], - }, - { - 'username': 'user02', - 'exam': 'TestExam B.Inf.0042', - 'exercise_groups': [groups[1]], - }, - { - 'username': 'user03', - 'exam': 'TestExam B.Inf.0042', - 'exercise_groups': [groups[1]], - } - ], - 'tutors': [{ - 'username': 'tutor', - 'exercise_groups': [groups[1]], - }], - 'reviewers': [{ - 'username': 'reviewer', - 'exercise_groups': ['Group 1337'], - }], - 'submissions': [{ - 'user': 'user01', - 'type': 'problem01', - 'text': 'Too hard for me ;-(', - 'feedback': { - 'score': 3, - 'feedback_lines': { - '1': [{ - 'text': 'This is very bad!', - 'of_tutor': 'tutor' - }], - } - } - }] - }) - - self.student = self.test_data['students'][0].student - self.reviewer = self.test_data['reviewers'][0] - self.tutor = self.test_data['tutors'][0] - self.submission = self.test_data['submissions'][0] - - self.request = self.factory.get(reverse('student-list')) - self.view = StudentReviewerApiViewSet.as_view({'get': 'list'}) - - force_authenticate(self.request, user=self.reviewer) - self.rev_response = self.view(self.request) - - force_authenticate(self.request, user=self.tutor) - self.tut_response = self.view(self.request) - - def test_reviewer_can_access(self): - self.assertEqual(self.rev_response.status_code, status.HTTP_200_OK) - - def test_tutor_can_see_no_students_when_not_in_exercise_mode(self): - self.assertEqual(0, len(self.tut_response.data)) - - def test_reviewer_can_see_all_students(self): - self.assertEqual(3, len(self.rev_response.data)) - - # ! Test fails in testing environtment, but cannot reproduced manually. - # Idea: make groups independent of exam_type, then look what happens. - - # @override_config(EXERCISE_MODE=True) - # def test_tutor_can_only_see_group_members_when_in_exercise_mode(self): - # force_authenticate(self.request, user=self.tutor) - # response = self.view(self.request) - # self.assertEqual(2, len(response.data)) - - def test_submissions_score_is_included(self): - res_with_sub = None - for res in self.rev_response.data: - if len(res['submissions']) > 0: - res_with_sub = res - self.assertEqual(self.student.submissions.first().feedback.score, - res_with_sub['submissions'][0]['score']) - - def test_submissions_full_score_is_included(self): - res_with_sub = None - for res in self.rev_response.data: - if len(res['submissions']) > 0: - res_with_sub = res - self.assertEqual(self.student.submissions.first().type.full_score, - res_with_sub['submissions'][0]['full_score']) - - def tutor_can_not_deactivate_students(self): - self.client.force_authenticate(self.tutor) - response = self.client.post(reverse('student-list') + 'deactivate/') - self.assertEqual(status.HTTP_401_UNAUTHORIZED, response.status_code) - users = [stud.user for stud in models.StudentInfo.objects.all()] - self.assertTrue(all([user.is_active for user in users])) - - def tutor_can_not_activate_students(self): - self.client.force_authenticate(self.tutor) - response = self.client.post(reverse('student-list') + 'activate/') - self.assertEqual(status.HTTP_401_UNAUTHORIZED, response.status_code) - - def test_can_deactivate_all_students(self): - self.client.force_authenticate(self.reviewer) - self.client.post(reverse('student-list') + 'deactivate/') - users = [stud.user for stud in models.StudentInfo.objects.all()] - self.assertTrue(all([not user.is_active for user in users])) - - def test_can_activate_all_students(self): - self.client.force_authenticate(self.reviewer) - self.client.post(reverse('student-list') + 'activate/') - users = [stud.user for stud in models.StudentInfo.objects.all()] - self.assertTrue(all([user.is_active for user in users])) diff --git a/grady/core/tests/test_submissiontypeview.py b/grady/core/tests/test_submissiontypeview.py deleted file mode 100644 index 864558fa2cf875b5256934fd0825ebe52517b4c4..0000000000000000000000000000000000000000 --- a/grady/core/tests/test_submissiontypeview.py +++ /dev/null @@ -1,102 +0,0 @@ -""" Tests that we can receive information about different submission types """ - -from constance.test import override_config -from django.urls import reverse -from rest_framework import status -from rest_framework.test import (APIRequestFactory, APITestCase, - force_authenticate) - -from core.models import SubmissionType -from core.views import SubmissionTypeApiView -from util.factories import GradyUserFactory, make_exams - -# TODO: add tests to test the remaining counts in conjunction with the assignment logic -# TODO: also test for pass only and stuff - - -class SubmissionTypeViewTestList(APITestCase): - - @classmethod - def setUpTestData(cls): - cls.factory = APIRequestFactory() - cls.user_factory = GradyUserFactory() - - def setUp(self): - self.request = self.factory.get(reverse('submissiontype-list')) - SubmissionType.objects.create(name='Hard question', - full_score=20, - description='Whatever') - force_authenticate(self.request, - self.user_factory.make_reviewer()) - self.view = SubmissionTypeApiView.as_view({'get': 'list'}) - self.response = self.view(self.request) - - def test_can_access_when_authenticated(self): - self.assertEqual(self.response.status_code, status.HTTP_200_OK) - - def test_get_all_available_submissiontypes(self): - self.assertEqual(1, len(self.response.data)) - - def test_get_sumbission_type_name(self): - self.assertEqual('Hard question', self.response.data[0]['name']) - - def test_get_full_score(self): - self.assertEqual(20, self.response.data[0]['full_score']) - - -class SubmissionTypeViewTestRetrieve(APITestCase): - - @classmethod - def setUpTestData(cls): - cls.factory = APIRequestFactory() - cls.user_factory = GradyUserFactory() - cls.exam = make_exams(exams=[{ - 'module_reference': 'Test Exam 01', - 'total_score': 100, - 'pass_score': 60, - }])[0] - cls.student = cls.user_factory.make_student(exam=cls.exam) - - def setUp(self): - self.request = self.factory.get('/api/submissiontype/') - SubmissionType.objects.create(name='Hard question', - full_score=20, - description='Whatever') - self.pk = SubmissionType.objects.first().pk - force_authenticate(self.request, - self.user_factory.make_reviewer()) - self.view = SubmissionTypeApiView.as_view({'get': 'retrieve'}) - self.response = self.view(self.request, pk=self.pk) - - def test_can_access_when_authenticated(self): - self.assertEqual(self.response.status_code, status.HTTP_200_OK) - - def test_students_can_not_access(self): - request = self.factory.get('/api/submissiontype/') - force_authenticate(request, self.student) - view = SubmissionTypeApiView.as_view({'get': 'retrieve'}) - response = view(request, pk=self.pk) - self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) - - @override_config(SHOW_SOLUTION_TO_STUDENTS=True) - def test_student_can_access_when_config_is_set(self): - request = self.factory.get('/api/submissiontype/') - force_authenticate(request, self.student) - view = SubmissionTypeApiView.as_view({'get': 'retrieve'}) - response = view(request, pk=self.pk) - self.assertEqual(response.status_code, status.HTTP_200_OK) - - def test_get_id(self): - self.assertEqual(str(self.pk), self.response.data['pk']) - - def test_get_sumbission_type_name(self): - self.assertEqual('Hard question', self.response.data['name']) - - def test_get_full_score(self): - self.assertEqual(20, self.response.data['full_score']) - - def test_get_descritpion(self): - self.assertEqual('Whatever', self.response.data['description']) - - def test_there_is_no_solution_to_nothing(self): - self.assertEqual('', self.response.data['solution']) diff --git a/grady/core/tests/test_tutor_api_endpoints.py b/grady/core/tests/test_tutor_api_endpoints.py deleted file mode 100644 index ee84cf7d9236e74acdcaa9746fb183ee7cf3d725..0000000000000000000000000000000000000000 --- a/grady/core/tests/test_tutor_api_endpoints.py +++ /dev/null @@ -1,256 +0,0 @@ -""" Two api endpoints are currently planned - - * GET /tutor/:id to retrive information about some tutor - * POST /tutor/:username/:email create a new tutor and email password - * GET /tutorlist list of all tutors with their scores -""" -from django.contrib.auth import get_user_model -from constance.test import override_config -from rest_framework import status -from rest_framework.reverse import reverse -from rest_framework.test import (APIClient, APIRequestFactory, APITestCase, - force_authenticate) - -from core.models import Feedback, TutorSubmissionAssignment -from core.views import CorrectorApiViewSet -from util.factories import GradyUserFactory, make_test_data, make_exams - -NUMBER_OF_TUTORS = 3 - - -class TutorDeleteTest(APITestCase): - - @classmethod - def setUpTestData(cls): - cls.factory = APIRequestFactory() - cls.user_factory = GradyUserFactory() - - def setUp(self): - self.tutor = self.user_factory.make_tutor(username='UFO') - self.reviewer = self.user_factory.make_reviewer() - self.request = self.factory.delete(reverse('corrector-detail', - args=[str(self.tutor.pk)])) - self.view = CorrectorApiViewSet.as_view({'delete': 'destroy'}) - - force_authenticate(self.request, user=self.reviewer) - self.response = self.view(self.request, pk=str(self.tutor.pk)) - - def test_can_delete_tutor_soapbox(self): - """ see if the tutor was deleted """ - self.assertEqual(0, get_user_model().get_tutors().count()) - - def test_user_is_deleted_too(self): - """ see if the associated user was deleted (reviewer remains) """ - self.assertNotIn(self.tutor, get_user_model().objects.all()) - - -class TutorListTests(APITestCase): - - @classmethod - def setUpTestData(cls): - factory = APIRequestFactory() - - request = factory.get(reverse('corrector-list')) - view = CorrectorApiViewSet.as_view({'get': 'list'}) - exams = make_exams([{ - 'module_reference': 'Test Exam 01', - 'total_score': 100, - 'pass_score': 60, - }] - ) - data = make_test_data(data_dict={ - 'exams': [{ - 'module_reference': 'Test Exam 01', - 'total_score': 100, - 'pass_score': 60, - 'exam_type': exams[0].exam_type_id - }], - 'submission_types': [{ - 'name': '01. Sort this or that', - 'full_score': 35, - 'description': 'Very complicated', - 'solution': 'Trivial!', - 'exam_type': exams[0] - }], - 'students': [ - { - 'username': 'student01', - 'exam': 'Test Exam 01' - }, - { - 'username': 'student02', - 'exam': 'Test Exam 01' - } - ], - 'tutors': [ - {'username': 'tutor01'}, - {'username': 'tutor02'} - ], - 'reviewers': [ - {'username': 'reviewer'} - ], - 'submissions': [ - { - 'text': 'function blabl\n' - ' on multi lines\n', - 'type': '01. Sort this or that', - 'user': 'student01' - }, - { - 'text': 'function blabl\n' - ' on multi lines\n', - 'type': '01. Sort this or that', - 'user': 'student02' - } - ]} - ) - - def feedback_cycle(tutor, stage): - submissions = TutorSubmissionAssignment.objects.available_assignments({ - 'owner': tutor, - 'stage': stage, - 'submission_type': data['submission_types'][0].pk - }) - assignment = TutorSubmissionAssignment.objects.create( - owner=tutor, - stage=stage, - submission=submissions.first().submission - ) - Feedback.objects.update_or_create( - of_submission=assignment.submission, - score=35) - assignment.finish() - - tutor01 = data['tutors'][0] - tutor02 = data['tutors'][1] - reviewer = data['reviewers'][0] - - feedback_cycle(tutor01, TutorSubmissionAssignment.FEEDBACK_CREATION) - feedback_cycle(tutor02, TutorSubmissionAssignment.FEEDBACK_VALIDATION) - - force_authenticate(request, user=reviewer) - cls.response = view(request) - - def test_can_access(self): - self.assertEqual(self.response.status_code, status.HTTP_200_OK) - - def test_get_a_list_of_all_correctos(self): - self.assertEqual(3, len(self.response.data)) - - def test_feedback_created_count_matches_database(self): - def verify_fields(tutor_obj): - t = get_user_model().objects.get(username=tutor_obj['username']) - feedback_created_count = TutorSubmissionAssignment.objects.filter( - is_done=True, - stage=TutorSubmissionAssignment.FEEDBACK_CREATION, # noqa - owner=t - ).count() - return feedback_created_count == tutor_obj['feedback_created'] - - self.assertTrue(all(map(verify_fields, self.response.data))) - - def test_feedback_validated_count_matches_database(self): - def verify_fields(tutor_obj): - t = get_user_model().objects.get(username=tutor_obj['username']) - feedback_validated_cnt = TutorSubmissionAssignment.objects.filter( - is_done=True, - stage=TutorSubmissionAssignment.FEEDBACK_VALIDATION, # noqa - owner=t - ).count() - return feedback_validated_cnt == tutor_obj['feedback_validated'] - - self.assertTrue(all(map(verify_fields, self.response.data))) - - def test_sum_of_done_assignments(self): - self.assertEqual( - sum(obj['feedback_created'] + obj['feedback_validated'] - for obj in self.response.data), - TutorSubmissionAssignment.objects.filter(is_done=True).count() - ) - - -class TutorCreateTests(APITestCase): - - USERNAME = 'some_weird_name' - - @classmethod - def setUpTestData(cls): - cls.factory = APIRequestFactory() - cls.user_factory = GradyUserFactory() - - def setUp(self): - self.reviewer = self.user_factory.make_reviewer() - self.request = self.factory.post(reverse('corrector-list'), - {'username': self.USERNAME}) - self.view = CorrectorApiViewSet.as_view({'post': 'create'}) - - force_authenticate(self.request, user=self.reviewer) - self.response = self.view(self.request, username=self.USERNAME) - - def test_can_access(self): - self.assertEqual(self.response.status_code, status.HTTP_201_CREATED) - - def test_can_create(self): - self.assertEqual(self.USERNAME, - get_user_model().get_tutors().first().username) - - -class TutorDetailViewTests(APITestCase): - - @classmethod - def setUpTestData(cls): - cls.user_factory = GradyUserFactory() - - def setUp(self): - self.tutor = self.user_factory.make_tutor(username='fetterotto') - self.reviewer = self.user_factory.make_reviewer() - self.client = APIClient() - self.client.force_authenticate(user=self.reviewer) - - url = reverse('corrector-detail', kwargs={'pk': str(self.tutor.pk)}) - self.response = self.client.get(url, format='json') - - def test_can_access(self): - self.assertEqual(self.response.status_code, status.HTTP_200_OK) - - def test_can_view_tutor(self): - self.assertEqual(self.response.data['username'], - self.tutor.username) - - -class TutorRegisterTests(APITestCase): - - @classmethod - def setUpTestData(cls): - cls.user_factory = GradyUserFactory() - - def setUp(self): - self.reviewer = self.user_factory.make_reviewer() - self.client = APIClient() - - @override_config(REGISTRATION_PASSWORD='pw') - def test_reviewer_can_activate_tutor(self): - response = self.client.post('/api/corrector/register/', { - 'username': 'hans', - 'password': 'safeandsound', - 'registration_password': 'pw', - }) - - self.assertEqual(status.HTTP_201_CREATED, response.status_code) - - self.client.force_authenticate(self.reviewer) - response = self.client.put('/api/corrector/%s/' % response.data['pk'], { - 'username': 'hans', - 'is_active': True - }) - - self.assertEqual(status.HTTP_200_OK, response.status_code) - - def test_trottle_is_not_active_while_testing(self): - r = self.client.post('/api/corrector/register/', {'username': 'hans'}) - r = self.client.post('/api/corrector/register/', {'username': 'the'}) - r = self.client.post('/api/corrector/register/', {'username': 'brave'}) - r = self.client.post('/api/corrector/register/', {'username': 'fears'}) - r = self.client.post('/api/corrector/register/', {'username': 'spiders'}) - - self.assertNotEqual(status.HTTP_429_TOO_MANY_REQUESTS, r.status_code) diff --git a/grady/core/tests/test_user_account_views.py b/grady/core/tests/test_user_account_views.py deleted file mode 100644 index e64beb3c235e2bfee0ee6be58795befb5f63f6bd..0000000000000000000000000000000000000000 --- a/grady/core/tests/test_user_account_views.py +++ /dev/null @@ -1,170 +0,0 @@ -from rest_framework import status -from rest_framework.test import (APIClient, APITestCase) - -from util.factories import GradyUserFactory, make_exams - - -class TutorReviewerCanChangePasswordTests(APITestCase): - @classmethod - def setUpTestData(cls): - cls.user_factory = GradyUserFactory() - cls.data = { - 'old_password': 'l', - 'new_password': 'chompreviver0.' - } - - def setUp(self): - self.reviewer = self.user_factory.make_reviewer(password='l') - self.tutor1 = self.user_factory.make_tutor(password='l') - self.tutor2 = self.user_factory.make_tutor(password='l') - self.client = APIClient() - - def _change_password(self, changing_user, user_to_change=None, data=None): - if user_to_change is None: - user_to_change = changing_user - if data is None: - data = self.data - - self.client.force_authenticate(user=changing_user) - url = f"/api/user/{user_to_change.pk}/change_password/" - return self.client.patch(url, data=data) - - def test_tutor_needs_to_provide_current_password(self): - res = self._change_password(self.tutor1, - data={'new_password': 'chompreviver0.'}) - self.assertEqual(status.HTTP_401_UNAUTHORIZED, res.status_code) - ret = self.client.login(username=self.tutor1.username, - password='chompreviver0.') - self.assertFalse(ret) - - def test_reviewer_needs_to_provide_current_password_for_self(self): - res = self._change_password(self.reviewer, - data={'new_password': 'chompreviver0.'}) - self.assertEqual(status.HTTP_401_UNAUTHORIZED, res.status_code) - ret = self.client.login(username=self.tutor1.username, - password='chompreviver0.') - self.assertFalse(ret) - - def test_tutor_can_change_own_password(self): - res = self._change_password(self.tutor1) - self.assertEqual(status.HTTP_200_OK, res.status_code) - ret = self.client.login(username=self.tutor1.username, - password='chompreviver0.') - self.assertTrue(ret) - - def test_tutor_cant_change_other_password(self): - res = self._change_password(self.tutor1, self.tutor2) - self.assertEqual(status.HTTP_403_FORBIDDEN, res.status_code) - ret = self.client.login(username=self.tutor2.username, - password='chompreviver0.') - self.assertFalse(ret) - - def test_reviewer_can_change_own_password(self): - res = self._change_password(self.reviewer) - self.assertEqual(status.HTTP_200_OK, res.status_code) - ret = self.client.login(username=self.reviewer.username, - password='chompreviver0.') - self.assertTrue(ret) - - def test_reviewer_can_change_tutor_password(self): - res = self._change_password(self.reviewer, self.tutor1, - data={'new_password': 'chompreviver0.'}) - self.assertEqual(status.HTTP_200_OK, res.status_code) - ret = self.client.login(username=self.tutor1.username, - password='chompreviver0.') - self.assertTrue(ret) - - def test_student_cant_change_password(self): - self.exam = make_exams(exams=[{ - 'module_reference': 'Test Exam 01', - 'total_score': 100, - 'pass_score': 60, - }])[0] - student = self.user_factory.make_student(password='l', exam=self.exam) - res = self._change_password(student) - self.assertEqual(status.HTTP_403_FORBIDDEN, res.status_code) - ret = self.client.login(username=student.username, - password='chompreviver0.') - self.assertFalse(ret) - - def test_reviewer_cannot_revoke_own_access(self): - user_pk = self.reviewer.pk - url = f"/api/user/{user_pk}/change_active/" - data = {'is_active': False} - self.client.force_authenticate(user=self.reviewer) - res = self.client.patch(url, data) - self.assertEqual(status.HTTP_403_FORBIDDEN, res.status_code) - - -class ReviewerCanChangeCorrectorRoleTests(APITestCase): - @classmethod - def setUpTestData(cls): - cls.user_factory = GradyUserFactory() - - def setUp(self): - self.reviewer1 = self.user_factory.make_reviewer() - self.client = APIClient() - - def _set_role(self, new_value, changing_user, user_to_change): - self.client.force_authenticate(user=changing_user) - url = f"/api/user/{user_to_change.pk}/change_role/" - return self.client.patch(url, data={'role': new_value}) - - def _make_reviewer(self, changing_user, user_to_change): - return self._set_role('Reviewer', changing_user, user_to_change) - - def _make_tutor(self, changing_user, user_to_change): - return self._set_role('Tutor', changing_user, user_to_change) - - def test_reviewer_can_promote_tutor_to_reviewer(self): - tutor = self.user_factory.make_tutor() - response = self._make_reviewer(self.reviewer1, tutor) - self.assertEqual(response.status_code, status.HTTP_200_OK) - tutor.refresh_from_db() - self.assertTrue(tutor.is_reviewer()) - - def test_reviewer_can_demote_other_reviewer_to_tutor(self): - reviewer2 = self.user_factory.make_reviewer() - response = self._make_tutor(self.reviewer1, reviewer2) - self.assertEqual(response.status_code, status.HTTP_200_OK) - reviewer2.refresh_from_db() - self.assertFalse(reviewer2.is_reviewer()) - - def test_reviewer_cannot_promote_student_to_reviewer(self): - exam = make_exams(exams=[{ - 'module_reference': 'Test Exam 01', - 'total_score': 100, - 'pass_score': 60, - }])[0] - student = self.user_factory.make_student(exam=exam) - response = self._make_reviewer(self.reviewer1, student) - self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) - - def test_reviewer_cannot_promote_student_to_tutor(self): - exam = make_exams(exams=[{ - 'module_reference': 'Test Exam 01', - 'total_score': 100, - 'pass_score': 60, - }])[0] - student = self.user_factory.make_student(exam=exam) - response = self._make_tutor(self.reviewer1, student) - self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) - - def test_student_cannot_change_access_rights(self): - exam = make_exams(exams=[{ - 'module_reference': 'Test Exam 01', - 'total_score': 100, - 'pass_score': 60, - }])[0] - student = self.user_factory.make_student(exam=exam) - response = self._make_reviewer(student, self.reviewer1) - self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) - - def test_tutor_cannot_change_access_rights(self): - tutor = self.user_factory.make_tutor() - response = self._make_reviewer(tutor, self.reviewer1) - self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) - - def test_reviewer_cannot_demote_self_to_tutor(self): - response = self._make_tutor(self.reviewer1, self.reviewer1) - self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) diff --git a/grady/core/urls.py b/grady/core/urls.py deleted file mode 100644 index ecceb7f59eaa02a368c5f1a13f9ca0ed064a8aa9..0000000000000000000000000000000000000000 --- a/grady/core/urls.py +++ /dev/null @@ -1,63 +0,0 @@ -from django.urls import path, re_path -from drf_yasg.views import get_schema_view -from drf_yasg import openapi -from rest_framework.routers import DefaultRouter -from rest_framework.permissions import AllowAny - -from core import views - -# Create a router and register our viewsets with it. - -router = DefaultRouter() -router.register('student', views.StudentReviewerApiViewSet, - basename='student') -router.register('examtype', views.ExamApiViewSet, basename='examtype') -router.register('feedback', views.FeedbackApiView, basename='feedback') -router.register('feedback-comment', views.FeedbackCommentApiView, basename='feedback-comment') -router.register('submission', views.SubmissionViewSet, - basename='submission') -router.register('submissiontype', views.SubmissionTypeApiView, basename='submissiontype') -router.register('corrector', views.CorrectorApiViewSet, basename='corrector') -router.register('assignment', views.AssignmentApiViewSet, basename='assignment') -router.register('statistics', views.StatisticsEndpoint, basename='statistics') -router.register('user', views.UserAccountViewSet, basename='user') -router.register('label', views.LabelApiViewSet, basename='label') -router.register('label-statistics', views.LabelStatistics, basename='label-statistics') -router.register('solution-comment', views.SolutionCommentApiViewSet, basename='solution-comment') -router.register('group', views.GroupApiViewSet, basename='group') -router.register('config', views.InstanceConfigurationViewSet, basename='config') - -schema_view = get_schema_view( - openapi.Info( - title="Grady API", - default_version='v1', - description="Blub", - ), - # validators=['flex', 'ssv'], - public=True, - permission_classes=(AllowAny,), -) - -# regular views that are not viewsets -regular_views_urlpatterns = [ - path('student-page/', - views.StudentSelfApiView.as_view(), - name='student-page'), - path('student-submissions/', - views.StudentSelfSubmissionsApiView.as_view(), - name='student-submissions'), - path('instance/export/', views.InstanceExport.as_view(), name="instance-export"), - path('export/json/', views.StudentJSONExport.as_view(), name='export-json'), - path('import/', views.ImportApiViewSet.as_view(), name='import-json'), - re_path(r'swagger(?P<format>\.json|\.yaml)$', - schema_view.without_ui(cache_timeout=0), name='schema-json'), - re_path(r'swagger/$', schema_view.with_ui('swagger', cache_timeout=0), - name='schema-swagger-ui'), - re_path(r'redoc/$', schema_view.with_ui('redoc', cache_timeout=0), - name='schema-redoc'), -] - -urlpatterns = [ - *router.urls, - *regular_views_urlpatterns, -] diff --git a/grady/core/views/__init__.py b/grady/core/views/__init__.py deleted file mode 100644 index 1073d2170a1a39dd559cc480b6f11e41921f8f01..0000000000000000000000000000000000000000 --- a/grady/core/views/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -from .feedback import FeedbackApiView, FeedbackCommentApiView # noqa -from .assignment import AssignmentApiViewSet # noqa -from .common_views import * # noqa -from .export import StudentJSONExport, InstanceExport # noqa -from .label import LabelApiViewSet, LabelStatistics # noqa -from .importer import ImportApiViewSet # noqa -from .group import GroupApiViewSet # noqa diff --git a/grady/core/views/assignment.py b/grady/core/views/assignment.py deleted file mode 100644 index 1182d7b946062f93b955a133071f8b610793f183..0000000000000000000000000000000000000000 --- a/grady/core/views/assignment.py +++ /dev/null @@ -1,126 +0,0 @@ -import logging - -from rest_framework import mixins, status, viewsets -from rest_framework import decorators -from rest_framework.exceptions import PermissionDenied -from rest_framework.response import Response - -from core import models, serializers -from core.models import TutorSubmissionAssignment -from core.permissions import IsReviewer, IsTutorOrReviewer -from core.serializers import AssignmentDetailSerializer, AssignmentSerializer - -from multiprocessing import Lock - -from core.views.util import tutor_attempts_to_patch_first_feedback_final - -log = logging.getLogger(__name__) - - -class AssignmentApiViewSet( - mixins.RetrieveModelMixin, - mixins.ListModelMixin, - viewsets.GenericViewSet): - serializer_class = AssignmentSerializer - permission_classes = (IsTutorOrReviewer, ) - - def get_queryset(self): - base_queryset = TutorSubmissionAssignment.objects.all() - if self.action in ['list', 'active', 'destroy']: - return base_queryset.all() - else: - return base_queryset.filter(owner=self.request.user) - - def _fetch_assignment(self, serializer): - try: - serializer.save() - except models.SubmissionTypeDepleted as err: - return Response({'Error': str(err)}, - status=status.HTTP_404_NOT_FOUND) - except models.NotMoreThanTwoOpenAssignmentsAllowed as err: - return Response({'Error': str(err)}, - status=status.HTTP_403_FORBIDDEN) - return Response(serializer.data, status=status.HTTP_201_CREATED) - - @decorators.permission_classes((IsReviewer,)) - def list(self, *args, **kwargs): - return super().list(*args, **kwargs) - - @decorators.action(detail=False, permission_classes=(IsReviewer,), methods=['get', 'delete']) - def active(self, request): - if request.method == 'GET': - queryset = self.get_queryset().filter(is_done=False) - serializer = self.get_serializer(queryset, many=True) - return Response(serializer.data) - else: - self.get_queryset().filter(is_done=False).delete() - return Response(status=status.HTTP_204_NO_CONTENT) - - @decorators.action(detail=False, permission_classes=(IsTutorOrReviewer,), methods=['delete']) - def release(self, request): - self.get_queryset().filter( - is_done=False - ).delete() - return Response(status=status.HTTP_204_NO_CONTENT) - - @decorators.action(detail=True, methods=['post']) - def finish(self, request, *args, **kwargs): - context = self.get_serializer_context() - instance = self.get_object() - if instance.is_done or (instance.owner != request.user): - return Response(status=status.HTTP_403_FORBIDDEN) - try: - orig_feedback = instance.submission.feedback - serializer = serializers.FeedbackSerializer( - orig_feedback, - data=request.data, - context=context, - partial=True) - if orig_feedback.final_by_reviewer and request.user.role == models.UserAccount.TUTOR: - raise PermissionDenied(detail="Unfortunately you won't be able to finish this" - "assignment since a reviewer has marked it as " - "final while you were assigned.") - except models.Feedback.DoesNotExist: - serializer = serializers.FeedbackSerializer( - data=request.data, - context=context) - - serializer.is_valid(raise_exception=True) - if tutor_attempts_to_patch_first_feedback_final(serializer, self.request.user, instance): - raise PermissionDenied( - detail='Cannot set the first feedback final.') - serializer.save() - instance.finish() - response_status = status.HTTP_201_CREATED if \ - instance.stage == \ - models.TutorSubmissionAssignment.FEEDBACK_CREATION else status.HTTP_200_OK - return Response(serializer.data, status=response_status) - - def destroy(self, request, pk=None): - """ Stop working on the assignment before it is finished """ - instance = self.get_object() - - if instance.is_done or (instance.owner != request.user and - not request.user.is_reviewer()): - return Response(status=status.HTTP_403_FORBIDDEN) - - instance.delete() - return Response(status=status.HTTP_204_NO_CONTENT) - - def create(self, request, *args, **kwargs): - with Lock(): - context = self.get_serializer_context() - data = request.data - serializer = AssignmentDetailSerializer(data=data, - context=context) - serializer.is_valid(raise_exception=True) - assignment = self._fetch_assignment(serializer) - - return assignment - - def retrieve(self, request, *args, **kwargs): - assignment = self.get_object() - if assignment.owner != request.user: - return Response(status=status.HTTP_403_FORBIDDEN) - serializer = AssignmentDetailSerializer(assignment) - return Response(serializer.data) diff --git a/grady/core/views/common_views.py b/grady/core/views/common_views.py deleted file mode 100644 index 237b394e4bc0b5a5750732c876472e63cdfffeb7..0000000000000000000000000000000000000000 --- a/grady/core/views/common_views.py +++ /dev/null @@ -1,434 +0,0 @@ -""" All API views that are used to retrieve data from the database. They -can be categorized by the permissions they require. All views require a -user to be authenticated and most are only accessible by one user group """ -import logging - -import os - -import constance -import django.contrib.auth.password_validation as validators -import nbformat -from django.conf import settings -from django.contrib.auth.hashers import check_password -from django.core import exceptions -from django.db.models import Avg -from nbconvert import HTMLExporter -from rest_framework import generics, mixins, status, viewsets -from rest_framework.decorators import (throttle_classes, - action) -from rest_framework.exceptions import PermissionDenied -from rest_framework.permissions import AllowAny -from rest_framework.response import Response -from rest_framework.throttling import AnonRateThrottle - -from core import models -from core.models import (ExamType, StudentInfo, - SubmissionType, TutorSubmissionAssignment, Group) -from core.permissions import IsReviewer, IsStudent, IsTutorOrReviewer, SolutionsEnabledToStudents -from core.serializers import (ExamSerializer, StudentInfoSerializer, - StudentInfoForListViewSerializer, - StudentSubmissionWithSolutionSerializer, - SubmissionNoTypeSerializer, StudentSubmissionSerializer, - SubmissionTypeSerializer, CorrectorSerializer, - UserAccountSerializer, SolutionCommentSerializer, - SubmissionNoTypeWithStudentSerializer) - -log = logging.getLogger(__name__) -config = constance.config - - -class StudentSelfApiView(generics.RetrieveAPIView): - """ Gets all data that belongs to one student """ - permission_classes = (IsStudent,) - serializer_class = StudentInfoSerializer - - def get_object(self) -> StudentInfo: - """ The object in question is the student associated with the requests - user. Since the permission IsStudent is satisfied the member exists """ - if self.request.user.is_superuser: - return StudentInfo.objects.last() - return self.request.user.student - - -class StudentSelfSubmissionsApiView(generics.ListAPIView): - permission_classes = (IsStudent,) - - def get_serializer_class(self): - if config.SHOW_SOLUTION_TO_STUDENTS: - return StudentSubmissionWithSolutionSerializer - - return StudentSubmissionSerializer - - def get_queryset(self): - return self.request.user.student.submissions - - -class StudentReviewerApiViewSet(viewsets.ReadOnlyModelViewSet): - """ Gets a list of all students without individual submissions """ - permission_classes = (IsTutorOrReviewer,) - serializer_class = StudentInfoForListViewSerializer - - def get_queryset(self): - queryset = StudentInfo.objects \ - .select_related('user') \ - .prefetch_related('submissions') \ - .prefetch_related('submissions__feedback') \ - .prefetch_related('submissions__type') \ - .all() - - if self.request.user.is_reviewer(): - return queryset - - elif self.request.user.is_tutor() and config.EXERCISE_MODE: - return queryset.filter( - user__exercise_groups__in=self.request.user.exercise_groups.all() - ) - - else: - return [] - - def _set_students_active(self, active): - for student in self.get_queryset(): - user = student.user - user.is_active = active - user.save() - - @action(detail=False, methods=['post'], permission_classes=(IsReviewer,)) - def deactivate(self, request): - self._set_students_active(False) - return Response(status=status.HTTP_200_OK) - - @action(detail=False, methods=['post'], permission_classes=(IsReviewer,)) - def activate(self, request): - self._set_students_active(True) - return Response(status=status.HTTP_200_OK) - - -class ExamApiViewSet(viewsets.ReadOnlyModelViewSet): - """ Gets a list of an individual exam by Id if provided """ - queryset = ExamType.objects.all() - serializer_class = ExamSerializer - - -class CorrectorApiViewSet( - mixins.RetrieveModelMixin, - mixins.UpdateModelMixin, - mixins.CreateModelMixin, - mixins.DestroyModelMixin, - mixins.ListModelMixin, - viewsets.GenericViewSet): - """ Api endpoint for creating, listing, viewing or deleting tutors """ - permission_classes = (IsReviewer,) - queryset = models.UserAccount.corrector \ - .with_feedback_count() \ - .prefetch_related('assignments') - serializer_class = CorrectorSerializer - - @action(detail=False, methods=['post'], permission_classes=[AllowAny]) - @throttle_classes([AnonRateThrottle]) - def register(self, request): - serializer = self.get_serializer(data=request.data) - serializer.is_valid(raise_exception=True) - - if serializer.validated_data.get('is_active', False): - raise PermissionDenied(detail='Cannot be created active') - - registration_password = request.data.get('registration_password', None) - if registration_password is None or registration_password != config.REGISTRATION_PASSWORD: - raise PermissionDenied(detail='Invalid registration password') - - serializer.save() - return Response(serializer.data, status=status.HTTP_201_CREATED) - - -class SubmissionTypeApiView(viewsets.ReadOnlyModelViewSet): - """ Gets a list or a detail view of a single SubmissionType """ - queryset = SubmissionType.objects.all() - serializer_class = SubmissionTypeSerializer - permission_classes = [IsTutorOrReviewer | SolutionsEnabledToStudents] - - @action(detail=False) - def available(self, request, *args, **kwargs): - """ - GET Endpoint to fetch available counts for SubmissionTypes. Can be queried - by group using the ?group query_parameter - - :return: Response with dictionary that contains available counts for each SubmissionType - """ - - group_param = request.query_params.get('group', None) - group = Group.objects.filter(pk=group_param).first() - sub_types = self.get_queryset() - res = {} - for sub_type in sub_types: - counts_for_type = {} - for stage, _ in models.TutorSubmissionAssignment.stages: - counts_in_stage = TutorSubmissionAssignment.objects.available_assignments({ - 'stage': stage, - 'submission_type': sub_type.pk, - 'owner': self.request.user, - 'group': None if not group else group.pk - }).count() - counts_for_type[str(stage)] = counts_in_stage - res[str(sub_type.pk)] = counts_for_type - - return Response(res) - - -class SolutionCommentApiViewSet( - mixins.CreateModelMixin, - mixins.UpdateModelMixin, - mixins.DestroyModelMixin, - viewsets.GenericViewSet): - permission_classes = (IsTutorOrReviewer,) - queryset = models.SolutionComment.objects.all() - serializer_class = SolutionCommentSerializer - - def destroy(self, request, *args, **kwargs): - instance = self.get_object() - if not request.user.is_reviewer() and instance.of_user != request.user: - raise PermissionDenied(detail="You can only delete comments you made") - self.perform_destroy(instance) - return Response(status=status.HTTP_204_NO_CONTENT) - - def update(self, request, *args, **kwargs): - instance = self.get_object() - if instance.of_user != request.user: - raise PermissionDenied(detail="You can only update comments you made") - return super().update(request, *args, **kwargs) - - -class StatisticsEndpoint(viewsets.ViewSet): - permission_classes = (IsTutorOrReviewer,) - - def retrieve(self, request, pk=None): - first_sub_type = models.SubmissionType.objects.filter(exam_type_id=pk).first() - - return Response({ - 'submissions_per_type': - first_sub_type.submissions.count() if first_sub_type is not None else 0, - - 'submissions_per_student': - models.SubmissionType.objects.filter(exam_type_id=pk).count(), - - 'current_mean_score': - models.Feedback.objects.filter(of_submission__type__exam_type_id=pk).aggregate - (avg=Avg('score')).get('avg', 0), - - 'submission_type_progress': - # Queryset is explicitly evaluated so camelizer plugin camelizes it - list(models.SubmissionType.get_annotated_feedback_count().filter( - exam_type_id=pk).values( - 'pk', - 'name', - 'submission_count', - 'feedback_final', - 'feedback_in_validation', - 'feedback_in_conflict')) - }) - - -class SubmissionViewSet(viewsets.ReadOnlyModelViewSet): - permission_classes = (IsTutorOrReviewer,) - - def get_serializer_class(self): - if self.request.user.is_reviewer() or config.EXERCISE_MODE: - # this contains student fullname - # in most cases a pseudonym, but useful for - # tracking students across views in the frontend - return SubmissionNoTypeWithStudentSerializer - return SubmissionNoTypeSerializer - - def get_queryset(self): - base_queryset = models.Submission.objects \ - .select_related('type') \ - .select_related('feedback') \ - .prefetch_related('tests') \ - .prefetch_related('feedback__feedback_lines') \ - .prefetch_related('feedback__feedback_lines__of_tutor') \ - .all() - - if self.request.user.is_reviewer() \ - or (self.request.user.is_tutor() and config.EXERCISE_MODE): - return base_queryset - elif self.request.user.is_student(): - return base_queryset.filter( - student__user=self.request.user - ) - else: - return base_queryset.filter( - assignments__owner=self.request.user - ) - - @action(detail=True, ) - def source_code(self, request, *args, **kwargs): - submission = self.get_object() - if submission.source_code_available: - return Response(data={'source_code': submission.source_code}) - return Response(status=status.HTTP_404_NOT_FOUND) - - @action(detail=True, permission_classes=(IsStudent,)) - def html(self, request, *args, **kwargs): - submission = self.get_object() - if submission.type.programming_language == models.SubmissionType.PYTHON and \ - submission.source_code_available: - notebook = nbformat.reads(submission.source_code, as_version=4) - html_exporter = HTMLExporter() - body, _ = html_exporter.from_notebook_node(notebook) - return Response(body, content_type='text/html') - return Response(status=status.HTTP_404_NOT_FOUND) - - -class UserAccountViewSet(viewsets.ReadOnlyModelViewSet): - serializer_class = UserAccountSerializer - queryset = models.UserAccount.objects.all() - - @action(detail=True, methods=['patch'], permission_classes=(IsTutorOrReviewer,)) - def change_password(self, request, *args, **kwargs): - user = self.get_object() - if request.user != user and not request.user.is_reviewer(): - return Response(status=status.HTTP_403_FORBIDDEN) - old_password = request.data.get('old_password') - - # tutors must always provide their current password - # reviewers must provide their current password when they change - # their own, not if they change the password of a tutor - if (request.user.is_tutor() or - request.user.is_reviewer and request.user == user) \ - and \ - (old_password is None or - not check_password(old_password, user.password)): - return Response(status=status.HTTP_401_UNAUTHORIZED) - - new_password = request.data.get('new_password') - # validate password - try: - if new_password is not None: - validators.validate_password(password=new_password, user=user) - except exceptions.ValidationError as err: - return Response({'new_password': list(err.messages)}, - status=status.HTTP_406_NOT_ACCEPTABLE) - user.set_password(new_password) - user.save() - log.info(f"User {request.user} changed password of {user}") - return Response(status=status.HTTP_200_OK) - - @action(detail=True, methods=['patch']) - def change_active(self, request, *args, **kwargs): - active = request.data.get('is_active') - req_user = request.user - user = self.get_object() - if active is None: - error_msg = "You need to provide an 'active' field" - return Response({'Error': error_msg}, status.HTTP_400_BAD_REQUEST) - if req_user.is_reviewer() and req_user == user: - error_msg = "As a reviewer, you cannot revoke your own access." - return Response({'Error': error_msg}, status.HTTP_403_FORBIDDEN) - if (req_user.is_student() or req_user.is_tutor()) and req_user != user: - return Response(status.HTTP_403_FORBIDDEN) - user.is_active = active - user.save() - return Response(status.HTTP_200_OK) - - @action(detail=True, methods=['patch'], permission_classes=(IsReviewer,)) - def change_groups(self, request, *args, **kwargs): - # for some reason only the newly added groups come as a group object - groups = [x.get('pk') if type(x) is not str else x for x in request.data] - req_user = request.user - user = self.get_object() - if groups is None: - error_msg = "You need to provide an 'groups' field" - return Response({'Error': error_msg}, status.HTTP_400_BAD_REQUEST) - if req_user.is_student() or req_user.is_tutor(): - return Response(status.HTTP_403_FORBIDDEN) - user.set_groups(groups) - user.save() - return Response(status.HTTP_200_OK) - - @action(detail=True) - def get_groups(self, request, *args, **kwargs): - req_user = request.user - if req_user.is_student() or req_user.is_tutor(): - return Response(status.HTTP_403_FORBIDDEN) - user = self.get_object() - return Response(user.exercise_groups, status=status.HTTP_200_OK) - - @action(detail=True, methods=["patch"]) - def change_role(self, request, *args, **kwargs): - new_role = request.data.get('role') - user = self.get_object() - valid_values = [ - models.UserAccount.STUDENT, - models.UserAccount.REVIEWER, - models.UserAccount.TUTOR, - ] - if new_role not in valid_values: - error_msg = ( - "You need to provide a 'role' field with one of these values: " - + ', '.join(valid_values) - ) - return Response({'Error': error_msg}, status.HTTP_400_BAD_REQUEST) - if not request.user.is_reviewer(): - error_msg = 'Only reviewers can manage access rights.' - return Response({'Error': error_msg}, status.HTTP_403_FORBIDDEN) - if user.is_student(): - error_msg = 'Cannot promote a student to another role.' - return Response({'Error': error_msg}, status.HTTP_403_FORBIDDEN) - if user == request.user and not new_role == models.UserAccount.REVIEWER: - error_msg = 'As a reviewer, you cannot demote yourself.' - return Response({'Error': error_msg}, status.HTTP_403_FORBIDDEN) - user.role = new_role - user.save() - return Response(status.HTTP_200_OK) - - @action(detail=False) - def me(self, request): - serializer = self.get_serializer(request.user) - return Response(serializer.data, status=status.HTTP_200_OK) - - -class InstanceConfigurationViewSet(viewsets.ViewSet): - @action(detail=False, methods=['patch']) - def change_config(self, request): - """ - PATCH Endpoint to modify constance settings. Requires reviewer permissions. - - :return: Response with dictionary of all modified constance fields. - """ - if not self.request.user.is_reviewer(): - return Response(status=status.HTTP_403_FORBIDDEN) - - res = {} - for key in request.data: - - # capitalize key and check if it is a valid constance entry - caps_key = key.upper() - if getattr(config, caps_key, None) is None: - return Response( - f"{key} is not a valid setting.", - status=status.HTTP_409_CONFLICT - ) - - val = request.data[key] - setattr(config, caps_key, val) - res[key] = val - - return Response(res, status=status.HTTP_206_PARTIAL_CONTENT) - - def list(self, request): - """ - GET Endpoint to list constance settings as well as additional config values. - Constance settings will be supplied in the "instance_settings" field. - - :return: Response with dictionary of all settings and config values. - """ - - # construct constance data, lowercase the key so that it is correctly camel-cased - settings_dict = {key.lower(): getattr(config, key) for key in dir(config)} - res = { - 'timeDelta': settings.JWT_AUTH['JWT_EXPIRATION_DELTA'].seconds * 1000, - 'version': os.environ.get('VERSION'), - 'instanceSettings': settings_dict, - } - - return Response(res, status=status.HTTP_200_OK) diff --git a/grady/core/views/export.py b/grady/core/views/export.py deleted file mode 100644 index 7a02c8e2a1b77e523c40ab40965d9a3cb97cc520..0000000000000000000000000000000000000000 --- a/grady/core/views/export.py +++ /dev/null @@ -1,79 +0,0 @@ -from django.db import transaction - -from rest_framework.response import Response -from rest_framework.views import APIView - -import xkcdpass.xkcd_password as xp - -from core.models import StudentInfo, UserAccount, ExamType, SubmissionType -from core.permissions import IsReviewer -from core.serializers import SubmissionTypeSerializer, \ - ExamSerializer, UserAccountSerializer -from core.serializers.student import StudentExportSerializer, ExamInfoSerializer -from core.serializers.tutor import CorrectorSerializer - -words = xp.generate_wordlist(wordfile=xp.locate_wordfile(), min_length=5, max_length=8) - - -@transaction.atomic -def _set_student_passwords(): - student_password_dict = {} - # TODO use bulk update with django makepassword function - for student in UserAccount.get_students(): - password = xp.generate_xkcdpassword(words, numwords=3, delimiter='-') - student.set_password(password) - student.save() - student_password_dict[student.pk] = password - - return student_password_dict - - -class StudentJSONExport(APIView): - permission_classes = (IsReviewer,) - - def post(self, request, format=None): - set_passwords = request.data.get('set_passwords') - passwords = _set_student_passwords() if set_passwords else None - - content = [ - {'Matrikel': student.matrikel_no, - 'Name': student.user.fullname, - 'Username': student.user.username, - 'Email': student.user.email, - 'Exams': ExamInfoSerializer(student.exams.all(), many=True).data, - 'Password': passwords[student.user.pk] if set_passwords else '********', - 'Scores': [ - { - 'exam': exam_info.exam.module_reference, - 'submissions': [ - { - 'type': submission_type, - 'score': score - } for submission_type, score in exam_info.score_per_submission().items()] - } for exam_info in student.exams.all()] - } for student - in StudentInfo.objects.all()] - return Response(content) - - -class InstanceExport(APIView): - permission_classes = (IsReviewer,) - - def get(self, request): - exam_types_serializer = ExamSerializer(ExamType.objects.all(), many=True) - submission_types_serializer = SubmissionTypeSerializer( - SubmissionType.objects.all(), many=True) - tutors_serializer = CorrectorSerializer( - UserAccount.corrector.with_feedback_count(), - many=True) - reviewer_serializer = UserAccountSerializer(UserAccount.get_reviewers(), many=True) - student_serializer = StudentExportSerializer(StudentInfo.objects.all(), many=True) - - content = { - "examTypes": exam_types_serializer.data, - "submissionTypes": submission_types_serializer.data, - "students": student_serializer.data, - "tutors": tutors_serializer.data, - "reviewers": reviewer_serializer.data - } - return Response(content) diff --git a/grady/core/views/feedback.py b/grady/core/views/feedback.py deleted file mode 100644 index 4225c86ae0073a2de74ba01f9d8f5028eaf8c6f6..0000000000000000000000000000000000000000 --- a/grady/core/views/feedback.py +++ /dev/null @@ -1,123 +0,0 @@ -import logging -from multiprocessing import Lock - -import constance -from rest_framework import mixins, status, viewsets -from rest_framework.exceptions import PermissionDenied -from rest_framework.response import Response - -from core import models, permissions, serializers -from core.views.util import tutor_attempts_to_patch_first_feedback_final, \ - get_implicit_assignment_for_user - -log = logging.getLogger(__name__) -config = constance.config - - -class FeedbackApiView( - mixins.CreateModelMixin, - mixins.RetrieveModelMixin, - mixins.ListModelMixin, - viewsets.GenericViewSet): - """ Gets a list of an individual exam by Id if provided """ - permission_classes = (permissions.IsTutorOrReviewer,) - lookup_field = 'of_submission__pk' - lookup_url_kwarg = 'submission_pk' - - def _tutor_attempts_to_change_final_feedback_of_reviewer(self, serializer): - feedback_final_by_reviewer = serializer.instance.final_by_reviewer - user_is_tutor = self.request.user.role == models.UserAccount.TUTOR - return feedback_final_by_reviewer and user_is_tutor - - def _tutor_attempts_to_set_first_feedback_final(self, serializer): - is_final_set = serializer.validated_data.get('is_final', False) - user_is_tutor = self.request.user.role == models.UserAccount.TUTOR - return is_final_set and user_is_tutor - - def get_serializer_class(self): - if config.EXERCISE_MODE: - return serializers.FeedbackWithStudentSerializer - return serializers.FeedbackSerializer - - def get_queryset(self): - base_queryset = models.Feedback.objects \ - .select_related('of_submission') \ - .select_related('of_submission__type') \ - .select_related('of_submission__student') \ - .select_related('of_submission__student__user') \ - .all() - - if self.request.user.is_reviewer(): - return base_queryset \ - .prefetch_related('feedback_lines') \ - .prefetch_related('feedback_lines__of_tutor') \ - .all() - - user_groups = self.request.user.exercise_groups.all() - if self.request.user.is_tutor() and config.EXERCISE_MODE: - return base_queryset.filter( - of_submission__student__user__exercise_groups__in=user_groups - ) - - return base_queryset.filter( - of_submission__assignments__owner=self.request.user - ) - - def create(self, request, *args, **kwargs): - if request.user.is_tutor() and not config.EXERCISE_MODE: - return Response(status=status.HTTP_401_UNAUTHORIZED) - - serializer = self.get_serializer(data=request.data) - serializer.is_valid(raise_exception=True) - self.perform_create(serializer) - - # update MetaSubmission information - meta = serializer.validated_data.get('of_submission').meta - meta.feedback_authors.add(self.request.user) - return Response(serializer.data, - status=status.HTTP_201_CREATED) - - def partial_update(self, request, **kwargs): - feedback = self.get_object() - serializer = self.get_serializer(feedback, data=request.data, - partial=True) - serializer.is_valid(raise_exception=True) - - assignment = get_implicit_assignment_for_user(feedback.of_submission, self.request.user) - - if self._tutor_attempts_to_change_final_feedback_of_reviewer(serializer): # noqa - raise PermissionDenied( - detail="Changing feedback set to final by a reviewer is not allowed.") - - if tutor_attempts_to_patch_first_feedback_final(serializer, self.request.user, assignment): - raise PermissionDenied( - detail='Cannot set the first feedback final.') - serializer.save() - return Response(serializer.data) - - -class FeedbackCommentApiView( - mixins.DestroyModelMixin, - viewsets.GenericViewSet): - """ Gets a list of an individual exam by Id if provided """ - permission_classes = (permissions.IsTutorOrReviewer,) - serializer_class = serializers.FeedbackCommentSerializer - - def get_queryset(self): - base_queryset = models.FeedbackComment.objects.all() - - user = self.request.user - if user.role == models.UserAccount.REVIEWER: - return base_queryset - return base_queryset.filter(of_tutor=user) - - def destroy(self, request, *args, **kwargs): - with Lock(): - instance = self.get_object() - if instance.of_feedback.feedback_lines.count() == 1 and \ - not instance.of_feedback.is_full_score(): - raise PermissionDenied(detail="Last comment can not be deleted for submissions " - "with non full score") - - self.perform_destroy(instance) - return Response(status=status.HTTP_204_NO_CONTENT) diff --git a/grady/core/views/group.py b/grady/core/views/group.py deleted file mode 100644 index e083f26d82bd02673e4a2028c377cb7b19e716a5..0000000000000000000000000000000000000000 --- a/grady/core/views/group.py +++ /dev/null @@ -1,14 +0,0 @@ -import logging - -from rest_framework import mixins, viewsets - -from core import models, permissions, serializers - -log = logging.getLogger(__name__) - - -class GroupApiViewSet(viewsets.GenericViewSet, - mixins.ListModelMixin): - permission_classes = (permissions.IsTutorOrReviewer, ) - queryset = models.Group.objects.all() - serializer_class = serializers.GroupSerializer diff --git a/grady/core/views/importer.py b/grady/core/views/importer.py deleted file mode 100644 index ee5c19756b11d956ea61c9a2f877257f3f92c348..0000000000000000000000000000000000000000 --- a/grady/core/views/importer.py +++ /dev/null @@ -1,25 +0,0 @@ -from rest_framework import status -from rest_framework.response import Response -from rest_framework.views import APIView -from rest_framework.exceptions import ValidationError -from core.permissions import IsReviewer -from util.importer import parse_and_import_hektor_json - - -class ImportApiViewSet(APIView): - permission_classes = (IsReviewer, ) - - def post(self, request): - exam_data = request.data - - if not exam_data: - return Response({"Error": "You need to submit the exam data to be imported"}, - status.HTTP_400_BAD_REQUEST) - - try: - parse_and_import_hektor_json(exam_data) - except ValidationError as err: - return Response({"ValidationError": err.detail}, - status.HTTP_409_CONFLICT) - - return Response({}, status.HTTP_201_CREATED) diff --git a/grady/core/views/label.py b/grady/core/views/label.py deleted file mode 100644 index 152b1cc7c147111b9fe24c2a78d71990edb96d1f..0000000000000000000000000000000000000000 --- a/grady/core/views/label.py +++ /dev/null @@ -1,56 +0,0 @@ -import logging - -from django.db.models import Case, When, IntegerField, Sum, Q - -from rest_framework import mixins, viewsets -from rest_framework.permissions import IsAuthenticated -from rest_framework.response import Response - -from core import models, permissions, serializers -from core.models import SubmissionType, FeedbackLabel - -log = logging.getLogger(__name__) - - -class LabelApiViewSet(viewsets.GenericViewSet, - mixins.CreateModelMixin, - mixins.UpdateModelMixin, - mixins.ListModelMixin): - permission_classes = (permissions.IsTutorOrReviewer, ) - queryset = models.FeedbackLabel.objects.all() - serializer_class = serializers.LabelSerializer - - def get_permissions(self): - if self.action == 'list': - return [IsAuthenticated(), ] - else: - return super().get_permissions() - - -class LabelStatistics(viewsets.ViewSet): - - permission_classes = (permissions.IsTutorOrReviewer, ) - - def list(self, *args, **kwargs): - # TODO This is horribly ugly and should be killed with fire - # however, i'm unsure whether there is a better way to retrieve the - # information that hits the database less often - labels = FeedbackLabel.objects.all() - - counts = list(SubmissionType.objects.annotate( - **{str(label.pk): Sum( - Case( - # if the feedback has a label or there is a visible comment with that - # label add 1 to the count - When( - Q(submissions__feedback__labels=label) | - Q(submissions__feedback__feedback_lines__labels=label) & - Q(submissions__feedback__feedback_lines__visible_to_student=True), - then=1), - output_field=IntegerField(), - default=0 - ) - ) for label in labels} - ).values('pk', *[str(label.pk) for label in labels])) - - return Response(list(counts)) diff --git a/grady/core/views/util.py b/grady/core/views/util.py deleted file mode 100644 index ecb483539bf1764ce472bb624eb6a80f40671cbd..0000000000000000000000000000000000000000 --- a/grady/core/views/util.py +++ /dev/null @@ -1,41 +0,0 @@ -import constance -from rest_framework.exceptions import PermissionDenied - -from core import models - -config = constance.config - - -class NoAssignmentForTutor(Exception): - pass - - -def tutor_attempts_to_patch_first_feedback_final(feedback_serializer, - user, - assignment=None): - # override assignment logic in exercise mode - if user.role == models.UserAccount.REVIEWER \ - or user.role == models.UserAccount.TUTOR and config.EXERCISE_MODE: - return False - if user.role == models.UserAccount.TUTOR and assignment is None: - raise NoAssignmentForTutor() - is_final_set = feedback_serializer.validated_data.get('is_final', False) - in_creation = assignment.stage == models.TutorSubmissionAssignment.FEEDBACK_CREATION # noqa - single_correction = config.SINGLE_CORRECTION - return is_final_set and in_creation and not single_correction - - -def get_implicit_assignment_for_user(submission, user): - """ Check for tutor if it exists. Not relevant for reviewer """ - try: - return models.TutorSubmissionAssignment.objects.get( - owner=user, - submission=submission - ) - except models.TutorSubmissionAssignment.DoesNotExist: - if user.role == models.UserAccount.REVIEWER \ - or (user.role == models.UserAccount.TUTOR and config.EXERCISE_MODE): - return None - - raise PermissionDenied( - detail='This user has no permission to create this feedback') diff --git a/grady/deploy.sh b/grady/deploy.sh deleted file mode 100755 index c4043783f9d55164d8f729ad024bf224b1679e51..0000000000000000000000000000000000000000 --- a/grady/deploy.sh +++ /dev/null @@ -1,13 +0,0 @@ -#!/bin/sh -sleep 5 -python manage.py migrate --noinput -if [ "$?" -ne "0" ]; then - exit 1 -fi -gunicorn \ - --bind 0.0.0.0:8000 \ - --workers=5 \ - --timeout=120 \ - --worker-class=sync \ - --log-level debug \ - grady.wsgi:application diff --git a/grady/docker-compose.yml b/grady/docker-compose.yml deleted file mode 100644 index 563b5f04c0fd4c483d699a42424690adaf19ae14..0000000000000000000000000000000000000000 --- a/grady/docker-compose.yml +++ /dev/null @@ -1,27 +0,0 @@ -version: '3' - -services: - - postgres: - image: postgres:13 - restart: always - networks: - - default - ports: - - 6543:5432 - - grady: - build: . - command: > - sh -c "sleep 2 && - ./manage.py migrate --noinput && - ./deploy.sh" - depends_on: - - postgres - restart: always - networks: - - default - expose: - - "8000" - ports: - - "8000:8000" diff --git a/grady/docs/Database Design/Entity Relation Model.erdplus b/grady/docs/Database Design/Entity Relation Model.erdplus deleted file mode 100644 index eee0a47bf3f01b39930979ea6d9bd00fecf7c58d..0000000000000000000000000000000000000000 --- a/grady/docs/Database Design/Entity Relation Model.erdplus +++ /dev/null @@ -1 +0,0 @@ -{"version":2,"www":"erdplus.com","shapes":[{"type":"Entity","details":{"name":"Student","type":"regular","x":634,"y":250,"id":1}},{"type":"Attribute","details":{"name":"Matrikel #","isDerived":false,"isMultivalued":false,"isOptional":false,"isComposite":false,"isUnique":true,"x":525,"y":177,"id":2}},{"type":"Attribute","details":{"name":"Anonymous Key","isDerived":false,"isMultivalued":false,"isOptional":false,"isComposite":false,"isUnique":false,"x":635,"y":178,"id":4}},{"type":"Attribute","details":{"name":"One Time Passwords","isDerived":false,"isMultivalued":true,"isOptional":false,"isComposite":false,"isUnique":false,"x":748,"y":182,"id":6}},{"type":"Entity","details":{"name":"Aufgaben Typ","type":"regular","x":278,"y":480,"id":8}},{"type":"Attribute","details":{"name":"ID","isDerived":false,"isMultivalued":false,"isOptional":false,"isComposite":false,"isUnique":true,"x":137,"y":550,"id":9}},{"type":"Attribute","details":{"name":"Korrekturvorgabe","isDerived":false,"isMultivalued":false,"isOptional":false,"isComposite":false,"isUnique":false,"x":136,"y":493,"id":11}},{"type":"Attribute","details":{"name":"Name","isDerived":false,"isMultivalued":false,"isOptional":false,"isComposite":false,"isUnique":false,"x":136,"y":433,"id":13}},{"type":"Attribute","details":{"name":"Musterlösung","isDerived":false,"isMultivalued":false,"isOptional":true,"isComposite":false,"isUnique":false,"x":137,"y":371,"id":24}},{"type":"Entity","details":{"name":"Aufgabe","type":"weak","x":634,"y":478,"id":26}},{"type":"Attribute","details":{"name":"Anonymous Key","isDerived":true,"isMultivalued":false,"isOptional":false,"isComposite":false,"isUnique":true,"x":741,"y":368,"id":27}},{"type":"Attribute","details":{"name":"Vorkorrektur","isDerived":false,"isMultivalued":false,"isOptional":false,"isComposite":false,"isUnique":false,"x":808,"y":416,"id":31}},{"type":"Relationship","details":{"name":"hat Typ","isIdentifying":false,"x":449,"y":480,"slots":[{"slotIndex":0,"minimum":"0","maximum":"n","participation":"unspecified","cardinality":"unspecified","role":"","entityId":26},{"slotIndex":1,"minimum":"1","maximum":"1","participation":"unspecified","cardinality":"unspecified","role":"","entityId":8}],"id":35}},{"type":"Relationship","details":{"name":"Abgabe","isIdentifying":true,"x":635,"y":360,"slots":[{"slotIndex":0,"minimum":"1","maximum":"1","participation":"unspecified","cardinality":"unspecified","role":"","entityId":1},{"slotIndex":1,"minimum":"0","maximum":"n","participation":"unspecified","cardinality":"unspecified","role":"","entityId":26}],"id":40}},{"type":"Entity","details":{"name":"Feedback","type":"weak","x":634,"y":761,"id":43}},{"type":"Attribute","details":{"name":"Punkte","isDerived":false,"isMultivalued":false,"isOptional":false,"isComposite":false,"isUnique":false,"x":500,"y":720,"id":44}},{"type":"Attribute","details":{"name":"Text","isDerived":false,"isMultivalued":false,"isOptional":false,"isComposite":false,"isUnique":false,"x":501,"y":779,"id":46}},{"type":"Relationship","details":{"name":"bewertet","isIdentifying":true,"x":634,"y":632,"slots":[{"slotIndex":0,"minimum":"1","maximum":"1","participation":"unspecified","cardinality":"unspecified","role":"","entityId":26},{"slotIndex":1,"minimum":"0","maximum":"n","participation":"unspecified","cardinality":"unspecified","role":"","entityId":43}],"id":48}},{"type":"Entity","details":{"name":"Tutor","type":"regular","x":1063,"y":585,"id":51}},{"type":"Attribute","details":{"name":"Name","isDerived":false,"isMultivalued":false,"isOptional":false,"isComposite":false,"isUnique":false,"x":1173,"y":530,"id":52}},{"type":"Attribute","details":{"name":"Benutzername","isDerived":false,"isMultivalued":false,"isOptional":false,"isComposite":false,"isUnique":true,"x":1177,"y":588,"id":54}},{"type":"Attribute","details":{"name":"Passwort","isDerived":false,"isMultivalued":false,"isOptional":false,"isComposite":false,"isUnique":false,"x":1182,"y":647,"id":56}},{"type":"Relationship","details":{"name":"erstellt","isIdentifying":false,"x":892,"y":704,"slots":[{"slotIndex":0,"minimum":"0","maximum":"n","participation":"unspecified","cardinality":"unspecified","role":"","entityId":43},{"slotIndex":1,"minimum":"1","maximum":"1","participation":"unspecified","cardinality":"unspecified","role":"","entityId":51}],"id":58}},{"type":"Relationship","details":{"name":"korrigiert","isIdentifying":false,"x":884,"y":474,"slots":[{"slotIndex":0,"minimum":"0","maximum":"n","participation":"unspecified","cardinality":"unspecified","role":"","entityId":26},{"slotIndex":1,"minimum":"0","maximum":"m","participation":"unspecified","cardinality":"unspecified","role":"","entityId":51}],"id":62}},{"type":"Entity","details":{"name":"Dozent","type":"regular","x":1064,"y":862,"id":69}},{"type":"Attribute","details":{"name":"Name","isDerived":false,"isMultivalued":false,"isOptional":false,"isComposite":false,"isUnique":false,"x":1174,"y":806,"id":70}},{"type":"Attribute","details":{"name":"Benutzername","isDerived":false,"isMultivalued":false,"isOptional":false,"isComposite":false,"isUnique":true,"x":1172,"y":860,"id":72}},{"type":"Attribute","details":{"name":"Password","isDerived":false,"isMultivalued":false,"isOptional":false,"isComposite":false,"isUnique":false,"x":1172,"y":916,"id":74}},{"type":"Relationship","details":{"name":"überprüft","isIdentifying":false,"x":890,"y":862,"slots":[{"slotIndex":0,"minimum":"0","maximum":"n","participation":"unspecified","cardinality":"unspecified","role":"","entityId":43},{"slotIndex":1,"minimum":"0","maximum":"m","participation":"unspecified","cardinality":"unspecified","role":"","entityId":69}],"id":78}},{"type":"Attribute","details":{"name":"Anonymus Key","isDerived":true,"isMultivalued":false,"isOptional":false,"isComposite":false,"isUnique":true,"x":504,"y":838,"id":82}}],"connectors":[{"type":"Connector","details":{"id":3},"source":2,"destination":1},{"type":"Connector","details":{"id":5},"source":4,"destination":1},{"type":"Connector","details":{"id":7},"source":6,"destination":1},{"type":"Connector","details":{"id":10},"source":9,"destination":8},{"type":"Connector","details":{"id":12},"source":11,"destination":8},{"type":"Connector","details":{"id":14},"source":13,"destination":8},{"type":"Connector","details":{"id":25},"source":24,"destination":8},{"type":"Connector","details":{"id":28},"source":27,"destination":26},{"type":"Connector","details":{"id":32},"source":31,"destination":26},{"type":"RelationshipConnector","details":{"slotIndex":0,"id":38},"source":26,"destination":35},{"type":"RelationshipConnector","details":{"slotIndex":1,"id":39},"source":8,"destination":35},{"type":"RelationshipConnector","details":{"slotIndex":0,"id":41},"source":1,"destination":40},{"type":"RelationshipConnector","details":{"slotIndex":1,"id":42},"source":26,"destination":40},{"type":"Connector","details":{"id":45},"source":44,"destination":43},{"type":"Connector","details":{"id":47},"source":46,"destination":43},{"type":"RelationshipConnector","details":{"slotIndex":0,"id":49},"source":26,"destination":48},{"type":"RelationshipConnector","details":{"slotIndex":1,"id":50},"source":43,"destination":48},{"type":"Connector","details":{"id":53},"source":52,"destination":51},{"type":"Connector","details":{"id":55},"source":54,"destination":51},{"type":"Connector","details":{"id":57},"source":56,"destination":51},{"type":"RelationshipConnector","details":{"slotIndex":0,"id":60},"source":43,"destination":58},{"type":"RelationshipConnector","details":{"slotIndex":1,"id":61},"source":51,"destination":58},{"type":"RelationshipConnector","details":{"slotIndex":0,"id":64},"source":26,"destination":62},{"type":"RelationshipConnector","details":{"slotIndex":1,"id":66},"source":51,"destination":62},{"type":"Connector","details":{"id":71},"source":70,"destination":69},{"type":"Connector","details":{"id":73},"source":72,"destination":69},{"type":"Connector","details":{"id":75},"source":74,"destination":69},{"type":"RelationshipConnector","details":{"slotIndex":0,"id":79},"source":43,"destination":78},{"type":"RelationshipConnector","details":{"slotIndex":1,"id":80},"source":69,"destination":78},{"type":"Connector","details":{"id":83},"source":82,"destination":43}],"width":2000,"height":1000} \ No newline at end of file diff --git a/grady/docs/Database Design/Relational Schema.erdplus b/grady/docs/Database Design/Relational Schema.erdplus deleted file mode 100644 index 7e4cb62547cc42988fd92e1bc007a58b535b1d69..0000000000000000000000000000000000000000 --- a/grady/docs/Database Design/Relational Schema.erdplus +++ /dev/null @@ -1 +0,0 @@ -{"version":2,"www":"erdplus.com","shapes":[{"type":"Table","details":{"name":"Students","x":268,"y":346,"sort":"manual","attributes":[{"names":["Name"],"order":1,"pkMember":false,"optional":false,"soloUnique":false,"fk":false,"dataType":"int","dataTypeSize":null,"id":1},{"names":["One Time Password"],"order":3,"pkMember":false,"optional":false,"soloUnique":false,"fk":false,"dataType":"int","dataTypeSize":null,"id":3},{"names":["Matrikelnummer"],"order":0,"pkMember":true,"optional":false,"soloUnique":false,"fk":false,"dataType":"int","dataTypeSize":null,"id":4}],"uniqueGroups":[],"id":1}},{"type":"Table","details":{"name":"Aufgabentyp","x":268,"y":420,"sort":"automatic","attributes":[{"names":["Musterlösung"],"order":1,"pkMember":false,"optional":false,"soloUnique":false,"fk":false,"dataType":"int","dataTypeSize":null,"id":1},{"names":["Name"],"order":2,"pkMember":false,"optional":false,"soloUnique":false,"fk":false,"dataType":"int","dataTypeSize":null,"id":2},{"names":["Korrekturvorgabe"],"order":3,"pkMember":false,"optional":false,"soloUnique":false,"fk":false,"dataType":"int","dataTypeSize":null,"id":3},{"names":["ID"],"order":4,"pkMember":true,"optional":false,"soloUnique":false,"fk":false,"dataType":"int","dataTypeSize":null,"id":4}],"uniqueGroups":[],"id":2}},{"type":"Table","details":{"name":"Aufgaben","x":484,"y":316,"sort":"manual","attributes":[{"names":["Vorkorrektur"],"order":1,"pkMember":false,"optional":false,"soloUnique":false,"fk":false,"dataType":"int","dataTypeSize":null,"id":1},{"names":["Matrikelnummer"],"order":2,"pkMember":false,"optional":false,"soloUnique":false,"fk":true,"dataType":"int","dataTypeSize":null,"references":[{"tableId":1,"attributeId":4}],"id":2},{"names":["ID"],"order":0,"pkMember":true,"optional":false,"soloUnique":false,"fk":false,"dataType":"int","dataTypeSize":null,"id":3},{"names":["Aufgabentyp"],"order":4,"pkMember":false,"optional":false,"soloUnique":false,"fk":true,"dataType":"int","dataTypeSize":null,"references":[{"tableId":2,"attributeId":4}],"id":5}],"uniqueGroups":[],"id":8}},{"type":"Table","details":{"name":"Tutor","x":921,"y":267,"sort":"automatic","attributes":[{"names":["Name"],"order":1,"pkMember":false,"optional":false,"soloUnique":false,"fk":false,"dataType":"int","dataTypeSize":null,"id":1},{"names":["Benutzername"],"order":2,"pkMember":true,"optional":false,"soloUnique":false,"fk":false,"dataType":"int","dataTypeSize":null,"id":2},{"names":["Passwort"],"order":3,"pkMember":false,"optional":false,"soloUnique":false,"fk":false,"dataType":"int","dataTypeSize":null,"id":3}],"uniqueGroups":[],"id":15}},{"type":"Table","details":{"name":"Feedback","x":697,"y":271,"sort":"manual","attributes":[{"names":["Punkte"],"order":1,"pkMember":false,"optional":false,"soloUnique":false,"fk":false,"dataType":"int","dataTypeSize":null,"id":1},{"names":["Text"],"order":2,"pkMember":false,"optional":false,"soloUnique":false,"fk":false,"dataType":"int","dataTypeSize":null,"id":2},{"names":["Tutor"],"order":4,"pkMember":false,"optional":false,"soloUnique":false,"fk":true,"dataType":"int","dataTypeSize":null,"references":[{"tableId":15,"attributeId":2}],"id":3},{"names":["Zugehörige Aufgabe"],"order":3,"pkMember":false,"optional":false,"soloUnique":false,"fk":true,"dataType":"int","dataTypeSize":null,"references":[{"tableId":8,"attributeId":3}],"id":4},{"names":["Reviewer"],"order":5,"pkMember":false,"optional":false,"soloUnique":false,"fk":true,"dataType":"int","dataTypeSize":null,"references":[{"tableId":20,"attributeId":2}],"id":5},{"names":["ID"],"order":0,"pkMember":true,"optional":false,"soloUnique":false,"fk":false,"dataType":"int","dataTypeSize":null,"id":6}],"uniqueGroups":[],"id":16}},{"type":"Table","details":{"name":"Dozent","x":921,"y":346,"sort":"automatic","attributes":[{"names":["Name"],"order":1,"pkMember":false,"optional":false,"soloUnique":false,"fk":false,"dataType":"int","dataTypeSize":null,"id":1},{"names":["Benutzername"],"order":2,"pkMember":true,"optional":false,"soloUnique":false,"fk":false,"dataType":"int","dataTypeSize":null,"id":2},{"names":["Passwort"],"order":3,"pkMember":false,"optional":false,"soloUnique":false,"fk":false,"dataType":"int","dataTypeSize":null,"id":3}],"uniqueGroups":[],"id":20}}],"connectors":[{"type":"TableConnector","details":{"fkAttributeId":2,"id":11},"source":1,"destination":8},{"type":"TableConnector","details":{"fkAttributeId":3,"id":17},"source":15,"destination":16},{"type":"TableConnector","details":{"fkAttributeId":4,"id":18},"source":8,"destination":16},{"type":"TableConnector","details":{"fkAttributeId":5,"id":19},"source":2,"destination":8},{"type":"TableConnector","details":{"fkAttributeId":5,"id":21},"source":20,"destination":16}],"width":2000,"height":1000} \ No newline at end of file diff --git a/grady/docs/Database Design/er-model.graphml b/grady/docs/Database Design/er-model.graphml deleted file mode 100644 index 53572fb56255bda0643cbb55c8df6f23c53363ea..0000000000000000000000000000000000000000 --- a/grady/docs/Database Design/er-model.graphml +++ /dev/null @@ -1,121 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<graphml xmlns="http://graphml.graphdrawing.org/xmlns" xmlns:java="http://www.yworks.com/xml/yfiles-common/1.0/java" xmlns:sys="http://www.yworks.com/xml/yfiles-common/markup/primitives/2.0" xmlns:x="http://www.yworks.com/xml/yfiles-common/markup/2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:y="http://www.yworks.com/xml/graphml" xmlns:yed="http://www.yworks.com/xml/yed/3" xsi:schemaLocation="http://graphml.graphdrawing.org/xmlns http://www.yworks.com/xml/schema/graphml/1.1/ygraphml.xsd"> - <!--Created by yEd 3.16.2.1--> - <key attr.name="Description" attr.type="string" for="graph" id="d0"/> - <key for="port" id="d1" yfiles.type="portgraphics"/> - <key for="port" id="d2" yfiles.type="portgeometry"/> - <key for="port" id="d3" yfiles.type="portuserdata"/> - <key attr.name="url" attr.type="string" for="node" id="d4"/> - <key attr.name="description" attr.type="string" for="node" id="d5"/> - <key for="node" id="d6" yfiles.type="nodegraphics"/> - <key for="graphml" id="d7" yfiles.type="resources"/> - <key attr.name="url" attr.type="string" for="edge" id="d8"/> - <key attr.name="description" attr.type="string" for="edge" id="d9"/> - <key for="edge" id="d10" yfiles.type="edgegraphics"/> - <graph edgedefault="directed" id="G"> - <data key="d0"/> - <node id="n0"> - <data key="d5"/> - <data key="d6"> - <y:GenericNode configuration="com.yworks.entityRelationship.small_entity"> - <y:Geometry height="40.0" width="80.0" x="456.0" y="158.0"/> - <y:Fill color="#E8EEF7" color2="#B7C9E3" transparent="false"/> - <y:BorderStyle color="#000000" type="line" width="1.0"/> - <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="48.572265625" x="15.7138671875" y="10.93359375">Student<y:LabelModel> - <y:SmartNodeLabelModel distance="4.0"/> - </y:LabelModel> - <y:ModelParameter> - <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/> - </y:ModelParameter> - </y:NodeLabel> - <y:StyleProperties> - <y:Property class="java.lang.Boolean" name="y.view.ShadowNodePainter.SHADOW_PAINTING" value="true"/> - </y:StyleProperties> - </y:GenericNode> - </data> - </node> - <node id="n1"> - <data key="d5"/> - <data key="d6"> - <y:GenericNode configuration="com.yworks.entityRelationship.small_entity"> - <y:Geometry height="40.0" width="80.0" x="456.0" y="428.0"/> - <y:Fill color="#E8EEF7" color2="#B7C9E3" transparent="false"/> - <y:BorderStyle color="#000000" type="line" width="1.0"/> - <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="52.486328125" x="13.7568359375" y="10.93359375">Aufgabe<y:LabelModel> - <y:SmartNodeLabelModel distance="4.0"/> - </y:LabelModel> - <y:ModelParameter> - <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/> - </y:ModelParameter> - </y:NodeLabel> - <y:StyleProperties> - <y:Property class="java.lang.Boolean" name="y.view.ShadowNodePainter.SHADOW_PAINTING" value="true"/> - <y:Property class="java.lang.Boolean" name="doubleBorder" value="true"/> - </y:StyleProperties> - </y:GenericNode> - </data> - </node> - <node id="n2"> - <data key="d5"/> - <data key="d6"> - <y:GenericNode configuration="com.yworks.entityRelationship.relationship"> - <y:Geometry height="56.0" width="90.0" x="451.0" y="285.0"/> - <y:Fill color="#E8EEF7" color2="#B7C9E3" transparent="false"/> - <y:BorderStyle color="#000000" type="line" width="1.0"/> - <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="11" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="16.955078125" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="41.5546875" x="24.22265625" y="19.5224609375">gibt ab<y:LabelModel> - <y:SmartNodeLabelModel distance="4.0"/> - </y:LabelModel> - <y:ModelParameter> - <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/> - </y:ModelParameter> - </y:NodeLabel> - <y:StyleProperties> - <y:Property class="java.lang.Boolean" name="y.view.ShadowNodePainter.SHADOW_PAINTING" value="true"/> - <y:Property class="java.lang.Boolean" name="doubleBorder" value="true"/> - </y:StyleProperties> - </y:GenericNode> - </data> - </node> - <edge id="e0" source="n0" target="n2"> - <data key="d9"/> - <data key="d10"> - <y:PolyLineEdge> - <y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/> - <y:LineStyle color="#000000" type="line" width="1.0"/> - <y:Arrows source="none" target="none"/> - <y:EdgeLabel alignment="center" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" horizontalTextPosition="center" iconTextGap="4" modelName="custom" preferredPlacement="anywhere" ratio="0.5" textColor="#000000" verticalTextPosition="bottom" visible="true" width="44.04296875" x="-52.021484375" y="34.427490234375"><1, *><y:LabelModel> - <y:SmartEdgeLabelModel autoRotationEnabled="false" defaultAngle="0.0" defaultDistance="10.0"/> - </y:LabelModel> - <y:ModelParameter> - <y:SmartEdgeLabelModelParameter angle="0.0" distance="30.0" distanceToCenter="true" position="right" ratio="0.5" segment="0"/> - </y:ModelParameter> - <y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" frozen="true" placement="anywhere" side="anywhere" sideReference="relative_to_edge_flow"/> - </y:EdgeLabel> - <y:BendStyle smoothed="false"/> - </y:PolyLineEdge> - </data> - </edge> - <edge id="e1" source="n2" target="n1"> - <data key="d9"/> - <data key="d10"> - <y:PolyLineEdge> - <y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/> - <y:LineStyle color="#000000" type="line" width="1.0"/> - <y:Arrows source="none" target="none"/> - <y:EdgeLabel alignment="center" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" horizontalTextPosition="center" iconTextGap="4" modelName="custom" preferredPlacement="anywhere" ratio="0.5" textColor="#000000" verticalTextPosition="bottom" visible="true" width="42.05078125" x="-51.025390625" y="34.451416015625"><1,1><y:LabelModel> - <y:SmartEdgeLabelModel autoRotationEnabled="false" defaultAngle="0.0" defaultDistance="10.0"/> - </y:LabelModel> - <y:ModelParameter> - <y:SmartEdgeLabelModelParameter angle="0.0" distance="30.0" distanceToCenter="true" position="right" ratio="0.5" segment="0"/> - </y:ModelParameter> - <y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" frozen="true" placement="anywhere" side="anywhere" sideReference="relative_to_edge_flow"/> - </y:EdgeLabel> - <y:BendStyle smoothed="false"/> - </y:PolyLineEdge> - </data> - </edge> - </graph> - <data key="d7"> - <y:Resources/> - </data> -</graphml> diff --git a/grady/docs/Database Design/erdplus-diagram-pdf-export.pdf b/grady/docs/Database Design/erdplus-diagram-pdf-export.pdf deleted file mode 100644 index 9d6e366c36954502beee2944cc3dc2a82abba52f..0000000000000000000000000000000000000000 Binary files a/grady/docs/Database Design/erdplus-diagram-pdf-export.pdf and /dev/null differ diff --git a/grady/docs/Database Design/erdplus-er-model-export.pdf b/grady/docs/Database Design/erdplus-er-model-export.pdf deleted file mode 100644 index 3e2148b22b9eff7cae06b7837eb3e5b067c6373e..0000000000000000000000000000000000000000 Binary files a/grady/docs/Database Design/erdplus-er-model-export.pdf and /dev/null differ diff --git a/grady/docs/core_uml.png b/grady/docs/core_uml.png deleted file mode 100644 index 2c32543b871c8f7099334c75fd3b81eac96c87d3..0000000000000000000000000000000000000000 Binary files a/grady/docs/core_uml.png and /dev/null differ diff --git a/grady/docs/deployment.md b/grady/docs/deployment.md deleted file mode 100644 index 0a380077a758704519c78cd7c278500490ea4841..0000000000000000000000000000000000000000 --- a/grady/docs/deployment.md +++ /dev/null @@ -1,11 +0,0 @@ -# Grady deployment instructions - -For every commit on master a Docker image is build which can be deployed -anywhere. The current deployment configurations is explained in another repo. - -## Environment variables - -- `GRADY_LOG_LEVEL` Sets the log level for our custom logging configuration - (default: DEBUG). -- `GRADY_LOG_FORMAT` Can be set to `json` in order to make logs readable - by Logstash (default: `default-format`). diff --git a/grady/docs/feedback.api.json b/grady/docs/feedback.api.json deleted file mode 100644 index c48beea4146bc18419f8a5b03ecf2d9de9826fe2..0000000000000000000000000000000000000000 --- a/grady/docs/feedback.api.json +++ /dev/null @@ -1,43 +0,0 @@ -GET /subscription/<id> - { - "subscription_id": "e313e608-7453-4053-a536-5d18fc9ec3a9", - "owner": "reviewer01", - "query_type": "random", - "query_key": "", - "assignments": [ - { - "assignment_id": "dbdde0d0-b1a6-474c-b2be-41edb5229803", - "submission_id": "1558c390-5598-482b-abd3-1f5780e75e0d", - "is_done": false - } - ] - } - -POST /subscription/ - { - "owner": "<some user>", - "query_type": "random|student|submission_type|exam", - "query_key": "<pk for query type>?" - } - -DELETE /subscription/<id> -PATCH /subscription/<id> { - "deactivate": true // or false for reactivation -} - -GET /subscription/assignments/current -GET /subscription/assignments/next -GET /subscription/assignments/past - -GET /assignment/<id> // only those belonging to the requests user - { - "assignment_id": "dbdde0d0-b1a6-474c-b2be-41edb5229803", - "submission_id": "1558c390-5598-482b-abd3-1f5780e75e0d", - "is_done": false - } - -DELETE /assignment/<id> // check done conditions - -// done conditions -// * feedback was posted -// * feedback was patched (every) diff --git a/grady/frontend/.browserslistrc b/grady/frontend/.browserslistrc deleted file mode 100644 index bd3ad98e5fd08856cc403e9260d24dee025c467e..0000000000000000000000000000000000000000 --- a/grady/frontend/.browserslistrc +++ /dev/null @@ -1,3 +0,0 @@ -> 1% -last 2 versions -not ie <= 8 \ No newline at end of file diff --git a/grady/frontend/.eslintrc.js b/grady/frontend/.eslintrc.js deleted file mode 100644 index 64a02468421195d5d1ec767e30a068bae9c7a74d..0000000000000000000000000000000000000000 --- a/grady/frontend/.eslintrc.js +++ /dev/null @@ -1,36 +0,0 @@ -module.exports = { - root: true, - env: { - node: true, - }, - extends: [ - 'plugin:vue/recommended', - '@vue/typescript', - ], - rules: { - 'no-console': process.env.NODE_ENV === 'production' ? 'error' : 'off', - 'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off', - 'semi': ['error', 'never'], - 'quotes': ['error', 'single'], - 'eqeqeq': 'error', - 'default-case': 'error', - 'guard-for-in': 'error', - 'yoda': 'error', - 'no-trailing-spaces': 'error', - '@typescript-eslint/consistent-type-assertions': ['error', { assertionStyle: 'as' }] - }, - parserOptions: { - parser: '@typescript-eslint/parser', - }, - plugins: ['@typescript-eslint'], - overrides: [ - { - files: [ - '**/__tests__/*.{j,t}s?(x)', - ], - env: { - mocha: true, - }, - }, - ], -} diff --git a/grady/frontend/.gitignore b/grady/frontend/.gitignore deleted file mode 100644 index 912d2e7079788e8cf3e8af11addaa9cbfbb9e899..0000000000000000000000000000000000000000 --- a/grady/frontend/.gitignore +++ /dev/null @@ -1,24 +0,0 @@ -.DS_Store -node_modules -/dist - -/tests/e2e/reports/ -selenium-debug.log - -# local env files -.env.local -.env.*.local - -# Log files -npm-debug.log* -yarn-debug.log* -yarn-error.log* - -# Editor directories and files -.idea -.vscode -*.suo -*.ntvs* -*.njsproj -*.sln -*.sw* diff --git a/grady/frontend/.postcssrc.js b/grady/frontend/.postcssrc.js deleted file mode 100644 index 961986e2b11eeebe1d4ddabdf2e6c85e2a2562e0..0000000000000000000000000000000000000000 --- a/grady/frontend/.postcssrc.js +++ /dev/null @@ -1,5 +0,0 @@ -module.exports = { - plugins: { - autoprefixer: {} - } -} diff --git a/grady/frontend/@types/v-clipboard/index.d.ts b/grady/frontend/@types/v-clipboard/index.d.ts deleted file mode 100644 index 8619c86521a4634b98954c93b4cede9db2e182fa..0000000000000000000000000000000000000000 --- a/grady/frontend/@types/v-clipboard/index.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -declare module 'v-clipboard' -declare module 'vue-color' diff --git a/grady/frontend/README.md b/grady/frontend/README.md deleted file mode 100644 index 82dcc1c749c37f3e8a4f14780936894948b1f336..0000000000000000000000000000000000000000 --- a/grady/frontend/README.md +++ /dev/null @@ -1,31 +0,0 @@ -# frontend - -## Project setup -``` -yarn install -``` - -### Compiles and hot-reloads for development -``` -yarn run serve -``` - -### Compiles and minifies for production -``` -yarn run build -``` - -### Lints and fixes files -``` -yarn run lint -``` - -### Run your unit tests -``` -yarn run test:unit -``` - -### Run your end-to-end tests -``` -yarn run test:e2e -``` diff --git a/grady/frontend/nightwatch.json b/grady/frontend/nightwatch.json deleted file mode 100644 index 333b96e583a946f42104f107337df4cee4546a3b..0000000000000000000000000000000000000000 --- a/grady/frontend/nightwatch.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "globals_path": "nightwatch_globals", - "test_settings": { - "chrome": { - "desiredCapabilities": { - "chromeOptions": { - "args": ["headless"] - } - } - } - } -} diff --git a/grady/frontend/nightwatch_globals.js b/grady/frontend/nightwatch_globals.js deleted file mode 100644 index ce0207f931ea2abab0357736feb2acaddd0fe77d..0000000000000000000000000000000000000000 --- a/grady/frontend/nightwatch_globals.js +++ /dev/null @@ -1,3 +0,0 @@ -module.exports = { - waitForConditionTimeout: 10000 -} diff --git a/grady/frontend/package-lock.json b/grady/frontend/package-lock.json deleted file mode 100644 index 2b1c31e2fb67aef1176dc46a7077299f2ca44fc8..0000000000000000000000000000000000000000 --- a/grady/frontend/package-lock.json +++ /dev/null @@ -1,12267 +0,0 @@ -{ - "name": "frontend", - "version": "0.1.0", - "lockfileVersion": 1, - "requires": true, - "dependencies": { - "@babel/code-frame": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.13.tgz", - "integrity": "sha512-HV1Cm0Q3ZrpCR93tkWOYiuYIgLxZXZFVG2VgK+MBWjUqZTundupbfx2aXarXuw5Ko5aMcjtJgbSs4vUGBS5v6g==", - "dev": true, - "requires": { - "@babel/highlight": "^7.12.13" - } - }, - "@babel/generator": { - "version": "7.13.9", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.13.9.tgz", - "integrity": "sha512-mHOOmY0Axl/JCTkxTU6Lf5sWOg/v8nUa+Xkt4zMTftX0wqmb6Sh7J8gvcehBw7q0AhrhAR+FDacKjCZ2X8K+Sw==", - "dev": true, - "requires": { - "@babel/types": "^7.13.0", - "jsesc": "^2.5.1", - "source-map": "^0.5.0" - }, - "dependencies": { - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - } - } - }, - "@babel/helper-function-name": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.12.13.tgz", - "integrity": "sha512-TZvmPn0UOqmvi5G4vvw0qZTpVptGkB1GL61R6lKvrSdIxGm5Pky7Q3fpKiIkQCAtRCBUwB0PaThlx9vebCDSwA==", - "dev": true, - "requires": { - "@babel/helper-get-function-arity": "^7.12.13", - "@babel/template": "^7.12.13", - "@babel/types": "^7.12.13" - } - }, - "@babel/helper-get-function-arity": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.12.13.tgz", - "integrity": "sha512-DjEVzQNz5LICkzN0REdpD5prGoidvbdYk1BVgRUOINaWJP2t6avB27X1guXK1kXNrX0WMfsrm1A/ZBthYuIMQg==", - "dev": true, - "requires": { - "@babel/types": "^7.12.13" - } - }, - "@babel/helper-split-export-declaration": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.12.13.tgz", - "integrity": "sha512-tCJDltF83htUtXx5NLcaDqRmknv652ZWCHyoTETf1CXYJdPC7nohZohjUgieXhv0hTJdRf2FjDueFehdNucpzg==", - "dev": true, - "requires": { - "@babel/types": "^7.12.13" - } - }, - "@babel/helper-validator-identifier": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz", - "integrity": "sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw==", - "dev": true - }, - "@babel/highlight": { - "version": "7.13.10", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.13.10.tgz", - "integrity": "sha512-5aPpe5XQPzflQrFwL1/QoeHkP2MsA4JCntcXHRhEsdsfPVkvPi2w7Qix4iV7t5S/oC9OodGrggd8aco1g3SZFg==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.12.11", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - }, - "dependencies": { - "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 - } - } - }, - "@babel/parser": { - "version": "7.13.13", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.13.13.tgz", - "integrity": "sha512-OhsyMrqygfk5v8HmWwOzlYjJrtLaFhF34MrfG/Z73DgYCI6ojNUTUp2TYbtnjo8PegeJp12eamsNettCQjKjVw==", - "dev": true - }, - "@babel/template": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.12.13.tgz", - "integrity": "sha512-/7xxiGA57xMo/P2GVvdEumr8ONhFOhfgq2ihK3h1e6THqzTAkHbkXgB0xI9yeTfIUoH3+oAeHhqm/I43OTbbjA==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.12.13", - "@babel/parser": "^7.12.13", - "@babel/types": "^7.12.13" - } - }, - "@babel/traverse": { - "version": "7.13.13", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.13.13.tgz", - "integrity": "sha512-CblEcwmXKR6eP43oQGG++0QMTtCjAsa3frUuzHoiIJWpaIIi8dwMyEFUJoXRLxagGqCK+jALRwIO+o3R9p/uUg==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.12.13", - "@babel/generator": "^7.13.9", - "@babel/helper-function-name": "^7.12.13", - "@babel/helper-split-export-declaration": "^7.12.13", - "@babel/parser": "^7.13.13", - "@babel/types": "^7.13.13", - "debug": "^4.1.0", - "globals": "^11.1.0" - }, - "dependencies": { - "debug": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", - "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", - "dev": true, - "requires": { - "ms": "2.1.2" - } - }, - "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.13.14", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.13.14.tgz", - "integrity": "sha512-A2aa3QTkWoyqsZZFl56MLUsfmh7O0gN41IPvXAE/++8ojpbz12SszD7JEGYVdn4f9Kt4amIei07swF1h4AqmmQ==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.12.11", - "lodash": "^4.17.19", - "to-fast-properties": "^2.0.0" - } - }, - "@hapi/address": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@hapi/address/-/address-2.1.4.tgz", - "integrity": "sha512-QD1PhQk+s31P1ixsX0H0Suoupp3VMXzIVMSwobR3F3MSUO2YCV0B7xqLcUw/Bh8yuvd3LhpyqLQWTNcRmp6IdQ==", - "dev": true - }, - "@hapi/bourne": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@hapi/bourne/-/bourne-1.3.2.tgz", - "integrity": "sha512-1dVNHT76Uu5N3eJNTYcvxee+jzX4Z9lfciqRRHCU27ihbUcYi+iSc2iml5Ke1LXe1SyJCLA0+14Jh4tXJgOppA==", - "dev": true - }, - "@hapi/hoek": { - "version": "8.5.1", - "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-8.5.1.tgz", - "integrity": "sha512-yN7kbciD87WzLGc5539Tn0sApjyiGHAJgKvG9W8C7O+6c7qmoQMfVs0W4bX17eqz6C78QJqqFrtgdK5EWf6Qow==", - "dev": true - }, - "@hapi/joi": { - "version": "15.1.1", - "resolved": "https://registry.npmjs.org/@hapi/joi/-/joi-15.1.1.tgz", - "integrity": "sha512-entf8ZMOK8sc+8YfeOlM8pCfg3b5+WZIKBfUaaJT8UsjAAPjartzxIYm3TIbjvA4u+u++KbcXD38k682nVHDAQ==", - "dev": true, - "requires": { - "@hapi/address": "2.x.x", - "@hapi/bourne": "1.x.x", - "@hapi/hoek": "8.x.x", - "@hapi/topo": "3.x.x" - } - }, - "@hapi/topo": { - "version": "3.1.6", - "resolved": "https://registry.npmjs.org/@hapi/topo/-/topo-3.1.6.tgz", - "integrity": "sha512-tAag0jEcjwH+P2quUfipd7liWCNX2F8NvYjQp2wtInsZxnMlypdw0FtAOLxtvvkO+GSRRbmNi8m/5y42PQJYCQ==", - "dev": true, - "requires": { - "@hapi/hoek": "^8.3.0" - } - }, - "@intervolga/optimize-cssnano-plugin": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/@intervolga/optimize-cssnano-plugin/-/optimize-cssnano-plugin-1.0.6.tgz", - "integrity": "sha512-zN69TnSr0viRSU6cEDIcuPcP67QcpQ6uHACg58FiN9PDrU6SLyGW3MR4tiISbYxy1kDWAVPwD+XwQTWE5cigAA==", - "dev": true, - "requires": { - "cssnano": "^4.0.0", - "cssnano-preset-default": "^4.0.0", - "postcss": "^7.0.0" - } - }, - "@mrmlnc/readdir-enhanced": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz", - "integrity": "sha512-bPHp6Ji8b41szTOcaP63VlnbbO5Ny6dwAATtY6JTjh5N2OLrb5Qk/Th5cRkRQhkWCt+EJsYrNB0MiL+Gpn6e3g==", - "dev": true, - "requires": { - "call-me-maybe": "^1.0.1", - "glob-to-regexp": "^0.3.0" - } - }, - "@nodelib/fs.stat": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-1.1.3.tgz", - "integrity": "sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw==", - "dev": true - }, - "@sinonjs/commons": { - "version": "1.8.3", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.3.tgz", - "integrity": "sha512-xkNcLAn/wZaX14RPlwizcKicDk9G3F8m2nU3L7Ukm5zBgTwiT0wsoFAHx9Jq56fJA1z/7uKGtCRu16sOUCLIHQ==", - "dev": true, - "requires": { - "type-detect": "4.0.8" - } - }, - "@sinonjs/formatio": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@sinonjs/formatio/-/formatio-3.1.0.tgz", - "integrity": "sha512-ZAR2bPHOl4Xg6eklUGpsdiIJ4+J1SNag1DHHrG/73Uz/nVwXqjgUtRPLoS+aVyieN9cSbc0E4LsU984tWcDyNg==", - "dev": true, - "requires": { - "@sinonjs/samsam": "^2 || ^3" - } - }, - "@sinonjs/samsam": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-3.3.3.tgz", - "integrity": "sha512-bKCMKZvWIjYD0BLGnNrxVuw4dkWCYsLqFOUWw8VgKF/+5Y+mE7LfHWPIYoDXowH+3a9LsWDMo0uAP8YDosPvHQ==", - "dev": true, - "requires": { - "@sinonjs/commons": "^1.3.0", - "array-from": "^2.1.1", - "lodash": "^4.17.15" - } - }, - "@soda/friendly-errors-webpack-plugin": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/@soda/friendly-errors-webpack-plugin/-/friendly-errors-webpack-plugin-1.7.1.tgz", - "integrity": "sha512-cWKrGaFX+rfbMrAxVv56DzhPNqOJPZuNIS2HGMELtgGzb+vsMzyig9mml5gZ/hr2BGtSLV+dP2LUEuAL8aG2mQ==", - "dev": true, - "requires": { - "chalk": "^1.1.3", - "error-stack-parser": "^2.0.0", - "string-width": "^2.0.0" - }, - "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" - } - }, - "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "dev": true, - "requires": { - "ansi-regex": "^2.0.0" - } - }, - "supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", - "dev": true - } - } - }, - "@types/chai": { - "version": "4.1.7", - "dev": true - }, - "@types/eslint-visitor-keys": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@types/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz", - "integrity": "sha512-OCutwjDZ4aFS6PB1UZ988C4YgwlBHJd6wCeQqaLdmadZ/7e+w79+hbMUFC1QXDNCmdyoRfAFdm0RypzwR+Qpag==", - "dev": true - }, - "@types/events": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@types/events/-/events-3.0.0.tgz", - "integrity": "sha512-EaObqwIvayI5a8dCzhFrjKzVwKLxjoG9T6Ppd5CEo07LRKfQ8Yokw54r5+Wq7FaBQ+yXRvQAYPrHwya1/UFt9g==", - "dev": true - }, - "@types/file-saver": { - "version": "2.0.1", - "dev": true - }, - "@types/glob": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.1.tgz", - "integrity": "sha512-1Bh06cbWJUHMC97acuD6UMG29nMt0Aqz1vF3guLfG+kHHJhy3AyohZFFxYk2f7Q1SQIrNwvncxAE0N/9s70F2w==", - "dev": true, - "requires": { - "@types/events": "*", - "@types/minimatch": "*", - "@types/node": "*" - } - }, - "@types/highlight.js": { - "version": "9.12.3", - "dev": true - }, - "@types/json-schema": { - "version": "7.0.7", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.7.tgz", - "integrity": "sha512-cxWFQVseBm6O9Gbw1IWb8r6OS4OhSt3hPZLkFApLjM8TEXROBuQGLAH2i2gZpcXdLBIrpXuTDhH7Vbm1iXmNGA==", - "dev": true - }, - "@types/minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-1z8k4wzFnNjVK/tlxvrWuK5WMt6mydWWP7+zvH5eFep4oj+UkrfiJTRtjCeBXNpwaA/FYqqtb4/QS4ianFpIRA==", - "dev": true - }, - "@types/mocha": { - "version": "5.2.5", - "dev": true - }, - "@types/nightwatch": { - "version": "0.9.11", - "dev": true - }, - "@types/node": { - "version": "14.14.37", - "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.37.tgz", - "integrity": "sha512-XYmBiy+ohOR4Lh5jE379fV2IU+6Jn4g5qASinhitfyO71b/sCo6MKsMLF5tc7Zf2CE8hViVQyYSobJNke8OvUw==", - "dev": true - }, - "@types/normalize-package-data": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.0.tgz", - "integrity": "sha512-f5j5b/Gf71L+dbqxIpQ4Z2WlmI/mPJ0fOkGGmFgtb6sAu97EPczzbS3/tJKxmcYDj55OX6ssqwDAWOHIYDRDGA==", - "dev": true - }, - "@types/q": { - "version": "1.5.4", - "resolved": "https://registry.npmjs.org/@types/q/-/q-1.5.4.tgz", - "integrity": "sha512-1HcDas8SEj4z1Wc696tH56G8OlRaH/sqZOynNNB+HF0WOeXPaxTtbYzJY2oEfiUxjSKjhCKr+MvR7dCHcEelug==", - "dev": true - }, - "@types/sinon": { - "version": "7.0.3", - "dev": true - }, - "@types/webpack-env": { - "version": "1.14.0", - "resolved": "https://registry.npmjs.org/@types/webpack-env/-/webpack-env-1.14.0.tgz", - "integrity": "sha512-Fv+0gYJzE/czLoRKq+gnXWr4yBpPM3tO3C8pDLFwqVKlMICQUq5OsxwwFZYDaVr7+L6mgNDp16iOcJHEz3J5RQ==", - "dev": true - }, - "@typescript-eslint/eslint-plugin": { - "version": "2.3.2", - "dev": true, - "requires": { - "@typescript-eslint/experimental-utils": "2.3.2", - "eslint-utils": "^1.4.2", - "functional-red-black-tree": "^1.0.1", - "regexpp": "^2.0.1", - "tsutils": "^3.17.1" - }, - "dependencies": { - "@typescript-eslint/experimental-utils": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-2.3.2.tgz", - "integrity": "sha512-t+JGdTT6dRbmvKDlhlVkEueoZa0fhJNfG6z2cpnRPLwm3VwYr2BjR//acJGC1Yza0I9ZNcDfRY7ubQEvvfG6Jg==", - "dev": true, - "requires": { - "@types/json-schema": "^7.0.3", - "@typescript-eslint/typescript-estree": "2.3.2", - "eslint-scope": "^5.0.0" - }, - "dependencies": { - "@types/json-schema": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.3.tgz", - "integrity": "sha512-Il2DtDVRGDcqjDtE+rF8iqg1CArehSK84HZJCT7AMITlyXRBpuPhqGLDQMowraqqu1coEaimg4ZOqggt6L6L+A==", - "dev": true - } - } - }, - "@typescript-eslint/typescript-estree": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-2.3.2.tgz", - "integrity": "sha512-eZNEAai16nwyhIVIEaWQlaUgAU3S9CkQ58qvK0+3IuSdLJD3W1PNuehQFMIhW/mTP1oFR9GNoTcLg7gtXz6lzA==", - "dev": true, - "requires": { - "glob": "^7.1.4", - "is-glob": "^4.0.1", - "lodash.unescape": "4.0.1", - "semver": "^6.3.0" - }, - "dependencies": { - "lodash.unescape": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/lodash.unescape/-/lodash.unescape-4.0.1.tgz", - "integrity": "sha1-vyJJiGzlFM2hEvrpIYzcBlIR/Jw=", - "dev": true - } - } - }, - "glob": { - "version": "7.1.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", - "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", - "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" - }, - "dependencies": { - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", - "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.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", - "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" - } - }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dev": true, - "requires": { - "wrappy": "1" - } - }, - "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 - } - } - }, - "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" - }, - "dependencies": { - "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 - } - } - }, - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - } - } - }, - "@typescript-eslint/experimental-utils": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-1.13.0.tgz", - "integrity": "sha512-zmpS6SyqG4ZF64ffaJ6uah6tWWWgZ8m+c54XXgwFtUv0jNz8aJAVx8chMCvnk7yl6xwn8d+d96+tWp7fXzTuDg==", - "dev": true, - "requires": { - "@types/json-schema": "^7.0.3", - "@typescript-eslint/typescript-estree": "1.13.0", - "eslint-scope": "^4.0.0" - }, - "dependencies": { - "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" - } - } - } - }, - "@typescript-eslint/parser": { - "version": "2.3.2", - "dev": true, - "requires": { - "@types/eslint-visitor-keys": "^1.0.0", - "@typescript-eslint/experimental-utils": "2.3.2", - "@typescript-eslint/typescript-estree": "2.3.2", - "eslint-visitor-keys": "^1.1.0" - }, - "dependencies": { - "@typescript-eslint/experimental-utils": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-2.3.2.tgz", - "integrity": "sha512-t+JGdTT6dRbmvKDlhlVkEueoZa0fhJNfG6z2cpnRPLwm3VwYr2BjR//acJGC1Yza0I9ZNcDfRY7ubQEvvfG6Jg==", - "dev": true, - "requires": { - "@types/json-schema": "^7.0.3", - "@typescript-eslint/typescript-estree": "2.3.2", - "eslint-scope": "^5.0.0" - } - }, - "@typescript-eslint/typescript-estree": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-2.3.2.tgz", - "integrity": "sha512-eZNEAai16nwyhIVIEaWQlaUgAU3S9CkQ58qvK0+3IuSdLJD3W1PNuehQFMIhW/mTP1oFR9GNoTcLg7gtXz6lzA==", - "dev": true, - "requires": { - "glob": "^7.1.4", - "is-glob": "^4.0.1", - "lodash.unescape": "4.0.1", - "semver": "^6.3.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 - }, - "glob": { - "version": "7.1.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", - "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", - "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" - }, - "dependencies": { - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", - "dev": true - }, - "inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "dev": true, - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true - }, - "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" - } - }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dev": true, - "requires": { - "wrappy": "1" - } - }, - "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 - } - } - }, - "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" - }, - "dependencies": { - "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 - } - } - }, - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - } - } - }, - "@typescript-eslint/typescript-estree": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-1.13.0.tgz", - "integrity": "sha512-b5rCmd2e6DCC6tCTN9GSUAuxdYwCM/k/2wdjHGrIRGPSJotWMCe/dGpi66u42bhuh8q3QBzqM4TMA1GUUCJvdw==", - "dev": true, - "requires": { - "lodash.unescape": "4.0.1", - "semver": "5.5.0" - }, - "dependencies": { - "semver": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz", - "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==", - "dev": true - } - } - }, - "@vue/cli-overlay": { - "version": "3.11.0", - "resolved": "https://registry.npmjs.org/@vue/cli-overlay/-/cli-overlay-3.11.0.tgz", - "integrity": "sha512-yYZP27vjioWmohwXQ9mTPHHxktfAaTM6RDehyG83yvY07wcdxhwrNNCMm8eE9My/K2F8oAPf8uoDZZmkr/EXBw==", - "dev": true - }, - "@vue/cli-plugin-eslint": { - "version": "3.11.0", - "dev": true, - "requires": { - "@vue/cli-shared-utils": "^3.11.0", - "babel-eslint": "^10.0.1", - "eslint": "^4.19.1", - "eslint-loader": "^2.1.2", - "eslint-plugin-vue": "^4.7.1", - "globby": "^9.2.0", - "webpack": "^4.0.0", - "yorkie": "^2.0.0" - }, - "dependencies": { - "acorn": { - "version": "5.7.4", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.4.tgz", - "integrity": "sha512-1D++VG7BhrtvQpNbBzovKNc1FLGGEE/oGe7b9xJm/RFHMBeUaUGpluV9RLjZa47YFdPcDAenEYuq9pQPcMdLJg==", - "dev": true, - "optional": true - }, - "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, - "optional": 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, - "optional": true - } - } - }, - "ajv": { - "version": "5.5.2", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz", - "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=", - "dev": true, - "requires": { - "co": "^4.6.0", - "fast-deep-equal": "^1.0.0", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.3.0" - }, - "dependencies": { - "co": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", - "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", - "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, - "optional": true - }, - "caller-path": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-0.1.0.tgz", - "integrity": "sha1-lAhe9jWB7NPaqSREqP6U6CV3dR8=", - "dev": true, - "optional": true, - "requires": { - "callsites": "^0.2.0" - } - }, - "callsites": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-0.2.0.tgz", - "integrity": "sha1-r6uWJikQp/M8GaV3WCXGnzTjUMo=", - "dev": true, - "optional": true - }, - "chardet": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.4.2.tgz", - "integrity": "sha1-tUc7M9yXxCTl2Y3IfVXU2KKci/I=", - "dev": true, - "optional": true - }, - "debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "optional": true, - "requires": { - "ms": "^2.1.1" - } - }, - "doctrine": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", - "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", - "dev": true, - "optional": true, - "requires": { - "esutils": "^2.0.2" - }, - "dependencies": { - "esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true, - "optional": true - } - } - }, - "eslint": { - "version": "4.19.1", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-4.19.1.tgz", - "integrity": "sha512-bT3/1x1EbZB7phzYu7vCr1v3ONuzDtX8WjuM9c0iYxe+cq+pwcKEoQjl7zd3RpC6YOLgnSy3cTN58M2jcoPDIQ==", - "dev": true, - "optional": true, - "requires": { - "ajv": "^5.3.0", - "babel-code-frame": "^6.22.0", - "chalk": "^2.1.0", - "concat-stream": "^1.6.0", - "cross-spawn": "^5.1.0", - "debug": "^3.1.0", - "doctrine": "^2.1.0", - "eslint-scope": "^3.7.1", - "eslint-visitor-keys": "^1.0.0", - "espree": "^3.5.4", - "esquery": "^1.0.0", - "esutils": "^2.0.2", - "file-entry-cache": "^2.0.0", - "functional-red-black-tree": "^1.0.1", - "glob": "^7.1.2", - "globals": "^11.0.1", - "ignore": "^3.3.3", - "imurmurhash": "^0.1.4", - "inquirer": "^3.0.6", - "is-resolvable": "^1.0.0", - "js-yaml": "^3.9.1", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.3.0", - "lodash": "^4.17.4", - "minimatch": "^3.0.2", - "mkdirp": "^0.5.1", - "natural-compare": "^1.4.0", - "optionator": "^0.8.2", - "path-is-inside": "^1.0.2", - "pluralize": "^7.0.0", - "progress": "^2.0.0", - "regexpp": "^1.0.1", - "require-uncached": "^1.0.3", - "semver": "^5.3.0", - "strip-ansi": "^4.0.0", - "strip-json-comments": "~2.0.1", - "table": "4.0.2", - "text-table": "~0.2.0" - }, - "dependencies": { - "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, - "optional": true, - "requires": { - "chalk": "^1.1.3", - "esutils": "^2.0.2", - "js-tokens": "^3.0.2" - }, - "dependencies": { - "chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", - "dev": true, - "optional": 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" - } - }, - "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, - "optional": true, - "requires": { - "ansi-regex": "^2.0.0" - } - } - } - }, - "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, - "optional": true, - "requires": { - "buffer-from": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^2.2.2", - "typedarray": "^0.0.6" - } - }, - "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, - "optional": true, - "requires": { - "lru-cache": "^4.0.1", - "shebang-command": "^1.2.0", - "which": "^1.2.9" - } - }, - "espree": { - "version": "3.5.4", - "resolved": "https://registry.npmjs.org/espree/-/espree-3.5.4.tgz", - "integrity": "sha512-yAcIQxtmMiB/jL32dzEp2enBeidsB7xWPLNiw3IIkpVds1P+h7qF9YwJq1yUNzp2OKXgAprs4F61ih66UsoD1A==", - "dev": true, - "optional": true, - "requires": { - "acorn": "^5.5.0", - "acorn-jsx": "^3.0.0" - } - }, - "esquery": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.0.1.tgz", - "integrity": "sha512-SmiyZ5zIWH9VM+SRUReLS5Q8a7GxtRdxEBVZpm98rJM7Sb+A9DVCndXfkeFUd3byderg+EbDkfnevfCwynWaNA==", - "dev": true, - "optional": true, - "requires": { - "estraverse": "^4.0.0" - } - }, - "esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true - }, - "glob": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", - "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" - } - }, - "ignore": { - "version": "3.3.10", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.10.tgz", - "integrity": "sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug==", - "dev": true, - "optional": true - }, - "imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", - "dev": true, - "optional": true - }, - "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, - "optional": true - }, - "json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", - "dev": true, - "optional": true - }, - "levn": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", - "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", - "dev": true, - "requires": { - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2" - } - }, - "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" - } - }, - "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, - "optional": true - }, - "optionator": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz", - "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=", - "dev": true, - "optional": 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" - } - }, - "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, - "optional": true - }, - "pluralize": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-7.0.0.tgz", - "integrity": "sha512-ARhBOdzS3e41FbkW/XWrTEtukqqLoK5+Z/4UeDaLuSW+39JPeFgs4gCGqsrJHVZX0fUrx//4OF0K1CUGwlIFow==", - "dev": true, - "optional": true - }, - "progress": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", - "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", - "dev": true, - "optional": 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, - "optional": true, - "requires": { - "caller-path": "^0.1.0", - "resolve-from": "^1.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, - "optional": 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, - "optional": true - } - } - }, - "eslint-plugin-vue": { - "version": "4.7.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-4.7.1.tgz", - "integrity": "sha512-esETKhVMI7Vdli70Wt4bvAwnZBJeM0pxVX9Yb0wWKxdCJc2EADalVYK/q2FzMw8oKN0wPMdqVCKS8kmR89recA==", - "dev": true, - "optional": true, - "requires": { - "vue-eslint-parser": "^2.0.3" - } - }, - "eslint-scope": { - "version": "3.7.3", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-3.7.3.tgz", - "integrity": "sha512-W+B0SvF4gamyCTmUc+uITPY0989iXVfKvhwtmJocTaYoc/3khEHmEmvfY/Gn9HA9VV75jrQECsHizkNw1b68FA==", - "dev": true, - "optional": true, - "requires": { - "esrecurse": "^4.1.0", - "estraverse": "^4.1.1" - } - }, - "external-editor": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-2.2.0.tgz", - "integrity": "sha512-bSn6gvGxKt+b7+6TKEv1ZycHleA7aHhRHyAqJyp5pbUFuYYNIzpZnQDk7AsYckyWdEnTeAnay0aCy2aV6iTk9A==", - "dev": true, - "optional": true, - "requires": { - "chardet": "^0.4.0", - "iconv-lite": "^0.4.17", - "tmp": "^0.0.33" - }, - "dependencies": { - "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, - "optional": true, - "requires": { - "safer-buffer": ">= 2.1.2 < 3" - } - }, - "tmp": { - "version": "0.0.33", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", - "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", - "dev": true, - "optional": true, - "requires": { - "os-tmpdir": "~1.0.2" - } - } - } - }, - "fast-deep-equal": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz", - "integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ=", - "dev": true - }, - "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, - "optional": true, - "requires": { - "flat-cache": "^1.2.1", - "object-assign": "^4.0.1" - }, - "dependencies": { - "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, - "optional": true - } - } - }, - "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, - "optional": true, - "requires": { - "circular-json": "^0.3.1", - "graceful-fs": "^4.1.2", - "rimraf": "~2.6.2", - "write": "^0.2.1" - }, - "dependencies": { - "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, - "optional": true - }, - "glob": { - "version": "7.1.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", - "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", - "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" - } - }, - "graceful-fs": { - "version": "4.1.15", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.15.tgz", - "integrity": "sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA==", - "dev": true, - "optional": true - }, - "minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "dev": true, - "optional": true, - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "rimraf": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", - "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", - "dev": true, - "optional": true, - "requires": { - "glob": "^7.1.3" - } - } - } - }, - "inquirer": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-3.3.0.tgz", - "integrity": "sha512-h+xtnyk4EwKvFWHrUYsWErEVR+igKtLdchu+o0Z1RL7VU/jVMFbYir2bp6bAj8efFNxWqHX0dIss6fJQ+/+qeQ==", - "dev": true, - "optional": true, - "requires": { - "ansi-escapes": "^3.0.0", - "chalk": "^2.0.0", - "cli-cursor": "^2.1.0", - "cli-width": "^2.0.0", - "external-editor": "^2.0.4", - "figures": "^2.0.0", - "lodash": "^4.3.0", - "mute-stream": "0.0.7", - "run-async": "^2.2.0", - "rx-lite": "^4.0.8", - "rx-lite-aggregates": "^4.0.8", - "string-width": "^2.1.0", - "strip-ansi": "^4.0.0", - "through": "^2.3.6" - }, - "dependencies": { - "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, - "optional": true - }, - "figures": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", - "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=", - "dev": true, - "optional": true, - "requires": { - "escape-string-regexp": "^1.0.5" - } - }, - "mute-stream": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz", - "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=", - "dev": true, - "optional": true - }, - "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, - "optional": true, - "requires": { - "is-promise": "^2.1.0" - } - }, - "rx-lite": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/rx-lite/-/rx-lite-4.0.8.tgz", - "integrity": "sha1-Cx4Rr4vESDbwSmQH6S2kJGe3lEQ=", - "dev": true - }, - "rx-lite-aggregates": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/rx-lite-aggregates/-/rx-lite-aggregates-4.0.8.tgz", - "integrity": "sha1-dTuHqJoRyVRnxKwWJsTvxOBcZ74=", - "dev": true, - "optional": true, - "requires": { - "rx-lite": "*" - } - }, - "through": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", - "dev": true, - "optional": true - } - } - }, - "json-schema-traverse": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz", - "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=", - "dev": true - }, - "ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true, - "optional": true - }, - "regexpp": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-1.1.0.tgz", - "integrity": "sha512-LOPw8FpgdQF9etWMaAfG/WRthIdXJGYp4mJ2Jgn/2lpkbod9jPn0t9UqN7AxBOKNfzRbYyVfgc7Vk4t/MpnXgw==", - "dev": true, - "optional": true - }, - "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, - "optional": true - }, - "slice-ansi": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-1.0.0.tgz", - "integrity": "sha512-POqxBK6Lb3q6s047D/XsDVNPnF9Dl8JSaqe9h9lURl0OdNqy/ujDrOiIHtsqXMGbWWTIomRzAMaTyawAU//Reg==", - "dev": true, - "optional": true, - "requires": { - "is-fullwidth-code-point": "^2.0.0" - } - }, - "supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", - "dev": true, - "optional": true - }, - "table": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/table/-/table-4.0.2.tgz", - "integrity": "sha512-UUkEAPdSGxtRpiV9ozJ5cMTtYiqz7Ni1OGqLXRCynrvzdtR1p+cfOWe2RJLwvUG8hNanaSRjecIqwOjqeatDsA==", - "dev": true, - "optional": true, - "requires": { - "ajv": "^5.2.3", - "ajv-keywords": "^2.1.0", - "chalk": "^2.1.0", - "lodash": "^4.17.4", - "slice-ansi": "1.0.0", - "string-width": "^2.1.1" - } - }, - "vue-eslint-parser": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/vue-eslint-parser/-/vue-eslint-parser-2.0.3.tgz", - "integrity": "sha512-ZezcU71Owm84xVF6gfurBQUGg8WQ+WZGxgDEQu1IHFBZNx7BFZg3L1yHxrCBNNwbwFtE1GuvfJKMtb6Xuwc/Bw==", - "dev": true, - "optional": true, - "requires": { - "debug": "^3.1.0", - "eslint-scope": "^3.7.1", - "eslint-visitor-keys": "^1.0.0", - "espree": "^3.5.2", - "esquery": "^1.0.0", - "lodash": "^4.17.4" - }, - "dependencies": { - "espree": { - "version": "3.5.4", - "resolved": "https://registry.npmjs.org/espree/-/espree-3.5.4.tgz", - "integrity": "sha512-yAcIQxtmMiB/jL32dzEp2enBeidsB7xWPLNiw3IIkpVds1P+h7qF9YwJq1yUNzp2OKXgAprs4F61ih66UsoD1A==", - "dev": true, - "optional": true, - "requires": { - "acorn": "^5.5.0", - "acorn-jsx": "^3.0.0" - } - }, - "esquery": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", - "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", - "dev": true, - "optional": true, - "requires": { - "estraverse": "^5.1.0" - } - }, - "estraverse": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", - "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", - "dev": true, - "optional": true - } - } - }, - "write": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/write/-/write-0.2.1.tgz", - "integrity": "sha1-X8A4KOJkzqP+kUVUdvejxWbLB1c=", - "dev": true, - "optional": true, - "requires": { - "mkdirp": "^0.5.1" - } - } - } - }, - "@vue/cli-plugin-typescript": { - "version": "3.11.0", - "dev": true, - "requires": { - "@types/webpack-env": "^1.13.9", - "@vue/cli-shared-utils": "^3.11.0", - "fork-ts-checker-webpack-plugin": "^0.5.2", - "globby": "^9.2.0", - "ts-loader": "^5.3.3", - "tslint": "^5.15.0", - "webpack": "^4.0.0", - "yorkie": "^2.0.0" - } - }, - "@vue/cli-plugin-unit-mocha": { - "version": "3.11.0", - "dev": true, - "requires": { - "@vue/cli-shared-utils": "^3.11.0", - "jsdom": "^13.2.0", - "jsdom-global": "^3.0.2", - "mocha": "^5.2.0", - "mocha-webpack": "^2.0.0-beta.0" - } - }, - "@vue/cli-service": { - "version": "3.11.0", - "dev": true, - "requires": { - "@intervolga/optimize-cssnano-plugin": "^1.0.5", - "@soda/friendly-errors-webpack-plugin": "^1.7.1", - "@vue/cli-overlay": "^3.11.0", - "@vue/cli-shared-utils": "^3.11.0", - "@vue/component-compiler-utils": "^3.0.0", - "@vue/preload-webpack-plugin": "^1.1.0", - "@vue/web-component-wrapper": "^1.2.0", - "acorn": "^6.1.1", - "acorn-walk": "^6.1.1", - "address": "^1.0.3", - "autoprefixer": "^9.5.1", - "browserslist": "^4.5.4", - "cache-loader": "^2.0.1", - "case-sensitive-paths-webpack-plugin": "^2.2.0", - "chalk": "^2.4.2", - "cli-highlight": "^2.1.0", - "clipboardy": "^2.0.0", - "cliui": "^5.0.0", - "copy-webpack-plugin": "^4.6.0", - "css-loader": "^1.0.1", - "cssnano": "^4.1.10", - "current-script-polyfill": "^1.0.0", - "debug": "^4.1.1", - "default-gateway": "^5.0.2", - "dotenv": "^7.0.0", - "dotenv-expand": "^5.1.0", - "escape-string-regexp": "^1.0.5", - "file-loader": "^3.0.1", - "fs-extra": "^7.0.1", - "globby": "^9.2.0", - "hash-sum": "^1.0.2", - "html-webpack-plugin": "^3.2.0", - "launch-editor-middleware": "^2.2.1", - "lodash.defaultsdeep": "^4.6.1", - "lodash.mapvalues": "^4.6.0", - "lodash.transform": "^4.6.0", - "mini-css-extract-plugin": "^0.6.0", - "minimist": "^1.2.0", - "ora": "^3.4.0", - "portfinder": "^1.0.20", - "postcss-loader": "^3.0.0", - "read-pkg": "^5.0.0", - "semver": "^6.0.0", - "slash": "^2.0.0", - "source-map-url": "^0.4.0", - "ssri": "^6.0.1", - "string.prototype.padend": "^3.0.0", - "terser-webpack-plugin": "^1.2.3", - "thread-loader": "^2.1.2", - "url-loader": "^1.1.2", - "vue-loader": "^15.7.0", - "webpack": "^4.0.0", - "webpack-bundle-analyzer": "^3.3.0", - "webpack-chain": "^4.11.0", - "webpack-dev-server": "^3.4.1", - "webpack-merge": "^4.2.1" - }, - "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" - } - }, - "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.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "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 - }, - "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" - } - }, - "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" - } - } - } - }, - "@vue/cli-shared-utils": { - "version": "3.11.0", - "resolved": "https://registry.npmjs.org/@vue/cli-shared-utils/-/cli-shared-utils-3.11.0.tgz", - "integrity": "sha512-D7pst/4v9H1DD66fLxlZOwRR09R03MV0ROdKxBHmh3FmnApCA/RiaolFA/8w+B3CnevYMlV3SJ5fOAgedbswbA==", - "dev": true, - "requires": { - "@hapi/joi": "^15.0.1", - "chalk": "^2.4.1", - "execa": "^1.0.0", - "launch-editor": "^2.2.1", - "lru-cache": "^5.1.1", - "node-ipc": "^9.1.1", - "open": "^6.3.0", - "ora": "^3.4.0", - "request": "^2.87.0", - "request-promise-native": "^1.0.7", - "semver": "^6.0.0", - "string.prototype.padstart": "^3.0.0" - }, - "dependencies": { - "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" - } - }, - "request-promise-core": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.4.tgz", - "integrity": "sha512-TTbAfBBRdWD7aNNOoVOBH4pN/KigV6LyapYNNlAPA8JwbovRti1E88m3sYAwsLi5ryhPKsE9APwnjFTgdUjTpw==", - "dev": true, - "requires": { - "lodash": "^4.17.19" - } - }, - "request-promise-native": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/request-promise-native/-/request-promise-native-1.0.9.tgz", - "integrity": "sha512-wcW+sIUiWnKgNY0dqCpOZkUbF/I+YPi+f09JZIDa39Ec+q82CpSYniDp+ISgTTbKmnpJWASeJBPZmoxH84wt3g==", - "dev": true, - "requires": { - "request-promise-core": "1.1.4", - "stealthy-require": "^1.1.1", - "tough-cookie": "^2.3.3" - } - }, - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - } - } - }, - "@vue/component-compiler-utils": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@vue/component-compiler-utils/-/component-compiler-utils-3.0.0.tgz", - "integrity": "sha512-am+04/0UX7ektcmvhYmrf84BDVAD8afFOf4asZjN84q8xzxFclbk5x0MtxuKGfp+zjN5WWPJn3fjFAWtDdIGSw==", - "dev": true, - "requires": { - "consolidate": "^0.15.1", - "hash-sum": "^1.0.2", - "lru-cache": "^4.1.2", - "merge-source-map": "^1.1.0", - "postcss": "^7.0.14", - "postcss-selector-parser": "^5.0.0", - "prettier": "1.16.3", - "source-map": "~0.6.1", - "vue-template-es2015-compiler": "^1.9.0" - }, - "dependencies": { - "cssesc": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-2.0.0.tgz", - "integrity": "sha512-MsCAG1z9lPdoO/IUMLSBWBSVxVtJ1395VGIQ+Fc2gNdkQ1hNDnQdw3YhA71WJCBW1vdwA0cAnk/DnW6bqoEUYg==", - "dev": true - }, - "postcss-selector-parser": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-5.0.0.tgz", - "integrity": "sha512-w+zLE5Jhg6Liz8+rQOWEAwtwkyqpfnmsinXjXg6cY7YIONZZtgvE0v2O0uhQBs0peNomOJwWRKt6JBfTdTd3OQ==", - "dev": true, - "requires": { - "cssesc": "^2.0.0", - "indexes-of": "^1.0.1", - "uniq": "^1.0.1" - } - } - } - }, - "@vue/eslint-config-typescript": { - "version": "4.0.0", - "dev": true, - "requires": { - "@typescript-eslint/eslint-plugin": "^1.1.0", - "@typescript-eslint/parser": "^1.1.0" - }, - "dependencies": { - "@typescript-eslint/eslint-plugin": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-1.13.0.tgz", - "integrity": "sha512-WQHCozMnuNADiqMtsNzp96FNox5sOVpU8Xt4meaT4em8lOG1SrOv92/mUbEHQVh90sldKSfcOc/I0FOb/14G1g==", - "dev": true, - "requires": { - "@typescript-eslint/experimental-utils": "1.13.0", - "eslint-utils": "^1.3.1", - "functional-red-black-tree": "^1.0.1", - "regexpp": "^2.0.1", - "tsutils": "^3.7.0" - } - }, - "@typescript-eslint/parser": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-1.13.0.tgz", - "integrity": "sha512-ITMBs52PCPgLb2nGPoeT4iU3HdQZHcPaZVw+7CsFagRJHUhyeTgorEwHXhFf3e7Evzi8oujKNpHc8TONth8AdQ==", - "dev": true, - "requires": { - "@types/eslint-visitor-keys": "^1.0.0", - "@typescript-eslint/experimental-utils": "1.13.0", - "@typescript-eslint/typescript-estree": "1.13.0", - "eslint-visitor-keys": "^1.0.0" - } - } - } - }, - "@vue/preload-webpack-plugin": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@vue/preload-webpack-plugin/-/preload-webpack-plugin-1.1.0.tgz", - "integrity": "sha512-rcn2KhSHESBFMPj5vc5X2pI9bcBNQQixvJXhD5gZ4rN2iym/uH2qfDSQfUS5+qwiz0a85TCkeUs6w6jxFDudbw==", - "dev": true - }, - "@vue/test-utils": { - "version": "1.0.0-beta.29", - "dev": true, - "requires": { - "dom-event-types": "^1.0.0", - "lodash": "^4.17.4" - } - }, - "@vue/web-component-wrapper": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@vue/web-component-wrapper/-/web-component-wrapper-1.2.0.tgz", - "integrity": "sha512-Xn/+vdm9CjuC9p3Ae+lTClNutrVhsXpzxvoTXXtoys6kVRX9FkueSUAqSWAyZntmVLlR4DosBV4pH8y5Z/HbUw==", - "dev": true - }, - "@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 - }, - "abab": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.5.tgz", - "integrity": "sha512-9IK9EadsbHo6jLWIpxpR6pL0sazTXV6+SQv25ZB+F7Bj9mJNaOc4nCRabwd5M/JwmUa8idz6Eci6eKfJryPs6Q==", - "dev": true - }, - "accepts": { - "version": "1.3.7", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", - "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", - "dev": true, - "requires": { - "mime-types": "~2.1.24", - "negotiator": "0.6.2" - }, - "dependencies": { - "mime-db": { - "version": "1.47.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.47.0.tgz", - "integrity": "sha512-QBmA/G2y+IfeS4oktet3qRZ+P5kPhCKRXxXnQEudYqUaEioAU1/Lq2us3D/t1Jfo4hE9REQPrbB7K5sOczJVIw==", - "dev": true - }, - "mime-types": { - "version": "2.1.30", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.30.tgz", - "integrity": "sha512-crmjA4bLtR8m9qLpHvgxSChT+XoSlZi8J4n/aIdn3z92e/U47Z0V/yl+Wh9W046GgFVAmoNR/fmdbZYcSSIUeg==", - "dev": true, - "requires": { - "mime-db": "1.47.0" - } - } - } - }, - "acorn": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.3.0.tgz", - "integrity": "sha512-/czfa8BwS88b9gWQVhc8eknunSA2DoJpJyTQkhheIf5E48u1N0R4q/YxxsAeqRrmK9TQ/uYfgLDfZo91UlANIA==", - "dev": true - }, - "acorn-globals": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-4.3.4.tgz", - "integrity": "sha512-clfQEh21R+D0leSbUdWf3OcfqyaCSAQ8Ryq00bofSekfr9W8u1jyYZo6ir0xu9Gtcf7BjcHJpnbZH7JOCpP60A==", - "dev": true, - "requires": { - "acorn": "^6.0.1", - "acorn-walk": "^6.0.1" - } - }, - "acorn-jsx": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.0.2.tgz", - "integrity": "sha512-tiNTrP1MP0QrChmD2DdupCr6HWSFeKVw5d/dHTu4Y7rkAkRhU/Dt7dphAfIUyxtHpl/eBVip5uTNSpQJHylpAw==", - "dev": true - }, - "acorn-walk": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-6.1.1.tgz", - "integrity": "sha512-OtUw6JUTgxA2QoqqmrmQ7F2NYqiBPi/L2jqHyFtllhOUvXYQXf0Z1CYUinIfyT4bTCGmrA7gX9FvHA81uzCoVw==", - "dev": true - }, - "address": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/address/-/address-1.0.3.tgz", - "integrity": "sha512-z55ocwKBRLryBs394Sm3ushTtBeg6VAeuku7utSoSnsJKvKcnXFIyC6vh27n3rXyxSgkJBBCAvyOn7gSUcTYjg==", - "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": "2.1.1", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-2.1.1.tgz", - "integrity": "sha1-YXmX/F9gV2iUxDX5QNgZ4TW4B2I=", - "dev": true, - "optional": true - }, - "alphanum-sort": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/alphanum-sort/-/alphanum-sort-1.0.2.tgz", - "integrity": "sha1-l6ERlkmyEa0zaR2fn0hqjsn74KM=", - "dev": true - }, - "ansi-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-html": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/ansi-html/-/ansi-html-0.0.7.tgz", - "integrity": "sha1-gTWEAhliqenm/QOflA0S9WynhZ4=", - "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" - } - }, - "any-promise": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", - "integrity": "sha1-q8av7tzqUugJzcA3au0845Y10X8=", - "dev": true - }, - "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" - } - }, - "aproba": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", - "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", - "dev": true - }, - "arch": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/arch/-/arch-2.2.0.tgz", - "integrity": "sha512-Of/R0wqp83cgHozfIYLbBMnej79U/SVGOOyuB3VVFv1NRM/PSFMK12x9KVtiYzJqmnU5WR2qp0Z5rHb7sWGnFQ==", - "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-equal": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/array-equal/-/array-equal-1.0.0.tgz", - "integrity": "sha1-jCpe8kcv2ep0KwTHenUJO6J1fJM=", - "dev": true - }, - "array-flatten": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", - "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=", - "dev": true - }, - "array-from": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/array-from/-/array-from-2.1.1.tgz", - "integrity": "sha1-z+nYwmYoudxa7MYqn12PHzUsEZU=", - "dev": true - }, - "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": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", - "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", - "dev": true, - "requires": { - "safer-buffer": "~2.1.0" - } - }, - "asn1.js": { - "version": "5.4.1", - "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-5.4.1.tgz", - "integrity": "sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==", - "dev": true, - "requires": { - "bn.js": "^4.0.0", - "inherits": "^2.0.1", - "minimalistic-assert": "^1.0.0", - "safer-buffer": "^2.1.0" - }, - "dependencies": { - "bn.js": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", - "dev": true - } - } - }, - "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" - } - } - } - }, - "assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", - "dev": true - }, - "assertion-error": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", - "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", - "dev": true - }, - "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": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", - "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=", - "dev": true - }, - "async-each": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.1.tgz", - "integrity": "sha1-GdOGodntxufByF04iu28xW0zYC0=", - "dev": true - }, - "async-limiter": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.0.tgz", - "integrity": "sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg==", - "dev": true - }, - "asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", - "dev": true - }, - "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 - }, - "autoprefixer": { - "version": "9.6.1", - "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-9.6.1.tgz", - "integrity": "sha512-aVo5WxR3VyvyJxcJC3h4FKfwCQvQWb1tSI5VHNibddCVWrcD1NvlxEweg3TSgiPztMnWfjpy2FURKA2kvDE+Tw==", - "dev": true, - "requires": { - "browserslist": "^4.6.3", - "caniuse-lite": "^1.0.30000980", - "chalk": "^2.4.2", - "normalize-range": "^0.1.2", - "num2fraction": "^1.2.2", - "postcss": "^7.0.17", - "postcss-value-parser": "^4.0.0" - } - }, - "aws-sign2": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", - "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=", - "dev": true - }, - "aws4": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz", - "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==", - "dev": true - }, - "axios": { - "version": "0.18.0", - "requires": { - "follow-redirects": "^1.3.0", - "is-buffer": "^1.1.5" - } - }, - "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" - } - }, - "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "dev": true, - "requires": { - "ansi-regex": "^2.0.0" - } - }, - "supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", - "dev": true - } - } - }, - "babel-eslint": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/babel-eslint/-/babel-eslint-10.0.1.tgz", - "integrity": "sha512-z7OT1iNV+TjOwHNLLyJk+HN+YVWX+CLE6fPD2SymJZOZQBs+QIexFjhm4keGTm8MW9xr4EC9Q0PbaLB24V5GoQ==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.0.0", - "@babel/parser": "^7.0.0", - "@babel/traverse": "^7.0.0", - "@babel/types": "^7.0.0", - "eslint-scope": "3.7.1", - "eslint-visitor-keys": "^1.0.0" - }, - "dependencies": { - "eslint-scope": { - "version": "3.7.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-3.7.1.tgz", - "integrity": "sha1-PWPD7f2gLgbgGkUq2IyqzHzctug=", - "dev": true, - "requires": { - "esrecurse": "^4.1.0", - "estraverse": "^4.1.1" - } - } - } - }, - "babel-runtime": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", - "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", - "dev": true, - "requires": { - "core-js": "^2.4.0", - "regenerator-runtime": "^0.11.0" - }, - "dependencies": { - "core-js": { - "version": "2.6.12", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.12.tgz", - "integrity": "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==", - "dev": true - } - } - }, - "balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true - }, - "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.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "dev": true - }, - "batch": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", - "integrity": "sha1-3DQxT05nkxgJP8dgJyUl+UvyXBY=", - "dev": true - }, - "bcrypt-pbkdf": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", - "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", - "dev": true, - "requires": { - "tweetnacl": "^0.14.3" - } - }, - "bfj": { - "version": "6.1.2", - "resolved": "https://registry.npmjs.org/bfj/-/bfj-6.1.2.tgz", - "integrity": "sha512-BmBJa4Lip6BPRINSZ0BPEIfB1wUY/9rwbwvIHQA1KjX9om29B6id0wnWXq7m3bn5JrUVjeOTnVuhPT1FiHwPGw==", - "dev": true, - "requires": { - "bluebird": "^3.5.5", - "check-types": "^8.0.3", - "hoopy": "^0.1.4", - "tryer": "^1.0.1" - } - }, - "big.js": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", - "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", - "dev": true - }, - "binary-extensions": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", - "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==", - "dev": true - }, - "bluebird": { - "version": "3.7.2", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", - "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", - "dev": true - }, - "bn.js": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.0.tgz", - "integrity": "sha512-D7iWRBvnZE8ecXiLj/9wbxH7Tk79fAh8IHaTNq1RWRixsS02W+5qS+iE9yq6RYl0asXx5tw0bLhmT5pIfbSquw==", - "dev": true - }, - "body-parser": { - "version": "1.19.0", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz", - "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==", - "dev": true, - "requires": { - "bytes": "3.1.0", - "content-type": "~1.0.4", - "debug": "2.6.9", - "depd": "~1.1.2", - "http-errors": "1.7.2", - "iconv-lite": "0.4.24", - "on-finished": "~2.3.0", - "qs": "6.7.0", - "raw-body": "2.4.0", - "type-is": "~1.6.17" - }, - "dependencies": { - "qs": { - "version": "6.7.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", - "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==", - "dev": true - } - } - }, - "bonjour": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/bonjour/-/bonjour-3.5.0.tgz", - "integrity": "sha1-jokKGD2O6aI5OzhExpGkK897yfU=", - "dev": true, - "requires": { - "array-flatten": "^2.1.0", - "deep-equal": "^1.0.1", - "dns-equal": "^1.0.0", - "dns-txt": "^2.0.2", - "multicast-dns": "^6.0.1", - "multicast-dns-service-types": "^1.1.0" - }, - "dependencies": { - "array-flatten": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-2.1.2.tgz", - "integrity": "sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ==", - "dev": true - } - } - }, - "boolbase": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", - "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=", - "dev": true - }, - "brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "braces": { - "version": "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 - }, - "browser-process-hrtime": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz", - "integrity": "sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==", - "dev": true - }, - "browser-stdout": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", - "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", - "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.1.0", - "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.1.0.tgz", - "integrity": "sha512-AdEER0Hkspgno2aR97SAf6vi0y0k8NuOpGnVH3O99rcA5Q6sh8QxcngtHuJ6uXwnfAXNM4Gn1Gb7/MV1+Ymbog==", - "dev": true, - "requires": { - "bn.js": "^5.0.0", - "randombytes": "^2.0.1" - } - }, - "browserify-sign": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.1.tgz", - "integrity": "sha512-/vrA5fguVAKKAVTNJjgSm1tRQDHUU6DbwO9IROu/0WAzC8PKhucDSh18J0RMvVeHAn5puMd+QHC2erPRNf8lmg==", - "dev": true, - "requires": { - "bn.js": "^5.1.1", - "browserify-rsa": "^4.0.1", - "create-hash": "^1.2.0", - "create-hmac": "^1.1.7", - "elliptic": "^6.5.3", - "inherits": "^2.0.4", - "parse-asn1": "^5.1.5", - "readable-stream": "^3.6.0", - "safe-buffer": "^5.2.0" - }, - "dependencies": { - "readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "dev": true, - "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - } - }, - "safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "dev": true - } - } - }, - "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.0", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.7.0.tgz", - "integrity": "sha512-9rGNDtnj+HaahxiVV38Gn8n8Lr8REKsel68v1sPFfIGEK6uSXTY3h9acgiT1dZVtOOUtifo/Dn8daDQ5dUgVsA==", - "dev": true, - "requires": { - "caniuse-lite": "^1.0.30000989", - "electron-to-chromium": "^1.3.247", - "node-releases": "^1.1.29" - } - }, - "buffer": { - "version": "4.9.2", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.2.tgz", - "integrity": "sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==", - "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-indexof": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/buffer-indexof/-/buffer-indexof-1.1.1.tgz", - "integrity": "sha512-4/rOEg86jivtPTeOUUT61jJO1Ya1TrR/OkqCSZDyq84WJh3LuuiphBYJN+fm5xufIk4XAFcEwte/8WzC8If/1g==", - "dev": true - }, - "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-modules": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", - "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", - "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 - }, - "bytes": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", - "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==", - "dev": true - }, - "cacache": { - "version": "10.0.4", - "resolved": "https://registry.npmjs.org/cacache/-/cacache-10.0.4.tgz", - "integrity": "sha512-Dph0MzuH+rTQzGPNT9fAnrPmMmjKfST6trxJeK7NQuHRaVw24VzPRWTmg9MpcwOVQZO0E1FBICUlFeNaKPIfHA==", - "dev": true, - "requires": { - "bluebird": "^3.5.1", - "chownr": "^1.0.1", - "glob": "^7.1.2", - "graceful-fs": "^4.1.11", - "lru-cache": "^4.1.1", - "mississippi": "^2.0.0", - "mkdirp": "^0.5.1", - "move-concurrently": "^1.0.1", - "promise-inflight": "^1.0.1", - "rimraf": "^2.6.2", - "ssri": "^5.2.4", - "unique-filename": "^1.1.0", - "y18n": "^4.0.0" - }, - "dependencies": { - "ssri": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/ssri/-/ssri-5.3.0.tgz", - "integrity": "sha512-XRSIPqLij52MtgoQavH/x/dU1qVKtWUAAZeOHsR9c2Ddi4XerFy3mc1alf+dLJKl9EUIm/Ht+EowFkTUOA6GAQ==", - "dev": true, - "requires": { - "safe-buffer": "^5.1.1" - } - } - } - }, - "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" - } - }, - "cache-loader": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/cache-loader/-/cache-loader-2.0.1.tgz", - "integrity": "sha512-V99T3FOynmGx26Zom+JrVBytLBsmUCzVG2/4NnUKgvXN4bEV42R1ERl1IyiH/cvFIDA1Ytq2lPZ9tXDSahcQpQ==", - "dev": true, - "requires": { - "loader-utils": "^1.1.0", - "mkdirp": "^0.5.1", - "neo-async": "^2.6.0", - "normalize-path": "^3.0.0", - "schema-utils": "^1.0.0" - }, - "dependencies": { - "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 - } - } - }, - "call-bind": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", - "dev": true, - "requires": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" - } - }, - "call-me-maybe": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/call-me-maybe/-/call-me-maybe-1.0.1.tgz", - "integrity": "sha1-JtII6onje1y95gJQoV8DHBak1ms=", - "dev": true - }, - "caller-callsite": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/caller-callsite/-/caller-callsite-2.0.0.tgz", - "integrity": "sha1-hH4PzgoiN1CpoCfFSzNzGtMVQTQ=", - "dev": true, - "requires": { - "callsites": "^2.0.0" - }, - "dependencies": { - "callsites": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-2.0.0.tgz", - "integrity": "sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA=", - "dev": true - } - } - }, - "caller-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-2.0.0.tgz", - "integrity": "sha1-Ro+DBE42mrIBD6xfBs7uFbsssfQ=", - "dev": true, - "requires": { - "caller-callsite": "^2.0.0" - } - }, - "callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true - }, - "camel-case": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-3.0.0.tgz", - "integrity": "sha1-yjw2iKTpzzpM2nd9xNy8cTJJz3M=", - "dev": true, - "requires": { - "no-case": "^2.2.0", - "upper-case": "^1.1.1" - } - }, - "camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "dev": true - }, - "caniuse-api": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-3.0.0.tgz", - "integrity": "sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==", - "dev": true, - "requires": { - "browserslist": "^4.0.0", - "caniuse-lite": "^1.0.0", - "lodash.memoize": "^4.1.2", - "lodash.uniq": "^4.5.0" - } - }, - "caniuse-lite": { - "version": "1.0.30001208", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001208.tgz", - "integrity": "sha512-OE5UE4+nBOro8Dyvv0lfx+SRtfVIOM9uhKqFmJeUbGriqhhStgp1A0OyBpgy3OUF8AhYCT+PVwPC1gMl2ZcQMA==", - "dev": true - }, - "case-sensitive-paths-webpack-plugin": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/case-sensitive-paths-webpack-plugin/-/case-sensitive-paths-webpack-plugin-2.2.0.tgz", - "integrity": "sha512-u5ElzokS8A1pm9vM3/iDgTcI3xqHxuCao94Oz8etI3cf0Tio0p8izkDYbTIn09uP3yUUr6+veaE6IkjnTYS46g==", - "dev": true - }, - "caseless": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", - "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", - "dev": true - }, - "chai": { - "version": "4.2.0", - "dev": true, - "requires": { - "assertion-error": "^1.1.0", - "check-error": "^1.0.2", - "deep-eql": "^3.0.1", - "get-func-name": "^2.0.0", - "pathval": "^1.1.0", - "type-detect": "^4.0.5" - } - }, - "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 - }, - "check-error": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", - "integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=", - "dev": true - }, - "check-types": { - "version": "8.0.3", - "resolved": "https://registry.npmjs.org/check-types/-/check-types-8.0.3.tgz", - "integrity": "sha512-YpeKZngUmG65rLudJ4taU7VLkOCTMhNl/u4ctNC56LQS/zJTyNH0Lrtwm1tfTsbLlwvlfsA2d1c8vCf/Kh2KwQ==", - "dev": true - }, - "chokidar": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.0.4.tgz", - "integrity": "sha512-z9n7yt9rOvIJrMhvDtDictKrkFHeihkNl6uWMmZlmL6tJtX9Cs+87oK+teBx+JIgzvbX3yZHT3eF8vpbDxHJXQ==", - "dev": true, - "requires": { - "anymatch": "^2.0.0", - "async-each": "^1.0.0", - "braces": "^2.3.0", - "fsevents": "^1.2.2", - "glob-parent": "^3.1.0", - "inherits": "^2.0.1", - "is-binary-path": "^1.0.0", - "is-glob": "^4.0.0", - "lodash.debounce": "^4.0.8", - "normalize-path": "^2.1.1", - "path-is-absolute": "^1.0.0", - "readdirp": "^2.0.0", - "upath": "^1.0.5" - }, - "dependencies": { - "fsevents": { - "version": "1.2.13", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz", - "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==", - "dev": true, - "optional": true - } - } - }, - "chownr": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.1.tgz", - "integrity": "sha512-j38EvO5+LHX84jlo6h4UzmOwi0UgW61WRyPtJz4qaadK5eY3BTS5TY/S1Stc3Uk2lIM6TPevAlULiEJwie860g==", - "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" - } - }, - "clamp": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/clamp/-/clamp-1.0.1.tgz", - "integrity": "sha1-ZqDmQBGBbjcZaCj9yMjBRzEshjQ=" - }, - "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" - } - } - } - }, - "clean-css": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.2.3.tgz", - "integrity": "sha512-VcMWDN54ZN/DS+g58HYL5/n4Zrqe8vHJpGA8KdgUXFU4fuP/aHNw8eld9SyEIyabIMJX/0RaY/fplOo5hYLSFA==", - "dev": true, - "requires": { - "source-map": "~0.6.0" - } - }, - "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-highlight": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/cli-highlight/-/cli-highlight-2.1.1.tgz", - "integrity": "sha512-0y0VlNmdD99GXZHYnvrQcmHxP8Bi6T00qucGgBgGv4kJ0RyDthNnnFPupHV7PYv/OXSVk+azFbOeaW6+vGmx9A==", - "dev": true, - "requires": { - "chalk": "^2.3.0", - "highlight.js": "^9.6.0", - "mz": "^2.4.0", - "parse5": "^4.0.0", - "yargs": "^13.0.0" - }, - "dependencies": { - "highlight.js": { - "version": "9.13.1", - "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-9.13.1.tgz", - "integrity": "sha512-Sc28JNQNDzaH6PORtRLMvif9RSn1mYuOoX3omVjnb0+HbpPygU2ALBI0R/wsiqCb4/fcp07Gdo8g+fhtFrQl6A==", - "dev": true - }, - "parse5": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-4.0.0.tgz", - "integrity": "sha512-VrZ7eOd3T1Fk4XWNXMgiGBK/z0MG48BWG2uQNU4I72fkQuKUTZpl+u9k+CxEG0twMVzSmXEEz12z5Fnw1jIQFA==", - "dev": true - } - } - }, - "cli-spinners": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.6.0.tgz", - "integrity": "sha512-t+4/y50K/+4xcCRosKkA7W4gTr1MySvLV0q+PxmG7FJ5g+66ChKurYjxBCjHggHH3HA5Hh9cy+lcUGWDqVH+4Q==", - "dev": true - }, - "cli-width": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.1.tgz", - "integrity": "sha512-GRMWDxpOB6Dgk2E5Uo+3eEBvtOOlimMmpbFiKuLFnQzYDavtLFY3K5ona41jgN/WdRZtG7utuVSVTL4HbZHGkw==", - "dev": true - }, - "clipboardy": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/clipboardy/-/clipboardy-2.1.0.tgz", - "integrity": "sha512-2pzOUxWcLlXWtn+Jd6js3o12TysNOOVes/aQfg+MT/35vrxWzedHlLwyoJpXjsFKWm95BTNEcMGD9+a7mKzZkQ==", - "dev": true, - "requires": { - "arch": "^2.1.1", - "execa": "^1.0.0" - } - }, - "cliui": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-4.1.0.tgz", - "integrity": "sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ==", - "dev": true, - "requires": { - "string-width": "^2.1.1", - "strip-ansi": "^4.0.0", - "wrap-ansi": "^2.0.0" - } - }, - "clone": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", - "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=", - "dev": true - }, - "coa": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/coa/-/coa-2.0.2.tgz", - "integrity": "sha512-q5/jG+YQnSy4nRTV4F7lPepBJZ8qBNJJDBuJdoejDyLXgmL7IEo+Le2JDZudFTFt7mrCqIRaSjws4ygRCTCAXA==", - "dev": true, - "requires": { - "@types/q": "^1.5.1", - "chalk": "^2.4.1", - "q": "^1.1.2" - } - }, - "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": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/color/-/color-3.1.3.tgz", - "integrity": "sha512-xgXAcTHa2HeFCGLE9Xs/R82hujGtu9Jd9x4NW3T34+OMs7VoPsjwzRczKHvTAHeJwWFwX5j15+MgAppE8ztObQ==", - "dev": true, - "requires": { - "color-convert": "^1.9.1", - "color-string": "^1.5.4" - } - }, - "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 - }, - "color-string": { - "version": "1.5.5", - "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.5.5.tgz", - "integrity": "sha512-jgIoum0OfQfq9Whcfc2z/VhCNcmQjWbey6qBX0vqt7YICflUmBCh9E9CiQD5GSJ+Uehixm3NUwHVhqUAWRivZg==", - "dev": true, - "requires": { - "color-name": "^1.0.0", - "simple-swizzle": "^0.2.2" - } - }, - "combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "dev": true, - "requires": { - "delayed-stream": "~1.0.0" - } - }, - "commander": { - "version": "2.17.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.17.1.tgz", - "integrity": "sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg==", - "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 - }, - "compressible": { - "version": "2.0.18", - "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", - "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", - "dev": true, - "requires": { - "mime-db": ">= 1.43.0 < 2" - }, - "dependencies": { - "mime-db": { - "version": "1.47.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.47.0.tgz", - "integrity": "sha512-QBmA/G2y+IfeS4oktet3qRZ+P5kPhCKRXxXnQEudYqUaEioAU1/Lq2us3D/t1Jfo4hE9REQPrbB7K5sOczJVIw==", - "dev": true - } - } - }, - "compression": { - "version": "1.7.4", - "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz", - "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==", - "dev": true, - "requires": { - "accepts": "~1.3.5", - "bytes": "3.0.0", - "compressible": "~2.0.16", - "debug": "2.6.9", - "on-headers": "~1.0.2", - "safe-buffer": "5.1.2", - "vary": "~1.1.2" - }, - "dependencies": { - "bytes": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", - "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=", - "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" - } - }, - "connect-history-api-fallback": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-1.6.0.tgz", - "integrity": "sha512-e54B99q/OUoH64zYYRf3HBP5z24G38h5D3qXu23JGRoigpX5Ss4r9ZnDk3g0Z8uQC2x2lPaJ+UlWBc1ZWBWdLg==", - "dev": true - }, - "console-browserify": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.2.0.tgz", - "integrity": "sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA==", - "dev": true - }, - "consolidate": { - "version": "0.15.1", - "resolved": "https://registry.npmjs.org/consolidate/-/consolidate-0.15.1.tgz", - "integrity": "sha512-DW46nrsMJgy9kqAbPt5rKaCr7uFtpo4mSUvLHIUbJEjm0vo+aY5QLwBUq3FK4tRnJr/X0Psc0C4jf/h+HtXSMw==", - "dev": true, - "requires": { - "bluebird": "^3.1.1" - } - }, - "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 - }, - "content-disposition": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz", - "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==", - "dev": true, - "requires": { - "safe-buffer": "5.1.2" - } - }, - "content-type": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", - "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==", - "dev": true - }, - "cookie": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz", - "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==", - "dev": true - }, - "cookie-signature": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", - "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=", - "dev": true - }, - "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": "4.6.0", - "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-4.6.0.tgz", - "integrity": "sha512-Y+SQCF+0NoWQryez2zXn5J5knmr9z/9qSQt7fbL78u83rxmigOy8X5+BFn8CFSuX+nKT8gpYwJX68ekqtQt6ZA==", - "dev": true, - "requires": { - "cacache": "^10.0.4", - "find-cache-dir": "^1.0.0", - "globby": "^7.1.1", - "is-glob": "^4.0.0", - "loader-utils": "^1.1.0", - "minimatch": "^3.0.4", - "p-limit": "^1.0.0", - "serialize-javascript": "^1.4.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 - }, - "slash": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz", - "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=", - "dev": true - } - } - }, - "core-js": { - "version": "0.8.4", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-0.8.4.tgz", - "integrity": "sha1-wiZl8eDRucPF4bCNq9HxCGleT88=", - "dev": true - }, - "core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", - "dev": true - }, - "cosmiconfig": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.2.1.tgz", - "integrity": "sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA==", - "dev": true, - "requires": { - "import-fresh": "^2.0.0", - "is-directory": "^0.3.1", - "js-yaml": "^3.13.1", - "parse-json": "^4.0.0" - }, - "dependencies": { - "js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", - "dev": true, - "requires": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - } - } - } - }, - "create-ecdh": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.4.tgz", - "integrity": "sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A==", - "dev": true, - "requires": { - "bn.js": "^4.1.0", - "elliptic": "^6.5.3" - }, - "dependencies": { - "bn.js": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", - "dev": true - } - } - }, - "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": "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" - } - }, - "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" - } - }, - "css-color-names": { - "version": "0.0.4", - "resolved": "https://registry.npmjs.org/css-color-names/-/css-color-names-0.0.4.tgz", - "integrity": "sha1-gIrcLnnPhHOAabZGyyDsJ762KeA=", - "dev": true - }, - "css-declaration-sorter": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-4.0.1.tgz", - "integrity": "sha512-BcxQSKTSEEQUftYpBVnsH4SF05NTuBokb19/sBt6asXGKZ/6VP7PLG1CBCkFDYOnhXhPh0jMhO6xZ71oYHXHBA==", - "dev": true, - "requires": { - "postcss": "^7.0.1", - "timsort": "^0.3.0" - } - }, - "css-loader": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-1.0.1.tgz", - "integrity": "sha512-+ZHAZm/yqvJ2kDtPne3uX0C+Vr3Zn5jFn2N4HywtS5ujwvsVkyg0VArEXpl3BgczDA8anieki1FIzhchX4yrDw==", - "dev": true, - "requires": { - "babel-code-frame": "^6.26.0", - "css-selector-tokenizer": "^0.7.0", - "icss-utils": "^2.1.0", - "loader-utils": "^1.0.2", - "lodash": "^4.17.11", - "postcss": "^6.0.23", - "postcss-modules-extract-imports": "^1.2.0", - "postcss-modules-local-by-default": "^1.2.0", - "postcss-modules-scope": "^1.1.0", - "postcss-modules-values": "^1.3.0", - "postcss-value-parser": "^3.3.0", - "source-list-map": "^2.0.0" - }, - "dependencies": { - "postcss": { - "version": "6.0.23", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.23.tgz", - "integrity": "sha512-soOk1h6J3VMTZtVeVpv15/Hpdl2cBLX3CAw4TAbkpTJiNPk9YP/zWcD1ND+xEtvyuuvKzbxliTOIyvkSeSJ6ag==", - "dev": true, - "requires": { - "chalk": "^2.4.1", - "source-map": "^0.6.1", - "supports-color": "^5.4.0" - } - }, - "postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", - "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", - "dev": true - } - } - }, - "css-select": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/css-select/-/css-select-2.1.0.tgz", - "integrity": "sha512-Dqk7LQKpwLoH3VovzZnkzegqNSuAziQyNZUcrdDM401iY+R5NkGBXGmtO05/yaXQziALuPogeG0b7UAgjnTJTQ==", - "dev": true, - "requires": { - "boolbase": "^1.0.0", - "css-what": "^3.2.1", - "domutils": "^1.7.0", - "nth-check": "^1.0.2" - } - }, - "css-select-base-adapter": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/css-select-base-adapter/-/css-select-base-adapter-0.1.1.tgz", - "integrity": "sha512-jQVeeRG70QI08vSTwf1jHxp74JoZsr2XSgETae8/xC8ovSnL2WF87GTLO86Sbwdt2lK4Umg4HnnwMO4YF3Ce7w==", - "dev": true - }, - "css-selector-tokenizer": { - "version": "0.7.3", - "resolved": "https://registry.npmjs.org/css-selector-tokenizer/-/css-selector-tokenizer-0.7.3.tgz", - "integrity": "sha512-jWQv3oCEL5kMErj4wRnK/OPoBi0D+P1FR2cDCKYPaMeD2eW3/mttav8HT4hT1CKopiJI/psEULjkClhvJo4Lvg==", - "dev": true, - "requires": { - "cssesc": "^3.0.0", - "fastparse": "^1.1.2" - } - }, - "css-tree": { - "version": "1.0.0-alpha.37", - "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.0.0-alpha.37.tgz", - "integrity": "sha512-DMxWJg0rnz7UgxKT0Q1HU/L9BeJI0M6ksor0OgqOnF+aRCDWg/N2641HmVyU9KVIu0OVVWOb2IpC9A+BJRnejg==", - "dev": true, - "requires": { - "mdn-data": "2.0.4", - "source-map": "^0.6.1" - } - }, - "css-what": { - "version": "3.4.2", - "resolved": "https://registry.npmjs.org/css-what/-/css-what-3.4.2.tgz", - "integrity": "sha512-ACUm3L0/jiZTqfzRM3Hi9Q8eZqd6IK37mMWPLz9PJxkLWllYeRf+EHUSHYEtFop2Eqytaq1FizFVh7XfBnXCDQ==", - "dev": true - }, - "cssesc": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", - "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", - "dev": true - }, - "cssnano": { - "version": "4.1.10", - "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-4.1.10.tgz", - "integrity": "sha512-5wny+F6H4/8RgNlaqab4ktc3e0/blKutmq8yNlBFXA//nSFFAqAngjNVRzUvCgYROULmZZUoosL/KSoZo5aUaQ==", - "dev": true, - "requires": { - "cosmiconfig": "^5.0.0", - "cssnano-preset-default": "^4.0.7", - "is-resolvable": "^1.0.0", - "postcss": "^7.0.0" - } - }, - "cssnano-preset-default": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-4.0.8.tgz", - "integrity": "sha512-LdAyHuq+VRyeVREFmuxUZR1TXjQm8QQU/ktoo/x7bz+SdOge1YKc5eMN6pRW7YWBmyq59CqYba1dJ5cUukEjLQ==", - "dev": true, - "requires": { - "css-declaration-sorter": "^4.0.1", - "cssnano-util-raw-cache": "^4.0.1", - "postcss": "^7.0.0", - "postcss-calc": "^7.0.1", - "postcss-colormin": "^4.0.3", - "postcss-convert-values": "^4.0.1", - "postcss-discard-comments": "^4.0.2", - "postcss-discard-duplicates": "^4.0.2", - "postcss-discard-empty": "^4.0.1", - "postcss-discard-overridden": "^4.0.1", - "postcss-merge-longhand": "^4.0.11", - "postcss-merge-rules": "^4.0.3", - "postcss-minify-font-values": "^4.0.2", - "postcss-minify-gradients": "^4.0.2", - "postcss-minify-params": "^4.0.2", - "postcss-minify-selectors": "^4.0.2", - "postcss-normalize-charset": "^4.0.1", - "postcss-normalize-display-values": "^4.0.2", - "postcss-normalize-positions": "^4.0.2", - "postcss-normalize-repeat-style": "^4.0.2", - "postcss-normalize-string": "^4.0.2", - "postcss-normalize-timing-functions": "^4.0.2", - "postcss-normalize-unicode": "^4.0.1", - "postcss-normalize-url": "^4.0.1", - "postcss-normalize-whitespace": "^4.0.2", - "postcss-ordered-values": "^4.1.2", - "postcss-reduce-initial": "^4.0.3", - "postcss-reduce-transforms": "^4.0.2", - "postcss-svgo": "^4.0.3", - "postcss-unique-selectors": "^4.0.1" - } - }, - "cssnano-util-get-arguments": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/cssnano-util-get-arguments/-/cssnano-util-get-arguments-4.0.0.tgz", - "integrity": "sha1-7ToIKZ8h11dBsg87gfGU7UnMFQ8=", - "dev": true - }, - "cssnano-util-get-match": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/cssnano-util-get-match/-/cssnano-util-get-match-4.0.0.tgz", - "integrity": "sha1-wOTKB/U4a7F+xeUiULT1lhNlFW0=", - "dev": true - }, - "cssnano-util-raw-cache": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/cssnano-util-raw-cache/-/cssnano-util-raw-cache-4.0.1.tgz", - "integrity": "sha512-qLuYtWK2b2Dy55I8ZX3ky1Z16WYsx544Q0UWViebptpwn/xDBmog2TLg4f+DBMg1rJ6JDWtn96WHbOKDWt1WQA==", - "dev": true, - "requires": { - "postcss": "^7.0.0" - } - }, - "cssnano-util-same-parent": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/cssnano-util-same-parent/-/cssnano-util-same-parent-4.0.1.tgz", - "integrity": "sha512-WcKx5OY+KoSIAxBW6UBBRay1U6vkYheCdjyVNDm85zt5K9mHoGOfsOsqIszfAqrQQFIIKgjh2+FDgIj/zsl21Q==", - "dev": true - }, - "csso": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/csso/-/csso-4.2.0.tgz", - "integrity": "sha512-wvlcdIbf6pwKEk7vHj8/Bkc0B4ylXZruLvOgs9doS5eOsOpuodOV2zJChSpkp+pRpYQLQMeF04nr3Z68Sta9jA==", - "dev": true, - "requires": { - "css-tree": "^1.1.2" - }, - "dependencies": { - "css-tree": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.1.3.tgz", - "integrity": "sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==", - "dev": true, - "requires": { - "mdn-data": "2.0.14", - "source-map": "^0.6.1" - } - }, - "mdn-data": { - "version": "2.0.14", - "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz", - "integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==", - "dev": true - } - } - }, - "cssom": { - "version": "0.3.8", - "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", - "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==", - "dev": true - }, - "cssstyle": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-1.4.0.tgz", - "integrity": "sha512-GBrLZYZ4X4x6/QEoBnIrqb8B/f5l4+8me2dkom/j1Gtbxy0kBv6OGzKuAsGM75bkGwGAFkt56Iwg28S3XTZgSA==", - "dev": true, - "requires": { - "cssom": "0.3.x" - } - }, - "current-script-polyfill": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/current-script-polyfill/-/current-script-polyfill-1.0.0.tgz", - "integrity": "sha1-8xz35PPiGLBybnOMqSoC00iO9hU=", - "dev": true - }, - "cyclist": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/cyclist/-/cyclist-0.2.2.tgz", - "integrity": "sha1-GzN5LhHpFKL9bW7WRHRkRE5fpkA=", - "dev": true - }, - "dashdash": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", - "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", - "dev": true, - "requires": { - "assert-plus": "^1.0.0" - } - }, - "data-urls": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-1.1.0.tgz", - "integrity": "sha512-YTWYI9se1P55u58gL5GkQHW4P6VJBJ5iBT+B5a7i2Tjadhv52paJG0qHX4A0OR6/t52odI64KP2YvFpkDOi3eQ==", - "dev": true, - "requires": { - "abab": "^2.0.0", - "whatwg-mimetype": "^2.2.0", - "whatwg-url": "^7.0.0" - } - }, - "de-indent": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/de-indent/-/de-indent-1.0.2.tgz", - "integrity": "sha1-sgOOhG3DO6pXlhKNCAS0VbjB4h0=", - "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-eql": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz", - "integrity": "sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==", - "dev": true, - "requires": { - "type-detect": "^4.0.0" - } - }, - "deep-equal": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.1.1.tgz", - "integrity": "sha512-yd9c5AdiqVcR+JjcwUQb9DkhJc8ngNr0MahEBGvDiJw8puWab2yZlh+nkasOnZP+EGTAP6rRp2JzJhJZzvNF8g==", - "dev": true, - "requires": { - "is-arguments": "^1.0.4", - "is-date-object": "^1.0.1", - "is-regex": "^1.0.4", - "object-is": "^1.0.1", - "object-keys": "^1.1.1", - "regexp.prototype.flags": "^1.2.0" - }, - "dependencies": { - "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 - } - } - }, - "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 - }, - "default-gateway": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-5.0.3.tgz", - "integrity": "sha512-zW+ld9xtN0+q48wIwhitUzhfERJN7BPgvijPhuCKG6bfWqnoqtSNSnrXfvAME2ZJLpgYpz6UorpBddGfLzrJBw==", - "dev": true, - "requires": { - "execa": "^2.0.3" - }, - "dependencies": { - "cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, - "requires": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - } - }, - "execa": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-2.1.0.tgz", - "integrity": "sha512-Y/URAVapfbYy2Xp/gb6A0E7iR8xeqOCXsuuaoMn7A5PzrXUK84E1gyiEfq0wQd/GHA6GsoHWwhNq8anb0mleIw==", - "dev": true, - "requires": { - "cross-spawn": "^7.0.0", - "get-stream": "^5.0.0", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^3.0.0", - "onetime": "^5.1.0", - "p-finally": "^2.0.0", - "signal-exit": "^3.0.2", - "strip-final-newline": "^2.0.0" - } - }, - "get-stream": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", - "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", - "dev": true, - "requires": { - "pump": "^3.0.0" - } - }, - "is-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz", - "integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==", - "dev": true - }, - "npm-run-path": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-3.1.0.tgz", - "integrity": "sha512-Dbl4A/VfiVGLgQv29URL9xshU8XDY1GeLy+fsaZ1AA8JDSfjvr5P5+pzRbWqRSBxk6/DW7MIh8lTM/PaGnP2kg==", - "dev": true, - "requires": { - "path-key": "^3.0.0" - } - }, - "p-finally": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-2.0.1.tgz", - "integrity": "sha512-vpm09aKwq6H9phqRQzecoDpD8TmVyGw70qmWlyq5onxY7tqyTTFVvxMykxQSQKILBSFlbXpypIw2T1Ml7+DDtw==", - "dev": true - }, - "path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true - }, - "shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "requires": { - "shebang-regex": "^3.0.0" - } - }, - "shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true - }, - "which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "requires": { - "isexe": "^2.0.0" - } - } - } - }, - "defaults": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.3.tgz", - "integrity": "sha1-xlYFHpgX2f8I7YgUd/P+QBnz730=", - "dev": true, - "requires": { - "clone": "^1.0.2" - } - }, - "define-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" - } - } - } - }, - "del": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/del/-/del-4.1.1.tgz", - "integrity": "sha512-QwGuEUouP2kVwQenAsOof5Fv8K9t3D8Ca8NxcXKrIpEHjTXK5J2nXLdP+ALI1cgv8wj7KuwBhTwBkOZSJKM5XQ==", - "dev": true, - "requires": { - "@types/glob": "^7.1.1", - "globby": "^6.1.0", - "is-path-cwd": "^2.0.0", - "is-path-in-cwd": "^2.0.0", - "p-map": "^2.0.0", - "pify": "^4.0.1", - "rimraf": "^2.6.3" - }, - "dependencies": { - "globby": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-6.1.0.tgz", - "integrity": "sha1-9abXDoOV4hyFj7BInWTfAkJNUGw=", - "dev": true, - "requires": { - "array-union": "^1.0.1", - "glob": "^7.0.3", - "object-assign": "^4.0.1", - "pify": "^2.0.0", - "pinkie-promise": "^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 - } - } - }, - "pify": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", - "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", - "dev": true - } - } - }, - "delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", - "dev": true - }, - "depd": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", - "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=", - "dev": true - }, - "des.js": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.0.1.tgz", - "integrity": "sha512-Q0I4pfFrv2VPd34/vfLrFOoRmlYj3OV50i7fskps1jZWK1kApMWWT9G6RRUeYedLcBDIhnSDaUvJMb3AhUlaEA==", - "dev": true, - "requires": { - "inherits": "^2.0.1", - "minimalistic-assert": "^1.0.0" - } - }, - "destroy": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", - "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=", - "dev": true - }, - "detect-node": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.0.5.tgz", - "integrity": "sha512-qi86tE6hRcFHy8jI1m2VG+LaPUR1LhqDa5G8tVjuUXmOrpuAgqsA1pN0+ldgr3aKUH+QLI9hCY/OcRYisERejw==", - "dev": true - }, - "diff": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", - "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", - "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" - }, - "dependencies": { - "bn.js": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", - "dev": true - } - } - }, - "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" - } - }, - "dns-equal": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/dns-equal/-/dns-equal-1.0.0.tgz", - "integrity": "sha1-s55/HabrCnW6nBcySzR1PEfgZU0=", - "dev": true - }, - "dns-packet": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-1.3.1.tgz", - "integrity": "sha512-0UxfQkMhYAUaZI+xrNZOz/as5KgDU0M/fQ9b6SpkyLbk3GEswDi6PADJVaYJradtRVsRIlF1zLyOodbcTCDzUg==", - "dev": true, - "requires": { - "ip": "^1.1.0", - "safe-buffer": "^5.0.1" - } - }, - "dns-txt": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/dns-txt/-/dns-txt-2.0.2.tgz", - "integrity": "sha1-uR2Ab10nGI5Ks+fRB9iBocxGQrY=", - "dev": true, - "requires": { - "buffer-indexof": "^1.0.0" - } - }, - "doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "dev": true, - "requires": { - "esutils": "^2.0.2" - } - }, - "dom-converter": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/dom-converter/-/dom-converter-0.2.0.tgz", - "integrity": "sha512-gd3ypIPfOMr9h5jIKq8E3sHOTCjeirnl0WK5ZdS1AW0Odt0b1PaWaHdJ4Qk4klv+YB9aJBS7mESXjFoDQPu6DA==", - "dev": true, - "requires": { - "utila": "~0.4" - } - }, - "dom-event-types": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/dom-event-types/-/dom-event-types-1.0.0.tgz", - "integrity": "sha512-2G2Vwi2zXTHBGqXHsJ4+ak/iP0N8Ar+G8a7LiD2oup5o4sQWytwqqrZu/O6hIMV0KMID2PL69OhpshLO0n7UJQ==", - "dev": true - }, - "dom-serializer": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.2.2.tgz", - "integrity": "sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g==", - "dev": true, - "requires": { - "domelementtype": "^2.0.1", - "entities": "^2.0.0" - }, - "dependencies": { - "domelementtype": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.2.0.tgz", - "integrity": "sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A==", - "dev": true - } - } - }, - "dom-walk": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/dom-walk/-/dom-walk-0.1.2.tgz", - "integrity": "sha512-6QvTW9mrGeIegrFXdtQi9pk7O/nSK6lSdXW2eqUspN5LWD7UTji2Fqw5V2YLjBpHEoU9Xl/eUWNpDeZvoyOv2w==", - "dev": true - }, - "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 - }, - "domelementtype": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz", - "integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==", - "dev": true - }, - "domexception": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/domexception/-/domexception-1.0.1.tgz", - "integrity": "sha512-raigMkn7CJNNo6Ihro1fzG7wr3fHuYVytzquZKX5n0yizGsTcYgzdIUwj1X9pK0VvjeihV+XiclP+DjwbsSKug==", - "dev": true, - "requires": { - "webidl-conversions": "^4.0.2" - } - }, - "domhandler": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.4.2.tgz", - "integrity": "sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA==", - "dev": true, - "requires": { - "domelementtype": "1" - } - }, - "domutils": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.7.0.tgz", - "integrity": "sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg==", - "dev": true, - "requires": { - "dom-serializer": "0", - "domelementtype": "1" - } - }, - "dot-prop": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", - "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==", - "dev": true, - "requires": { - "is-obj": "^2.0.0" - } - }, - "dotenv": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-7.0.0.tgz", - "integrity": "sha512-M3NhsLbV1i6HuGzBUH8vXrtxOk+tWmzWKDMbAVSUp3Zsjm7ywFeuwrUXhmhQyRK1q5B5GGy7hcXPbj3bnfZg2g==", - "dev": true - }, - "dotenv-expand": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-5.1.0.tgz", - "integrity": "sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA==", - "dev": true - }, - "duplexer": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz", - "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==", - "dev": true - }, - "duplexify": { - "version": "3.6.1", - "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.6.1.tgz", - "integrity": "sha512-vM58DwdnKmty+FSPzT14K9JXb90H+j5emaR4KYbr2KTIz00WHGbWOe5ghQTx233ZCLZtrGDALzKwcjEtSt35mA==", - "dev": true, - "requires": { - "end-of-stream": "^1.0.0", - "inherits": "^2.0.1", - "readable-stream": "^2.0.0", - "stream-shift": "^1.0.0" - } - }, - "easy-stack": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/easy-stack/-/easy-stack-1.0.1.tgz", - "integrity": "sha512-wK2sCs4feiiJeFXn3zvY0p41mdU5VUgbgs1rNsc/y5ngFUijdWd+iIN8eoyuZHKB8xN6BL4PdWmzqFmxNg6V2w==", - "dev": true - }, - "ecc-jsbn": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", - "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", - "dev": true, - "requires": { - "jsbn": "~0.1.0", - "safer-buffer": "^2.1.0" - } - }, - "ee-first": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=", - "dev": true - }, - "ejs": { - "version": "2.7.4", - "resolved": "https://registry.npmjs.org/ejs/-/ejs-2.7.4.tgz", - "integrity": "sha512-7vmuyh5+kuUyJKePhQfRQBhXV5Ce+RnaeeQArKu1EAMpL3WbgMt5WG6uQZpEVvYSSsxMXRKOewtDk9RaTKXRlA==", - "dev": true - }, - "electron-to-chromium": { - "version": "1.3.710", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.710.tgz", - "integrity": "sha512-b3r0E2o4yc7mNmBeJviejF1rEx49PUBi+2NPa7jHEX3arkAXnVgLhR0YmV8oi6/Qf3HH2a8xzQmCjHNH0IpXWQ==", - "dev": true - }, - "elliptic": { - "version": "6.5.4", - "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz", - "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==", - "dev": true, - "requires": { - "bn.js": "^4.11.9", - "brorand": "^1.1.0", - "hash.js": "^1.0.0", - "hmac-drbg": "^1.0.1", - "inherits": "^2.0.4", - "minimalistic-assert": "^1.0.1", - "minimalistic-crypto-utils": "^1.0.1" - }, - "dependencies": { - "bn.js": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", - "dev": true - } - } - }, - "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 - }, - "encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=", - "dev": true - }, - "end-of-stream": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz", - "integrity": "sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==", - "dev": true, - "requires": { - "once": "^1.4.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" - } - }, - "entities": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", - "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", - "dev": true - }, - "errno": { - "version": "0.1.8", - "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.8.tgz", - "integrity": "sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==", - "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" - } - }, - "error-stack-parser": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/error-stack-parser/-/error-stack-parser-2.0.6.tgz", - "integrity": "sha512-d51brTeqC+BHlwF0BhPtcYgF5nlzf9ZZ0ZIUQNZpc9ZB9qw5IJ2diTrBY9jlCJkTLITYPjmiX6OWCwH+fuyNgQ==", - "dev": true, - "requires": { - "stackframe": "^1.1.1" - } - }, - "es-abstract": { - "version": "1.18.0", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.0.tgz", - "integrity": "sha512-LJzK7MrQa8TS0ja2w3YNLzUgJCGPdPOV1yVvezjNnS89D+VR08+Szt2mz3YB2Dck/+w5tfIq/RoUAFqJJGM2yw==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "get-intrinsic": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.2", - "is-callable": "^1.2.3", - "is-negative-zero": "^2.0.1", - "is-regex": "^1.1.2", - "is-string": "^1.0.5", - "object-inspect": "^1.9.0", - "object-keys": "^1.1.1", - "object.assign": "^4.1.2", - "string.prototype.trimend": "^1.0.4", - "string.prototype.trimstart": "^1.0.4", - "unbox-primitive": "^1.0.0" - }, - "dependencies": { - "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 - } - } - }, - "es-to-primitive": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", - "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", - "dev": true, - "requires": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" - } - }, - "escape-html": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=", - "dev": true - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "dev": true - }, - "escodegen": { - "version": "1.14.3", - "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.14.3.tgz", - "integrity": "sha512-qFcX0XJkdg+PB3xjZZG/wKSuT1PnQWx57+TVSjIMmILd2yC/6ByYElPwJnslDsuWuSAp4AwJGumarAAmJch5Kw==", - "dev": true, - "requires": { - "esprima": "^4.0.1", - "estraverse": "^4.2.0", - "esutils": "^2.0.2", - "optionator": "^0.8.1", - "source-map": "~0.6.1" - } - }, - "eslint": { - "version": "5.16.0", - "dev": true, - "requires": { - "@babel/code-frame": "^7.0.0", - "ajv": "^6.9.1", - "chalk": "^2.1.0", - "cross-spawn": "^6.0.5", - "debug": "^4.0.1", - "doctrine": "^3.0.0", - "eslint-scope": "^4.0.3", - "eslint-utils": "^1.3.1", - "eslint-visitor-keys": "^1.0.0", - "espree": "^5.0.1", - "esquery": "^1.0.1", - "esutils": "^2.0.2", - "file-entry-cache": "^5.0.1", - "functional-red-black-tree": "^1.0.1", - "glob": "^7.1.2", - "globals": "^11.7.0", - "ignore": "^4.0.6", - "import-fresh": "^3.0.0", - "imurmurhash": "^0.1.4", - "inquirer": "^6.2.2", - "js-yaml": "^3.13.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.3.0", - "lodash": "^4.17.11", - "minimatch": "^3.0.4", - "mkdirp": "^0.5.1", - "natural-compare": "^1.4.0", - "optionator": "^0.8.2", - "path-is-inside": "^1.0.2", - "progress": "^2.0.0", - "regexpp": "^2.0.1", - "semver": "^5.5.1", - "strip-ansi": "^4.0.0", - "strip-json-comments": "^2.0.1", - "table": "^5.2.3", - "text-table": "^0.2.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 - }, - "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" - } - }, - "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" - } - }, - "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" - } - }, - "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 - }, - "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 - }, - "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" - }, - "dependencies": { - "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" - } - } - } - }, - "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" - } - }, - "ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true - }, - "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 - }, - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true - }, - "strip-ansi": { - "version": "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" - } - } - } - }, - "eslint-loader": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/eslint-loader/-/eslint-loader-2.2.1.tgz", - "integrity": "sha512-RLgV9hoCVsMLvOxCuNjdqOrUqIj9oJg8hF44vzJaYqsAHuY9G2YAeN3joQ9nxP0p5Th9iFSIpKo+SD8KISxXRg==", - "dev": true, - "requires": { - "loader-fs-cache": "^1.0.0", - "loader-utils": "^1.0.2", - "object-assign": "^4.0.1", - "object-hash": "^1.1.4", - "rimraf": "^2.6.1" - } - }, - "eslint-plugin-vue": { - "version": "5.2.3", - "dev": true, - "requires": { - "vue-eslint-parser": "^5.0.0" - } - }, - "eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", - "dev": true, - "requires": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" - }, - "dependencies": { - "esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, - "requires": { - "estraverse": "^5.2.0" - }, - "dependencies": { - "estraverse": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", - "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", - "dev": true - } - } - } - } - }, - "eslint-utils": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.4.2.tgz", - "integrity": "sha512-eAZS2sEUMlIeCjBeubdj45dmBHQwPHWyBcT1VSYB7o9x9WRRqKxyUoiXlRjyAwzN7YEzHJlYg0NmzDRWx6GP4Q==", - "dev": true, - "requires": { - "eslint-visitor-keys": "^1.0.0" - } - }, - "eslint-visitor-keys": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz", - "integrity": "sha512-qzm/XxIbxm/FHyH341ZrbnMUpe+5Bocte9xkmFMzPMjRaZMcXww+MpBptFvtU+79L362nqiLhekCxCxDPaUMBQ==", - "dev": true - }, - "espree": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-5.0.1.tgz", - "integrity": "sha512-qWAZcWh4XE/RwzLJejfcofscgMc9CamR6Tn1+XRXNzrvUSSbiAjGOI/fggztjIi7y9VLPqnICMIPiGyr8JaZ0A==", - "dev": true, - "requires": { - "acorn": "^6.0.7", - "acorn-jsx": "^5.0.0", - "eslint-visitor-keys": "^1.0.0" - } - }, - "esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true - }, - "esquery": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", - "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", - "dev": true, - "requires": { - "estraverse": "^5.1.0" - }, - "dependencies": { - "estraverse": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", - "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", - "dev": true - } - } - }, - "esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, - "requires": { - "estraverse": "^5.2.0" - }, - "dependencies": { - "estraverse": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", - "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", - "dev": true - } - } - }, - "estraverse": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz", - "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=", - "dev": true - }, - "esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true - }, - "etag": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=", - "dev": true - }, - "event-pubsub": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/event-pubsub/-/event-pubsub-4.3.0.tgz", - "integrity": "sha512-z7IyloorXvKbFx9Bpie2+vMJKKx1fH1EN5yiTfp8CiLOTptSYy1g8H4yDpGlEdshL1PBiFtBHepF2cNsqeEeFQ==", - "dev": true - }, - "eventemitter3": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", - "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", - "dev": true - }, - "events": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", - "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", - "dev": true - }, - "eventsource": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-1.1.0.tgz", - "integrity": "sha512-VSJjT5oCNrFvCS6igjzPAt5hBzQ2qPBFIbJ03zLI9SE0mxwZpMw6BfJrbFHm1a141AavMEB8JHmBhWAd66PfCg==", - "dev": true, - "requires": { - "original": "^1.0.0" - } - }, - "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": "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" - }, - "dependencies": { - "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" - } - }, - "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" - } - } - } - }, - "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" - } - } - } - }, - "express": { - "version": "4.17.1", - "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz", - "integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==", - "dev": true, - "requires": { - "accepts": "~1.3.7", - "array-flatten": "1.1.1", - "body-parser": "1.19.0", - "content-disposition": "0.5.3", - "content-type": "~1.0.4", - "cookie": "0.4.0", - "cookie-signature": "1.0.6", - "debug": "2.6.9", - "depd": "~1.1.2", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "finalhandler": "~1.1.2", - "fresh": "0.5.2", - "merge-descriptors": "1.0.1", - "methods": "~1.1.2", - "on-finished": "~2.3.0", - "parseurl": "~1.3.3", - "path-to-regexp": "0.1.7", - "proxy-addr": "~2.0.5", - "qs": "6.7.0", - "range-parser": "~1.2.1", - "safe-buffer": "5.1.2", - "send": "0.17.1", - "serve-static": "1.14.1", - "setprototypeof": "1.1.1", - "statuses": "~1.5.0", - "type-is": "~1.6.18", - "utils-merge": "1.0.1", - "vary": "~1.1.2" - }, - "dependencies": { - "qs": { - "version": "6.7.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", - "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==", - "dev": true - } - } - }, - "extend": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", - "dev": true - }, - "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" - } - } - } - }, - "extsprintf": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", - "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", - "dev": true - }, - "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-glob": { - "version": "2.2.7", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-2.2.7.tgz", - "integrity": "sha512-g1KuQwHOZAmOZMuBtHdxDtju+T2RT8jgCC9aANsbpdiDDTSnjgfuVsIBNKbUeJI3oKMRExcfNDtJl4OhbffMsw==", - "dev": true, - "requires": { - "@mrmlnc/readdir-enhanced": "^2.2.1", - "@nodelib/fs.stat": "^1.1.2", - "glob-parent": "^3.1.0", - "is-glob": "^4.0.0", - "merge2": "^1.2.3", - "micromatch": "^3.1.10" - } - }, - "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 - }, - "fastparse": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/fastparse/-/fastparse-1.1.2.tgz", - "integrity": "sha512-483XLLxTVIwWK3QTrMGRqUfUpoOs/0hbQrl2oz4J0pAcm3A3bu84wxTFqGqkJzewCLdME38xJLJAxBABfQT8sQ==", - "dev": true - }, - "faye-websocket": { - "version": "0.10.0", - "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.10.0.tgz", - "integrity": "sha1-TkkvjQTftviQA1B/btvy1QHnxvQ=", - "dev": true, - "requires": { - "websocket-driver": ">=0.5.1" - } - }, - "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" - } - }, - "file-loader": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/file-loader/-/file-loader-3.0.1.tgz", - "integrity": "sha512-4sNIOXgtH/9WZq4NvlfU3Opn5ynUsqBwSLyM+I7UOwdGigTBYfVVQEwe/msZNX/j4pCJTIM14Fsw66Svo1oVrw==", - "dev": true, - "requires": { - "loader-utils": "^1.0.2", - "schema-utils": "^1.0.0" - } - }, - "file-saver": { - "version": "2.0.2" - }, - "filesize": { - "version": "3.6.1", - "resolved": "https://registry.npmjs.org/filesize/-/filesize-3.6.1.tgz", - "integrity": "sha512-7KjR1vv6qnicaPMi1iiTcI85CyYwRO/PSFCu6SvqL8jN2Wjt/NIYQTFtFs7fSDCYOstUkEWIQGFUg5YZQfjlcg==", - "dev": true - }, - "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" - } - } - } - }, - "finalhandler": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", - "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", - "dev": true, - "requires": { - "debug": "2.6.9", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "on-finished": "~2.3.0", - "parseurl": "~1.3.3", - "statuses": "~1.5.0", - "unpipe": "~1.0.0" - } - }, - "find-cache-dir": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-1.0.0.tgz", - "integrity": "sha1-kojj6ePMN0hxfTnq3hfPcfww7m8=", - "dev": true, - "requires": { - "commondir": "^1.0.1", - "make-dir": "^1.0.0", - "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-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" - } - }, - "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" - } - } - } - }, - "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" - } - }, - "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" - }, - "dependencies": { - "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" - } - } - } - }, - "flatted": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.2.tgz", - "integrity": "sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA==", - "dev": true - }, - "flush-write-stream": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.0.3.tgz", - "integrity": "sha512-calZMC10u0FMUqoiunI2AiGIIUtUIvifNwkHhNupZH4cbNnW1Itkoh/Nf5HFYmDrwWPjrUxpkZT0KhuCq0jmGw==", - "dev": true, - "requires": { - "inherits": "^2.0.1", - "readable-stream": "^2.0.4" - } - }, - "follow-redirects": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.6.1.tgz", - "integrity": "sha512-t2JCjbzxQpWvbhts3l6SH1DKzSrx8a+SsaVf4h6bG4kOXUuPYS/kg2Lr4gQSb7eemaHqJkOThF1BGyjlUkO1GQ==", - "requires": { - "debug": "=3.1.0" - }, - "dependencies": { - "debug": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", - "requires": { - "ms": "2.0.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 - }, - "forever-agent": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", - "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", - "dev": true - }, - "fork-ts-checker-webpack-plugin": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-0.5.2.tgz", - "integrity": "sha512-a5IG+xXyKnpruI0CP/anyRLAoxWtp3lzdG6flxicANnoSzz64b12dJ7ASAVRrI2OaWwZR2JyBaMHFQqInhWhIw==", - "dev": true, - "requires": { - "babel-code-frame": "^6.22.0", - "chalk": "^2.4.1", - "chokidar": "^2.0.4", - "micromatch": "^3.1.10", - "minimatch": "^3.0.4", - "tapable": "^1.0.0" - } - }, - "form-data": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", - "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", - "dev": true, - "requires": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.6", - "mime-types": "^2.1.12" - } - }, - "forwarded": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", - "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=", - "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" - } - }, - "fresh": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=", - "dev": true - }, - "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-extra": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz", - "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" - } - }, - "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": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "dev": true, - "optional": true - }, - "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true - }, - "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 - }, - "get-caller-file": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz", - "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==", - "dev": true - }, - "get-func-name": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz", - "integrity": "sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=", - "dev": true - }, - "get-intrinsic": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", - "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", - "dev": true, - "requires": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1" - }, - "dependencies": { - "has-symbols": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz", - "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==", - "dev": true - } - } - }, - "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 - }, - "getpass": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", - "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", - "dev": true, - "requires": { - "assert-plus": "^1.0.0" - } - }, - "glob": { - "version": "7.1.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", - "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", - "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" - } - } - } - }, - "glob-to-regexp": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.3.0.tgz", - "integrity": "sha1-jFoUlNIGbFcMw7/kSWF1rMTVAqs=", - "dev": true - }, - "global": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/global/-/global-4.3.2.tgz", - "integrity": "sha1-52mJJopsdMOJCLEwWxD8DjlOnQ8=", - "dev": true, - "requires": { - "min-document": "^2.19.0", - "process": "~0.5.1" - }, - "dependencies": { - "process": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/process/-/process-0.5.2.tgz", - "integrity": "sha1-FjjYqONML0QKkduVq5rrZ3/Bhc8=", - "dev": true - } - } - }, - "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 - }, - "globby": { - "version": "9.2.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-9.2.0.tgz", - "integrity": "sha512-ollPHROa5mcxDEkwg6bPt3QbEf4pDQSNtd6JPL1YvOvAo/7/0VAm9TccUeoTmarjPw4pfUthSCqcyfNB1I3ZSg==", - "dev": true, - "requires": { - "@types/glob": "^7.1.1", - "array-union": "^1.0.2", - "dir-glob": "^2.2.2", - "fast-glob": "^2.2.6", - "glob": "^7.1.3", - "ignore": "^4.0.3", - "pify": "^4.0.1", - "slash": "^2.0.0" - }, - "dependencies": { - "pify": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", - "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", - "dev": true - } - } - }, - "graceful-fs": { - "version": "4.2.6", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz", - "integrity": "sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ==", - "dev": true - }, - "growl": { - "version": "1.10.5", - "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", - "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", - "dev": true - }, - "gzip-size": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-5.1.1.tgz", - "integrity": "sha512-FNHi6mmoHvs1mxZAds4PpdCS6QG8B4C1krxJsMutgxl5t3+GlRTzzI3NEkifXx2pVsOvJdOGSmIgDhQ55FwdPA==", - "dev": true, - "requires": { - "duplexer": "^0.1.1", - "pify": "^4.0.1" - }, - "dependencies": { - "pify": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", - "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", - "dev": true - } - } - }, - "handle-thing": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz", - "integrity": "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==", - "dev": true - }, - "har-schema": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", - "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=", - "dev": true - }, - "har-validator": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", - "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", - "dev": true, - "requires": { - "ajv": "^6.12.3", - "har-schema": "^2.0.0" - }, - "dependencies": { - "ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "requires": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - } - }, - "fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true - } - } - }, - "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-bigints": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.1.tgz", - "integrity": "sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA==", - "dev": true - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true - }, - "has-symbols": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz", - "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==", - "dev": true - }, - "has-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.1.0", - "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.0.tgz", - "integrity": "sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==", - "dev": true, - "requires": { - "inherits": "^2.0.4", - "readable-stream": "^3.6.0", - "safe-buffer": "^5.2.0" - }, - "dependencies": { - "readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "dev": true, - "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - } - }, - "safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "dev": true - } - } - }, - "hash-sum": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/hash-sum/-/hash-sum-1.0.2.tgz", - "integrity": "sha1-M7QHd3VMZDJXPBIMw4CLvRDUfwQ=", - "dev": true - }, - "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" - } - }, - "he": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", - "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", - "dev": true - }, - "hex-color-regex": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/hex-color-regex/-/hex-color-regex-1.1.0.tgz", - "integrity": "sha512-l9sfDFsuqtOqKDsQdqrMRk0U85RZc0RtOR9yPI7mRVOa4FsR/BVnZ0shmQRM96Ji99kYZP/7hn1cedc1+ApsTQ==", - "dev": true - }, - "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" - } - }, - "hoopy": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/hoopy/-/hoopy-0.1.4.tgz", - "integrity": "sha512-HRcs+2mr52W0K+x8RzcLzuPPmVIKMSv97RGHy0Ea9y/mpcaK+xTrjICA04KAHi4GRzxliNqNJEFYWHghy3rSfQ==", - "dev": true - }, - "hosted-git-info": { - "version": "2.8.9", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", - "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", - "dev": true - }, - "hpack.js": { - "version": "2.1.6", - "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", - "integrity": "sha1-h3dMCUnlE/QuhFdbPEVoH63ioLI=", - "dev": true, - "requires": { - "inherits": "^2.0.1", - "obuf": "^1.0.0", - "readable-stream": "^2.0.1", - "wbuf": "^1.1.0" - } - }, - "hsl-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/hsl-regex/-/hsl-regex-1.0.0.tgz", - "integrity": "sha1-1JMwx4ntgZ4nakwNJy3/owsY/m4=", - "dev": true - }, - "hsla-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/hsla-regex/-/hsla-regex-1.0.0.tgz", - "integrity": "sha1-wc56MWjIxmFAM6S194d/OyJfnDg=", - "dev": true - }, - "html-encoding-sniffer": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-1.0.2.tgz", - "integrity": "sha512-71lZziiDnsuabfdYiUeWdCVyKuqwWi23L8YeIgV9jSSZHCtb6wB1BKWooH7L3tn4/FuZJMVWyNaIDr4RGmaSYw==", - "dev": true, - "requires": { - "whatwg-encoding": "^1.0.1" - } - }, - "html-entities": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-1.4.0.tgz", - "integrity": "sha512-8nxjcBcd8wovbeKx7h3wTji4e6+rhaVuPNpMqwWgnHh+N9ToqsCs6XztWRBPQ+UtzsoMAdKZtUENoVzU/EMtZA==", - "dev": true - }, - "html-minifier": { - "version": "3.5.21", - "resolved": "https://registry.npmjs.org/html-minifier/-/html-minifier-3.5.21.tgz", - "integrity": "sha512-LKUKwuJDhxNa3uf/LPR/KVjm/l3rBqtYeCOAekvG8F1vItxMUpueGd94i/asDDr8/1u7InxzFA5EeGjhhG5mMA==", - "dev": true, - "requires": { - "camel-case": "3.0.x", - "clean-css": "4.2.x", - "commander": "2.17.x", - "he": "1.2.x", - "param-case": "2.1.x", - "relateurl": "0.2.x", - "uglify-js": "3.4.x" - } - }, - "html-webpack-plugin": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-3.2.0.tgz", - "integrity": "sha1-sBq71yOsqqeze2r0SS69oD2d03s=", - "dev": true, - "requires": { - "html-minifier": "^3.2.3", - "loader-utils": "^0.2.16", - "lodash": "^4.17.3", - "pretty-error": "^2.0.2", - "tapable": "^1.0.0", - "toposort": "^1.0.0", - "util.promisify": "1.0.0" - }, - "dependencies": { - "big.js": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/big.js/-/big.js-3.2.0.tgz", - "integrity": "sha512-+hN/Zh2D08Mx65pZ/4g5bsmNiZUuChDiQfTUQ7qJr4/kuopCr88xZsAXv6mBoZEsUI4OuGHlX59qE94K2mMW8Q==", - "dev": true - }, - "json5": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz", - "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=", - "dev": true - }, - "loader-utils": { - "version": "0.2.17", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-0.2.17.tgz", - "integrity": "sha1-+G5jdNQyBabmxg6RlvF8Apm/s0g=", - "dev": true, - "requires": { - "big.js": "^3.1.3", - "emojis-list": "^2.0.0", - "json5": "^0.5.0", - "object-assign": "^4.0.1" - } - }, - "util.promisify": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/util.promisify/-/util.promisify-1.0.0.tgz", - "integrity": "sha512-i+6qA2MPhvoKLuxnJNpXAGhg7HphQOSUq2LKMZD0m15EiskXUkMvKdF4Uui0WYeCUGea+o2cw/ZuwehtfsrNkA==", - "dev": true, - "requires": { - "define-properties": "^1.1.2", - "object.getownpropertydescriptors": "^2.0.3" - } - } - } - }, - "htmlparser2": { - "version": "3.10.1", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.10.1.tgz", - "integrity": "sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ==", - "dev": true, - "requires": { - "domelementtype": "^1.3.1", - "domhandler": "^2.3.0", - "domutils": "^1.5.1", - "entities": "^1.1.1", - "inherits": "^2.0.1", - "readable-stream": "^3.1.1" - }, - "dependencies": { - "entities": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz", - "integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==", - "dev": true - }, - "readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "dev": true, - "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - } - } - } - }, - "http-deceiver": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", - "integrity": "sha1-+nFolEq5pRnTN8sL7HKE3D5yPYc=", - "dev": true - }, - "http-errors": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", - "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==", - "dev": true, - "requires": { - "depd": "~1.1.2", - "inherits": "2.0.3", - "setprototypeof": "1.1.1", - "statuses": ">= 1.5.0 < 2", - "toidentifier": "1.0.0" - }, - "dependencies": { - "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", - "dev": true - } - } - }, - "http-parser-js": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.3.tgz", - "integrity": "sha512-t7hjvef/5HEK7RWTdUzVUhl8zkEu+LlaE0IYzdMuvbSDipxBRpOn4Uhw8ZyECEa808iVT8XCjzo6xmYt4CiLZg==", - "dev": true - }, - "http-proxy": { - "version": "1.18.1", - "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", - "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", - "dev": true, - "requires": { - "eventemitter3": "^4.0.0", - "follow-redirects": "^1.0.0", - "requires-port": "^1.0.0" - } - }, - "http-proxy-middleware": { - "version": "0.19.2", - "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-0.19.2.tgz", - "integrity": "sha512-aYk1rTKqLTus23X3L96LGNCGNgWpG4cG0XoZIT1GUPhhulEHX/QalnO6Vbo+WmKWi4AL2IidjuC0wZtbpg0yhQ==", - "dev": true, - "requires": { - "http-proxy": "^1.18.1", - "is-glob": "^4.0.0", - "lodash": "^4.17.11", - "micromatch": "^3.1.10" - } - }, - "http-signature": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", - "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", - "dev": true, - "requires": { - "assert-plus": "^1.0.0", - "jsprim": "^1.2.2", - "sshpk": "^1.7.0" - } - }, - "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" - } - }, - "icss-replace-symbols": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/icss-replace-symbols/-/icss-replace-symbols-1.1.0.tgz", - "integrity": "sha1-Bupvg2ead0njhs/h/oEq5dsiPe0=", - "dev": true - }, - "icss-utils": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-2.1.0.tgz", - "integrity": "sha1-g/Cg7DeL8yRheLbCrZE28TWxyWI=", - "dev": true, - "requires": { - "postcss": "^6.0.1" - }, - "dependencies": { - "postcss": { - "version": "6.0.23", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.23.tgz", - "integrity": "sha512-soOk1h6J3VMTZtVeVpv15/Hpdl2cBLX3CAw4TAbkpTJiNPk9YP/zWcD1ND+xEtvyuuvKzbxliTOIyvkSeSJ6ag==", - "dev": true, - "requires": { - "chalk": "^2.4.1", - "source-map": "^0.6.1", - "supports-color": "^5.4.0" - } - } - } - }, - "ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", - "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 - }, - "import-cwd": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/import-cwd/-/import-cwd-2.1.0.tgz", - "integrity": "sha1-qmzzbnInYShcs3HsZRn1PiQ1sKk=", - "dev": true, - "requires": { - "import-from": "^2.1.0" - } - }, - "import-fresh": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-2.0.0.tgz", - "integrity": "sha1-2BNVwVYS04bGH53dOSLUMEgipUY=", - "dev": true, - "requires": { - "caller-path": "^2.0.0", - "resolve-from": "^3.0.0" - } - }, - "import-from": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/import-from/-/import-from-2.1.0.tgz", - "integrity": "sha1-M1238qev/VOqpHHUuAId7ja387E=", - "dev": true, - "requires": { - "resolve-from": "^3.0.0" - } - }, - "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 - }, - "indexes-of": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/indexes-of/-/indexes-of-1.0.1.tgz", - "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", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "dev": true, - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true - }, - "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" - } - } - } - }, - "internal-ip": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/internal-ip/-/internal-ip-4.3.0.tgz", - "integrity": "sha512-S1zBo1D6zcsyuC6PMmY5+55YMILQ9av8lotMx447Bq6SAgo/sDK6y6uUKmuYhW7eacnIhFfsPmCNYdDzsnnDCg==", - "dev": true, - "requires": { - "default-gateway": "^4.2.0", - "ipaddr.js": "^1.9.0" - }, - "dependencies": { - "default-gateway": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-4.2.0.tgz", - "integrity": "sha512-h6sMrVB1VMWVrW13mSc6ia/DwYYw5MN6+exNu1OaJeFac5aSAvwM7lZ0NVfTABuSkQelr4h5oebg3KB1XPdjgA==", - "dev": true, - "requires": { - "execa": "^1.0.0", - "ip-regex": "^2.1.0" - } - } - } - }, - "interpret": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz", - "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==", - "dev": true - }, - "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 - }, - "ip": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz", - "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=", - "dev": true - }, - "ip-regex": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-2.1.0.tgz", - "integrity": "sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk=", - "dev": true - }, - "ipaddr.js": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", - "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", - "dev": true - }, - "is-absolute-url": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-absolute-url/-/is-absolute-url-2.1.0.tgz", - "integrity": "sha1-UFMN+4T8yap9vnhS6Do3uTufKqY=", - "dev": true - }, - "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-arguments": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.0.tgz", - "integrity": "sha512-1Ij4lOMPl/xB5kBDn7I+b2ttPMKa8szhEIrXDuXQD/oe3HJLTLhqhgGspwgyGd6MOywBUqVvYicF72lkgDnIHg==", - "dev": true, - "requires": { - "call-bind": "^1.0.0" - } - }, - "is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", - "dev": true - }, - "is-bigint": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.1.tgz", - "integrity": "sha512-J0ELF4yHFxHy0cmSxZuheDOz2luOdVvqjwmEcj8H/L1JHeuEDSDbeRP+Dk9kFVk5RTFzbucJ2Kb9F7ixY2QaCg==", - "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-boolean-object": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.0.tgz", - "integrity": "sha512-a7Uprx8UtD+HWdyYwnD1+ExtTgqQtD2k/1yJgtXP6wnMm8byhkoTZRl+95LLThpzNZJ5aEvi46cdH+ayMFRwmA==", - "dev": true, - "requires": { - "call-bind": "^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==" - }, - "is-callable": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.3.tgz", - "integrity": "sha512-J1DcMe8UYTBSrKezuIUTUwjXsho29693unXM2YhJUTR2txK/eG47bvNa/wipPFmZFgr/N6f1GA66dv0mEyTIyQ==", - "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-color-stop": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-color-stop/-/is-color-stop-1.1.0.tgz", - "integrity": "sha1-z/9HGu5N1cnhWFmPvhKWe1za00U=", - "dev": true, - "requires": { - "css-color-names": "^0.0.4", - "hex-color-regex": "^1.1.0", - "hsl-regex": "^1.0.0", - "hsla-regex": "^1.0.0", - "rgb-regex": "^1.0.1", - "rgba-regex": "^1.0.0" - } - }, - "is-core-module": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.2.0.tgz", - "integrity": "sha512-XRAfAdyyY5F5cOXn7hYQDqh2Xmii+DEfIcQGxK/uNwMHhIkPWO0g8msXcbzLe+MpGoR951MlqM/2iIlU4vKDdQ==", - "dev": true, - "requires": { - "has": "^1.0.3" - } - }, - "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-directory": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/is-directory/-/is-directory-0.3.1.tgz", - "integrity": "sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE=", - "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.0", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.0.tgz", - "integrity": "sha1-lSHHaEXMJhCoUgPd8ICpWML/q8A=", - "dev": true, - "requires": { - "is-extglob": "^2.1.1" - } - }, - "is-negative-zero": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.1.tgz", - "integrity": "sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w==", - "dev": true - }, - "is-number": { - "version": "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-number-object": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.4.tgz", - "integrity": "sha512-zohwelOAur+5uXtk8O3GPQ1eAcu4ZX3UwxQhUlfFFMNpUd83gXgjbhJh6HmB6LUNV/ieOLQuDwJO3dWJosUeMw==", - "dev": true - }, - "is-obj": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", - "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", - "dev": true - }, - "is-path-cwd": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-2.2.0.tgz", - "integrity": "sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ==", - "dev": true - }, - "is-path-in-cwd": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-2.1.0.tgz", - "integrity": "sha512-rNocXHgipO+rvnP6dk3zI20RpOtrAM/kzbB258Uw5BWr3TpXi861yzjo16Dn4hUox07iw5AyeMLHWsujkjzvRQ==", - "dev": true, - "requires": { - "is-path-inside": "^2.1.0" - } - }, - "is-path-inside": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-2.1.0.tgz", - "integrity": "sha512-wiyhTzfDWsvwAW53OBWF5zuvaOGlZ6PwYxAbPVDhpm+gM09xKQGjBq/8uYN12aDvMxnAnq3dxTyoSoRNmg5YFg==", - "dev": true, - "requires": { - "path-is-inside": "^1.0.2" - } - }, - "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.2.2", - "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.2.2.tgz", - "integrity": "sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==", - "dev": true, - "optional": true - }, - "is-regex": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.2.tgz", - "integrity": "sha512-axvdhb5pdhEVThqJzYXwMlVuZwC+FF2DpcOhTS+y/8jVq4trxyPgfcwIxIKiyeuLlSQYKkmUaPQJ8ZE4yNKXDg==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "has-symbols": "^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-stream": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", - "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", - "dev": true - }, - "is-string": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.5.tgz", - "integrity": "sha512-buY6VNRjhQMiF1qWDouloZlQbRhDPCebwxSjxMjxgemYT46YMd2NR0/H+fBhEfWX4A/w9TBJ+ol+okqJKFE6vQ==", - "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-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", - "dev": true - }, - "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=", - "dev": true - }, - "isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", - "dev": true - }, - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true - }, - "isstream": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", - "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", - "dev": true - }, - "javascript-stringify": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/javascript-stringify/-/javascript-stringify-1.6.0.tgz", - "integrity": "sha1-FC0RHzpuPa6PSpr9d9RYVbWpzOM=", - "dev": true - }, - "js-message": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/js-message/-/js-message-1.0.7.tgz", - "integrity": "sha512-efJLHhLjIyKRewNS9EGZ4UpI8NguuL6fKkhRxVuMmrGV2xN/0APGdQYwLFky5w9naebSZ0OwAGp0G6/2Cg90rA==", - "dev": true - }, - "js-queue": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/js-queue/-/js-queue-2.0.2.tgz", - "integrity": "sha512-pbKLsbCfi7kriM3s1J4DDCo7jQkI58zPLHi0heXPzPlj0hjUsm+FesPUbE0DSbIVIK503A36aUBoCN7eMFedkA==", - "dev": true, - "requires": { - "easy-stack": "^1.0.1" - } - }, - "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 - }, - "js-yaml": { - "version": "3.12.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.12.1.tgz", - "integrity": "sha512-um46hB9wNOKlwkHgiuyEVAybXBjwFUV0Z/RaHJblRd9DXltue9FTYvzCr9ErQrK9Adz5MU4gHWVaNUfdmrC8qA==", - "dev": true, - "optional": true, - "requires": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - } - }, - "jsbn": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", - "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", - "dev": true - }, - "jsdom": { - "version": "13.2.0", - "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-13.2.0.tgz", - "integrity": "sha512-cG1NtMWO9hWpqRNRR3dSvEQa8bFI6iLlqU2x4kwX51FQjp0qus8T9aBaAO6iGp3DeBrhdwuKxckknohkmfvsFw==", - "dev": true, - "requires": { - "abab": "^2.0.0", - "acorn": "^6.0.4", - "acorn-globals": "^4.3.0", - "array-equal": "^1.0.0", - "cssom": "^0.3.4", - "cssstyle": "^1.1.1", - "data-urls": "^1.1.0", - "domexception": "^1.0.1", - "escodegen": "^1.11.0", - "html-encoding-sniffer": "^1.0.2", - "nwsapi": "^2.0.9", - "parse5": "5.1.0", - "pn": "^1.1.0", - "request": "^2.88.0", - "request-promise-native": "^1.0.5", - "saxes": "^3.1.5", - "symbol-tree": "^3.2.2", - "tough-cookie": "^2.5.0", - "w3c-hr-time": "^1.0.1", - "w3c-xmlserializer": "^1.0.1", - "webidl-conversions": "^4.0.2", - "whatwg-encoding": "^1.0.5", - "whatwg-mimetype": "^2.3.0", - "whatwg-url": "^7.0.0", - "ws": "^6.1.2", - "xml-name-validator": "^3.0.0" - } - }, - "jsdom-global": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/jsdom-global/-/jsdom-global-3.0.2.tgz", - "integrity": "sha1-a9KZwTsMRiay2iwDk81DhdYGrLk=", - "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-parse-even-better-errors": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", - "dev": true - }, - "json-schema": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", - "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=", - "dev": true - }, - "json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, - "json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", - "dev": true - }, - "json-stringify-safe": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", - "dev": true - }, - "json3": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/json3/-/json3-3.3.3.tgz", - "integrity": "sha512-c7/8mbUsKigAbLkD5B010BK4D9LZm7A1pNItkEwiUZRpIN66exu/e7YQWysGun+TRKaJp8MhemM+VkfWv42aCA==", - "dev": true - }, - "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" - } - }, - "jsonfile": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", - "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", - "dev": true, - "requires": { - "graceful-fs": "^4.1.6" - } - }, - "jsprim": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", - "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", - "dev": true, - "requires": { - "assert-plus": "1.0.0", - "extsprintf": "1.3.0", - "json-schema": "0.2.3", - "verror": "1.10.0" - } - }, - "just-extend": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/just-extend/-/just-extend-4.2.1.tgz", - "integrity": "sha512-g3UB796vUFIY90VIv/WX3L2c8CS2MdWUww3CNrYmqza1Fg0DURc2K/O4YrnklBdQarSJ/y8JnJYDGc+1iumQjg==", - "dev": true - }, - "killable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/killable/-/killable-1.0.1.tgz", - "integrity": "sha512-LzqtLKlUwirEUyl/nicirVmNiPvYs7l5n8wOPP7fyJVpUPkvCnW/vuiXGpylGUlnPDnB7311rARzAt3Mhswpjg==", - "dev": true - }, - "kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "dev": true - }, - "launch-editor": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/launch-editor/-/launch-editor-2.2.1.tgz", - "integrity": "sha512-On+V7K2uZK6wK7x691ycSUbLD/FyKKelArkbaAMSSJU8JmqmhwN2+mnJDNINuJWSrh2L0kDk+ZQtbC/gOWUwLw==", - "dev": true, - "requires": { - "chalk": "^2.3.0", - "shell-quote": "^1.6.1" - } - }, - "launch-editor-middleware": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/launch-editor-middleware/-/launch-editor-middleware-2.2.1.tgz", - "integrity": "sha512-s0UO2/gEGiCgei3/2UN3SMuUj1phjQN8lcpnvgLSz26fAzNWPQ6Nf/kF5IFClnfU2ehp6LrmKdMU/beveO+2jg==", - "dev": true, - "requires": { - "launch-editor": "^2.2.1" - } - }, - "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" - } - }, - "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" - } - }, - "lines-and-columns": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.1.6.tgz", - "integrity": "sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA=", - "dev": true - }, - "loader-fs-cache": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/loader-fs-cache/-/loader-fs-cache-1.0.3.tgz", - "integrity": "sha512-ldcgZpjNJj71n+2Mf6yetz+c9bM4xpKtNds4LbqXzU/PTdeAX0g3ytnU1AJMEcTk2Lex4Smpe3Q/eCTsvUBxbA==", - "dev": true, - "requires": { - "find-cache-dir": "^0.1.1", - "mkdirp": "^0.5.1" - }, - "dependencies": { - "find-cache-dir": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-0.1.1.tgz", - "integrity": "sha1-yN765XyKUqinhPnjHFfHQumToLk=", - "dev": true, - "requires": { - "commondir": "^1.0.1", - "mkdirp": "^0.5.1", - "pkg-dir": "^1.0.0" - } - }, - "find-up": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", - "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", - "dev": true, - "requires": { - "path-exists": "^2.0.0", - "pinkie-promise": "^2.0.0" - } - }, - "path-exists": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", - "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", - "dev": true, - "requires": { - "pinkie-promise": "^2.0.0" - } - }, - "pkg-dir": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-1.0.0.tgz", - "integrity": "sha1-ektQio1bstYp1EcFb/TpyTFM89Q=", - "dev": true, - "requires": { - "find-up": "^1.0.0" - } - } - } - }, - "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" - } - }, - "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" - } - }, - "lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true - }, - "lodash.debounce": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", - "integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168=", - "dev": true - }, - "lodash.defaultsdeep": { - "version": "4.6.1", - "resolved": "https://registry.npmjs.org/lodash.defaultsdeep/-/lodash.defaultsdeep-4.6.1.tgz", - "integrity": "sha512-3j8wdDzYuWO3lM3Reg03MuQR957t287Rpcxp1njpEa8oDrikb+FwGdW3n+FELh/A6qib6yPit0j/pv9G/yeAqA==", - "dev": true - }, - "lodash.mapvalues": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/lodash.mapvalues/-/lodash.mapvalues-4.6.0.tgz", - "integrity": "sha1-G6+lAF3p3W9PJmaMMMo3IwzJaJw=", - "dev": true - }, - "lodash.memoize": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", - "integrity": "sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=", - "dev": true - }, - "lodash.sortby": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", - "integrity": "sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=", - "dev": true - }, - "lodash.throttle": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/lodash.throttle/-/lodash.throttle-4.1.1.tgz", - "integrity": "sha1-wj6RtxAkKscMN/HhzaknTMOb8vQ=" - }, - "lodash.transform": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/lodash.transform/-/lodash.transform-4.6.0.tgz", - "integrity": "sha1-EjBkIvYzJK7YSD0/ODMrX2cFR6A=", - "dev": true - }, - "lodash.unescape": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/lodash.unescape/-/lodash.unescape-4.0.1.tgz", - "integrity": "sha1-vyJJiGzlFM2hEvrpIYzcBlIR/Jw=", - "dev": true - }, - "lodash.uniq": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", - "integrity": "sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=", - "dev": true - }, - "log-symbols": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-2.2.0.tgz", - "integrity": "sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg==", - "dev": true, - "requires": { - "chalk": "^2.0.1" - } - }, - "loglevel": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.7.1.tgz", - "integrity": "sha512-Hesni4s5UkWkwCGJMQGAh71PaLUmKFM60dHvq0zi/vDhhrzuk+4GgNbTXJ12YYQJn6ZKBDNIjYcuQGKudvqrIw==", - "dev": true - }, - "lolex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/lolex/-/lolex-3.0.0.tgz", - "integrity": "sha512-hcnW80h3j2lbUfFdMArd5UPA/vxZJ+G8vobd+wg3nVEQA0EigStbYcrG030FJxL6xiDDPEkoMatV9xIh5OecQQ==", - "dev": true - }, - "lower-case": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-1.1.4.tgz", - "integrity": "sha1-miyr0bno4K6ZOkv31YdcOcQujqw=", - "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" - }, - "dependencies": { - "yallist": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", - "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", - "dev": true - } - } - }, - "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" - } - }, - "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" - } - }, - "marked": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/marked/-/marked-2.0.1.tgz", - "integrity": "sha512-5+/fKgMv2hARmMW7DOpykr2iLhl0NgjyELk5yn92iE7z8Se1IS9n3UsFm86hFXIkvMBmVxki8+ckcpjBeyo/hw==" - }, - "material-colors": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/material-colors/-/material-colors-1.2.6.tgz", - "integrity": "sha512-6qE4B9deFBIa9YSpOc9O0Sgc43zTeVYbgDT5veRKSlB2+ZuHNoVVxA1L/ckMUayV9Ay9y7Z/SZCLcGteW9i7bg==" - }, - "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" - } - }, - "mdn-data": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.4.tgz", - "integrity": "sha512-iV3XNKw06j5Q7mi6h+9vbx23Tv7JkjEVgKHW4pimwyDGWm0OIQntJJ+u1C6mg6mK1EaTv42XQ7w76yuzH7M2cA==", - "dev": true - }, - "media-typer": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", - "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=", - "dev": true - }, - "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 - }, - "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 - } - } - }, - "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" - } - }, - "merge-descriptors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", - "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=", - "dev": true - }, - "merge-source-map": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/merge-source-map/-/merge-source-map-1.1.0.tgz", - "integrity": "sha512-Qkcp7P2ygktpMPh2mCQZaf3jhN6D3Z/qVZHSdWvQ+2Ef5HgRAPBO57A77+ENm0CPx2+1Ce/MYKi3ymqdfuqibw==", - "dev": true, - "requires": { - "source-map": "^0.6.1" - } - }, - "merge-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "dev": true - }, - "merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true - }, - "methods": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", - "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=", - "dev": true - }, - "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" - }, - "dependencies": { - "bn.js": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", - "dev": true - } - } - }, - "mime": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/mime/-/mime-2.5.2.tgz", - "integrity": "sha512-tqkh47FzKeCPD2PUiPB6pkbMzsCasjxAfC62/Wap5qrUWcb+sFasXUC5I3gYM5iBM8v/Qpn4UK0x+j0iHyFPDg==", - "dev": true - }, - "mime-db": { - "version": "1.37.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.37.0.tgz", - "integrity": "sha512-R3C4db6bgQhlIhPU48fUtdVmKnflq+hRdad7IyKhtFj06VPNVdk2RhiYL3UjQIlso8L+YxAtFkobT0VK+S/ybg==", - "dev": true - }, - "mime-types": { - "version": "2.1.21", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.21.tgz", - "integrity": "sha512-3iL6DbwpyLzjR3xHSFNFeb9Nz/M8WDkX33t1GFQnFOllWk8pOrh/LSrB5OXlnlW5P9LH73X6loW/eogc+F5lJg==", - "dev": true, - "requires": { - "mime-db": "~1.37.0" - } - }, - "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 - }, - "min-document": { - "version": "2.19.0", - "resolved": "https://registry.npmjs.org/min-document/-/min-document-2.19.0.tgz", - "integrity": "sha1-e9KC4/WELtKVu3SM3Z8f+iyCRoU=", - "dev": true, - "requires": { - "dom-walk": "^0.1.0" - } - }, - "mini-css-extract-plugin": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-0.6.0.tgz", - "integrity": "sha512-79q5P7YGI6rdnVyIAV4NXpBQJFWdkzJxCim3Kog4078fM0piAaFlwocqbejdWtLW1cEzCexPrh6EdyFsPgVdAw==", - "dev": true, - "requires": { - "loader-utils": "^1.1.0", - "normalize-url": "^2.0.1", - "schema-utils": "^1.0.0", - "webpack-sources": "^1.1.0" - }, - "dependencies": { - "normalize-url": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-2.0.1.tgz", - "integrity": "sha512-D6MUW4K/VzoJ4rJ01JFKxDrtY1v9wrgzCX5f2qj/lzH1m/lW6MhUZFKerVsnyjOhOsYzI9Kqqak+10l4LvLpMw==", - "dev": true, - "requires": { - "prepend-http": "^2.0.0", - "query-string": "^5.0.1", - "sort-keys": "^2.0.0" - } - } - } - }, - "minimalistic-assert": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", - "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", - "dev": true - }, - "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": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", - "dev": true - }, - "mississippi": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/mississippi/-/mississippi-2.0.0.tgz", - "integrity": "sha512-zHo8v+otD1J10j/tC+VNoGK9keCuByhKovAvdn74dmxJl9+mWHnx6EMsDN4lgRoMI/eYo2nchAxniIbUPb5onw==", - "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": "^2.0.1", - "pumpify": "^1.3.3", - "stream-each": "^1.1.0", - "through2": "^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" - } - } - } - }, - "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" - }, - "dependencies": { - "minimist": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", - "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", - "dev": true - } - } - }, - "mocha": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-5.2.0.tgz", - "integrity": "sha512-2IUgKDhc3J7Uug+FxMXuqIyYzH7gJjXECKe/w43IGgQHTSj3InJi+yAA7T24L9bQMRKiUEHxEX37G5JpVUGLcQ==", - "dev": true, - "requires": { - "browser-stdout": "1.3.1", - "commander": "2.15.1", - "debug": "3.1.0", - "diff": "3.5.0", - "escape-string-regexp": "1.0.5", - "glob": "7.1.2", - "growl": "1.10.5", - "he": "1.1.1", - "minimatch": "3.0.4", - "mkdirp": "0.5.1", - "supports-color": "5.4.0" - }, - "dependencies": { - "commander": { - "version": "2.15.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.15.1.tgz", - "integrity": "sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag==", - "dev": true - }, - "debug": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "glob": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", - "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", - "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" - } - }, - "he": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/he/-/he-1.1.1.tgz", - "integrity": "sha1-k0EP0hsAlzUVH4howvJx80J+I/0=", - "dev": true - }, - "supports-color": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz", - "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "mocha-webpack": { - "version": "2.0.0-beta.0", - "resolved": "https://registry.npmjs.org/mocha-webpack/-/mocha-webpack-2.0.0-beta.0.tgz", - "integrity": "sha512-2ezbW0h5cYWr874F/hzytQCqINxk+GVelMY4xWTSHwwH1LrPAOzjlUljZ+/PhpaP6QeqYbL5x5vK/bnaXqkfEw==", - "dev": true, - "requires": { - "babel-runtime": "^6.18.0", - "chalk": "^2.3.0", - "chokidar": "^2.0.2", - "glob-parent": "^3.1.0", - "globby": "^7.1.1", - "interpret": "^1.0.1", - "is-glob": "^4.0.0", - "loader-utils": "^1.1.0", - "lodash": "^4.3.0", - "memory-fs": "^0.4.1", - "nodent-runtime": "^3.0.3", - "normalize-path": "^2.0.1", - "progress": "^2.0.0", - "source-map-support": "^0.5.0", - "strip-ansi": "^4.0.0", - "toposort": "^1.0.0", - "yargs": "^11.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 - }, - "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" - } - }, - "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 - }, - "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-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" - } - }, - "slash": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz", - "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=", - "dev": true - }, - "y18n": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.2.tgz", - "integrity": "sha512-uGZHXkHnhF0XeeAPgnKfPv1bgKAYyVvmNL1xlKsPYZPaIHxGti2hHqvOCQv71XMsLxu1QjergkqogUnms5D3YQ==", - "dev": true - }, - "yargs": { - "version": "11.1.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-11.1.1.tgz", - "integrity": "sha512-PRU7gJrJaXv3q3yQZ/+/X6KBswZiaQ+zOmdprZcouPYtQgvNU35i+68M4b1ZHLZtYFT5QObFLV+ZkmJYcwKdiw==", - "dev": true, - "requires": { - "cliui": "^4.0.0", - "decamelize": "^1.1.1", - "find-up": "^2.1.0", - "get-caller-file": "^1.0.1", - "os-locale": "^3.1.0", - "require-directory": "^2.1.1", - "require-main-filename": "^1.0.1", - "set-blocking": "^2.0.0", - "string-width": "^2.0.0", - "which-module": "^2.0.0", - "y18n": "^3.2.1", - "yargs-parser": "^9.0.2" - } - }, - "yargs-parser": { - "version": "9.0.2", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-9.0.2.tgz", - "integrity": "sha1-nM9qQ0YP5O1Aqbto9I1DuKaMwHc=", - "dev": true, - "requires": { - "camelcase": "^4.1.0" - } - } - } - }, - "mock-local-storage": { - "version": "1.1.8", - "dev": true, - "requires": { - "core-js": "^0.8.3", - "global": "^4.3.2" - } - }, - "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=" - }, - "multicast-dns": { - "version": "6.2.3", - "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-6.2.3.tgz", - "integrity": "sha512-ji6J5enbMyGRHIAkAOu3WdV8nggqviKCEKtXcOqfphZZtQrmHKycfynJ2V7eVPUA4NhJ6V7Wf4TmGbTwKE9B6g==", - "dev": true, - "requires": { - "dns-packet": "^1.3.1", - "thunky": "^1.0.2" - } - }, - "multicast-dns-service-types": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/multicast-dns-service-types/-/multicast-dns-service-types-1.1.0.tgz", - "integrity": "sha1-iZ8R2WhuXgXLkbNdXw5jt3PPyQE=", - "dev": true - }, - "mute-stream": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz", - "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=", - "dev": true - }, - "mz": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", - "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", - "dev": true, - "requires": { - "any-promise": "^1.0.0", - "object-assign": "^4.0.1", - "thenify-all": "^1.0.0" - } - }, - "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 - }, - "negotiator": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", - "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==", - "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 - }, - "nice-try": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", - "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", - "dev": true - }, - "nise": { - "version": "1.4.8", - "resolved": "https://registry.npmjs.org/nise/-/nise-1.4.8.tgz", - "integrity": "sha512-kGASVhuL4tlAV0tvA34yJYZIVihrUt/5bDwpp4tTluigxUr2bBlJeDXmivb6NuEdFkqvdv/Ybb9dm16PSKUhtw==", - "dev": true, - "requires": { - "@sinonjs/formatio": "^3.1.0", - "just-extend": "^4.0.2", - "lolex": "^2.3.2", - "path-to-regexp": "^1.7.0", - "text-encoding": "^0.6.4" - }, - "dependencies": { - "isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", - "dev": true - }, - "lolex": { - "version": "2.7.5", - "resolved": "https://registry.npmjs.org/lolex/-/lolex-2.7.5.tgz", - "integrity": "sha512-l9x0+1offnKKIzYVjyXU2SiwhXDLekRzKyhnbyldPHvC7BvLPVpdNUNR2KeMAiCN2D/kLNttZgQD5WjSxuBx3Q==", - "dev": true - }, - "path-to-regexp": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz", - "integrity": "sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==", - "dev": true, - "requires": { - "isarray": "0.0.1" - } - } - } - }, - "no-case": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/no-case/-/no-case-2.3.2.tgz", - "integrity": "sha512-rmTZ9kz+f3rCvK2TD1Ue/oZlns7OGoIWP4fc3llxxRXlOkHKoWPPWJOfFYpITabSow43QJbRIoHQXtt10VldyQ==", - "dev": true, - "requires": { - "lower-case": "^1.1.1" - } - }, - "node-forge": { - "version": "0.10.0", - "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.10.0.tgz", - "integrity": "sha512-PPmu8eEeG9saEUvI97fm4OYxXVB6bFvyNTyiUOBichBpFG8A1Ljw3bY62+5oOjDEMHRnd0Y7HQ+x7uzxOzC6JA==", - "dev": true - }, - "node-ipc": { - "version": "9.1.4", - "resolved": "https://registry.npmjs.org/node-ipc/-/node-ipc-9.1.4.tgz", - "integrity": "sha512-A+f0mn2KxUt1uRTSd5ktxQUsn2OEhj5evo7NUi/powBzMSZ0vocdzDjlq9QN2v3LH6CJi3e5xAenpZ1QwU5A8g==", - "dev": true, - "requires": { - "event-pubsub": "4.3.0", - "js-message": "1.0.7", - "js-queue": "2.0.2" - } - }, - "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": { - "punycode": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", - "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", - "dev": true - } - } - }, - "node-releases": { - "version": "1.1.71", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.71.tgz", - "integrity": "sha512-zR6HoT6LrLCRBwukmrVbHv0EpEQjksO6GmFcZQQuCAy139BEsoVKPYnf3jongYW83fAa1torLGYwxxky/p28sg==", - "dev": true - }, - "nodent-runtime": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/nodent-runtime/-/nodent-runtime-3.2.1.tgz", - "integrity": "sha512-7Ws63oC+215smeKJQCxzrK21VFVlCFBkwl0MOObt0HOpVQXs3u483sAmtkF33nNqZ5rSOQjB76fgyPBmAUrtCA==", - "dev": true - }, - "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": "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" - } - }, - "normalize-range": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", - "integrity": "sha1-LRDAa9/TEuqXd2laTShDlFa3WUI=", - "dev": true - }, - "normalize-url": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-3.3.0.tgz", - "integrity": "sha512-U+JJi7duF1o+u2pynbp2zXDW2/PADgC30f0GsHZtRh+HOcXHnw137TrNlyxxRvWW5fjKd3bcLHPxofWuCjaeZg==", - "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" - } - }, - "nth-check": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-1.0.2.tgz", - "integrity": "sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg==", - "dev": true, - "requires": { - "boolbase": "~1.0.0" - } - }, - "num2fraction": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/num2fraction/-/num2fraction-1.2.2.tgz", - "integrity": "sha1-b2gragJ6Tp3fpFZM0lidHU5mnt4=", - "dev": true - }, - "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 - }, - "nwsapi": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.0.tgz", - "integrity": "sha512-h2AatdwYH+JHiZpv7pt/gSX1XoRGb7L/qSIeuqA6GwYoF9w1vP1cw42TO0aI2pNyshRK5893hNSl+1//vHK7hQ==", - "dev": true - }, - "oauth-sign": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", - "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", - "dev": true - }, - "object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", - "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-hash": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-1.3.1.tgz", - "integrity": "sha512-OSuu/pU4ENM9kmREg0BdNrUDIl1heYa4mBZacJc+vVWz4GtAwu7jO8s4AIt2aGRUTqxykpWzI3Oqnsm13tTMDA==", - "dev": true - }, - "object-inspect": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.9.0.tgz", - "integrity": "sha512-i3Bp9iTqwhaLZBxGkRfo5ZbE07BQRT7MGu8+nNgwW9ItGp1TzCTw2DLEoWwjClxBjOFI/hWljTAmYGCEwmtnOw==", - "dev": true - }, - "object-is": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.5.tgz", - "integrity": "sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" - } - }, - "object-keys": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.0.12.tgz", - "integrity": "sha512-FTMyFUm2wBcGHnH2eXmz7tC6IwlqQZ6mVZ+6dm6vZ4IQIHjs6FdNsQBuKGPuUUUY6NfJw2PshC08Tn6LzLDOag==", - "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.2", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", - "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", - "dev": true, - "requires": { - "call-bind": "^1.0.0", - "define-properties": "^1.1.3", - "has-symbols": "^1.0.1", - "object-keys": "^1.1.1" - }, - "dependencies": { - "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.getownpropertydescriptors": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.2.tgz", - "integrity": "sha512-WtxeKSzfBjlzL+F9b7M7hewDzMwy+C8NRssHd1YrNlzHzIDrXcXiNOMrezdAEM4UXixgV+vvnyBeN7Rygl2ttQ==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.18.0-next.2" - } - }, - "object.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.3", - "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.3.tgz", - "integrity": "sha512-nkF6PfDB9alkOUxpf1HNm/QlkeW3SReqL5WXeBLpEJJnlPSvRaDQpW3gQTksTN3fgJX4hL42RzKyOin6ff3tyw==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.18.0-next.2", - "has": "^1.0.3" - } - }, - "obuf": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", - "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==", - "dev": true - }, - "on-finished": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", - "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", - "dev": true, - "requires": { - "ee-first": "1.1.1" - } - }, - "on-headers": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", - "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", - "dev": true - }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dev": true, - "requires": { - "wrappy": "1" - } - }, - "onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", - "dev": true, - "requires": { - "mimic-fn": "^2.1.0" - }, - "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 - } - } - }, - "open": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/open/-/open-6.4.0.tgz", - "integrity": "sha512-IFenVPgF70fSm1keSd2iDBIDIBZkroLeuffXq+wKTzTJlBpesFWojV9lb8mzOfaAzM1sr7HQHuO0vtV0zYekGg==", - "dev": true, - "requires": { - "is-wsl": "^1.1.0" - } - }, - "opener": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/opener/-/opener-1.5.2.tgz", - "integrity": "sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==", - "dev": true - }, - "opn": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/opn/-/opn-5.5.0.tgz", - "integrity": "sha512-PqHpggC9bLV0VeWcdKhkpxY+3JTzetLSqTCWL/z/tFIbI6G8JCjondXklT1JinczLz2Xib62sSp0T/gKT4KksA==", - "dev": true, - "requires": { - "is-wsl": "^1.1.0" - } - }, - "optionator": { - "version": "0.8.3", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", - "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", - "dev": true, - "requires": { - "deep-is": "~0.1.3", - "fast-levenshtein": "~2.0.6", - "levn": "~0.3.0", - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2", - "word-wrap": "~1.2.3" - } - }, - "ora": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/ora/-/ora-3.4.0.tgz", - "integrity": "sha512-eNwHudNbO1folBP3JsZ19v9azXWtQZjICdr3Q0TDPIaeBQ3mXLrh54wM+er0+hSp+dWKf+Z8KM58CYzEyIYxYg==", - "dev": true, - "requires": { - "chalk": "^2.4.2", - "cli-cursor": "^2.1.0", - "cli-spinners": "^2.0.0", - "log-symbols": "^2.2.0", - "strip-ansi": "^5.2.0", - "wcwidth": "^1.0.1" - }, - "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" - } - } - } - }, - "original": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/original/-/original-1.0.2.tgz", - "integrity": "sha512-hyBVl6iqqUOJ8FqRe+l/gS8H+kKYjrEndd5Pm1MfBtsEKA038HkkdbAl/72EAXGyonD/PFsvmVG+EvcIpliMBg==", - "dev": true, - "requires": { - "url-parse": "^1.4.3" - } - }, - "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-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" - } - }, - "os-tmpdir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", - "dev": true - }, - "p-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-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": "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" - }, - "dependencies": { - "p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "requires": { - "p-try": "^2.0.0" - } - }, - "p-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 - } - } - }, - "p-map": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-2.1.0.tgz", - "integrity": "sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==", - "dev": true - }, - "p-retry": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-3.0.1.tgz", - "integrity": "sha512-XE6G4+YTTkT2a0UWb2kjZe8xNwf8bIbnqpc/IS/idOBVhyves0mK5OJgeocjx7q5pvX/6m23xuzVPYT1uGM73w==", - "dev": true, - "requires": { - "retry": "^0.12.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 - }, - "pako": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", - "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", - "dev": true - }, - "parallel-transform": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/parallel-transform/-/parallel-transform-1.1.0.tgz", - "integrity": "sha1-1BDwZbBdojCB/NEPKIVMKb2jOwY=", - "dev": true, - "requires": { - "cyclist": "~0.2.2", - "inherits": "^2.0.3", - "readable-stream": "^2.1.5" - } - }, - "param-case": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/param-case/-/param-case-2.1.1.tgz", - "integrity": "sha1-35T9jPZTHs915r75oIWPvHK+Ikc=", - "dev": true, - "requires": { - "no-case": "^2.2.0" - } - }, - "parse-asn1": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.6.tgz", - "integrity": "sha512-RnZRo1EPU6JBnra2vGHj0yhp6ebyjBZpmUCLHWiFhxlzvBCCpAuZ7elsBp1PVAbQN0/04VD/19rfzlBSwLstMw==", - "dev": true, - "requires": { - "asn1.js": "^5.2.0", - "browserify-aes": "^1.0.0", - "evp_bytestokey": "^1.0.0", - "pbkdf2": "^3.0.3", - "safe-buffer": "^5.1.1" - } - }, - "parse-json": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", - "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", - "dev": true, - "requires": { - "error-ex": "^1.3.1", - "json-parse-better-errors": "^1.0.1" - } - }, - "parse5": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-5.1.0.tgz", - "integrity": "sha512-fxNG2sQjHvlVAYmzBZS9YlDp6PTSSDwa98vkD4QgVDDCAo84z5X1t5XyJQ62ImdLXx5NdIIfihey6xpum9/gRQ==", - "dev": true - }, - "parseurl": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", - "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", - "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-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", - "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-to-regexp": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", - "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=", - "dev": true - }, - "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" - } - }, - "pathval": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.0.tgz", - "integrity": "sha1-uULm1L3mUwBe9rcTYd74cn0GReA=", - "dev": true - }, - "pbkdf2": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.1.tgz", - "integrity": "sha512-4Ejy1OPxi9f2tt1rRV7Go7zmfDQ+ZectEQz3VGUQhgq62HtIRPDyG/JtnwIxs6x3uNMwo2V7q1fMvKjb+Tnpqg==", - "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" - } - }, - "performance-now": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", - "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", - "dev": true - }, - "picomatch": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz", - "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==", - "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 - }, - "pinkie": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", - "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", - "dev": true - }, - "pinkie-promise": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", - "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", - "dev": true, - "requires": { - "pinkie": "^2.0.0" - } - }, - "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" - } - }, - "pn": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/pn/-/pn-1.1.0.tgz", - "integrity": "sha512-2qHaIQr2VLRFoxe2nASzsV6ef4yOOH+Fi9FBOVH6cqeSgUnoyySPZkxzLuzd+RYOQTRpROA0ztTMqxROKSb/nA==", - "dev": true - }, - "portfinder": { - "version": "1.0.20", - "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.20.tgz", - "integrity": "sha512-Yxe4mTyDzTd59PZJY4ojZR8F+E5e97iq2ZOHPz3HDgSvYC5siNad2tLooQ5y5QHyQhc3xVqvyk/eNA3wuoa7Sw==", - "dev": true, - "requires": { - "async": "^1.5.2", - "debug": "^2.2.0", - "mkdirp": "0.5.x" - } - }, - "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 - }, - "postcss": { - "version": "7.0.35", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", - "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", - "dev": true, - "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" - }, - "dependencies": { - "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" - } - } - } - }, - "postcss-calc": { - "version": "7.0.5", - "resolved": "https://registry.npmjs.org/postcss-calc/-/postcss-calc-7.0.5.tgz", - "integrity": "sha512-1tKHutbGtLtEZF6PT4JSihCHfIVldU72mZ8SdZHIYriIZ9fh9k9aWSppaT8rHsyI3dX+KSR+W+Ix9BMY3AODrg==", - "dev": true, - "requires": { - "postcss": "^7.0.27", - "postcss-selector-parser": "^6.0.2", - "postcss-value-parser": "^4.0.2" - } - }, - "postcss-colormin": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-4.0.3.tgz", - "integrity": "sha512-WyQFAdDZpExQh32j0U0feWisZ0dmOtPl44qYmJKkq9xFWY3p+4qnRzCHeNrkeRhwPHz9bQ3mo0/yVkaply0MNw==", - "dev": true, - "requires": { - "browserslist": "^4.0.0", - "color": "^3.0.0", - "has": "^1.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "dependencies": { - "postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", - "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", - "dev": true - } - } - }, - "postcss-convert-values": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-4.0.1.tgz", - "integrity": "sha512-Kisdo1y77KUC0Jmn0OXU/COOJbzM8cImvw1ZFsBgBgMgb1iL23Zs/LXRe3r+EZqM3vGYKdQ2YJVQ5VkJI+zEJQ==", - "dev": true, - "requires": { - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "dependencies": { - "postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", - "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", - "dev": true - } - } - }, - "postcss-discard-comments": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-4.0.2.tgz", - "integrity": "sha512-RJutN259iuRf3IW7GZyLM5Sw4GLTOH8FmsXBnv8Ab/Tc2k4SR4qbV4DNbyyY4+Sjo362SyDmW2DQ7lBSChrpkg==", - "dev": true, - "requires": { - "postcss": "^7.0.0" - } - }, - "postcss-discard-duplicates": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-4.0.2.tgz", - "integrity": "sha512-ZNQfR1gPNAiXZhgENFfEglF93pciw0WxMkJeVmw8eF+JZBbMD7jp6C67GqJAXVZP2BWbOztKfbsdmMp/k8c6oQ==", - "dev": true, - "requires": { - "postcss": "^7.0.0" - } - }, - "postcss-discard-empty": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-4.0.1.tgz", - "integrity": "sha512-B9miTzbznhDjTfjvipfHoqbWKwd0Mj+/fL5s1QOz06wufguil+Xheo4XpOnc4NqKYBCNqqEzgPv2aPBIJLox0w==", - "dev": true, - "requires": { - "postcss": "^7.0.0" - } - }, - "postcss-discard-overridden": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-4.0.1.tgz", - "integrity": "sha512-IYY2bEDD7g1XM1IDEsUT4//iEYCxAmP5oDSFMVU/JVvT7gh+l4fmjciLqGgwjdWpQIdb0Che2VX00QObS5+cTg==", - "dev": true, - "requires": { - "postcss": "^7.0.0" - } - }, - "postcss-load-config": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-2.1.2.tgz", - "integrity": "sha512-/rDeGV6vMUo3mwJZmeHfEDvwnTKKqQ0S7OHUi/kJvvtx3aWtyWG2/0ZWnzCt2keEclwN6Tf0DST2v9kITdOKYw==", - "dev": true, - "requires": { - "cosmiconfig": "^5.0.0", - "import-cwd": "^2.0.0" - } - }, - "postcss-loader": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-3.0.0.tgz", - "integrity": "sha512-cLWoDEY5OwHcAjDnkyRQzAXfs2jrKjXpO/HQFcc5b5u/r7aa471wdmChmwfnv7x2u840iat/wi0lQ5nbRgSkUA==", - "dev": true, - "requires": { - "loader-utils": "^1.1.0", - "postcss": "^7.0.0", - "postcss-load-config": "^2.0.0", - "schema-utils": "^1.0.0" - } - }, - "postcss-merge-longhand": { - "version": "4.0.11", - "resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-4.0.11.tgz", - "integrity": "sha512-alx/zmoeXvJjp7L4mxEMjh8lxVlDFX1gqWHzaaQewwMZiVhLo42TEClKaeHbRf6J7j82ZOdTJ808RtN0ZOZwvw==", - "dev": true, - "requires": { - "css-color-names": "0.0.4", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0", - "stylehacks": "^4.0.0" - }, - "dependencies": { - "postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", - "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", - "dev": true - } - } - }, - "postcss-merge-rules": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-4.0.3.tgz", - "integrity": "sha512-U7e3r1SbvYzO0Jr3UT/zKBVgYYyhAz0aitvGIYOYK5CPmkNih+WDSsS5tvPrJ8YMQYlEMvsZIiqmn7HdFUaeEQ==", - "dev": true, - "requires": { - "browserslist": "^4.0.0", - "caniuse-api": "^3.0.0", - "cssnano-util-same-parent": "^4.0.0", - "postcss": "^7.0.0", - "postcss-selector-parser": "^3.0.0", - "vendors": "^1.0.0" - }, - "dependencies": { - "postcss-selector-parser": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-3.1.2.tgz", - "integrity": "sha512-h7fJ/5uWuRVyOtkO45pnt1Ih40CEleeyCHzipqAZO2e5H20g25Y48uYnFUiShvY4rZWNJ/Bib/KVPmanaCtOhA==", - "dev": true, - "requires": { - "dot-prop": "^5.2.0", - "indexes-of": "^1.0.1", - "uniq": "^1.0.1" - } - } - } - }, - "postcss-minify-font-values": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-4.0.2.tgz", - "integrity": "sha512-j85oO6OnRU9zPf04+PZv1LYIYOprWm6IA6zkXkrJXyRveDEuQggG6tvoy8ir8ZwjLxLuGfNkCZEQG7zan+Hbtg==", - "dev": true, - "requires": { - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "dependencies": { - "postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", - "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", - "dev": true - } - } - }, - "postcss-minify-gradients": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-4.0.2.tgz", - "integrity": "sha512-qKPfwlONdcf/AndP1U8SJ/uzIJtowHlMaSioKzebAXSG4iJthlWC9iSWznQcX4f66gIWX44RSA841HTHj3wK+Q==", - "dev": true, - "requires": { - "cssnano-util-get-arguments": "^4.0.0", - "is-color-stop": "^1.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "dependencies": { - "postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", - "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", - "dev": true - } - } - }, - "postcss-minify-params": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-4.0.2.tgz", - "integrity": "sha512-G7eWyzEx0xL4/wiBBJxJOz48zAKV2WG3iZOqVhPet/9geefm/Px5uo1fzlHu+DOjT+m0Mmiz3jkQzVHe6wxAWg==", - "dev": true, - "requires": { - "alphanum-sort": "^1.0.0", - "browserslist": "^4.0.0", - "cssnano-util-get-arguments": "^4.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0", - "uniqs": "^2.0.0" - }, - "dependencies": { - "postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", - "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", - "dev": true - } - } - }, - "postcss-minify-selectors": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-4.0.2.tgz", - "integrity": "sha512-D5S1iViljXBj9kflQo4YutWnJmwm8VvIsU1GeXJGiG9j8CIg9zs4voPMdQDUmIxetUOh60VilsNzCiAFTOqu3g==", - "dev": true, - "requires": { - "alphanum-sort": "^1.0.0", - "has": "^1.0.0", - "postcss": "^7.0.0", - "postcss-selector-parser": "^3.0.0" - }, - "dependencies": { - "postcss-selector-parser": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-3.1.2.tgz", - "integrity": "sha512-h7fJ/5uWuRVyOtkO45pnt1Ih40CEleeyCHzipqAZO2e5H20g25Y48uYnFUiShvY4rZWNJ/Bib/KVPmanaCtOhA==", - "dev": true, - "requires": { - "dot-prop": "^5.2.0", - "indexes-of": "^1.0.1", - "uniq": "^1.0.1" - } - } - } - }, - "postcss-modules-extract-imports": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-1.2.1.tgz", - "integrity": "sha512-6jt9XZwUhwmRUhb/CkyJY020PYaPJsCyt3UjbaWo6XEbH/94Hmv6MP7fG2C5NDU/BcHzyGYxNtHvM+LTf9HrYw==", - "dev": true, - "requires": { - "postcss": "^6.0.1" - }, - "dependencies": { - "postcss": { - "version": "6.0.23", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.23.tgz", - "integrity": "sha512-soOk1h6J3VMTZtVeVpv15/Hpdl2cBLX3CAw4TAbkpTJiNPk9YP/zWcD1ND+xEtvyuuvKzbxliTOIyvkSeSJ6ag==", - "dev": true, - "requires": { - "chalk": "^2.4.1", - "source-map": "^0.6.1", - "supports-color": "^5.4.0" - } - } - } - }, - "postcss-modules-local-by-default": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-1.2.0.tgz", - "integrity": "sha1-99gMOYxaOT+nlkRmvRlQCn1hwGk=", - "dev": true, - "requires": { - "css-selector-tokenizer": "^0.7.0", - "postcss": "^6.0.1" - }, - "dependencies": { - "postcss": { - "version": "6.0.23", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.23.tgz", - "integrity": "sha512-soOk1h6J3VMTZtVeVpv15/Hpdl2cBLX3CAw4TAbkpTJiNPk9YP/zWcD1ND+xEtvyuuvKzbxliTOIyvkSeSJ6ag==", - "dev": true, - "requires": { - "chalk": "^2.4.1", - "source-map": "^0.6.1", - "supports-color": "^5.4.0" - } - } - } - }, - "postcss-modules-scope": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-1.1.0.tgz", - "integrity": "sha1-1upkmUx5+XtipytCb75gVqGUu5A=", - "dev": true, - "requires": { - "css-selector-tokenizer": "^0.7.0", - "postcss": "^6.0.1" - }, - "dependencies": { - "postcss": { - "version": "6.0.23", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.23.tgz", - "integrity": "sha512-soOk1h6J3VMTZtVeVpv15/Hpdl2cBLX3CAw4TAbkpTJiNPk9YP/zWcD1ND+xEtvyuuvKzbxliTOIyvkSeSJ6ag==", - "dev": true, - "requires": { - "chalk": "^2.4.1", - "source-map": "^0.6.1", - "supports-color": "^5.4.0" - } - } - } - }, - "postcss-modules-values": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-1.3.0.tgz", - "integrity": "sha1-7P+p1+GSUYOJ9CrQ6D9yrsRW6iA=", - "dev": true, - "requires": { - "icss-replace-symbols": "^1.1.0", - "postcss": "^6.0.1" - }, - "dependencies": { - "postcss": { - "version": "6.0.23", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.23.tgz", - "integrity": "sha512-soOk1h6J3VMTZtVeVpv15/Hpdl2cBLX3CAw4TAbkpTJiNPk9YP/zWcD1ND+xEtvyuuvKzbxliTOIyvkSeSJ6ag==", - "dev": true, - "requires": { - "chalk": "^2.4.1", - "source-map": "^0.6.1", - "supports-color": "^5.4.0" - } - } - } - }, - "postcss-normalize-charset": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-4.0.1.tgz", - "integrity": "sha512-gMXCrrlWh6G27U0hF3vNvR3w8I1s2wOBILvA87iNXaPvSNo5uZAMYsZG7XjCUf1eVxuPfyL4TJ7++SGZLc9A3g==", - "dev": true, - "requires": { - "postcss": "^7.0.0" - } - }, - "postcss-normalize-display-values": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/postcss-normalize-display-values/-/postcss-normalize-display-values-4.0.2.tgz", - "integrity": "sha512-3F2jcsaMW7+VtRMAqf/3m4cPFhPD3EFRgNs18u+k3lTJJlVe7d0YPO+bnwqo2xg8YiRpDXJI2u8A0wqJxMsQuQ==", - "dev": true, - "requires": { - "cssnano-util-get-match": "^4.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "dependencies": { - "postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", - "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", - "dev": true - } - } - }, - "postcss-normalize-positions": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/postcss-normalize-positions/-/postcss-normalize-positions-4.0.2.tgz", - "integrity": "sha512-Dlf3/9AxpxE+NF1fJxYDeggi5WwV35MXGFnnoccP/9qDtFrTArZ0D0R+iKcg5WsUd8nUYMIl8yXDCtcrT8JrdA==", - "dev": true, - "requires": { - "cssnano-util-get-arguments": "^4.0.0", - "has": "^1.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "dependencies": { - "postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", - "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", - "dev": true - } - } - }, - "postcss-normalize-repeat-style": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-4.0.2.tgz", - "integrity": "sha512-qvigdYYMpSuoFs3Is/f5nHdRLJN/ITA7huIoCyqqENJe9PvPmLhNLMu7QTjPdtnVf6OcYYO5SHonx4+fbJE1+Q==", - "dev": true, - "requires": { - "cssnano-util-get-arguments": "^4.0.0", - "cssnano-util-get-match": "^4.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "dependencies": { - "postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", - "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", - "dev": true - } - } - }, - "postcss-normalize-string": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/postcss-normalize-string/-/postcss-normalize-string-4.0.2.tgz", - "integrity": "sha512-RrERod97Dnwqq49WNz8qo66ps0swYZDSb6rM57kN2J+aoyEAJfZ6bMx0sx/F9TIEX0xthPGCmeyiam/jXif0eA==", - "dev": true, - "requires": { - "has": "^1.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "dependencies": { - "postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", - "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", - "dev": true - } - } - }, - "postcss-normalize-timing-functions": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-4.0.2.tgz", - "integrity": "sha512-acwJY95edP762e++00Ehq9L4sZCEcOPyaHwoaFOhIwWCDfik6YvqsYNxckee65JHLKzuNSSmAdxwD2Cud1Z54A==", - "dev": true, - "requires": { - "cssnano-util-get-match": "^4.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "dependencies": { - "postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", - "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", - "dev": true - } - } - }, - "postcss-normalize-unicode": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/postcss-normalize-unicode/-/postcss-normalize-unicode-4.0.1.tgz", - "integrity": "sha512-od18Uq2wCYn+vZ/qCOeutvHjB5jm57ToxRaMeNuf0nWVHaP9Hua56QyMF6fs/4FSUnVIw0CBPsU0K4LnBPwYwg==", - "dev": true, - "requires": { - "browserslist": "^4.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "dependencies": { - "postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", - "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", - "dev": true - } - } - }, - "postcss-normalize-url": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-4.0.1.tgz", - "integrity": "sha512-p5oVaF4+IHwu7VpMan/SSpmpYxcJMtkGppYf0VbdH5B6hN8YNmVyJLuY9FmLQTzY3fag5ESUUHDqM+heid0UVA==", - "dev": true, - "requires": { - "is-absolute-url": "^2.0.0", - "normalize-url": "^3.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "dependencies": { - "postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", - "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", - "dev": true - } - } - }, - "postcss-normalize-whitespace": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/postcss-normalize-whitespace/-/postcss-normalize-whitespace-4.0.2.tgz", - "integrity": "sha512-tO8QIgrsI3p95r8fyqKV+ufKlSHh9hMJqACqbv2XknufqEDhDvbguXGBBqxw9nsQoXWf0qOqppziKJKHMD4GtA==", - "dev": true, - "requires": { - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "dependencies": { - "postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", - "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", - "dev": true - } - } - }, - "postcss-ordered-values": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-4.1.2.tgz", - "integrity": "sha512-2fCObh5UanxvSxeXrtLtlwVThBvHn6MQcu4ksNT2tsaV2Fg76R2CV98W7wNSlX+5/pFwEyaDwKLLoEV7uRybAw==", - "dev": true, - "requires": { - "cssnano-util-get-arguments": "^4.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "dependencies": { - "postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", - "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", - "dev": true - } - } - }, - "postcss-reduce-initial": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-4.0.3.tgz", - "integrity": "sha512-gKWmR5aUulSjbzOfD9AlJiHCGH6AEVLaM0AV+aSioxUDd16qXP1PCh8d1/BGVvpdWn8k/HiK7n6TjeoXN1F7DA==", - "dev": true, - "requires": { - "browserslist": "^4.0.0", - "caniuse-api": "^3.0.0", - "has": "^1.0.0", - "postcss": "^7.0.0" - } - }, - "postcss-reduce-transforms": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-4.0.2.tgz", - "integrity": "sha512-EEVig1Q2QJ4ELpJXMZR8Vt5DQx8/mo+dGWSR7vWXqcob2gQLyQGsionYcGKATXvQzMPn6DSN1vTN7yFximdIAg==", - "dev": true, - "requires": { - "cssnano-util-get-match": "^4.0.0", - "has": "^1.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "dependencies": { - "postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", - "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", - "dev": true - } - } - }, - "postcss-selector-parser": { - "version": "6.0.4", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.4.tgz", - "integrity": "sha512-gjMeXBempyInaBqpp8gODmwZ52WaYsVOsfr4L4lDQ7n3ncD6mEyySiDtgzCT+NYC0mmeOLvtsF8iaEf0YT6dBw==", - "dev": true, - "requires": { - "cssesc": "^3.0.0", - "indexes-of": "^1.0.1", - "uniq": "^1.0.1", - "util-deprecate": "^1.0.2" - } - }, - "postcss-svgo": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-4.0.3.tgz", - "integrity": "sha512-NoRbrcMWTtUghzuKSoIm6XV+sJdvZ7GZSc3wdBN0W19FTtp2ko8NqLsgoh/m9CzNhU3KLPvQmjIwtaNFkaFTvw==", - "dev": true, - "requires": { - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0", - "svgo": "^1.0.0" - }, - "dependencies": { - "postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", - "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", - "dev": true - } - } - }, - "postcss-unique-selectors": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-4.0.1.tgz", - "integrity": "sha512-+JanVaryLo9QwZjKrmJgkI4Fn8SBgRO6WXQBJi7KiAVPlmxikB5Jzc4EvXMT2H0/m0RjrVVm9rGNhZddm/8Spg==", - "dev": true, - "requires": { - "alphanum-sort": "^1.0.0", - "postcss": "^7.0.0", - "uniqs": "^2.0.0" - } - }, - "postcss-value-parser": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.1.0.tgz", - "integrity": "sha512-97DXOFbQJhk71ne5/Mt6cOu6yxsSfM0QGQyl0L25Gca4yGWEGJaig7l7gbCX623VqTBNGLRLaVUCnNkcedlRSQ==", - "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": "2.0.0", - "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz", - "integrity": "sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=", - "dev": true - }, - "prettier": { - "version": "1.16.3", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.16.3.tgz", - "integrity": "sha512-kn/GU6SMRYPxUakNXhpP0EedT/KmaPzr0H5lIsDogrykbaxOpOfAFfk5XA7DZrJyMAv1wlMV3CPcZruGXVVUZw==", - "dev": true - }, - "pretty-error": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/pretty-error/-/pretty-error-2.1.2.tgz", - "integrity": "sha512-EY5oDzmsX5wvuynAByrmY0P0hcp+QpnAKbJng2A2MPjVKXCxrDSUkzghVJ4ZGPIv+JC4gX8fPUWscC0RtjsWGw==", - "dev": true, - "requires": { - "lodash": "^4.17.20", - "renderkid": "^2.0.4" - } - }, - "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": "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 - }, - "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 - }, - "proxy-addr": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.6.tgz", - "integrity": "sha512-dh/frvCBVmSsDYzw6n926jv974gddhkFPfiN8hPOi30Wax25QZyZEGveluCgliBnqmuM+UJmBErbAUFIoDbjOw==", - "dev": true, - "requires": { - "forwarded": "~0.1.2", - "ipaddr.js": "1.9.1" - } - }, - "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 - }, - "psl": { - "version": "1.1.31", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.1.31.tgz", - "integrity": "sha512-/6pt4+C+T+wZUieKR620OpzN/LlnNKuWjy1iFLQ/UG35JqHlR/89MP1d96dUfkf6Dne3TuLQzOYEYshJ+Hx8mw==", - "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" - }, - "dependencies": { - "bn.js": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", - "dev": true - } - } - }, - "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 - }, - "q": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", - "integrity": "sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=", - "dev": true - }, - "qs": { - "version": "6.5.2", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", - "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==", - "dev": true - }, - "query-string": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/query-string/-/query-string-5.1.1.tgz", - "integrity": "sha512-gjWOsm2SoGlgLEdAGt7a6slVOk9mGiXmPFMqrEhLQ68rhQuBnpfs3+EmlvqKyxnCo9/PPlF+9MtY02S1aFg+Jw==", - "dev": true, - "requires": { - "decode-uri-component": "^0.2.0", - "object-assign": "^4.1.0", - "strict-uri-encode": "^1.0.0" - } - }, - "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 - }, - "querystringify": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", - "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==", - "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" - } - }, - "range-parser": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", - "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", - "dev": true - }, - "raw-body": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz", - "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==", - "dev": true, - "requires": { - "bytes": "3.1.0", - "http-errors": "1.7.2", - "iconv-lite": "0.4.24", - "unpipe": "1.0.0" - } - }, - "read-pkg": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", - "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", - "dev": true, - "requires": { - "@types/normalize-package-data": "^2.4.0", - "normalize-package-data": "^2.5.0", - "parse-json": "^5.0.0", - "type-fest": "^0.6.0" - }, - "dependencies": { - "parse-json": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", - "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.0.0", - "error-ex": "^1.3.1", - "json-parse-even-better-errors": "^2.3.0", - "lines-and-columns": "^1.1.6" - } - } - } - }, - "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" - } - } - } - }, - "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" - } - }, - "regenerator-runtime": { - "version": "0.11.1", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", - "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==", - "dev": true - }, - "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" - } - }, - "regexp.prototype.flags": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.3.1.tgz", - "integrity": "sha512-JiBdRBq91WlY7uRJ0ds7R+dU02i6LKi8r3BuQhNXn+kmeLN+EfHhfjqMRis1zJxnlu88hq/4dx0P2OP3APRTOA==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" - } - }, - "regexpp": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-2.0.1.tgz", - "integrity": "sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw==", - "dev": true - }, - "relateurl": { - "version": "0.2.7", - "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz", - "integrity": "sha1-VNvzd+UUQKypCkzSdGANP/LYiKk=", - "dev": true - }, - "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 - }, - "renderkid": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/renderkid/-/renderkid-2.0.5.tgz", - "integrity": "sha512-ccqoLg+HLOHq1vdfYNm4TBeaCDIi1FLt3wGojTDSvdewUv65oTmI3cnT2E4hRjl1gzKZIPK+KZrXzlUYKnR+vQ==", - "dev": true, - "requires": { - "css-select": "^2.0.2", - "dom-converter": "^0.2", - "htmlparser2": "^3.10.1", - "lodash": "^4.17.20", - "strip-ansi": "^3.0.0" - }, - "dependencies": { - "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" - } - } - } - }, - "repeat-element": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.4.tgz", - "integrity": "sha512-LFiNfRcSu7KK3evMyYOuCzv3L10TW7yC1G2/+StMjK8Y6Vqd2MG7r/Qjw4ghtuCOjFvlnms/iMmLqpvW/ES/WQ==", - "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 - }, - "request": { - "version": "2.88.0", - "resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz", - "integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==", - "dev": true, - "requires": { - "aws-sign2": "~0.7.0", - "aws4": "^1.8.0", - "caseless": "~0.12.0", - "combined-stream": "~1.0.6", - "extend": "~3.0.2", - "forever-agent": "~0.6.1", - "form-data": "~2.3.2", - "har-validator": "~5.1.0", - "http-signature": "~1.2.0", - "is-typedarray": "~1.0.0", - "isstream": "~0.1.2", - "json-stringify-safe": "~5.0.1", - "mime-types": "~2.1.19", - "oauth-sign": "~0.9.0", - "performance-now": "^2.1.0", - "qs": "~6.5.2", - "safe-buffer": "^5.1.2", - "tough-cookie": "~2.4.3", - "tunnel-agent": "^0.6.0", - "uuid": "^3.3.2" - }, - "dependencies": { - "punycode": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", - "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", - "dev": true - }, - "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==", - "dev": true, - "requires": { - "psl": "^1.1.24", - "punycode": "^1.4.1" - } - } - } - }, - "request-promise-core": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.4.tgz", - "integrity": "sha512-TTbAfBBRdWD7aNNOoVOBH4pN/KigV6LyapYNNlAPA8JwbovRti1E88m3sYAwsLi5ryhPKsE9APwnjFTgdUjTpw==", - "dev": true, - "requires": { - "lodash": "^4.17.19" - } - }, - "request-promise-native": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/request-promise-native/-/request-promise-native-1.0.9.tgz", - "integrity": "sha512-wcW+sIUiWnKgNY0dqCpOZkUbF/I+YPi+f09JZIDa39Ec+q82CpSYniDp+ISgTTbKmnpJWASeJBPZmoxH84wt3g==", - "dev": true, - "requires": { - "request-promise-core": "1.1.4", - "stealthy-require": "^1.1.1", - "tough-cookie": "^2.3.3" - } - }, - "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": "1.0.1", - "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", - "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=", - "dev": true - }, - "requires-port": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", - "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=", - "dev": true - }, - "resolve": { - "version": "1.20.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz", - "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==", - "dev": true, - "requires": { - "is-core-module": "^2.2.0", - "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" - } - }, - "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-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" - }, - "dependencies": { - "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" - } - } - } - }, - "ret": { - "version": "0.1.15", - "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", - "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", - "dev": true - }, - "retry": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", - "integrity": "sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs=", - "dev": true - }, - "rgb-regex": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/rgb-regex/-/rgb-regex-1.0.1.tgz", - "integrity": "sha1-wODWiC3w4jviVKR16O3UGRX+rrE=", - "dev": true - }, - "rgba-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/rgba-regex/-/rgba-regex-1.0.0.tgz", - "integrity": "sha1-QzdOLiyglosO8VI0YLfXMP8i7rM=", - "dev": true - }, - "rimraf": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", - "dev": true, - "requires": { - "glob": "^7.1.3" - } - }, - "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.4.1", - "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", - "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==", - "dev": true - }, - "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" - } - }, - "rxjs": { - "version": "6.6.7", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", - "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", - "dev": true, - "requires": { - "tslib": "^1.9.0" - } - }, - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true - }, - "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 - }, - "sax": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", - "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", - "dev": true - }, - "saxes": { - "version": "3.1.11", - "resolved": "https://registry.npmjs.org/saxes/-/saxes-3.1.11.tgz", - "integrity": "sha512-Ydydq3zC+WYDJK1+gRxRapLIED9PWeSuuS41wqyoRmzvhhh9nc+QQrVMKJYzJFULazeGhzSV0QleN2wD3boh2g==", - "dev": true, - "requires": { - "xmlchars": "^2.1.1" - } - }, - "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.5.2", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", - "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", - "dev": true - } - } - }, - "select-hose": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", - "integrity": "sha1-Yl2GWPhlr0Psliv8N2o3NZpJlMo=", - "dev": true - }, - "selfsigned": { - "version": "1.10.8", - "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-1.10.8.tgz", - "integrity": "sha512-2P4PtieJeEwVgTU9QEcwIRDQ/mXJLX8/+I3ur+Pg16nS8oNbrGxEso9NyYWy8NAmXiNl4dlAp5MwoNeCWzON4w==", - "dev": true, - "requires": { - "node-forge": "^0.10.0" - } - }, - "semver": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.6.0.tgz", - "integrity": "sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg==", - "dev": true - }, - "send": { - "version": "0.17.1", - "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz", - "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==", - "dev": true, - "requires": { - "debug": "2.6.9", - "depd": "~1.1.2", - "destroy": "~1.0.4", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "fresh": "0.5.2", - "http-errors": "~1.7.2", - "mime": "1.6.0", - "ms": "2.1.1", - "on-finished": "~2.3.0", - "range-parser": "~1.2.1", - "statuses": "~1.5.0" - }, - "dependencies": { - "mime": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", - "dev": true - }, - "ms": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", - "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", - "dev": true - } - } - }, - "serialize-javascript": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-1.9.1.tgz", - "integrity": "sha512-0Vb/54WJ6k5v8sSWN09S0ora+Hnr+cX40r9F170nT+mSkaxltoE/7R3OrIdBSUv1OoiobH1QoWQbCnAO+e8J1A==", - "dev": true - }, - "serve-index": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", - "integrity": "sha1-03aNabHn2C5c4FD/9bRTvqEqkjk=", - "dev": true, - "requires": { - "accepts": "~1.3.4", - "batch": "0.6.1", - "debug": "2.6.9", - "escape-html": "~1.0.3", - "http-errors": "~1.6.2", - "mime-types": "~2.1.17", - "parseurl": "~1.3.2" - }, - "dependencies": { - "http-errors": { - "version": "1.6.3", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", - "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", - "dev": true, - "requires": { - "depd": "~1.1.2", - "inherits": "2.0.3", - "setprototypeof": "1.1.0", - "statuses": ">= 1.4.0 < 2" - } - }, - "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", - "dev": true - }, - "setprototypeof": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", - "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==", - "dev": true - } - } - }, - "serve-static": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz", - "integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==", - "dev": true, - "requires": { - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "parseurl": "~1.3.3", - "send": "0.17.1" - } - }, - "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 - }, - "setprototypeof": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", - "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==", - "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 - }, - "shell-quote": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.7.2.tgz", - "integrity": "sha512-mRz/m/JVscCrkMyPqHc/bczi3OQHkLTqXHEFu0zDhK/qfv3UcOA4SVmRCLmos4bhjr9ekVQubj/R7waKapmiQg==", - "dev": true - }, - "signal-exit": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", - "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", - "dev": true - }, - "simple-swizzle": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", - "integrity": "sha1-pNprY1/8zMoz9w0Xy5JZLeleVXo=", - "dev": true, - "requires": { - "is-arrayish": "^0.3.1" - }, - "dependencies": { - "is-arrayish": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", - "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==", - "dev": true - } - } - }, - "sinon": { - "version": "7.2.2", - "dev": true, - "requires": { - "@sinonjs/commons": "^1.2.0", - "@sinonjs/formatio": "^3.1.0", - "@sinonjs/samsam": "^3.0.2", - "diff": "^3.5.0", - "lolex": "^3.0.0", - "nise": "^1.4.7", - "supports-color": "^5.5.0" - } - }, - "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" - } - }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - } - } - }, - "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" - } - } - } - }, - "sockjs": { - "version": "0.3.19", - "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.19.tgz", - "integrity": "sha512-V48klKZl8T6MzatbLlzzRNhMepEys9Y4oGFpypBFFn1gLI/QQ9HtLLyWJNbPlwGLelOVOEijUbTTJeLLI59jLw==", - "dev": true, - "requires": { - "faye-websocket": "^0.10.0", - "uuid": "^3.0.1" - } - }, - "sockjs-client": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/sockjs-client/-/sockjs-client-1.4.0.tgz", - "integrity": "sha512-5zaLyO8/nri5cua0VtOrFXBPK1jbL4+1cebT/mmKA1E1ZXOvJrII75bPu0l0k843G/+iAbhEqzyKr0w/eCCj7g==", - "dev": true, - "requires": { - "debug": "^3.2.5", - "eventsource": "^1.0.7", - "faye-websocket": "~0.11.1", - "inherits": "^2.0.3", - "json3": "^3.3.2", - "url-parse": "^1.4.3" - }, - "dependencies": { - "debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - }, - "faye-websocket": { - "version": "0.11.3", - "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.3.tgz", - "integrity": "sha512-D2y4bovYpzziGgbHYtGCMjlJM36vAl/y+xUyn1C+FVx8szd1E+86KwVw6XvYSzOP8iMpm1X0I4xJD+QtUb36OA==", - "dev": true, - "requires": { - "websocket-driver": ">=0.5.1" - } - }, - "ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true - } - } - }, - "sort-keys": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-2.0.0.tgz", - "integrity": "sha1-ZYU1WEhh7JfXMNbPQYIuH1ZoQSg=", - "dev": true, - "requires": { - "is-plain-obj": "^1.0.0" - } - }, - "source-list-map": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.1.tgz", - "integrity": "sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw==", - "dev": true - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - }, - "source-map-resolve": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz", - "integrity": "sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==", - "dev": true, - "requires": { - "atob": "^2.1.2", - "decode-uri-component": "^0.2.0", - "resolve-url": "^0.2.1", - "source-map-url": "^0.4.0", - "urix": "^0.1.0" - } - }, - "source-map-support": { - "version": "0.5.19", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz", - "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==", - "dev": true, - "requires": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.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.1", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", - "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==", - "dev": true, - "requires": { - "spdx-expression-parse": "^3.0.0", - "spdx-license-ids": "^3.0.0" - } - }, - "spdx-exceptions": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", - "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", - "dev": true - }, - "spdx-expression-parse": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", - "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", - "dev": true, - "requires": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" - } - }, - "spdx-license-ids": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.7.tgz", - "integrity": "sha512-U+MTEOO0AiDzxwFvoa4JVnMV6mZlJKk2sBLt90s7G0Gd0Mlknc7kxEn3nuDPNZRta7O2uy8oLcZLVT+4sqNZHQ==", - "dev": true - }, - "spdy": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.2.tgz", - "integrity": "sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA==", - "dev": true, - "requires": { - "debug": "^4.1.0", - "handle-thing": "^2.0.0", - "http-deceiver": "^1.2.7", - "select-hose": "^2.0.0", - "spdy-transport": "^3.0.0" - }, - "dependencies": { - "debug": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", - "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", - "dev": true, - "requires": { - "ms": "2.1.2" - } - }, - "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 - } - } - }, - "spdy-transport": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-3.0.0.tgz", - "integrity": "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==", - "dev": true, - "requires": { - "debug": "^4.1.0", - "detect-node": "^2.0.4", - "hpack.js": "^2.1.6", - "obuf": "^1.1.2", - "readable-stream": "^3.0.6", - "wbuf": "^1.7.3" - }, - "dependencies": { - "debug": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", - "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", - "dev": true, - "requires": { - "ms": "2.1.2" - } - }, - "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 - }, - "readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "dev": true, - "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - } - } - } - }, - "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 - }, - "sshpk": { - "version": "1.16.1", - "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", - "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", - "dev": true, - "requires": { - "asn1": "~0.2.3", - "assert-plus": "^1.0.0", - "bcrypt-pbkdf": "^1.0.0", - "dashdash": "^1.12.0", - "ecc-jsbn": "~0.1.1", - "getpass": "^0.1.1", - "jsbn": "~0.1.0", - "safer-buffer": "^2.0.2", - "tweetnacl": "~0.14.0" - } - }, - "ssri": { - "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" - } - }, - "stable": { - "version": "0.1.8", - "resolved": "https://registry.npmjs.org/stable/-/stable-0.1.8.tgz", - "integrity": "sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==", - "dev": true - }, - "stackframe": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/stackframe/-/stackframe-1.2.0.tgz", - "integrity": "sha512-GrdeshiRmS1YLMYgzF16olf2jJ/IzxXY9lhKOskuVziubpTYcYqyOwYeJKzQkwy7uN0fYSsbsC4RQaXf9LCrYA==", - "dev": true - }, - "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" - } - } - } - }, - "statuses": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", - "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=", - "dev": true - }, - "stealthy-require": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz", - "integrity": "sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks=", - "dev": true - }, - "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" - } - }, - "stream-shift": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.1.tgz", - "integrity": "sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==", - "dev": true - }, - "strict-uri-encode": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz", - "integrity": "sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM=", - "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" - } - }, - "string.prototype.padend": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/string.prototype.padend/-/string.prototype.padend-3.0.0.tgz", - "integrity": "sha1-86rvfBcZ8XDF6rHDK/eA2W4h8vA=", - "dev": true, - "requires": { - "define-properties": "^1.1.2", - "es-abstract": "^1.4.3", - "function-bind": "^1.0.2" - } - }, - "string.prototype.padstart": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/string.prototype.padstart/-/string.prototype.padstart-3.1.2.tgz", - "integrity": "sha512-HDpngIP3pd0DeazrfqzuBrQZa+D2arKWquEHfGt5LzVjd+roLC3cjqVI0X8foaZz5rrrhcu8oJAQamW8on9dqw==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.18.0-next.2" - }, - "dependencies": { - "es-abstract": { - "version": "1.18.0", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.0.tgz", - "integrity": "sha512-LJzK7MrQa8TS0ja2w3YNLzUgJCGPdPOV1yVvezjNnS89D+VR08+Szt2mz3YB2Dck/+w5tfIq/RoUAFqJJGM2yw==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "get-intrinsic": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.2", - "is-callable": "^1.2.3", - "is-negative-zero": "^2.0.1", - "is-regex": "^1.1.2", - "is-string": "^1.0.5", - "object-inspect": "^1.9.0", - "object-keys": "^1.1.1", - "object.assign": "^4.1.2", - "string.prototype.trimend": "^1.0.4", - "string.prototype.trimstart": "^1.0.4", - "unbox-primitive": "^1.0.0" - } - }, - "es-to-primitive": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", - "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", - "dev": true, - "requires": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" - } - }, - "is-callable": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.3.tgz", - "integrity": "sha512-J1DcMe8UYTBSrKezuIUTUwjXsho29693unXM2YhJUTR2txK/eG47bvNa/wipPFmZFgr/N6f1GA66dv0mEyTIyQ==", - "dev": true - }, - "is-regex": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.2.tgz", - "integrity": "sha512-axvdhb5pdhEVThqJzYXwMlVuZwC+FF2DpcOhTS+y/8jVq4trxyPgfcwIxIKiyeuLlSQYKkmUaPQJ8ZE4yNKXDg==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "has-symbols": "^1.0.1" - } - }, - "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 - } - } - }, - "string.prototype.trimend": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz", - "integrity": "sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" - } - }, - "string.prototype.trimstart": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz", - "integrity": "sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" - } - }, - "string_decoder": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.2.0.tgz", - "integrity": "sha512-6YqyX6ZWEYguAxgZzHGL7SsCeGx3V2TtOTqZz1xSTSWnqsbWwbptafNyvf/ACquZUXV3DANr5BDIwNYe1mN42w==", - "dev": true, - "requires": { - "safe-buffer": "~5.1.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" - }, - "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-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-final-newline": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", - "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", - "dev": true - }, - "strip-indent": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-2.0.0.tgz", - "integrity": "sha1-XvjbKV0B5u1sv3qrlpmNeCJSe2g=", - "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 - }, - "stylehacks": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-4.0.3.tgz", - "integrity": "sha512-7GlLk9JwlElY4Y6a/rmbH2MhVlTyVmiJd1PfTCqFaIBEGMYNsrO/v3SeGTdhBThLg4Z+NbOk/qFMwCa+J+3p/g==", - "dev": true, - "requires": { - "browserslist": "^4.0.0", - "postcss": "^7.0.0", - "postcss-selector-parser": "^3.0.0" - }, - "dependencies": { - "postcss-selector-parser": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-3.1.2.tgz", - "integrity": "sha512-h7fJ/5uWuRVyOtkO45pnt1Ih40CEleeyCHzipqAZO2e5H20g25Y48uYnFUiShvY4rZWNJ/Bib/KVPmanaCtOhA==", - "dev": true, - "requires": { - "dot-prop": "^5.2.0", - "indexes-of": "^1.0.1", - "uniq": "^1.0.1" - } - } - } - }, - "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" - } - }, - "svgo": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/svgo/-/svgo-1.3.2.tgz", - "integrity": "sha512-yhy/sQYxR5BkC98CY7o31VGsg014AKLEPxdfhora76l36hD9Rdy5NZA/Ocn6yayNPgSamYdtX2rFJdcv07AYVw==", - "dev": true, - "requires": { - "chalk": "^2.4.1", - "coa": "^2.0.2", - "css-select": "^2.0.0", - "css-select-base-adapter": "^0.1.1", - "css-tree": "1.0.0-alpha.37", - "csso": "^4.0.2", - "js-yaml": "^3.13.1", - "mkdirp": "~0.5.1", - "object.values": "^1.1.0", - "sax": "~1.2.4", - "stable": "^0.1.8", - "unquote": "~1.1.1", - "util.promisify": "~1.0.0" - }, - "dependencies": { - "js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", - "dev": true, - "requires": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - } - } - } - }, - "symbol-tree": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", - "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", - "dev": true - }, - "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.1", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-1.1.1.tgz", - "integrity": "sha512-9I2ydhj8Z9veORCw5PRm4u9uebCn0mcCa6scWoNcbZ6dAtoo2618u9UUzxgmsCOreJpqDDuv61LvwofW7hLcBA==", - "dev": true - }, - "terser": { - "version": "4.8.0", - "resolved": "https://registry.npmjs.org/terser/-/terser-4.8.0.tgz", - "integrity": "sha512-EAPipTNeWsb/3wLPeup1tVPaXfIaU68xMnVdPafIL1TV05OhASArYyIfFvnvJCNrR2NIOvDVNNTFRa+Re2MWyw==", - "dev": true, - "requires": { - "commander": "^2.20.0", - "source-map": "~0.6.1", - "source-map-support": "~0.5.12" - }, - "dependencies": { - "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 - }, - "source-map-support": { - "version": "0.5.19", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz", - "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==", - "dev": true, - "requires": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - } - } - }, - "terser-webpack-plugin": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-1.4.1.tgz", - "integrity": "sha512-ZXmmfiwtCLfz8WKZyYUuuHf3dMYEjg8NrjHMb0JqHVHVOSkzp3cW2/XG1fP3tRhqEqSzMwzzRQGtAPbs4Cncxg==", - "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": "^1.7.0", - "source-map": "^0.6.1", - "terser": "^4.1.2", - "webpack-sources": "^1.4.0", - "worker-farm": "^1.7.0" - }, - "dependencies": { - "bluebird": { - "version": "3.7.2", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", - "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", - "dev": true - }, - "cacache": { - "version": "12.0.4", - "resolved": "https://registry.npmjs.org/cacache/-/cacache-12.0.4.tgz", - "integrity": "sha512-a0tMB40oefvuInr4Cwb3GerbL9xTj1D5yg0T5xrjGCGyfvbxseIXX7BAO/u/hIXdafzOI5JC3wDwHyf24buOAQ==", - "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" - } - }, - "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" - } - }, - "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" - } - }, - "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" - } - }, - "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" - } - }, - "pify": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", - "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", - "dev": true - }, - "serialize-javascript": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-1.9.1.tgz", - "integrity": "sha512-0Vb/54WJ6k5v8sSWN09S0ora+Hnr+cX40r9F170nT+mSkaxltoE/7R3OrIdBSUv1OoiobH1QoWQbCnAO+e8J1A==", - "dev": true - } - } - }, - "text-encoding": { - "version": "0.6.4", - "resolved": "https://registry.npmjs.org/text-encoding/-/text-encoding-0.6.4.tgz", - "integrity": "sha1-45mpgiV6J22uQou5KEXLcb3CbRk=", - "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 - }, - "thenify": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", - "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", - "dev": true, - "requires": { - "any-promise": "^1.0.0" - } - }, - "thenify-all": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", - "integrity": "sha1-GhkY1ALY/D+Y+/I02wvMjMEOlyY=", - "dev": true, - "requires": { - "thenify": ">= 3.1.0 < 4" - } - }, - "thread-loader": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/thread-loader/-/thread-loader-2.1.3.tgz", - "integrity": "sha512-wNrVKH2Lcf8ZrWxDF/khdlLlsTMczdcwPA9VEK4c2exlEPynYWxi9op3nPTo5lAnDIkE0rQEB3VBP+4Zncc9Hg==", - "dev": true, - "requires": { - "loader-runner": "^2.3.1", - "loader-utils": "^1.1.0", - "neo-async": "^2.6.0" - } - }, - "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" - } - }, - "thunky": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", - "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==", - "dev": true - }, - "timers-browserify": { - "version": "2.0.12", - "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.12.tgz", - "integrity": "sha512-9phl76Cqm6FhSX9Xe1ZUAMLtm1BLkKj2Qd5ApyWkXzsMRaA7dgr81kf4wJmQf/hAvg8EEyJxDo3du/0KlhPiKQ==", - "dev": true, - "requires": { - "setimmediate": "^1.0.4" - } - }, - "timsort": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/timsort/-/timsort-0.3.0.tgz", - "integrity": "sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q=", - "dev": true - }, - "tinycolor2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/tinycolor2/-/tinycolor2-1.4.1.tgz", - "integrity": "sha1-9PrTM0R7wLB9TcjpIJ2POaisd+g=" - }, - "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" - } - }, - "toidentifier": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", - "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==", - "dev": true - }, - "toposort": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/toposort/-/toposort-1.0.7.tgz", - "integrity": "sha1-LmhELZ9k7HILjMieZEOsbKqVACk=", - "dev": true - }, - "tough-cookie": { - "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.28", - "punycode": "^2.1.1" - } - }, - "tr46": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-1.0.1.tgz", - "integrity": "sha1-qLE/1r/SSJUZZ0zN5VujaTtwbQk=", - "dev": true, - "requires": { - "punycode": "^2.1.0" - } - }, - "tryer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/tryer/-/tryer-1.0.1.tgz", - "integrity": "sha512-c3zayb8/kWWpycWYg87P71E1S1ZL6b6IJxfb5fvsUgsf0S2MVGaDhDXXjDMpdCpfWXqptc+4mXwmiy1ypXqRAA==", - "dev": true - }, - "ts-loader": { - "version": "5.4.5", - "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-5.4.5.tgz", - "integrity": "sha512-XYsjfnRQCBum9AMRZpk2rTYSVpdZBpZK+kDh0TeT3kxmQNBDVIeUjdPjY5RZry4eIAb8XHc4gYSUiUWPYvzSRw==", - "dev": true, - "requires": { - "chalk": "^2.3.0", - "enhanced-resolve": "^4.0.0", - "loader-utils": "^1.0.2", - "micromatch": "^3.1.4", - "semver": "^5.0.1" - } - }, - "tslib": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.3.tgz", - "integrity": "sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ==", - "dev": true - }, - "tslint": { - "version": "5.20.0", - "resolved": "https://registry.npmjs.org/tslint/-/tslint-5.20.0.tgz", - "integrity": "sha512-2vqIvkMHbnx8acMogAERQ/IuINOq6DFqgF8/VDvhEkBqQh/x6SP0Y+OHnKth9/ZcHQSroOZwUQSN18v8KKF0/g==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.0.0", - "builtin-modules": "^1.1.1", - "chalk": "^2.3.0", - "commander": "^2.12.1", - "diff": "^4.0.1", - "glob": "^7.1.1", - "js-yaml": "^3.13.1", - "minimatch": "^3.0.4", - "mkdirp": "^0.5.1", - "resolve": "^1.3.2", - "semver": "^5.3.0", - "tslib": "^1.8.0", - "tsutils": "^2.29.0" - }, - "dependencies": { - "diff": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", - "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", - "dev": true - }, - "js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", - "dev": true, - "requires": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - } - }, - "tsutils": { - "version": "2.29.0", - "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.29.0.tgz", - "integrity": "sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA==", - "dev": true, - "requires": { - "tslib": "^1.8.1" - } - } - } - }, - "tsutils": { - "version": "3.17.1", - "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.17.1.tgz", - "integrity": "sha512-kzeQ5B8H3w60nFY2g8cJIuH7JDpsALXySGtwGJ0p2LSjLgay3NdIpqq5SoOBe46bKDW2iq25irHCr8wjomUS2g==", - "dev": true, - "requires": { - "tslib": "^1.8.1" - } - }, - "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 - }, - "tunnel-agent": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", - "dev": true, - "requires": { - "safe-buffer": "^5.0.1" - } - }, - "tweetnacl": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", - "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", - "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" - } - }, - "type-detect": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", - "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", - "dev": true - }, - "type-fest": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", - "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", - "dev": true - }, - "type-is": { - "version": "1.6.18", - "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", - "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", - "dev": true, - "requires": { - "media-typer": "0.3.0", - "mime-types": "~2.1.24" - }, - "dependencies": { - "mime-db": { - "version": "1.47.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.47.0.tgz", - "integrity": "sha512-QBmA/G2y+IfeS4oktet3qRZ+P5kPhCKRXxXnQEudYqUaEioAU1/Lq2us3D/t1Jfo4hE9REQPrbB7K5sOczJVIw==", - "dev": true - }, - "mime-types": { - "version": "2.1.30", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.30.tgz", - "integrity": "sha512-crmjA4bLtR8m9qLpHvgxSChT+XoSlZi8J4n/aIdn3z92e/U47Z0V/yl+Wh9W046GgFVAmoNR/fmdbZYcSSIUeg==", - "dev": true, - "requires": { - "mime-db": "1.47.0" - } - } - } - }, - "typedarray": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", - "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", - "dev": true - }, - "typescript": { - "version": "3.6.3", - "dev": true - }, - "uglify-js": { - "version": "3.4.10", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.4.10.tgz", - "integrity": "sha512-Y2VsbPVs0FIshJztycsO2SfPk7/KAF/T72qzv9u5EpQ4kB2hQoHlhNQTsNyy6ul7lQtqJN/AoWeS23OzEiEFxw==", - "dev": true, - "requires": { - "commander": "~2.19.0", - "source-map": "~0.6.1" - }, - "dependencies": { - "commander": { - "version": "2.19.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.19.0.tgz", - "integrity": "sha512-6tvAOO+D6OENvRAh524Dh9jcfKTYDQAqvqezbCW82xj5X0pSrcpxtvRKHLG0yBY6SD7PSDrJaj+0AiOcKVd1Xg==", - "dev": true - } - } - }, - "unbox-primitive": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.1.tgz", - "integrity": "sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw==", - "dev": true, - "requires": { - "function-bind": "^1.1.1", - "has-bigints": "^1.0.1", - "has-symbols": "^1.0.2", - "which-boxed-primitive": "^1.0.2" - } - }, - "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" - } - }, - "uniq": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/uniq/-/uniq-1.0.1.tgz", - "integrity": "sha1-sxxa6CVIRKOoKBVBzisEuGWnNP8=", - "dev": true - }, - "uniqs": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/uniqs/-/uniqs-2.0.0.tgz", - "integrity": "sha1-/+3ks2slKQaW5uFl1KWe25mOawI=", - "dev": true - }, - "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" - } - }, - "universalify": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", - "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", - "dev": true - }, - "unpipe": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=", - "dev": true - }, - "unquote": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/unquote/-/unquote-1.1.1.tgz", - "integrity": "sha1-j97XMk7G6IoP+LkF58CYzcCG1UQ=", - "dev": true - }, - "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 - } - } - }, - "upath": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz", - "integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==", - "dev": true - }, - "upper-case": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/upper-case/-/upper-case-1.1.3.tgz", - "integrity": "sha1-9rRQHC7EzdJrp4vnIilh3ndiFZg=", - "dev": true - }, - "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-loader": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/url-loader/-/url-loader-1.1.2.tgz", - "integrity": "sha512-dXHkKmw8FhPqu8asTc1puBfe3TehOCo2+RmOOev5suNCIYBcT626kxiWg1NBVkwc4rO8BGa7gP70W7VXuqHrjg==", - "dev": true, - "requires": { - "loader-utils": "^1.1.0", - "mime": "^2.0.3", - "schema-utils": "^1.0.0" - } - }, - "url-parse": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.1.tgz", - "integrity": "sha512-HOfCOUJt7iSYzEx/UqgtwKRMC6EU91NFhsCHMv9oM03VJcVo2Qrp8T8kI9D7amFf1cu+/3CEhgb3rF9zL7k85Q==", - "dev": true, - "requires": { - "querystringify": "^2.1.1", - "requires-port": "^1.0.0" - } - }, - "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=", - "dev": true - }, - "util.promisify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/util.promisify/-/util.promisify-1.0.1.tgz", - "integrity": "sha512-g9JpC/3He3bm38zsLupWryXHoEcS22YHthuPQSJdMy6KNrzIRzWqcsHzD/WUnqe45whVou4VIsPew37DoXWNrA==", - "dev": true, - "requires": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.2", - "has-symbols": "^1.0.1", - "object.getownpropertydescriptors": "^2.1.0" - } - }, - "utila": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/utila/-/utila-0.4.0.tgz", - "integrity": "sha1-ihagXURWV6Oupe7MWxKk+lN5dyw=", - "dev": true - }, - "utils-merge": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", - "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=", - "dev": true - }, - "uuid": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", - "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==", - "dev": true - }, - "v-clipboard": { - "version": "2.2.1" - }, - "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" - } - }, - "vary": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", - "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=", - "dev": true - }, - "vendors": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/vendors/-/vendors-1.0.4.tgz", - "integrity": "sha512-/juG65kTL4Cy2su4P8HjtkTxk6VmJDiOPBufWniqQ6wknac6jNiXS9vU+hO3wgusiyqWlzTbVHi0dyJqRONg3w==", - "dev": true - }, - "verror": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", - "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", - "dev": true, - "requires": { - "assert-plus": "^1.0.0", - "core-util-is": "1.0.2", - "extsprintf": "^1.2.0" - } - }, - "vm-browserify": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.2.tgz", - "integrity": "sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==", - "dev": true - }, - "vue": { - "version": "2.5.22" - }, - "vue-color": { - "version": "2.7.0", - "requires": { - "clamp": "^1.0.1", - "lodash.throttle": "^4.0.0", - "material-colors": "^1.0.0", - "tinycolor2": "^1.1.2" - } - }, - "vue-eslint-parser": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/vue-eslint-parser/-/vue-eslint-parser-5.0.0.tgz", - "integrity": "sha512-JlHVZwBBTNVvzmifwjpZYn0oPWH2SgWv5dojlZBsrhablDu95VFD+hriB1rQGwbD+bms6g+rAFhQHk6+NyiS6g==", - "dev": true, - "requires": { - "debug": "^4.1.0", - "eslint-scope": "^4.0.0", - "eslint-visitor-keys": "^1.0.0", - "espree": "^4.1.0", - "esquery": "^1.0.1", - "lodash": "^4.17.11" - }, - "dependencies": { - "debug": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", - "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", - "dev": true, - "requires": { - "ms": "2.1.2" - } - }, - "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" - } - }, - "espree": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-4.1.0.tgz", - "integrity": "sha512-I5BycZW6FCVIub93TeVY1s7vjhP9CY6cXCznIRfiig7nRviKZYdRnj/sHEWC6A7WE9RDWOFq9+7OsWSYz8qv2w==", - "dev": true, - "requires": { - "acorn": "^6.0.2", - "acorn-jsx": "^5.0.0", - "eslint-visitor-keys": "^1.0.0" - } - }, - "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 - } - } - }, - "vue-hot-reload-api": { - "version": "2.3.4", - "resolved": "https://registry.npmjs.org/vue-hot-reload-api/-/vue-hot-reload-api-2.3.4.tgz", - "integrity": "sha512-BXq3jwIagosjgNVae6tkHzzIk6a8MHFtzAdwhnV5VlvPTFxDCvIttgSiHWjdGoTJvXtmRu5HacExfdarRcFhog==", - "dev": true - }, - "vue-loader": { - "version": "15.7.1", - "resolved": "https://registry.npmjs.org/vue-loader/-/vue-loader-15.7.1.tgz", - "integrity": "sha512-fwIKtA23Pl/rqfYP5TSGK7gkEuLhoTvRYW+TU7ER3q9GpNLt/PjG5NLv3XHRDiTg7OPM1JcckBgds+VnAc+HbA==", - "dev": true, - "requires": { - "@vue/component-compiler-utils": "^3.0.0", - "hash-sum": "^1.0.2", - "loader-utils": "^1.1.0", - "vue-hot-reload-api": "^2.3.0", - "vue-style-loader": "^4.1.0" - } - }, - "vue-notification": { - "version": "1.3.14" - }, - "vue-property-decorator": { - "version": "7.3.0", - "requires": { - "vue-class-component": "^6.2.0" - }, - "dependencies": { - "vue-class-component": { - "version": "6.3.2", - "resolved": "https://registry.npmjs.org/vue-class-component/-/vue-class-component-6.3.2.tgz", - "integrity": "sha512-cH208IoM+jgZyEf/g7mnFyofwPDJTM/QvBNhYMjqGB8fCsRyTf68rH2ISw/G20tJv+5mIThQ3upKwoL4jLTr1A==" - } - } - }, - "vue-router": { - "version": "3.0.2" - }, - "vue-style-loader": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/vue-style-loader/-/vue-style-loader-4.1.3.tgz", - "integrity": "sha512-sFuh0xfbtpRlKfm39ss/ikqs9AbKCoXZBpHeVZ8Tx650o0k0q/YCM7FRvigtxpACezfq6af+a7JeqVTWvncqDg==", - "dev": true, - "requires": { - "hash-sum": "^1.0.2", - "loader-utils": "^1.0.2" - } - }, - "vue-template-compiler": { - "version": "2.5.22", - "dev": true, - "requires": { - "de-indent": "^1.0.2", - "he": "^1.1.0" - } - }, - "vue-template-es2015-compiler": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/vue-template-es2015-compiler/-/vue-template-es2015-compiler-1.9.1.tgz", - "integrity": "sha512-4gDntzrifFnCEvyoO8PqyJDmguXgVPxKiIxrBKjIowvL9l+N66196+72XVYR8BBf1Uv1Fgt3bGevJ+sEmxfZzw==", - "dev": true - }, - "vuetify": { - "version": "1.4.2" - }, - "w3c-hr-time": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz", - "integrity": "sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ==", - "dev": true, - "requires": { - "browser-process-hrtime": "^1.0.0" - } - }, - "w3c-xmlserializer": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-1.1.2.tgz", - "integrity": "sha512-p10l/ayESzrBMYWRID6xbuCKh2Fp77+sA0doRuGn4tTIMrrZVeqfpKjXHY+oDh3K4nLdPgNwMTVP6Vp4pvqbNg==", - "dev": true, - "requires": { - "domexception": "^1.0.1", - "webidl-conversions": "^4.0.2", - "xml-name-validator": "^3.0.0" - } - }, - "watchpack": { - "version": "1.7.5", - "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.7.5.tgz", - "integrity": "sha512-9P3MWk6SrKjHsGkLT2KHXdQ/9SNkyoJbabxnKOoJepsvJjJG8uYTR3yTPxPQvNDI3w4Nz1xnE0TLHK4RIVe/MQ==", - "dev": true, - "requires": { - "chokidar": "^3.4.1", - "graceful-fs": "^4.1.2", - "neo-async": "^2.5.0", - "watchpack-chokidar2": "^2.0.1" - }, - "dependencies": { - "anymatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", - "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", - "dev": true, - "optional": true, - "requires": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - } - }, - "binary-extensions": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", - "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", - "dev": true, - "optional": true - }, - "braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "optional": true, - "requires": { - "fill-range": "^7.0.1" - } - }, - "chokidar": { - "version": "3.5.1", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.1.tgz", - "integrity": "sha512-9+s+Od+W0VJJzawDma/gvBNQqkTiqYTWLuZoyAsivsI4AaWTCzHG06/TMjsf1cYe9Cb97UCEhjz7HvnPk2p/tw==", - "dev": true, - "optional": true, - "requires": { - "anymatch": "~3.1.1", - "braces": "~3.0.2", - "fsevents": "~2.3.1", - "glob-parent": "~5.1.0", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.5.0" - } - }, - "fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, - "optional": true, - "requires": { - "to-regex-range": "^5.0.1" - } - }, - "glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "optional": true, - "requires": { - "is-glob": "^4.0.1" - } - }, - "is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "dev": true, - "optional": true, - "requires": { - "binary-extensions": "^2.0.0" - } - }, - "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-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true, - "optional": true - }, - "normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true - }, - "readdirp": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.5.0.tgz", - "integrity": "sha512-cMhu7c/8rdhkHXWsY+osBhfSy0JikwpHK/5+imo+LpeasTF8ouErHrlYkwT0++njiyuDvc7OFY5T3ukvZ8qmFQ==", - "dev": true, - "optional": true, - "requires": { - "picomatch": "^2.2.1" - } - }, - "to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "optional": true, - "requires": { - "is-number": "^7.0.0" - } - } - } - }, - "watchpack-chokidar2": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/watchpack-chokidar2/-/watchpack-chokidar2-2.0.1.tgz", - "integrity": "sha512-nCFfBIPKr5Sh61s4LPpy1Wtfi0HE8isJ3d2Yb5/Ppw2P2B/3eVSEBjKfN0fmHJSK14+31KwMKmcrzs2GM4P0Ww==", - "dev": true, - "optional": true, - "requires": { - "chokidar": "^2.1.8" - }, - "dependencies": { - "chokidar": { - "version": "2.1.8", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz", - "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==", - "dev": true, - "optional": 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" - } - }, - "fsevents": { - "version": "1.2.13", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz", - "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==", - "dev": true, - "optional": true - }, - "normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true, - "optional": 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, - "optional": true - } - } - }, - "wbuf": { - "version": "1.7.3", - "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz", - "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==", - "dev": true, - "requires": { - "minimalistic-assert": "^1.0.0" - } - }, - "wcwidth": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", - "integrity": "sha1-8LDc+RW8X/FSivrbLA4XtTLaL+g=", - "dev": true, - "requires": { - "defaults": "^1.0.3" - } - }, - "webidl-conversions": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz", - "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==", - "dev": true - }, - "webpack": { - "version": "4.41.0", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-4.41.0.tgz", - "integrity": "sha512-yNV98U4r7wX1VJAj5kyMsu36T8RPPQntcb5fJLOsMz/pt/WrKC0Vp1bAlqPLkA1LegSwQwf6P+kAbyhRKVQ72g==", - "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": { - "ajv-keywords": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", - "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", - "dev": true - }, - "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" - } - }, - "tapable": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-1.1.3.tgz", - "integrity": "sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==", - "dev": true - } - } - }, - "webpack-bundle-analyzer": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/webpack-bundle-analyzer/-/webpack-bundle-analyzer-3.5.2.tgz", - "integrity": "sha512-g9spCNe25QYUVqHRDkwG414GTok2m7pTTP0wr6l0J50Z3YLS04+BGodTqqoVBL7QfU/U/9p/oiI5XFOyfZ7S/A==", - "dev": true, - "requires": { - "acorn": "^6.0.7", - "acorn-walk": "^6.1.1", - "bfj": "^6.1.1", - "chalk": "^2.4.1", - "commander": "^2.18.0", - "ejs": "^2.6.1", - "express": "^4.16.3", - "filesize": "^3.6.1", - "gzip-size": "^5.0.0", - "lodash": "^4.17.15", - "mkdirp": "^0.5.1", - "opener": "^1.5.1", - "ws": "^6.0.0" - }, - "dependencies": { - "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 - } - } - }, - "webpack-chain": { - "version": "4.12.1", - "resolved": "https://registry.npmjs.org/webpack-chain/-/webpack-chain-4.12.1.tgz", - "integrity": "sha512-BCfKo2YkDe2ByqkEWe1Rw+zko4LsyS75LVr29C6xIrxAg9JHJ4pl8kaIZ396SUSNp6b4815dRZPSTAS8LlURRQ==", - "dev": true, - "requires": { - "deepmerge": "^1.5.2", - "javascript-stringify": "^1.6.0" - }, - "dependencies": { - "deepmerge": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-1.5.2.tgz", - "integrity": "sha512-95k0GDqvBjZavkuvzx/YqVLv/6YYa17fz6ILMSf7neqQITCPbnfEnQvEgMPNjH4kgobe7+WIL0yJEHku+H3qtQ==", - "dev": true - } - } - }, - "webpack-dev-middleware": { - "version": "3.7.3", - "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-3.7.3.tgz", - "integrity": "sha512-djelc/zGiz9nZj/U7PTBi2ViorGJXEWo/3ltkPbDyxCXhhEXkW0ce99falaok4TPj+AsxLiXJR0EBOb0zh9fKQ==", - "dev": true, - "requires": { - "memory-fs": "^0.4.1", - "mime": "^2.4.4", - "mkdirp": "^0.5.1", - "range-parser": "^1.2.1", - "webpack-log": "^2.0.0" - } - }, - "webpack-dev-server": { - "version": "3.8.1", - "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-3.8.1.tgz", - "integrity": "sha512-9F5DnfFA9bsrhpUCAfQic/AXBVHvq+3gQS+x6Zj0yc1fVVE0erKh2MV4IV12TBewuTrYeeTIRwCH9qLMvdNvTw==", - "dev": true, - "requires": { - "ansi-html": "0.0.7", - "bonjour": "^3.5.0", - "chokidar": "^2.1.8", - "compression": "^1.7.4", - "connect-history-api-fallback": "^1.6.0", - "debug": "^4.1.1", - "del": "^4.1.1", - "express": "^4.17.1", - "html-entities": "^1.2.1", - "http-proxy-middleware": "^0.19.1", - "import-local": "^2.0.0", - "internal-ip": "^4.3.0", - "ip": "^1.1.5", - "is-absolute-url": "^3.0.2", - "killable": "^1.0.1", - "loglevel": "^1.6.4", - "opn": "^5.5.0", - "p-retry": "^3.0.1", - "portfinder": "^1.0.24", - "schema-utils": "^1.0.0", - "selfsigned": "^1.10.6", - "semver": "^6.3.0", - "serve-index": "^1.9.1", - "sockjs": "0.3.19", - "sockjs-client": "1.4.0", - "spdy": "^4.0.1", - "strip-ansi": "^3.0.1", - "supports-color": "^6.1.0", - "url": "^0.11.0", - "webpack-dev-middleware": "^3.7.1", - "webpack-log": "^2.0.0", - "ws": "^6.2.1", - "yargs": "12.0.5" - }, - "dependencies": { - "async": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz", - "integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==", - "dev": true, - "requires": { - "lodash": "^4.17.14" - } - }, - "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" - } - }, - "debug": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", - "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", - "dev": true, - "requires": { - "ms": "2.1.2" - } - }, - "fsevents": { - "version": "1.2.13", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz", - "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==", - "dev": true, - "optional": true - }, - "is-absolute-url": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/is-absolute-url/-/is-absolute-url-3.0.3.tgz", - "integrity": "sha512-opmNIX7uFnS96NtPmhWQgQx6/NYFgsUXYMllcfzwWKUMwfo8kku1TvE6hkNcH+Q1ts5cMVrsY7j0bxXQDciu9Q==", - "dev": true - }, - "minimist": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", - "dev": true - }, - "mkdirp": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", - "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", - "dev": true, - "requires": { - "minimist": "^1.2.5" - } - }, - "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 - }, - "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 - }, - "portfinder": { - "version": "1.0.28", - "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.28.tgz", - "integrity": "sha512-Se+2isanIcEqf2XMHjyUKskczxbPH7dQnlMjXX6+dybayyHvAf/TCgyMRlzf/B6QDhAEFOGes0pzRo3by4AbMA==", - "dev": true, - "requires": { - "async": "^2.6.2", - "debug": "^3.1.1", - "mkdirp": "^0.5.5" - }, - "dependencies": { - "debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - } - } - }, - "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": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "dev": true, - "requires": { - "ansi-regex": "^2.0.0" - } - }, - "supports-color": { - "version": "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" - } - }, - "ws": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/ws/-/ws-6.2.1.tgz", - "integrity": "sha512-GIyAXC2cB7LjvpgMt9EKS2ldqr0MTrORaleiOno6TweZ6r3TKtoFQWay/2PceJ3RuBasOHzXNn5Lrw1X0bEjqA==", - "dev": true, - "requires": { - "async-limiter": "~1.0.0" - } - }, - "yargs": { - "version": "12.0.5", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-12.0.5.tgz", - "integrity": "sha512-Lhz8TLaYnxq/2ObqHDql8dX8CJi97oHxrjUcYtzKbbykPtVW9WB+poxI+NM2UIzsMgNCZTIf0AQwsjK5yMAqZw==", - "dev": true, - "requires": { - "cliui": "^4.0.0", - "decamelize": "^1.2.0", - "find-up": "^3.0.0", - "get-caller-file": "^1.0.1", - "os-locale": "^3.0.0", - "require-directory": "^2.1.1", - "require-main-filename": "^1.0.1", - "set-blocking": "^2.0.0", - "string-width": "^2.0.0", - "which-module": "^2.0.0", - "y18n": "^3.2.1 || ^4.0.0", - "yargs-parser": "^11.1.1" - } - }, - "yargs-parser": { - "version": "11.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-11.1.1.tgz", - "integrity": "sha512-C6kB/WJDiaxONLJQnF8ccx9SEeoTTLek8RVbaOIsrAUS8VrBEXfmeSnCZxygc+XC2sNMBIwOOnfcxiynjHsVSQ==", - "dev": true, - "requires": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.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-merge": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-4.2.2.tgz", - "integrity": "sha512-TUE1UGoTX2Cd42j3krGYqObZbOD+xF7u28WB7tfUordytSjbWTIjK/8V0amkBfTYN4/pB/GIDlJZZ657BGG19g==", - "dev": true, - "requires": { - "lodash": "^4.17.15" - } - }, - "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" - } - }, - "websocket-driver": { - "version": "0.7.4", - "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", - "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==", - "dev": true, - "requires": { - "http-parser-js": ">=0.5.1", - "safe-buffer": ">=5.1.0", - "websocket-extensions": ">=0.1.1" - } - }, - "websocket-extensions": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz", - "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==", - "dev": true - }, - "whatwg-encoding": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz", - "integrity": "sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw==", - "dev": true, - "requires": { - "iconv-lite": "0.4.24" - } - }, - "whatwg-mimetype": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz", - "integrity": "sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g==", - "dev": true - }, - "whatwg-url": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.1.0.tgz", - "integrity": "sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==", - "dev": true, - "requires": { - "lodash.sortby": "^4.7.0", - "tr46": "^1.0.1", - "webidl-conversions": "^4.0.2" - } - }, - "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-boxed-primitive": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", - "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", - "dev": true, - "requires": { - "is-bigint": "^1.0.1", - "is-boolean-object": "^1.1.0", - "is-number-object": "^1.0.4", - "is-string": "^1.0.5", - "is-symbol": "^1.0.3" - }, - "dependencies": { - "is-symbol": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz", - "integrity": "sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==", - "dev": true, - "requires": { - "has-symbols": "^1.0.1" - } - } - } - }, - "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 - }, - "word-wrap": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", - "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", - "dev": true - }, - "wordwrap": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", - "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", - "dev": true, - "optional": true - }, - "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" - } - }, - "wrap-ansi": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", - "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", - "dev": true, - "requires": { - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1" - }, - "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" - } - }, - "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-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" - } - } - } - }, - "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" - } - }, - "ws": { - "version": "6.1.2", - "resolved": "https://registry.npmjs.org/ws/-/ws-6.1.2.tgz", - "integrity": "sha512-rfUqzvz0WxmSXtJpPMX2EeASXabOrSMk1ruMOV3JBTBjo4ac2lDjGGsbQSyxj8Odhw5fBib8ZKEjDNvgouNKYw==", - "dev": true, - "requires": { - "async-limiter": "~1.0.0" - } - }, - "xml-name-validator": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz", - "integrity": "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==", - "dev": true - }, - "xmlchars": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", - "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", - "dev": true - }, - "xtend": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", - "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=", - "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 - }, - "yallist": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.3.tgz", - "integrity": "sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A==", - "dev": true - }, - "yargs": { - "version": "13.3.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz", - "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==", - "dev": true, - "requires": { - "cliui": "^5.0.0", - "find-up": "^3.0.0", - "get-caller-file": "^2.0.1", - "require-directory": "^2.1.1", - "require-main-filename": "^2.0.0", - "set-blocking": "^2.0.0", - "string-width": "^3.0.0", - "which-module": "^2.0.0", - "y18n": "^4.0.0", - "yargs-parser": "^13.1.2" - }, - "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" - } - }, - "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 - }, - "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 - }, - "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" - } - }, - "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" - } - } - } - }, - "yargs-parser": { - "version": "13.1.2", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz", - "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==", - "dev": true, - "requires": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" - } - }, - "yorkie": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/yorkie/-/yorkie-2.0.0.tgz", - "integrity": "sha512-jcKpkthap6x63MB4TxwCyuIGkV0oYP/YRyuQU5UO0Yz/E/ZAu+653/uov+phdmO54n6BcvFRyyt0RRrWdN2mpw==", - "dev": true, - "requires": { - "execa": "^0.8.0", - "is-ci": "^1.0.10", - "normalize-path": "^1.0.0", - "strip-indent": "^2.0.0" - }, - "dependencies": { - "execa": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-0.8.0.tgz", - "integrity": "sha1-2NdrvBtVIX7RkP1t1J08d07PyNo=", - "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" - } - }, - "normalize-path": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-1.0.0.tgz", - "integrity": "sha1-MtDkcvkf80VwHBWoMRAY07CpA3k=", - "dev": true - } - } - } - } -} diff --git a/grady/frontend/package.json b/grady/frontend/package.json deleted file mode 100644 index 6ed231a385aa98dae3d39974ca4d24efde8d638c..0000000000000000000000000000000000000000 --- a/grady/frontend/package.json +++ /dev/null @@ -1,41 +0,0 @@ -{ - "name": "frontend", - "version": "0.1.0", - "private": true, - "description": "Vue.js frontend for Grady", - "author": "robinwilliam.hundt <robinwilliam.hundt@stud.uni-goettingen.de>", - "scripts": { - "serve": "vue-cli-service serve", - "build": "vue-cli-service build", - "lint": "vue-cli-service lint" - }, - "dependencies": { - "axios": "^0.18.0", - "file-saver": "^2.0.2", - "highlight.js": "^9.12.0", - "v-clipboard": "^2.0.1", - "vue": "^2.6.12", - "vue-class-component": "^6.0.0", - "vue-notification": "^1.3.12", - "vue-property-decorator": "^7.3.0", - "vue-router": "^3.0.1", - "vuetify": "^2.4.5", - "vuex": "^3.0.1", - "vuex-typex": "https://github.com/robinhundt/vuex-typex.git" - }, - "devDependencies": { - "@types/file-saver": "^2.0.1", - "@types/highlight.js": "^9.12.3", - "@typescript-eslint/eslint-plugin": "^4.13.0", - "@typescript-eslint/parser": "^4.13.0", - "@vue/cli-plugin-eslint": "^3.11.0", - "@vue/cli-plugin-typescript": "^4.5.10", - "@vue/cli-service": "^3.11.0", - "@vue/eslint-config-typescript": "^4.0.0", - "eslint": "^5.16.0", - "eslint-plugin-vue": "^5.0.0", - "typescript": "^4.1.3", - "vue-template-compiler": "^2.6.12", - "webpack": "^4.41.0" - } -} diff --git a/grady/frontend/src/App.vue b/grady/frontend/src/App.vue deleted file mode 100644 index 854e12bd3337eb5ed32a2b791d712e7507fe8301..0000000000000000000000000000000000000000 --- a/grady/frontend/src/App.vue +++ /dev/null @@ -1,48 +0,0 @@ -<template> - <div - id="app" - @click="logInteraction" - > - <v-app> - <notifications /> - <notifications - group="msg" - position="bottom left" - /> - <router-view /> - <auto-logout /> - </v-app> - </div> -</template> - -<script> -// load fonts and icons so that webpack processes them -import '@/assets/material-icons.css' -import '@/assets/fonts.css' - -import { UI } from '@/store/modules/ui' -import AutoLogout from '@/components/AutoLogout' -import { mutations } from './store/mutations' - -export default { - name: 'App', - components: { AutoLogout }, - methods: { - logInteraction () { - mutations.SET_LAST_INTERACTION() - } - } -} -</script> - -<style> - #app { - font-family: Roboto, sans-serif; - } - a { - text-decoration: none; - } - span { - tab-size: 4; - } -</style> diff --git a/grady/frontend/src/api.ts b/grady/frontend/src/api.ts deleted file mode 100644 index eedfc67ac1af5942c8f26b83515accf45ae69fd4..0000000000000000000000000000000000000000 --- a/grady/frontend/src/api.ts +++ /dev/null @@ -1,324 +0,0 @@ -import axios, { AxiosInstance, AxiosResponse } from 'axios' -import { errorInterceptor } from '@/util/interceptor' -import { Credentials } from '@/store/modules/authentication' -import { - Assignment, - Exam, - Feedback, FeedbackComment, - JSONWebToken, Statistics, - StudentInfo, - StudentInfoForListView, - Submission, - SubmissionNoType, SubmissionType, - Tutor, UserAccount, LabelStatisticsForSubType, - FeedbackLabel, SolutionComment, - CreateUpdateFeedback, - AvailableSubmissionCounts, - Group, - Config, - GitlabRelease, -} from '@/models' -import { CreateAssignment } from './models' - -export function getInstanceBaseUrl (): string { - if (process.env.NODE_ENV === 'production' || process.env.NODE_ENV === 'test') { - return `${window.location.protocol}//${window.location.host}${window.location.pathname}`.replace(/\/+$/, '') - } else { - return 'http://localhost:8000/' - } -} - -let ax: AxiosInstance = axios.create({ - baseURL: getInstanceBaseUrl() -}) - -export async function registerTutor (credentials: Credentials): Promise<AxiosResponse<Tutor>> { - return ax.post<Tutor>('/api/corrector/register/', credentials) -} - -export async function fetchJWT (credentials: Credentials): Promise<JSONWebToken> { - const token: string = (await ax.post('/api/get-token/', credentials)).data.token - ax.defaults.headers['Authorization'] = `JWT ${token}` - return { token } -} - -export async function refreshJWT (oldToken: string): Promise<JSONWebToken> { - const token: string = (await ax.post('/api/refresh-token/', { token: oldToken })).data.token - ax.defaults.headers['Authorization'] = `JWT ${token}` - return { token } -} - -export async function fetchConfig (): Promise<Config> { - return (await ax.get('/api/config/')).data -} - -export async function fetchStudentSelfData (): Promise<StudentInfo> { - return (await ax.get('/api/student-page/')).data -} - -export async function fetchStudentSubmissions (): Promise<Array<Submission>> { - return (await ax.get('/api/student-submissions/')).data -} - -export async function fetchSubmissionFeedbackTests ({ pk }: {pk: string}): Promise<SubmissionNoType> { - return (await ax.get(`/api/submission/${pk}/`)).data -} - -export async function fetchSubmissionSourceCode(pk: string): Promise<{sourceCode: string}> { - return (await ax.get(`/api/submission/${pk}/source_code/`)).data -} - -export async function fetchNotebookSubmissionAsHtml(pk: string): Promise<any> { - return (await ax.get(`/api/submission/${pk}/html/`)).data -} - -export async function fetchAllStudents (): Promise<Array<StudentInfoForListView>> { - const url = '/api/student/' - return (await ax.get(url)).data -} - -export async function fetchStudent ({ pk }: -{pk: string}): Promise<StudentInfoForListView> { - const url = `/api/student/${pk}/` - return (await ax.get(url)).data -} - -export async function fetchAllTutors (): Promise<Array<Tutor>> { - const url = '/api/corrector/' - return (await ax.get(url)).data -} - -export async function fetchAllFeedback (): Promise<Array<Feedback>> { - const url = '/api/feedback/' - return (await ax.get(url)).data -} - -export async function fetchFeedback ({ ofSubmission }: {ofSubmission: string}): Promise<Feedback> { - const url = `/api/feedback/${ofSubmission}/` - return (await ax.get(url)).data -} - -export async function fetchExamTypes (): Promise<Array<Exam>> { - const url = '/api/examtype/' - return (await ax.get(url)).data -} - -export async function fetchStatistics (examPk: string): Promise<Statistics> { - const url = `/api/statistics/${examPk}/` - return (await ax.get(url)).data -} - -export async function fetchLabelStatistics (): Promise<LabelStatisticsForSubType[]> { - const url = '/api/label-statistics' - return (await ax.get(url)).data -} - - -export async function createAssignment (data: CreateAssignment): Promise<Assignment> { - return (await ax.post('/api/assignment/', data)).data -} - -export async function submitFeedbackForAssignment ({ feedback, assignment }: - { feedback: Partial<CreateUpdateFeedback>, assignment: Assignment}): Promise<CreateUpdateFeedback> { - return (await ax.post(`/api/assignment/${assignment.pk}/finish/`, feedback)).data -} - -export async function submitUpdatedFeedback ({ feedback }: - {feedback: CreateUpdateFeedback}): Promise<CreateUpdateFeedback> { - return (await ax.patch(`/api/feedback/${feedback.ofSubmission}/`, feedback)).data -} - -export async function submitFeedback ({ feedback }: {feedback: CreateUpdateFeedback}): Promise<Feedback> { - return (await ax.post('/api/feedback/', feedback)).data -} - -export async function fetchSubmissionTypes (): Promise<Array<SubmissionType>> { - const url = '/api/submissiontype/' - return (await ax.get(url)).data -} - -export async function fetchSubmissionType (pk: string): Promise<SubmissionType> { - const url = `/api/submissiontype/${pk}/` - return (await ax.get(url)).data -} - -export async function fetchAvailableSubmissionCounts(group: Group | undefined): Promise<AvailableSubmissionCounts> { - const query = group ? '?group=' + group.pk : '' - const url = '/api/submissiontype/available/' + query - return (await ax.get(url)).data -} - -export async function fetchGroups(): Promise<Group[]> { - const url = '/api/group/' - return (await ax.get(url)).data -} - -export async function fetchUserGroups(userPk: string): Promise<Group[]> { - const url = `/api/user/${userPk}/get_groups/` - return (await ax.get(url)).data -} - -export async function setGroups (userPk: string, groups: Group[]): Promise<UserAccount> { - return (await ax.patch(`/api/user/${userPk}/change_groups/`, groups)).data -} - -export async function deleteSolutionComment (pk: number): Promise<AxiosResponse<void>> { - const url = `/api/solution-comment/${pk}/` - return ax.delete(url) -} - -export async function createSolutionComment(comment: Partial<SolutionComment>): Promise<SolutionComment> { - const url = '/api/solution-comment/' - return (await ax.post(url, comment)).data -} - -export async function patchSolutionComment(comment: Partial<SolutionComment>): Promise<SolutionComment> { - const url = `/api/solution-comment/${comment.pk}/` - return (await ax.patch(url, comment)).data -} - -export async function fetchAllAssignments (): Promise<Array<Assignment>> { - const url = '/api/assignment/' - return (await ax.get(url)).data -} - -export async function fetchActiveAssignments (): Promise<Assignment[]> { - const url = '/api/assignment/active/' - return (await ax.get(url)).data -} - -export async function deleteAssignment ({ assignment }: {assignment: Assignment}): Promise<AxiosResponse<void>> { - const url = `/api/assignment/${assignment.pk}/` - return ax.delete(url) -} - -export async function deleteAllActiveAssignments () { - const url = '/api/assignment/active/' - return ax.delete(url) -} - -export async function deleteComment (comment: FeedbackComment): Promise<AxiosResponse<void>> { - const url = `/api/feedback-comment/${comment.pk}/` - return ax.delete(url) -} - -export async function activateAllStudentAccess (): Promise<AxiosResponse<void>> { - return ax.post('/api/student/activate/') -} - -export async function deactivateAllStudentAccess (): Promise<AxiosResponse<void>> { - return ax.post('/api/student/deactivate/') -} - -export async function changePassword (userPk: string, data: {password: string}): Promise<UserAccount> { - return (await ax.patch(`/api/user/${userPk}/change_password/`, data)).data -} - -export async function getOwnUser (): Promise<UserAccount> { - return (await ax.get('/api/user/me/')).data -} - -export async function changeActiveForUser (userPk: string, active: boolean): Promise<UserAccount> { - return (await ax.patch(`/api/user/${userPk}/change_active/`, { 'is_active': active })).data -} - -export async function changeUserRole (userPk: string, role: UserAccount.RoleEnum): Promise<UserAccount> { - return (await ax.patch(`/api/user/${userPk}/change_role/`, { role })).data -} - -export async function fetchUsers (): Promise<UserAccount[]> { - return (await ax.get('api/user/')).data -} - -export async function fetchUser(userPk: string): Promise<UserAccount> { - return (await ax.get(`/api/user/${userPk}`)).data -} - -export async function getLabels (): Promise<FeedbackLabel[]> { - return (await ax.get('/api/label/')).data -} - -export async function createLabel (payload: Partial<FeedbackLabel>) { - return (await ax.post('/api/label/', payload)).data -} - -export async function updateLabel (payload: FeedbackLabel) { - return (await ax.put('/api/label/' + payload.pk + '/', payload)).data -} - -export async function fetchSubmissionCounts () { - return (await ax.get('/api/submissiontype/available_counts/')).data -} - -export async function releaseUndoneAssignments () { - return (await ax.delete('/api/assignment/release')).data -} - -export async function patchInstanceSettings(config: { [config: string]: boolean }) { - return (await ax.patch('/api/config/change_config/', config)).data -} - -/** - * Issues a synchronized request to release all undone assignments of given user - * @param accessToken The access token to authenticate against the backend - */ -export function releaseUndoneAssignmentsSynchronized (accessToken: string) { - var request = new XMLHttpRequest() - request.open('DELETE', getInstanceBaseUrl() + 'api/assignment/release/', false) - request.setRequestHeader('Authorization', 'JWT ' + accessToken) - request.send() -} - -/** - * Issues a synchronized request to disable the account for the given details - * @param accessToken The access token to authenticate against the backend - * @param userPk The pk of the user account to disable - */ -export function disableAccount (accessToken: string, userPk: string) { - var request = new XMLHttpRequest() - request.open('PATCH', getInstanceBaseUrl() + `api/user/${userPk}/change_active/`, false) - request.setRequestHeader('Authorization', 'JWT ' + accessToken) - request.setRequestHeader('Content-Type', 'application/json') - request.send('{ "is_active": false }') -} - -export async function fetchReleases () { - const id = 'j.michal%2Fgrady' - const url = `https://gitlab.gwdg.de/api/v4/projects/${id}/releases` - return (await ax.get(url)).data as GitlabRelease[] -} - -export interface StudentExportOptions { setPasswords?: boolean } -export interface StudentExportItem { - Matrikel: string, - Name: string, - Username: string, - Sum: number, - Exam: string, - Password: string, - Email: string, - Scores: { type: string, score: number }[] -} -export async function fetchStudentExportData (options: StudentExportOptions): Promise<StudentExportItem[]> { - return (await ax.post('/api/export/json/', options)).data -} - -export async function importData (data: Object): Promise<AxiosResponse<void>> { - return ax.post('/api/import/', data) -} - -// Note, this interface does not represent all of the returned data, -// but only the fields which have to be transformed for deanonymisation -export interface InstanceExportData { - students: { - name: string, - matrikelNo: string - }[] -} -export async function fetchInstanceExportData (): Promise<InstanceExportData> { - return (await ax.get('/api/instance/export')).data -} - -ax.interceptors.response.use(undefined, errorInterceptor) - -export default ax diff --git a/grady/frontend/src/assets/brand.svg b/grady/frontend/src/assets/brand.svg deleted file mode 100644 index b245aec7335e8490f2e88070499f41f6b5ad34cd..0000000000000000000000000000000000000000 --- a/grady/frontend/src/assets/brand.svg +++ /dev/null @@ -1,241 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<!-- Created with Inkscape (http://www.inkscape.org/) --> - -<svg - xmlns:dc="http://purl.org/dc/elements/1.1/" - xmlns:cc="http://creativecommons.org/ns#" - xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" - xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" - inkscape:version="0.91 r13725" - version="1.1" - id="svg2" - viewBox="0 0 1500 400.00001" - height="400" - width="1500" - sodipodi:docname="brand.svg"> - <sodipodi:namedview - inkscape:window-maximized="1" - inkscape:window-y="19" - inkscape:window-x="0" - inkscape:window-height="1059" - inkscape:window-width="1918" - units="px" - showgrid="false" - inkscape:current-layer="layer1" - inkscape:document-units="px" - inkscape:cy="147.05606" - inkscape:cx="546.48529" - inkscape:zoom="0.5" - inkscape:pageshadow="2" - inkscape:pageopacity="0.0" - borderopacity="1.0" - bordercolor="#666666" - pagecolor="#ffffff" - id="base" - inkscape:object-paths="true" - inkscape:snap-intersection-paths="true" - inkscape:object-nodes="true" - inkscape:snap-smooth-nodes="true" - inkscape:snap-midpoints="true" - inkscape:snap-center="true" - inkscape:snap-grids="true" - inkscape:snap-to-guides="true"> - <inkscape:grid - type="xygrid" - id="grid7530" /> - </sodipodi:namedview> - <defs - id="defs4" /> - <metadata - id="metadata7"> - <rdf:RDF> - <cc:Work - rdf:about=""> - <dc:format>image/svg+xml</dc:format> - <dc:type - rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> - <dc:title /> - </cc:Work> - </rdf:RDF> - </metadata> - <g - transform="translate(0,-652.36216)" - id="layer1" - inkscape:groupmode="layer" - inkscape:label="Layer 1"> - <text - sodipodi:linespacing="125%" - id="text4155" - y="785.93359" - x="40" - style="font-style:normal;font-weight:normal;font-size:18.75px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" - xml:space="preserve"><tspan - y="785.93359" - x="40" - id="tspan4157" - sodipodi:role="line" /></text> - <g - transform="matrix(1.1234412,0,0,1.1234412,13.803675,-49.587352)" - id="g4148"> - <text - xml:space="preserve" - style="font-style:normal;font-weight:normal;font-size:49.09632111px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" - x="43.577591" - y="769.30743" - id="text4136" - sodipodi:linespacing="125%"><tspan - sodipodi:role="line" - id="tspan4138" - x="43.577591" - y="769.30743" - style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:45px;font-family:monospace;-inkscape-font-specification:monospace">free(buf);</tspan></text> - <g - id="g4144" - transform="translate(0.9074132,-22.142857)"> - <rect - y="828.83081" - x="51.259876" - height="90.981384" - width="466.75812" - id="rect4140" - style="opacity:1;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:#3d8fc1;stroke-width:7.82999992;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:10;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" /> - <path - transform="matrix(0.95142245,0.00906165,-0.01875887,0.45959361,40.435709,459.17271)" - inkscape:transform-center-y="-3.3172406" - inkscape:transform-center-x="-0.10382355" - d="M 102.5,802.71928 51.866074,804.09565 75.991067,759.5572 Z" - inkscape:randomized="0" - inkscape:rounded="0" - inkscape:flatsided="true" - sodipodi:arg2="1.5436203" - sodipodi:arg1="0.49642275" - sodipodi:r2="14.622154" - sodipodi:r1="29.244308" - sodipodi:cy="788.79071" - sodipodi:cx="76.785713" - sodipodi:sides="3" - id="path4142" - style="opacity:1;fill:#3d8fc1;fill-opacity:1;fill-rule:nonzero;stroke:#3d8fc1;stroke-width:7.83047009;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" - sodipodi:type="star" /> - </g> - <text - sodipodi:linespacing="125%" - id="text4217" - y="576.64789" - x="395.71426" - style="font-style:normal;font-weight:normal;font-size:18.75px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" - xml:space="preserve"><tspan - y="576.64789" - x="395.71426" - id="tspan4219" - sodipodi:role="line" /></text> - </g> - <text - sodipodi:linespacing="125%" - id="text4159" - y="817.44897" - x="27.760962" - style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:50.55485535px;line-height:125%;font-family:monospace;-inkscape-font-specification:monospace;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" - xml:space="preserve"><tspan - y="817.44897" - x="27.760962" - id="tspan4161" - sodipodi:role="line" - style="-inkscape-font-specification:'monospace Bold';font-family:monospace;font-weight:bold;font-style:normal;font-stretch:normal;font-variant:normal">7</tspan></text> - <text - sodipodi:linespacing="125%" - id="text4159-3" - y="752.0816" - x="28.401009" - style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:42.0922699px;line-height:125%;font-family:monospace;-inkscape-font-specification:monospace;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:0.31606218;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" - xml:space="preserve"><tspan - y="752.0816" - x="28.401009" - id="tspan4161-6" - sodipodi:role="line" - style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:monospace;-inkscape-font-specification:'monospace Bold'">6</tspan></text> - <text - sodipodi:linespacing="125%" - id="text4159-3-7" - y="1030.8582" - x="28.442116" - style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:42.0922699px;line-height:125%;font-family:monospace;-inkscape-font-specification:monospace;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:0.31606218;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" - xml:space="preserve"><tspan - y="1030.8582" - x="28.442116" - id="tspan4161-6-5" - sodipodi:role="line" - style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:monospace;-inkscape-font-specification:'monospace Bold'">8</tspan></text> - <text - sodipodi:linespacing="125%" - id="text4159-3-3" - y="703.95551" - x="27.846083" - style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:42.0922699px;line-height:125%;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:0.31606218;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" - xml:space="preserve"><tspan - y="703.95551" - x="27.846083" - id="tspan4161-6-56" - sodipodi:role="line">5</tspan></text> - <path - id="path6554" - title="sin(x)" - d="m 93.74644,911.92137 c 7.84438,-6.96836 15.68876,-13.29074 23.53314,-13.23944 7.84438,0.0513 15.68877,6.48775 23.53315,13.45526 7.84437,6.96753 15.68875,13.18498 23.53314,13.0201 7.84438,-0.16489 15.68875,-6.7027 23.53314,-13.66753 7.84438,-6.96483 15.68876,-13.07571 23.53315,-12.79728 7.84437,0.27842 15.68875,6.91584 23.53313,13.87614 7.84439,6.9603 15.68876,12.96297 23.53314,12.57108 7.84439,-0.39188 15.68877,-7.12717 23.53314,-14.08107 7.84438,-6.95391 15.68877,-12.84678 23.53315,-12.34154 7.84438,0.50526 15.68876,7.3366 23.53314,14.28226 7.84438,6.94568 15.68877,12.72719 23.53314,12.10871 7.84438,-0.61848 15.68876,-7.54407 23.53315,-14.47966 7.84437,-6.93558 15.68875,-12.60419 23.53314,-11.87265 7.84438,0.73154 15.68876,7.74954 23.53314,14.6732 7.84438,6.92366 15.68876,12.47787 23.53314,11.63346 7.84438,-0.84441 15.68876,-7.95296 23.53314,-14.86285 7.84439,-6.90989 15.68877,-12.34823 23.53314,-11.39117 7.84439,0.95705 15.68877,8.15427 23.53315,15.04855 7.84437,6.89429 15.68876,12.21529 23.53314,11.14584" - style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:none;fill-opacity:0.31606218;fill-rule:nonzero;stroke:#ff0000;stroke-width:8;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:0.7150259;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" - inkscape:connector-curvature="0" /> - <g - transform="scale(0.98991789,1.0101848)" - style="font-style:italic;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:167.73872375px;line-height:125%;font-family:'Shining NFI Demo';-inkscape-font-specification:'Shining NFI Demo Italic';letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" - id="text6581"> - <path - d="m 711.55349,918.83164 q -1.34191,-1.00644 -3.0193,-1.34191 -1.50965,-0.33548 -3.18704,-0.67096 -1.50964,-0.33548 -3.01929,-0.67095 -1.50965,-0.33548 -2.68382,-1.34191 l -1.00644,-2.01287 q -0.50321,-0.33548 -2.51608,-0.67095 -1.84512,-0.33548 -2.51608,-0.33548 -4.02573,-3.35477 -8.72241,-7.54824 -4.52895,-4.36121 -6.03859,-9.22563 -0.8387,-2.68382 -1.00644,-3.69025 0,-1.17418 -2.01286,-3.18704 -0.33548,-0.83869 -1.00643,-3.0193 -0.50322,-2.34834 -1.17417,-4.86442 -0.50322,-2.51608 -1.00644,-4.69668 -0.50321,-2.34835 -0.67095,-3.35478 -0.16774,-0.83869 -0.16774,-1.50965 l 0,-2.51608 q 0,-7.54824 1.67739,-14.76101 1.84512,-7.3805 3.35477,-14.761 0,-0.50322 0.33548,-2.01287 0.33548,-1.67739 0.67095,-3.52251 0.33548,-1.84513 0.50322,-3.35478 0.33548,-1.67738 0.50322,-2.01286 0,-0.33548 0.50321,-1.67739 0.50322,-1.34191 1.00643,-2.85156 0.50322,-1.50964 1.00644,-2.68382 0.50321,-1.34191 0.50321,-1.67738 0.16774,-0.67096 0.50322,-3.0193 0.50321,-2.34834 1.00643,-4.86442 0.50322,-2.68382 0.83869,-5.03216 0.50322,-2.34835 0.50322,-3.0193 1.00643,-4.69669 4.19347,-10.3998 3.35477,-5.70312 7.54824,-11.2385 4.36121,-5.53537 9.05789,-10.23206 4.86443,-4.86442 8.89015,-7.71598 16.27066,-5.36764 32.37358,-7.21277 16.27065,-2.01286 33.21227,-2.01286 1.34191,0 3.52251,0 2.1806,0 4.19347,0.16774 2.1806,0 3.69025,0 1.67739,0 2.01286,0 0.67096,0 3.69026,0.33548 3.18703,0.33547 7.04502,0.67095 3.85799,0.33548 7.54824,0.67096 3.69026,0.33547 5.70312,0.50321 0.50322,0 2.01287,0.16774 1.50964,0.16774 3.18703,0.67096 1.67739,0.33547 3.0193,1.17417 1.50965,0.83869 1.67739,2.01286 0,0.33548 0,0.67096 0.16773,0.16773 0.16773,0.50321 0,3.0193 -1.17417,8.72242 -1.17417,5.70311 -2.68382,11.90945 -1.50964,6.03859 -3.18703,11.40623 -1.50965,5.36764 -2.34834,7.54824 l -7.54825,0 q -3.35477,0 -6.37407,-0.50322 -3.01929,-0.50321 -6.37407,-1.50964 l -33.54774,0 q -2.34835,1.67738 -5.1999,2.51608 -2.68382,0.67095 -5.03217,2.1806 -5.87085,3.85799 -10.23206,10.90302 -4.19347,6.87729 -7.04502,14.92874 -2.68382,7.88372 -4.19347,15.93518 -1.34191,8.05146 -1.34191,14.25779 0,0.33548 0,1.50965 0,1.00644 0,2.18061 0,1.17417 0,2.1806 0.16774,1.00643 0.16774,1.50965 0.83869,3.35477 3.35477,6.20633 2.68382,2.68382 6.54181,2.68382 l 15.76744,0 q 1.50965,0 2.34834,-1.34191 0.8387,-1.34191 1.17417,-3.0193 0.33548,-1.84512 0.33548,-3.52251 0.16774,-1.84513 0.16774,-2.85156 l 0,-0.16774 q 0,-2.34834 -1.17417,-3.52251 -1.00643,-1.17417 -2.34834,-1.84513 -1.34191,-0.83869 -2.51608,-1.34191 -1.00644,-0.50321 -1.00644,-1.67738 l 0,-0.50322 q 2.01287,-6.37407 3.69026,-12.91588 1.84512,-6.70955 4.19346,-12.74814 0.67096,-2.01287 1.17417,-2.85156 0.50322,-0.8387 0.8387,-1.50965 0.33548,-0.67096 0.50321,-1.50965 0.33548,-1.00643 0.50322,-3.35477 l 60.55368,0 q 0,1.84512 -0.83869,3.69025 -0.8387,1.67739 -1.34191,3.52251 l -3.85799,15.76744 q -0.16774,0.33548 -0.67096,1.67739 -0.33548,1.34191 -0.83869,2.85156 -0.50322,1.50965 -1.00643,2.85156 -0.50322,1.17417 -0.50322,1.50964 -0.16774,0.67096 -0.83869,3.18704 -0.50322,2.34834 -1.17418,5.1999 -0.67095,2.85156 -1.34191,5.36764 -0.50321,2.51608 -0.67095,3.18704 0,0.50321 -0.50322,1.67738 -0.33547,1.17417 -0.83869,2.68382 -0.50322,1.34191 -1.00643,2.68382 -0.33548,1.34191 -0.50322,1.84513 -1.50965,3.85799 -2.1806,7.88372 -0.67096,4.02573 -1.84513,8.05146 -1.34191,4.3612 -3.18703,8.38693 -1.84513,4.02573 -3.69026,8.2192 -1.00643,2.1806 -1.34191,4.52895 -0.33547,2.34834 -1.67738,4.3612 -0.67096,0.8387 -3.52252,1.50965 -2.85155,0.67096 -6.87728,1.17417 -4.02573,0.50322 -8.89016,0.67096 -4.69668,0.33547 -9.22563,0.50321 -4.52894,0.16774 -8.38693,0.16774 -3.85799,0.16774 -5.87086,0.16774 -5.36764,0 -10.06432,-0.50322 -4.69669,-0.33547 -9.22563,-1.00643 -4.52895,-0.67095 -9.22563,-1.67739 -4.52895,-1.00643 -9.89659,-2.1806 -0.67095,-0.16774 -1.3419,-0.33548 -0.67096,-0.16773 -1.50965,-0.33547 z" - style="font-style:italic;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:'Shining NFI Demo';-inkscape-font-specification:'Shining NFI Demo Italic'" - id="path4253" /> - <path - d="m 908.82472,811.47885 q 0.16774,2.51608 0.67095,3.0193 0.50322,0.33548 1.34191,0.33548 6.0386,0 11.2385,-0.16774 5.36764,-0.33548 9.22563,-1.17417 4.02573,-1.00643 6.20633,-2.85156 2.34834,-2.01287 2.34834,-5.53538 0,-2.34834 -1.34191,-4.02573 -1.17417,-1.67738 -3.18703,-2.68382 -2.01287,-1.17417 -4.36121,-1.67738 -2.34834,-0.50322 -4.52895,-0.50322 -5.36764,0 -9.72884,0.67095 -4.36121,0.50322 -4.69669,2.68382 l -3.18703,11.90945 z m -44.45076,-55.52151 q 11.90944,-2.68382 24.82533,-4.02573 13.08362,-1.50965 27.67689,-1.50965 3.52251,0 7.04502,0 3.69025,0 7.54824,0.33548 0.33548,0 3.52252,0.16773 3.35477,0.16774 7.71598,0.67096 4.36121,0.33548 8.89015,0.83869 4.69669,0.50322 7.71598,1.17417 10.23206,2.34835 17.94805,6.37408 7.71598,3.85799 12.74814,9.89658 5.1999,6.03859 7.71598,14.25779 2.51606,8.2192 2.51606,19.28995 0,12.91589 -7.04501,22.30925 -7.04502,9.22563 -18.45125,15.59971 -5.19991,3.01929 -11.74172,5.1999 -6.54181,2.01286 -12.41266,3.35477 2.1806,10.3998 4.52894,19.62543 0,0.16774 0.33548,2.34834 0.33548,2.01287 1.00643,5.03217 0.67096,3.01929 1.34191,6.70954 0.67096,3.52252 1.34191,6.54181 0.67096,3.0193 1.00644,5.19991 0.50321,2.01286 0.50321,2.01286 1.67739,6.20633 2.51608,9.39337 0.8387,3.18703 1.17417,4.52894 0.50322,1.34191 0.50322,1.50965 0.16774,0 0.16774,0.16774 0.16774,0 0.33548,0.67096 0.16774,0.67095 0.83869,3.01929 0.67096,2.34835 1.84513,6.87729 1.17417,4.69668 3.18703,12.91588 -0.33548,0 -0.67095,0.33548 -0.33548,0.33548 -0.8387,0.33548 -0.33547,0 -0.50321,-0.16774 l -45.28946,0 q -2.34834,0 -4.3612,-0.50322 -2.01287,-0.50321 -3.0193,-2.34834 l -5.03216,-15.5997 q -2.18061,-8.38694 -3.69026,-16.4384 -1.50964,-8.21919 -3.35477,-16.60613 -0.50322,-2.1806 -1.00643,-7.21276 -0.33548,-5.03217 -1.00643,-10.23207 -0.50322,-5.1999 -1.50965,-9.22563 -1.00644,-4.02573 -2.51608,-4.02573 -0.67096,0 -1.67739,2.01287 -1.00643,1.84512 -2.01287,4.19347 -1.00643,2.34834 -2.01286,4.69668 -0.83869,2.34834 -1.00643,3.0193 0,0.50321 -0.67096,2.34834 -0.67095,1.84513 -1.50965,4.36121 -0.67095,2.34834 -1.50964,4.69668 -0.67096,2.1806 -1.17418,3.35478 -0.16773,0.50321 -0.83869,2.34834 -0.67095,1.67739 -1.50965,4.3612 -0.83869,2.51609 -2.01286,5.70312 -1.00644,3.18704 -2.01287,6.54181 -1.17417,3.85799 -2.01286,7.38051 -0.8387,3.35477 -2.01287,6.20633 -0.83869,2.51608 -1.84512,4.02573 -1.00644,1.34191 -1.50965,1.34191 l -58.20534,0 q -0.16774,0 -0.67095,-0.50322 -0.50322,-0.50322 -0.67096,-0.67095 l 0,-1.00644 q 4.36121,-13.08362 8.55468,-26.50271 4.3612,-13.4191 9.05789,-26.16725 2.68382,-7.21276 5.53538,-15.76744 2.85155,-8.55467 5.70311,-17.27708 3.0193,-8.89016 5.70312,-17.44483 2.68382,-8.72241 4.86442,-16.27066 l 11.40624,-43.7798 z" - style="font-style:italic;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:'Shining NFI Demo';-inkscape-font-specification:'Shining NFI Demo Italic'" - id="path4255" /> - <path - d="m 1076.4219,834.6268 q -0.3355,-4.19347 -1.0064,-10.06433 -0.671,-6.03859 -1.5097,-11.57397 -0.8387,-5.53538 -1.6774,-9.39337 -0.8387,-3.85799 -1.5096,-3.85799 -0.671,0 -2.0129,3.85799 -1.1741,3.85799 -2.5161,9.39337 -1.1741,5.53538 -2.3483,11.57397 -1.1742,5.87086 -1.8451,10.06433 l 14.4255,0 z m 69.1084,86.38544 q -1.3419,0.16774 -2.8516,0.16774 -1.3419,0 -2.8516,0 -4.6966,0 -10.3998,-0.33548 -5.7031,-0.33548 -11.5739,-0.67095 -5.7031,-0.50322 -11.2385,-0.8387 -5.5354,-0.33547 -9.8966,-0.33547 -1.0064,0 -3.0193,0 -2.0129,-0.16774 -2.1806,-0.16774 l -2.0129,-1.00644 q 0,0 -0.5032,-1.34191 -0.5032,-1.34191 -1.1742,-3.18703 -0.6709,-2.01287 -1.3419,-4.02573 -0.5032,-2.01287 -0.6709,-3.35478 l -4.6967,-21.63829 q -0.3355,-1.34191 -0.5032,-2.51608 -0.1678,-1.17417 -0.5032,-2.01287 -0.1678,-1.00643 -1.0065,-1.50964 -0.6709,-0.67096 -2.1806,-0.67096 l -17.2771,0 q -3.3547,0 -5.0321,1.67739 -1.6774,1.50965 -3.3548,5.36764 -1.5096,3.69025 -3.6902,10.06432 -2.0129,6.20633 -6.0386,15.43196 -0.3355,0.33548 -0.8387,0.50322 -0.3355,0.16774 -0.671,0.33548 -0.3355,0.16774 -0.5032,0.16774 l -50.99258,0 q -0.83869,0 -1.00643,-1.00644 0,-1.17417 0,-1.67738 l 0,-0.33548 q 0,-2.34834 1.34191,-7.54824 1.50965,-5.36764 3.69025,-12.07719 2.34834,-6.87729 4.86442,-14.09006 2.51608,-7.21276 4.69673,-13.41909 2.3483,-6.37407 3.6902,-10.56754 1.5097,-4.36121 1.5097,-5.1999 0,-3.35478 0.8387,-5.53538 1.0064,-2.1806 2.1806,-6.20633 0.3354,-0.67096 1.0064,-3.0193 0.8387,-2.51608 2.0129,-5.70312 1.1741,-3.18703 2.3483,-6.87729 1.3419,-3.69025 2.3483,-6.87728 1.1742,-3.18704 2.0129,-5.53538 0.8387,-2.51608 1.0064,-3.35478 0,-0.16773 0.3355,-0.83869 0.3355,-0.67095 0.671,-1.50965 0.3354,-0.83869 0.6709,-1.50965 0.3355,-0.83869 0.3355,-1.00643 0.5032,-1.50965 1.3419,-4.52894 1.0064,-3.18704 2.8516,-8.05146 1.8451,-4.86443 5.0321,-11.74171 3.1871,-7.04503 8.2192,-16.27066 0.1678,-0.16774 0.8387,-0.83869 0.8387,-0.67096 1.1742,-2.18061 l 65.4181,0 37.5735,167.40325 z" - style="font-style:italic;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:'Shining NFI Demo';-inkscape-font-specification:'Shining NFI Demo Italic'" - id="path4257" /> - <path - d="m 1210.5552,875.05183 0.8387,5.53538 13.2514,-0.8387 q 2.3483,-1.67738 5.0321,-2.34834 2.8516,-0.83869 5.1999,-2.34834 5.7031,-3.85799 10.0643,-10.06432 4.3613,-6.20634 7.0451,-13.4191 2.8515,-7.21277 4.1934,-14.59327 1.5097,-7.3805 1.5097,-13.58684 0,-0.33547 0,-1.34191 0,-1.17417 0,-2.34834 0,-1.17417 -0.1677,-2.1806 0,-1.00644 0,-1.50965 -0.8387,-3.35478 -3.5226,-6.0386 -2.516,-2.68381 -6.374,-2.85155 l -12.9159,-0.50322 q -0.671,0.33548 -1.3419,1.67739 -0.671,1.34191 -1.3419,3.01929 -0.5032,1.67739 -1.0065,3.35478 -0.3354,1.67739 -0.3354,2.68382 l 0,0.16774 -20.1287,57.53438 z m 65.5859,-112.88816 q 2.8515,1.84512 6.7095,3.18703 4.0257,1.34191 6.3741,3.18704 l 1.0064,2.01286 q 0.5032,0.33548 2.3483,0.67096 2.0129,0.33548 2.6839,0.33548 4.0257,3.35477 8.5546,7.71598 4.6967,4.19347 6.2064,9.05789 0.8387,2.68382 0.8387,3.85799 0.1677,1.00643 2.1806,3.0193 0.1677,0.83869 0.6709,3.18703 0.671,2.18061 1.3419,4.69669 0.671,2.51608 1.1742,4.86442 0.5032,2.1806 0.671,3.18704 l 0,1.50964 q 0,0.67096 0,1.50965 0.1677,0.67096 0.1677,1.00644 0,3.85799 -0.5032,6.87728 -0.5032,3.0193 -1.3419,5.87086 -0.671,2.85156 -1.6774,5.87085 -0.8387,2.85156 -1.5097,6.54181 0,0.50322 -0.3354,2.18061 -0.3355,1.50965 -0.671,3.35477 -0.3355,1.84513 -0.6709,3.52251 -0.1678,1.50965 -0.3355,1.84513 0,0.33548 -0.5032,1.67739 -0.5033,1.34191 -1.0065,2.85156 -0.5032,1.50964 -1.0064,2.85155 -0.5032,1.17418 -0.5032,1.50965 -0.1678,0.67096 -0.671,2.34835 -0.3355,1.50964 -0.8387,3.35477 -0.3354,1.67739 -0.8387,3.18704 -0.3354,1.50964 -0.3354,2.1806 -1.0065,4.69668 -3.858,10.06432 -2.6839,5.1999 -6.3741,10.23206 -3.5225,5.03217 -7.716,9.39337 -4.1935,4.19347 -8.2192,7.04503 -9.0579,4.52894 -15.5997,6.87729 -6.3741,2.34834 -12.5804,3.69025 -6.2063,1.17417 -13.4191,1.67739 -7.045,0.50321 -17.4448,1.17417 l -71.7922,0 q 0,-0.50322 0.8387,-3.85799 0.8387,-3.35478 2.0129,-8.05146 1.3419,-4.69669 2.8515,-10.06433 1.5097,-5.53537 2.8516,-10.23206 1.3419,-4.69668 2.1806,-7.88372 1.0064,-3.35477 1.1742,-4.02573 l 3.858,-15.76744 11.0707,-33.54774 q 1.8451,-5.1999 3.187,-9.39337 1.342,-4.36121 2.5161,-7.71598 1.6774,-5.53538 2.6838,-9.22563 1.1742,-3.85799 1.8452,-6.37407 0.6709,-2.68382 1.0064,-4.36121 0.3355,-1.67739 0.8387,-3.18704 1.3419,-4.3612 3.187,-8.38693 1.8452,-4.02573 3.6903,-8.2192 1.0064,-2.1806 1.3419,-4.52894 0.3355,-2.34835 1.6774,-4.36121 l 0.1677,-0.16774 q 0.5032,-0.83869 1.5097,-1.84513 1.0064,-1.17417 4.3612,-1.67738 l 50.9925,0 q 0.5033,-0.16774 1.6774,-0.16774 2.8516,0 7.8838,1.17417 5.1999,1.17417 13.4191,2.68382 z" - style="font-style:italic;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:'Shining NFI Demo';-inkscape-font-specification:'Shining NFI Demo Italic'" - id="path4259" /> - <path - d="m 1325.2545,919.67033 q 2.8515,-20.12865 7.5482,-39.58634 4.6967,-19.45769 9.3934,-39.25086 -4.6967,-10.23206 -8.7224,-20.63186 -3.858,-10.56754 -7.716,-20.96734 -3.858,-10.56754 -8.0515,-20.79961 -4.1934,-10.3998 -9.3933,-20.46412 4.0257,-1.00643 8.3869,-1.34191 4.5289,-0.50322 9.2256,-0.50322 l 15.7675,0 q 2.8515,0 5.7031,0 2.8515,0 5.5354,-0.33547 l 4.8644,-0.67096 2.0128,0.67096 q 1.0065,1.34191 1.5097,3.35477 0.6709,1.84513 1.1742,4.02573 0.5032,2.01287 1.0064,4.02573 0.5032,1.84513 1.5096,3.35477 2.1806,6.37408 3.1871,11.74172 1.1741,5.36763 3.6902,11.57397 1.6774,-2.85156 2.8516,-5.36764 1.1742,-2.68382 2.5161,-5.53538 l 10.232,-20.63186 6.0386,-5.70312 q 3.858,0.16774 7.716,0.33548 4.0257,0.16774 7.8837,0.50321 l 12.7482,0.8387 19.9609,-1.17417 1.0064,1.50965 q 0.1677,0.67095 0.1677,1.84512 -0.8386,9.56111 -5.1999,17.94804 -4.1934,8.2192 -9.0578,16.27066 l -2.0129,3.35478 q -3.3548,5.87085 -6.7096,11.57397 -3.187,5.70311 -6.5418,11.57397 -3.3547,5.87085 -6.5418,12.07719 -3.0193,6.03859 -6.5418,11.90945 -0.8387,6.20633 -1.6774,12.41266 -0.6709,6.0386 -1.6774,12.07719 -1.3419,7.3805 -3.0193,14.59327 -1.1741,4.36121 -2.1806,8.89015 -1.0064,4.36121 -2.0128,8.72242 -0.671,7.21276 -2.5161,14.25779 -0.671,1.34191 -1.1742,3.01929 -0.3355,1.50965 -1.5096,2.68382 l -29.6898,0 -0.6709,0.16774 q -3.6903,0.16774 -7.3805,0 -3.5226,0 -7.2128,0.33548 l 0,-0.50322 -12.7481,0 -1.5097,-1.17417 -0.1677,-1.00643 z" - style="font-style:italic;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:'Shining NFI Demo';-inkscape-font-specification:'Shining NFI Demo Italic'" - id="path4261" /> - </g> - <path - inkscape:connector-curvature="0" - id="path4221-1-0-3" - d="m 68.775738,1012.3622 311.224262,0" - style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#000000;fill-opacity:0.31606218;fill-rule:nonzero;stroke:none;stroke-width:9.52231693px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:0.31764706;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" /> - <rect - style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#000000;fill-opacity:0.31764706;fill-rule:nonzero;stroke:none;stroke-width:8;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:0.7150259;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" - id="rect7532" - width="225" - height="10" - x="67.574112" - y="1010.536" /> - <rect - style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#000000;fill-opacity:0.31764706;fill-rule:nonzero;stroke:none;stroke-width:8;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:0.7150259;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" - id="rect7532-6" - width="342.5" - height="10" - x="67.574112" - y="731.80054" /> - <rect - style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#000000;fill-opacity:0.31764706;fill-rule:nonzero;stroke:none;stroke-width:8;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:0.7150259;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" - id="rect7532-0" - width="250" - height="10" - x="67.574112" - y="683.91083" /> - </g> -</svg> diff --git a/grady/frontend/src/assets/fonts.css b/grady/frontend/src/assets/fonts.css deleted file mode 100644 index 4a3b402ea499843fbeb73875fda84cc299c68da4..0000000000000000000000000000000000000000 --- a/grady/frontend/src/assets/fonts.css +++ /dev/null @@ -1,48 +0,0 @@ -/* latin */ -@font-face { - font-family: 'Roboto'; - font-style: normal; - font-weight: 100; - src: local('Roboto Thin'), local('Roboto-Thin'), url(fonts/roboto-thin.woff2) format('woff2'); - unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; -} -/* latin */ -@font-face { - font-family: 'Roboto'; - font-style: normal; - font-weight: 300; - src: local('Roboto Light'), local('Roboto-Light'), url(fonts/roboto-light.woff2) format('woff2'); - unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; -} -/* latin */ -@font-face { - font-family: 'Roboto'; - font-style: normal; - font-weight: 400; - src: local('Roboto'), local('Roboto-Regular'), url(fonts/roboto-regular.woff2) format('woff2'); - unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; -} -/* latin */ -@font-face { - font-family: 'Roboto'; - font-style: normal; - font-weight: 500; - src: local('Roboto Medium'), local('Roboto-Medium'), url(fonts/roboto-medium.woff2) format('woff2'); - unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; -} -/* latin */ -@font-face { - font-family: 'Roboto'; - font-style: normal; - font-weight: 700; - src: local('Roboto Bold'), local('Roboto-Bold'), url(fonts/roboto-bold.woff2) format('woff2'); - unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; -} -/* latin */ -@font-face { - font-family: 'Roboto'; - font-style: normal; - font-weight: 900; - src: local('Roboto Black'), local('Roboto-Black'), url(fonts/roboto-black.woff2) format('woff2'); - unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; -} diff --git a/grady/frontend/src/assets/fonts/Material-Icons.woff2 b/grady/frontend/src/assets/fonts/Material-Icons.woff2 deleted file mode 100644 index 34cdd2afba56b9dd3c7f0e3b758069a92db6b7bf..0000000000000000000000000000000000000000 Binary files a/grady/frontend/src/assets/fonts/Material-Icons.woff2 and /dev/null differ diff --git a/grady/frontend/src/assets/fonts/roboto-black.woff2 b/grady/frontend/src/assets/fonts/roboto-black.woff2 deleted file mode 100644 index 689d7cb05c69ab723eb3a7a8140ef2c900699f2d..0000000000000000000000000000000000000000 Binary files a/grady/frontend/src/assets/fonts/roboto-black.woff2 and /dev/null differ diff --git a/grady/frontend/src/assets/fonts/roboto-bold.woff2 b/grady/frontend/src/assets/fonts/roboto-bold.woff2 deleted file mode 100644 index 1cdd68c821394eaf0e4a87e1dd9c4df1c6e8bf0d..0000000000000000000000000000000000000000 Binary files a/grady/frontend/src/assets/fonts/roboto-bold.woff2 and /dev/null differ diff --git a/grady/frontend/src/assets/fonts/roboto-light.woff2 b/grady/frontend/src/assets/fonts/roboto-light.woff2 deleted file mode 100644 index dc034ba45e32b5faee7612dc47a216feefe63f60..0000000000000000000000000000000000000000 Binary files a/grady/frontend/src/assets/fonts/roboto-light.woff2 and /dev/null differ diff --git a/grady/frontend/src/assets/fonts/roboto-medium.woff2 b/grady/frontend/src/assets/fonts/roboto-medium.woff2 deleted file mode 100644 index 5ab8a6561a35603d2223a320e335561134c3529e..0000000000000000000000000000000000000000 Binary files a/grady/frontend/src/assets/fonts/roboto-medium.woff2 and /dev/null differ diff --git a/grady/frontend/src/assets/fonts/roboto-regular.woff2 b/grady/frontend/src/assets/fonts/roboto-regular.woff2 deleted file mode 100644 index 4fc449afdba7aeb19b03c1f216e369f20a3e2191..0000000000000000000000000000000000000000 Binary files a/grady/frontend/src/assets/fonts/roboto-regular.woff2 and /dev/null differ diff --git a/grady/frontend/src/assets/fonts/roboto-thin.woff2 b/grady/frontend/src/assets/fonts/roboto-thin.woff2 deleted file mode 100644 index 32fd373c3f4b4a1e8dd61f3c3eb7867b596efd14..0000000000000000000000000000000000000000 Binary files a/grady/frontend/src/assets/fonts/roboto-thin.woff2 and /dev/null differ diff --git a/grady/frontend/src/assets/material-icons.css b/grady/frontend/src/assets/material-icons.css deleted file mode 100644 index d380d74c086cb5444826baed634cb705e41cc9df..0000000000000000000000000000000000000000 --- a/grady/frontend/src/assets/material-icons.css +++ /dev/null @@ -1,23 +0,0 @@ -/* fallback */ -@font-face { - font-family: 'Material Icons'; - font-style: normal; - font-weight: 400; - src: url(fonts/Material-Icons.woff2) format('woff2'); -} - -.material-icons { - font-family: 'Material Icons'; - font-weight: normal; - font-style: normal; - font-size: 24px; - line-height: 1; - letter-spacing: normal; - text-transform: none; - display: inline-block; - white-space: nowrap; - word-wrap: normal; - direction: ltr; - -moz-font-feature-settings: 'liga'; - -moz-osx-font-smoothing: grayscale; -} \ No newline at end of file diff --git a/grady/frontend/src/class-component-hooks.ts b/grady/frontend/src/class-component-hooks.ts deleted file mode 100644 index 2518b8b6207fb82e8516129e3996333066c9f253..0000000000000000000000000000000000000000 --- a/grady/frontend/src/class-component-hooks.ts +++ /dev/null @@ -1,8 +0,0 @@ -import Component from 'vue-class-component' - -// Register the router hooks with their names -Component.registerHooks([ - 'beforeRouteEnter', - 'beforeRouteLeave', - 'beforeRouteUpdate' // for vue-router 2.2+ -]) diff --git a/grady/frontend/src/components/AutoLogout.vue b/grady/frontend/src/components/AutoLogout.vue deleted file mode 100644 index 2d4d662b05eaf2e992b36cebd87d91af18c7a553..0000000000000000000000000000000000000000 --- a/grady/frontend/src/components/AutoLogout.vue +++ /dev/null @@ -1,117 +0,0 @@ -<template> - <v-dialog - v-model="logoutDialog" - persistent - max-width="30%" - > - <v-card id="logout-dialog"> - <v-card-title class="headline"> - You'll be logged out! - </v-card-title> - <v-card-text> - Due to inactivity you'll be logged out in a couple of moments.<br> - Any unsaved work will be lost. - Click Continue to stay logged in. - </v-card-text> - <v-card-actions> - <v-btn - id="logout-btn" - text - color="grey lighten-0" - @click="logout" - > - Logout now - </v-btn> - <v-spacer /> - <v-btn - id="continue-btn" - text - color="blue darken-2" - @click="continueWork" - > - Continue - </v-btn> - </v-card-actions> - </v-card> - </v-dialog> -</template> - -<script lang="ts"> -import Vue from 'vue' -import Component, { mixins } from 'vue-class-component' -import { Watch } from 'vue-property-decorator' -import { mapState } from 'vuex' -import { Authentication } from '@/store/modules/authentication' -import { actions } from '@/store/actions' -import { getters } from '@/store/getters' -import { ConfigModule } from '../store/modules/config' -import * as api from '@/api' - -@Component({ - name: 'auto-logout' -}) -export default class AutoLogout extends Vue { - timer = 0 - logoutDialog = false - - get lastTokenRefreshTry () { return Authentication.state.lastTokenRefreshTry } - get refreshingToken () { return Authentication.state.refreshingToken } - get jwtTimeDelta () { return ConfigModule.state.config.timeDelta } - get lastAppInteraction () { return getters.state.lastAppInteraction } - get accessToken () { return Authentication.state.token } - - logout () { - this.logoutDialog = false - actions.logout('You have been logged out due to inactivity.') - } - - continueWork () { - Authentication.refreshJWT() - this.logoutDialog = false - } - - @Watch('lastAppInteraction') - onLastInteractionChange () { - const timeSinceLastRefresh = Date.now() - this.lastTokenRefreshTry - const timeDelta = this.jwtTimeDelta - // refresh jwt if it's older than 20% of his maximum age - if (this.$route.name !== 'login' && timeSinceLastRefresh > timeDelta * 0.2 && - !this.refreshingToken) { - Authentication.refreshJWT() - } - } - - mounted () { - // release locked assignments when user is logged in and page is closed - window.addEventListener('unload', (event: Event) => { - // we use synchronous xhr's here to prevent the page from unloading before the request was finished - if (this.accessToken !== '' && Authentication.isTutorOrReviewer) { - api.releaseUndoneAssignmentsSynchronized(this.accessToken) - } - if (this.accessToken !== '' && Authentication.isStudent && !ConfigModule.state.config.instanceSettings.exerciseMode) { - api.disableAccount(this.accessToken, Authentication.state.user.pk) - } - }, false) - - this.timer = setInterval(() => { - const timeDialogAppearsBeforeLogout = Math.min(600 * 1e3, - this.jwtTimeDelta ? this.jwtTimeDelta * 0.5 : Infinity) - if (this.$route.name !== 'login' && Authentication.isLoggedIn) { - if (Date.now() > this.lastTokenRefreshTry + this.jwtTimeDelta) { - this.logoutDialog = false - actions.logout('You\'ve been logged out due to inactivity.') - } else if (Date.now() + timeDialogAppearsBeforeLogout > this.lastTokenRefreshTry + this.jwtTimeDelta) { - this.logoutDialog = true - } - } - }, 1 * 1e3) - } - - beforeDestroy () { - clearInterval(this.timer) - } -} -</script> - -<style> -</style> diff --git a/grady/frontend/src/components/BaseLayout.vue b/grady/frontend/src/components/BaseLayout.vue deleted file mode 100644 index 6ba26e3dc382b4778def8d31e502d17be52229bb..0000000000000000000000000000000000000000 --- a/grady/frontend/src/components/BaseLayout.vue +++ /dev/null @@ -1,199 +0,0 @@ -<template> - <div> - <v-navigation-drawer - fixed - clipped - app - permanent - width="300" - :mini-variant="mini" - > - <v-toolbar> - <v-list> - <v-list-item> - <v-list-item-action v-if="mini"> - <v-btn - icon - @click.native.stop="mini = !mini" - > - <v-icon>chevron_right</v-icon> - </v-btn> - </v-list-item-action> - <v-list-item-content - class="title" - > - {{ currentExam }} - </v-list-item-content> - <v-list-item-action v-if="!mini"> - <v-btn - icon - @click.native.stop="mini = !mini" - > - <v-icon>chevron_left</v-icon> - </v-btn> - </v-list-item-action> - </v-list-item> - </v-list> - </v-toolbar> - <slot name="sidebar-content" /> - <div class="sidebar-footer"> - <v-btn - id="feedback-btn" - href="https://gitlab.gwdg.de/j.michal/grady/issues" - target="_blank" - :block="!mini" - :fab="mini" - :text="mini" - :tile="!mini" - depressed - :class="{ 'fab-button': mini }" - > - <v-icon :left="!mini"> - feedback - </v-icon> - <div v-show="!mini"> - Feedback - </div> - </v-btn> - </div> - </v-navigation-drawer> - <v-app-bar - app - dense - clipped-left - fixed - dark - color="indigo darken-4" - class="grady-toolbar" - > - <router-link to="/home"> - <v-app-bar-title>Grady</v-app-bar-title> - </router-link> - <v-tooltip - v-if="multipleExams" - bottom - > - <template #activator="{ on }"> - <v-btn - id="examsButton" - color="cyan" - @click="changeExamSelection" - v-on="on" - > - Exams - </v-btn> - </template> - <span>Change selected Exam</span> - </v-tooltip> - <span class="pl-2 grady-speak">{{ gradySpeak }}</span> - <v-spacer /> - <instance-actions /> - <v-divider vertical /> - <user-options /> - </v-app-bar> - </div> -</template> - -<script> -import { mapGetters, mapState } from 'vuex' -import { UI } from '@/store/modules/ui' -import { mapStateToComputedGetterSetter } from '@/util/helpers' -import UserOptions from '@/components/UserOptions' -import InstanceActions from '@/components/InstanceActions' -import { Authentication } from '@/store/modules/authentication' -import { ConfigModule } from '../store/modules/config' -import ax, { fetchExamTypes } from '@/api' - - -export default { - name: 'BaseLayout', - components: { InstanceActions, UserOptions }, - data () { - return { - examTypes: [], - } - }, - computed: { - gradySpeak () { return Authentication.gradySpeak }, - currentExam () { return ConfigModule.state.config.currentExam }, - multipleExams () { - return this.examTypes.length > 1 - }, - isStudent () { return Authentication.isStudent }, - ...mapStateToComputedGetterSetter({ - pathPrefix: 'UI', - items: [ - { - name: 'mini', - path: 'sideBarCollapsed', - mutation: UI.SET_SIDEBAR_COLLAPSED - } - ] - }) - }, - created () { - this.loadExamTypes() - }, - methods: { - logFeedbackClick () { - this.darkModeUnlocked = true - }, - changeExamSelection () { - this.$router.push({ name: 'exam-selection' }) - }, - async loadExamTypes () { - try { - const response = (await ax.get('/api/examtype/')).data - this.examTypes = response - console.log('loaded examtypes') - } catch (ex) { - console.log(ex) - } - } - } -} -</script> - -<style scoped> - .sidebar-footer { - width: 100%; - bottom: 0px; - } - - .grady-toolbar { - font-weight: bold; - } - - .title { - color: gray; - white-space: nowrap; - } - - .fab-button { - margin: 0 12px; - } - - .fab-button-white { - color: grey !important; - } - - .dark-mode-switch { - margin-left: 22px; - } - - .v-btn { - margin: 15px; - } - -</style> - -<style> - .grady-toolbar > div { - padding-right: 0; - } - - .grady-toolbar .v-btn { - letter-spacing: initial; - text-transform: none; - } -</style> diff --git a/grady/frontend/src/components/ChangeLog.vue b/grady/frontend/src/components/ChangeLog.vue deleted file mode 100644 index a1785ab2f0f5b605fc8f3b29e3bcff4d0b066ff9..0000000000000000000000000000000000000000 --- a/grady/frontend/src/components/ChangeLog.vue +++ /dev/null @@ -1,91 +0,0 @@ -<template> - <v-card name="change-log"> - <v-toolbar - color="teal" - > - <v-toolbar-title - style="min-width: fit-content;" - > - Change Log - </v-toolbar-title> - <v-spacer /> - <span style="font-size:16px;"> - Current version: {{ version }} - </span> - <v-btn - icon - @click="sendReq" - > - <v-icon v-if="!updating"> - refresh - </v-icon> - <v-progress-circular - v-else - indeterminate - color="black" - size="20" - /> - </v-btn> - </v-toolbar> - <ul id="releaseList"> - <li - v-for="release in releases" - :key="release.tag_name" - > - <h2 style="margin: 2%;"> - Release: {{ release.tag_name }} - </h2> - <!-- eslint-disable-next-line --> - <span class="releaseInfo" v-html="release.description_html"/> - <v-divider /> - </li> - </ul> - </v-card> -</template> - -<script lang="ts"> -import Vue from 'vue' -import * as api from '@/api' -import { GitlabRelease } from '@/models' - -const Changelog = Vue.extend({ - name: 'Changelog', - data() { - return { - releases: [] as GitlabRelease[], - version: '', - updating: false, - } - }, - mounted() { - this.sendReq() - }, - methods: { - async sendReq() { - this.updating = true - - try { - this.releases = await api.fetchReleases() - this.version = (await api.fetchConfig()).version - } - catch (ex) { - throw new Error('Error fetching grady version.') - } finally { - this.updating = false - } - } - } -}) - -export default Changelog -</script> - -<style> - .releaseInfo h2 { - font-size: 19px; - } - ul { - max-height: 350px; - overflow: auto; - } -</style> diff --git a/grady/frontend/src/components/CorrectionStatistics.vue b/grady/frontend/src/components/CorrectionStatistics.vue deleted file mode 100644 index 6defa04cfda6e932d04ce2bef6664f9efc94e9d5..0000000000000000000000000000000000000000 --- a/grady/frontend/src/components/CorrectionStatistics.vue +++ /dev/null @@ -1,73 +0,0 @@ -<template> - <v-card - id="correction-statistics" - class="py-2" - > - <v-card-title> - <span class="title">Statistics</span> - </v-card-title> - <div v-if="loaded"> - <ul class="inline-list mx-3"> - <li>Submissions per participant: <span>{{ statistics.submissionsPerStudent }}</span></li> - <li>Submissions per type: <span>{{ statistics.submissionsPerType }}</span></li> - <li> - Curr. mean score: - <span> - {{ statistics.currentMeanScore === null ? 'N.A.' : statistics.currentMeanScore.toFixed(2) }} - </span> - </li> - </ul> - <v-divider class="mx-2 my-2" /> - <div - v-for="(progress, index) in statistics.submissionTypeProgress" - :key="index" - > - <v-card-title class="py-0"> - {{ progress.name }} - </v-card-title> - <div class="mx-3"> - <v-progress-linear - :value="progress.feedbackFinal / progress.submissionCount * 100" - buffer - :buffer-value="(progress.feedbackInValidation + progress.feedbackFinal) * 100 / progress.submissionCount" - :color="progress.feedbackFinal === progress.submissionCount ? 'green' : 'blue'" - /> - </div> - </div> - </div> - </v-card> -</template> - -<script> -import { actions } from '@/store/actions' -import { ConfigModule } from '@/store/modules/config' - -export default { - name: 'CorrectionStatistics', - data () { - return { - loaded: false - } - }, - computed: { - statistics () { - return this.$store.state.statistics - } - }, - created () { - if (ConfigModule.state.config.examId !== '') { - actions.getStatistics().then(() => { this.loaded = true }) - } - } -} -</script> - -<style scoped> - .inline-list li { - display: inline; - margin: 0px 5px; - } - .inline-list span { - font-weight: bolder; - } -</style> diff --git a/grady/frontend/src/components/FreeLocksButton.vue b/grady/frontend/src/components/FreeLocksButton.vue deleted file mode 100644 index df5bb258f804740a5da69d07b568e182301c19e5..0000000000000000000000000000000000000000 --- a/grady/frontend/src/components/FreeLocksButton.vue +++ /dev/null @@ -1,54 +0,0 @@ -<template> - <v-tooltip bottom> - <template #activator="{ on }"> - <v-btn - text - icon - :disabled="!activeAssignmentsExist" - :loading="loading" - @click="freeLocks" - v-on="on" - > - <v-icon>vpn_key</v-icon> - </v-btn> - </template> - <span>Free all locked Submissions</span> - </v-tooltip> -</template> - -<script> -import { deleteAllActiveAssignments, fetchActiveAssignments } from '@/api' -import { TutorOverview } from '@/store/modules/tutor-overview' - -export default { - name: 'FreeLocksButton', - data () { - return { - activeAssignmentsExist: false, - loading: false, - shortPollInterval: null - } - }, - async created () { - this.activeAssignmentsExist = await this.checkForActiveAssignments() - this.shortPollInterval = setInterval(async () => { - this.activeAssignmentsExist = await this.checkForActiveAssignments() - } , 5e3) - }, - beforeDestroy () { - clearInterval(this.shortPollInterval) - }, - methods: { - async checkForActiveAssignments () { - return (await fetchActiveAssignments()).length > 0 - }, - async freeLocks () { - this.loading = true - await deleteAllActiveAssignments() - this.loading = false - // Just lie to the user for now. The actual value will be fetched by the timeout soon. - this.activeAssignmentsExist = false - } - } -} -</script> diff --git a/grady/frontend/src/components/GDPRNotice.vue b/grady/frontend/src/components/GDPRNotice.vue deleted file mode 100644 index 482710108e05d938f5f98bf4ff6f08bc6699b195..0000000000000000000000000000000000000000 --- a/grady/frontend/src/components/GDPRNotice.vue +++ /dev/null @@ -1,151 +0,0 @@ -<template> - <div> - <h4>Allgemeiner Hinweis und Pflichtinformationen</h4> - <p /> - - <h4>Benennung der verantwortlichen Stelle</h4> - <p>Die verantwortliche Stelle für die Datenverarbeitung auf dieser Website ist:</p> - <p> - <span id="s3-t-firma">Institut für Informatik - Georg-August-Universität Göttingen</span><br> - <span id="s3-t-ansprechpartner">Dr. Henrik Brosenne</span><br><span id="s3-t-strasse">Goldschmidtstraße 7</span><br> - <span id="s3-t-plz">37077</span> <span id="s3-t-ort">Göttingen</span> - </p> - <p> - Die verantwortliche Stelle entscheidet allein oder gemeinsam mit anderen über die Zwecke und Mittel der - Verarbeitung von personenbezogenen Daten (z.B. Namen, Kontaktdaten o. Ä.). - </p> - - <h4>Recht auf Beschwerde bei der zuständigen Aufsichtsbehörde</h4> - <p> - Als Betroffener steht Ihnen im Falle eines datenschutzrechtlichen Verstoßes ein Beschwerderecht bei der zuständigen - Aufsichtsbehörde zu. Zuständige Aufsichtsbehörde bezüglich datenschutzrechtlicher Fragen ist: - </p> - <p> - Die Landesbeauftragte für den Datenschutz Niedersachsen<br> - Prinzenstraße 5<br> - 30159 Hannover<br> - </p> - - <h4>Recht auf Datenübertragbarkeit</h4> - <p> - Ihnen steht das Recht zu, Daten, die wir auf Grundlage der Erfüllung eines Vertrags - automatisiert verarbeiten, an sich oder an Dritte aushändigen zu lassen. Die Bereitstellung erfolgt in einem - maschinenlesbaren Format. Sofern Sie die direkte Übertragung der Daten an einen anderen Verantwortlichen verlangen, erfolgt dies nur, soweit es technisch machbar ist. - </p> - - <h4>Recht auf Auskunft, Berichtigung, Sperrung, Löschung</h4> - <p> - Sie haben jederzeit im Rahmen der geltenden gesetzlichen Bestimmungen das Recht auf unentgeltliche Auskunft über - Ihre gespeicherten personenbezogenen Daten, Herkunft der Daten, deren Empfänger und den Zweck der - Datenverarbeitung und ggf. ein Recht auf Berichtigung, Sperrung oder Löschung dieser Daten. Diesbezüglich und - auch zu weiteren Fragen zum Thema personenbezogene Daten können Sie sich jederzeit über die im Impressum aufgeführten Kontaktmöglichkeiten an uns wenden. - </p> - - <h4>SSL- bzw. TLS-Verschlüsselung</h4> - <p> - Aus Sicherheitsgründen und zum Schutz der Übertragung vertraulicher Inhalte, die Sie an uns als Seitenbetreiber - senden, nutzt unsere Website eine SSL-bzw. TLS-Verschlüsselung. Damit sind Daten, die Sie über diese Website - übermitteln, für Dritte nicht mitlesbar. Sie erkennen eine verschlüsselte Verbindung an der „https://“ - Adresszeile Ihres Browsers und am Schloss-Symbol in der Browserzeile. - </p> - - <h4>Datenschutzbeauftragter</h4> - <p>Wir haben einen Datenschutzbeauftragten bestellt.</p> - <p> - Datenschutzbeauftragter der Universität<br> - Prof. Dr. Andreas Wiebe<br> - Lehrstuhl für Bürgerliches Recht, Wettbewerbs- und Immaterialgüterrecht, Medien- und Informationsrecht<br> - Platz der Göttinger Sieben 6<br> - 37073 Göttingen<br> - Tel.: 0551 39 - 7381<br> - Fax: 0551 39 - 4437<br> - E-Mail: lehrstuhl.wiebe@jura.uni-goettingen.de - </p> - - <h4>Server-Log-Dateien</h4> - <p>Der Provider der Website erhebt automatisch Informationen, die Ihr Browser automatisch an uns übermittelt. Dies sind:</p> - <p> - <ul> - <li>Besuchte Seite auf unserer Domain</li> - <li>Datum und Uhrzeit der Serveranfrage</li> - <li>Browsertyp und Browserversion</li> - <li>Verwendetes Betriebssystem</li> - <li>Referrer URL</li> - <li>Hostname des zugreifenden Rechners</li> - <li>IP-Adresse</li> - </ul> - </p> - <p> - Es findet keine Zusammenführung dieser Daten mit anderen Datenquellen statt. Grundlage der Datenverarbeitung - bildet Art. 6 Abs. 1 lit. b DSGVO, der die Verarbeitung von Daten zur Erfüllung eines Vertrags oder - vorvertraglicher Maßnahmen gestattet. - </p> - - <h4>Registrierung auf dieser Website</h4> - <p> - Zur Nutzung bestimmter Funktionen müssen Sie sich auf unserer Website registrieren. Die übermittelten Daten - dienen ausschließlich zum Zwecke der Nutzung des jeweiligen Angebotes oder Dienstes. Bei der Registrierung - abgefragte Pflichtangaben sind vollständig anzugeben. Andernfalls werden wir die Registrierung ablehnen. - </p> - <p>Im Falle wichtiger Änderungen, etwa aus technischen Gründen, informieren wir Sie</p> - <p> - Wir speichern die bei der Registrierung erfassten Daten während des Zeitraums, den Sie auf unserer Website - registriert sind. - Gesetzliche Aufbewahrungsfristen bleiben unberührt. - </p> - - <h4>Speicherdauer von Beiträgen und Kommentaren</h4> - <p> - Beiträge und Kommentare sowie damit in Verbindung stehende Daten, wie beispielsweise der Benutzername, - werden gespeichert. Der Inhalt verbleibt auf unserer Website, bis er vollständig gelöscht wurde oder aus - rechtlichen Gründen gelöscht werden musste. - </p> - <p> - Die Speicherung der Beiträge und Kommentare erfolgt auf Grundlage Art. 6 Abs. 1 lit. b DSGVO zur Erfüllung des - Arbeitsvertrages. - </p> - - <h4>Session storage</h4> - <p> - Unsere Website verwendet den Session storage des Browsers. In diesem werden für die Dauer einer Sitzun (Session) - Daten auf Ihrem Endgerät gespeichert. - </p> - - <h4>Google Web Fonts</h4> - <p>Unsere Website verwendet Web Fonts von Google. Anbieter ist die Google Inc., 1600 Amphitheatre Parkway, Mountain View, CA 94043, USA.</p> - <p> - Durch den Einsatz dieser Web Fonts wird es möglich Ihnen die von uns gewünschte Darstellung unserer Website - zu präsentieren, unabhängig davon welche Schriften Ihnen lokal zur Verfügung stehen. Dies erfolgt über - den Abruf der Google Web Fonts von einem Server von Google in den USA und der damit verbundenen Weitergabe - Ihrer Daten an Google. Dabei handelt es sich um Ihre IP-Adresse und welche Seite Sie bei uns besucht haben. - Der Einsatz von Google Web Fonts erfolgt auf Grundlage von Art. 6 Abs. 1 lit. f DSGVO. Als Betreiber dieser - Website haben wir ein berechtigtes Interesse an der optimalen Darstellung und Übertragung unseres Webauftritts. - </p> - <p> - Das Unternehmen Google ist für das us-europäische Datenschutzübereinkommen "Privacy Shield" zertifiziert. - Dieses Datenschutzübereinkommen soll die Einhaltung des in der EU geltenden Datenschutzniveaus gewährleisten. - </p> - <p> - Einzelheiten über Google Web Fonts finden Sie unter: - <a href="https://www.google.com/fonts#AboutPlace:about">https://www.google.com/fonts#AboutPlace:about</a> - und weitere Informationen in den Datenschutzbestimmungen von Google: - <a href="https://policies.google.com/privacy/partners?hl=de">https://policies.google.com/privacy/partners?hl=de</a> - </p> - <p> - <small>Quelle: Datenschutz-Konfigurator von <a - href="http://www.mein-datenschutzbeauftragter.de" - target="_blank" - >mein-datenschutzbeauftragter.de</a></small> - </p> - </div> -</template> - -<script> -export default { - name: 'GDPRNotice' -} -</script> - -<style scoped> - -</style> diff --git a/grady/frontend/src/components/ImportDialog.vue b/grady/frontend/src/components/ImportDialog.vue deleted file mode 100644 index ef9aeddb234307ee03458654d714763f794dea83..0000000000000000000000000000000000000000 --- a/grady/frontend/src/components/ImportDialog.vue +++ /dev/null @@ -1,108 +0,0 @@ -<template> - <v-dialog - v-model="show" - width="30%" - > - <v-card> - <v-card-title class="title"> - Import data - </v-card-title> - <v-card-text> - <p> - You can use this component to import data into Grady. - You can use - <a - href="https://gitlab.gwdg.de/grady-corp/rusty-hektor" - target="_blank" - >rusty-hektor</a> to convert - and pseudonomize ILIAS output. - </p> - <v-file-input - id="file-input" - v-model="hektorFile" - label="Select file" - accept="application/JSON" - /> - </v-card-text> - <v-card-actions> - <v-btn - id="submit-import" - :loading="loading" - @click="submitData" - > - Import - </v-btn> - <v-btn - color="red" - @click="$emit('hide')" - > - Cancel - </v-btn> - </v-card-actions> - </v-card> - </v-dialog> -</template> - -<script> - import { importData } from '@/api' - - export default { - name: 'ImportDialog', - data: () => { - return { - show: true, - loading: false, - hektorFile: null - } - }, - watch: { - show(val) { - if (!val) { - this.$emit('hide') - } - } - }, - methods: { - async submitData() { - this.loading = true - let data - try { - data = await this.readFile() - data = JSON.parse(data) - } catch (error) { - this.$notify({ - type: 'error', - title: 'Error reading import file', - text: error.message - }) - this.loading = false - return - } - - try { - await importData(data) - this.$emit('imported') - this.$notify({ - title: 'Successfully imported data. Please log out and in again.', - type: 'success' - }) - } finally { - this.loading = false - } - }, - readFile() { - const fileReader = new FileReader() - return new Promise((resolve, reject) => { - fileReader.onload = event => { - resolve(event.target.result) - } - fileReader.onerror = () => { - fileReader.abort() - reject(new Error('Problem parsing input file.')) - } - fileReader.readAsText(this.hektorFile) - }) - } - } - } -</script> diff --git a/grady/frontend/src/components/InstanceActions.vue b/grady/frontend/src/components/InstanceActions.vue deleted file mode 100644 index 694e557b536270a613bf32dae055e3d0ddd2b30d..0000000000000000000000000000000000000000 --- a/grady/frontend/src/components/InstanceActions.vue +++ /dev/null @@ -1,75 +0,0 @@ -<template> - <div> - <export-dialog v-if="isReviewer" /> - <template v-for="(a, i) in actions"> - <v-tooltip - v-if="a.condition()" - :key="i" - bottom - > - <template #activator="{ on }"> - <v-btn - :id="a.id" - text - icon - @click="a.action" - v-on="on" - > - <v-icon>{{ a.icon }}</v-icon> - </v-btn> - </template> - {{ a.text }} - </v-tooltip> - </template> - <free-locks-button v-if="isReviewer" /> - <component - :is="displayComponent" - v-if="displayComponent" - @hide="hideComponent" - /> - </div> -</template> - -<script> -import ExportDialog from '@/components/export/ExportDialog' -import ImportDialog from '@/components/ImportDialog' -import ConfigDialog from '@/components/instance_config/ConfigDialog' -import FreeLocksButton from '@/components/FreeLocksButton' -import { Authentication } from '@/store/modules/authentication' -export default { - name: 'InstanceActions', - components: { ExportDialog, ImportDialog, FreeLocksButton }, - data () { - return { - displayComponent: null, - actions: [ - { - icon: 'publish', - text: 'Import exam data', - action: () => { this.displayComponent = ImportDialog }, - condition: () => Authentication.isReviewer, - id: 'import-data-list-item' - }, - { - icon: 'settings', - text: 'Instance settings', - action: () => { this.displayComponent = ConfigDialog }, - condition: () => Authentication.isReviewer, - id: 'configure-instance-item', - }, - ] - } - }, - computed: { - isReviewer: () => Authentication.isReviewer, - }, - methods: { - hideComponent () { - this.displayComponent = null - }, - logout () { - actions.logout() - } - } -} -</script> diff --git a/grady/frontend/src/components/LabelStatistics.vue b/grady/frontend/src/components/LabelStatistics.vue deleted file mode 100644 index 343958badb835c39f061b8d924c7fc573f4cc09a..0000000000000000000000000000000000000000 --- a/grady/frontend/src/components/LabelStatistics.vue +++ /dev/null @@ -1,159 +0,0 @@ -<template> - <v-card> - <v-card-title class="title"> - Accumulated Label Statistics - </v-card-title> - <v-data-table - :headers="headers" - :items-per-page="-1" - sort-by="count" - sort-desc - :loading="loading" - :items="summedLabelCounts" - hide-default-footer - /> - - <div - v-for="([subType, labelCounts]) in mappedLabelCounts" - :key="subType" - > - <v-card-title class="title"> - Statistics for: {{ subType }} - </v-card-title> - <v-data-table - :headers="headers" - :items-per-page="-1" - sort-by="count" - sort-desc - :loading="loading" - :items="labelCounts" - hide-default-footer - /> - </div> - </v-card> -</template> - - -<script lang="ts"> -import Vue from 'vue' -import Component from 'vue-class-component' -import * as api from '@/api' -import { LabelStatisticsForSubType, SubmissionType} from '../models' -import { getters } from '../store/getters' -import { FeedbackLabels } from '../store/modules/feedback-labels' -import { ConfigModule } from '@/store/modules/config' - - -@Component -export default class LabelStatistics extends Vue{ - labelStatistics: LabelStatisticsForSubType[] = [] - submissionTypes: SubmissionType[] = [] - timer = 0 - - headers = [ - { - text: 'Label', - align: 'left', - value: 'name' - }, - { - text: 'Count', - align: 'center', - value: 'count' - } - ] - - get loading(): boolean { - return this.labelStatistics.length === 0 - } - - /** - * Returns total count for all existing labels for the currently selected exam - */ - get summedLabelCounts () { - // list of subtype IDs filtered by the selected exam - const subTypeIDs = this.submissionTypes.filter(subType => { - return subType.examType.pk === ConfigModule.state.config.examId - }).map(subType => { - return subType.pk - }) - // filter the statistics - const filteredStatistics = this.labelStatistics.filter(subType => { - return subTypeIDs.includes(subType.pk) - }) - const summedLabelCounts = filteredStatistics - .reduce((acc: {[labelPk: string]: number}, curr) => { - Object.entries(curr) - .filter(([key, val]) => key !== 'pk') - .forEach(([labelPk, count]: [string, number]) => { - if (!acc[labelPk]) { - acc[labelPk] = 0 - } - acc[labelPk] += count - }) - return acc - }, {}) - // TODO map label pks to names - const mappedLabelCounts = this.mapLabelList(Object - .entries(summedLabelCounts)) - return mappedLabelCounts - } - - /** - * - * Returns Label Names and number of occurances for each Submission Type of the currently selected Exam. - */ - get mappedLabelCounts () { - var allowedTypes: string[] = [] // needed to filter if submissionType belongs to current selected Exam - const counts = this.labelStatistics.map(labelStatistics => { - const labelValues = Object - .entries(labelStatistics) - .filter(([key, val]) => key !== 'pk') - const subType = getters.submissionType(labelStatistics.pk) - - // determine which submissionTypes belong to current selected exam - if (subType.examType.moduleReference === ConfigModule.state.config.currentExam) { - allowedTypes.push(subType.name) - } - - const subTypeName = subType.name - return [subTypeName, this.mapLabelList(labelValues)] - // it seems the typechecker has a bug here... - }).sort((a: any, b: any) => a[0].localeCompare(b[0])) - return counts.filter(tmp => { // filter submissionTypes by current selected Exam - return allowedTypes.includes(tmp[0].toString()) - }) - } - - mapLabelList (labelList: [string, number][]) { - return labelList.map(entry => { - const label = FeedbackLabels.state.labels.find(label => { - return String(label.pk) === entry[0] - }) - const labelName = label ? label.name : 'Unknown label' - return {name: labelName, count: entry[1]} - }) - } - - async loadLabelStatistics () { - this.labelStatistics = await api.fetchLabelStatistics() - } - - async loadSubmissionTypes () { - this.submissionTypes = await api.fetchSubmissionTypes() - } - - created () { - this.timer = setInterval(() => { - this.loadLabelStatistics() - }, 10 * 1e3) - this.loadLabelStatistics() - this.loadSubmissionTypes() - } - - beforeDestroy () { - clearInterval(this.timer) - } - -} -</script> diff --git a/grady/frontend/src/components/MathRenderer.vue b/grady/frontend/src/components/MathRenderer.vue deleted file mode 100644 index 667a5987df9d82cc789e487fa16e6ab4ab5cc3bc..0000000000000000000000000000000000000000 --- a/grady/frontend/src/components/MathRenderer.vue +++ /dev/null @@ -1,51 +0,0 @@ -<template> - <div - ref="wrapper" - :key="key" - > - <slot /> - </div> -</template> - -<script lang="ts"> -import { Vue, Component, Prop, Watch } from 'vue-property-decorator' - -@Component -export default class MathRenderer extends Vue { - @Prop({ type: Boolean, default: true }) enabled!: boolean - - key: Boolean = false - - forceRefresh() { - this.key = !this.key - } - - renderMath() { - window.MathJax.typeset([this.$refs.wrapper]) - } - - resetMath() { - window.MathJax.typesetClear([this.$refs.wrapper]) - // typesetClear only clears the cache but leaves the DOM untouched, so we - // need to force it to rerender. - this.forceRefresh() - } - - mounted() { - if (this.enabled) - this.renderMath() - } - - beforeDestroy() { - this.resetMath() - } - - @Watch('enabled') - onEnabledChanged(changedToEnabled: boolean) { - if (changedToEnabled) - this.renderMath() - else - this.resetMath() - } -} -</script> diff --git a/grady/frontend/src/components/PasswordChangeDialog.vue b/grady/frontend/src/components/PasswordChangeDialog.vue deleted file mode 100644 index 547fc8a232aaed48e19d68b8f4984df9c6c1907c..0000000000000000000000000000000000000000 --- a/grady/frontend/src/components/PasswordChangeDialog.vue +++ /dev/null @@ -1,147 +0,0 @@ -<template> - <v-dialog - v-model="show" - max-width="400" - > - <v-card> - <v-form - ref="form" - v-model="formIsValid" - lazy-validation - @submit.prevent="submitChange" - > - <v-card-title class="title"> - Change your password - </v-card-title> - <v-card-text> - <v-text-field - v-model="currentPassword" - label="Current password" - type="password" - autofocus - required - :error-messages="oldPasswordRejected ? 'Wrong password.' : undefined" - :rules="[ rules.required ]" - @input="oldPasswordRejected = false" - /> - <v-text-field - v-model="newPassword" - label="New password" - type="password" - required - :error-messages="newPasswordErrors" - :rules="[ rules.required ]" - @input="newPasswordErrors = null" - /> - <v-text-field - v-model="newPasswordRepeated" - label="Repeat new password" - type="password" - required - :rules="[ rules.required, rules.matchesPassword ]" - /> - <v-alert - type="error" - :value="errorAlert !== null" - > - {{ errorAlert }} - </v-alert> - </v-card-text> - <v-card-actions class="justify-end"> - <v-btn - text - color="primary" - @click="$emit('hide')" - > - Cancel - </v-btn> - <v-btn - :disabled="!formIsValid" - text - color="primary" - type="submit" - > - Change password - </v-btn> - </v-card-actions> - </v-form> - </v-card> - </v-dialog> -</template> - -<script> -import { mapState } from 'vuex' -import { changePassword } from '@/api' -import { Authentication } from '@/store/modules/authentication' -import { required } from '@/util/form-rules' - -export default { - name: 'PasswordChangeDialog', - data () { - return { - show: true, - currentPassword: '', - newPassword: '', - newPasswordRepeated: '', - formIsValid: false, - rules: { - required, - matchesPassword: v => v === this.newPassword || 'Passwords do not match.', - }, - errorAlert: null, - oldPasswordRejected: false, - newPasswordErrors: null - } - }, - computed: { - userPk () { return Authentication.state.user.pk } - }, - watch: { - show (val) { - if (!val) { - this.$emit('hide') - } - }, - newPassword () { - if (this.newPasswordRepeated !== '') - this.$refs.form.validate() - } - }, - methods: { - submitChange () { - if (!this.$refs.form.validate()) - return - - const data = { - oldPassword: this.currentPassword, - newPassword: this.newPassword - } - changePassword(this.userPk, data).then(() => { - this.$notify({ - title: 'Success!', - text: 'Successfully changed password!', - type: 'success' - }) - this.$emit('hide') - }).catch(error => { - if (error.response && error.response.status === 401) { - this.oldPasswordRejected = true - this.$refs.form.validate() - return - } - - if (error.response && error.response.data && error.response.data.newPassword) { - this.newPasswordErrors = error.response.data.newPassword - return - } - - this.errorAlert = error.toString() - }) - } - } -} -</script> - -<style scoped> - -</style> diff --git a/grady/frontend/src/components/RegisterDialog.vue b/grady/frontend/src/components/RegisterDialog.vue deleted file mode 100644 index 75f212dcf9b75854081ce47d885957489fe2d4b0..0000000000000000000000000000000000000000 --- a/grady/frontend/src/components/RegisterDialog.vue +++ /dev/null @@ -1,149 +0,0 @@ -<template> - <v-card v-if="!acceptedGDPR"> - <v-card-title class="title"> - Datenschutzerklärung - </v-card-title> - <v-divider /> - <v-card-text class="content"> - <GDPRNotice id="gdpr-notice" /> - </v-card-text> - <v-divider /> - <v-card-actions class="justify-end"> - <v-btn - id="accept-gdpr-notice" - color="primary" - text - @click="acceptedGDPR = true" - > - Einwilligen - </v-btn> - </v-card-actions> - </v-card> - <v-card v-else> - <v-form - ref="registrationForm" - v-model="registrationFormIsValid" - lazy-validation - @submit.prevent="register" - > - <v-card-title class="title"> - Register - </v-card-title> - <v-card-text> - <v-text-field - id="input-register-username" - v-model="credentials.username" - label="Username" - required - :error-messages="usernameErrors" - :rules="[ required ]" - autofocus - @input="usernameErrors = null" - /> - <v-text-field - id="input-register-instance-password" - v-model="credentials.registrationPassword" - label="Instance-Password" - required - :rules="[ required ]" - type="password" - /> - <v-text-field - id="input-register-password" - v-model="credentials.password" - label="Password" - required - :rules="[ required ]" - type="password" - :error-messages="passwordErrors" - @input="passwordErrors = null" - /> - <v-text-field - id="input-register-password-repeat" - v-model="credentials.passwordRepeat" - label="Repeat Password" - required - :rules="[ required, checkPasswordsMatch ]" - type="password" - /> - <v-alert - type="error" - :value="errorAlert !== null" - > - {{ errorAlert }} - </v-alert> - </v-card-text> - <v-card-actions class="justify-center"> - <v-btn - id="register-submit" - text - :loading="loading" - :disabled="!registrationFormIsValid" - type="submit" - > - submit - </v-btn> - </v-card-actions> - </v-form> - </v-card> -</template> - -<script> -import { registerTutor } from '@/api' -import GDPRNotice from '@/components/GDPRNotice' -import { required } from '@/util/form-rules' - -export default { - name: 'RegisterDialog', - components: { GDPRNotice }, - data () { - return { - credentials: { - username: '', - password: '', - passwordRepeat: '', - registrationPassword: '' - }, - loading: false, - acceptedGDPR: false, - registrationFormIsValid: false, - required, - checkPasswordsMatch: v => v === this.credentials.password || 'Passwords do not match.', - errorAlert: null, - usernameErrors: null, - passwordErrors: null, - } - }, - watch: { - credentials: { - handler() { - if (this.credentials.passwordRepeat !== '') - this.$refs.registrationForm.validate() - }, - deep: true - } - }, - methods: { - register () { - if (!this.$refs.registrationForm.validate()) - return - - this.loading = true - registerTutor(this.credentials).then(() => { - this.$emit('registered', this.credentials) - }).catch(error => { - this.usernameErrors = error.response && error.response.data && error.response.data.username - this.passwordErrors = error.response && error.response.data && error.response.data.password - if (!this.usernameErrors && !this.passwordErrors) - this.errorAlert = `Couldn't register a tutor account: ${error}` - }).finally(() => { this.loading = false }) - } - }, -} -</script> - -<style scoped> - .content { - height: 50vh; - } -</style> diff --git a/grady/frontend/src/components/SubmissionTests.vue b/grady/frontend/src/components/SubmissionTests.vue deleted file mode 100644 index 4ad1287a4e66a1179b653c7b8f6ed5778593a1e6..0000000000000000000000000000000000000000 --- a/grady/frontend/src/components/SubmissionTests.vue +++ /dev/null @@ -1,72 +0,0 @@ -<template> - <v-card id="submission-tests"> - <v-card-title - v-if="tests.length > 0" - class="title py-0" - > - Tests - <v-spacer /> - <v-btn - icon - @click="expanded = !expanded" - > - <v-icon v-if="expanded"> - keyboard_arrow_up - </v-icon> - <v-icon v-else> - keyboard_arrow_down - </v-icon> - </v-btn> - </v-card-title> - <v-card-title v-else> - No Tests available - </v-card-title> - <v-card-text v-if="expanded"> - <v-col - v-for="item in tests" - :key="item.pk" - sm="12" - > - <div name="test-name-label"> - <v-row - - class="pr-4" - > - <h3>{{ item.name }}</h3> - <v-spacer /> - <h3>{{ item.label }}</h3> - </v-row> - </div> - <span class="test-output">{{ item.annotation }}</span> - </v-col> - </v-card-text> - </v-card> -</template> - -<script> -export default { - name: 'SubmissionTests', - props: { - tests: { - type: Array, - default: () => [] - }, - expand: { - type: Boolean, - default: true - } - }, - data () { - return { - expanded: this.expand, - panels: this.tests.map(_ => true) - } - } -} -</script> - -<style scoped> - .test-output { - white-space: pre-wrap; - } -</style> diff --git a/grady/frontend/src/components/TwoPaneLayout.vue b/grady/frontend/src/components/TwoPaneLayout.vue deleted file mode 100644 index 90dc2c6c8e91523b738fbd1574422da90581a021..0000000000000000000000000000000000000000 --- a/grady/frontend/src/components/TwoPaneLayout.vue +++ /dev/null @@ -1,52 +0,0 @@ -<template> - <v-row - class="pane-wrapper" - no-gutters - > - <v-col - ref="leftPane" - class="pane" - > - <slot name="left" /> - </v-col> - <v-divider - v-if="showRightPane" - vertical - /> - <v-col - v-if="showRightPane" - ref="rightPane" - class="pane" - > - <slot name="right" /> - </v-col> - </v-row> -</template> - -<script lang="ts"> -import { Vue, Component, Prop } from 'vue-property-decorator' - -@Component -export default class TwoPaneLayout extends Vue { - @Prop({ type: Boolean, default: true }) showRightPane!: boolean - - leftPane(): HTMLElement { - return this.$refs.leftPane as HTMLElement - } - - rightPane(): HTMLElement { - return this.$refs.rightPane as HTMLElement - } -} -</script> - -<style scoped> - .pane-wrapper { - height: 100%; - } - - .pane { - height: 100%; - overflow: auto; - } -</style> diff --git a/grady/frontend/src/components/UserOptions.vue b/grady/frontend/src/components/UserOptions.vue deleted file mode 100644 index 5fffef875f66fef0def2897162eaf4306f8543b1..0000000000000000000000000000000000000000 --- a/grady/frontend/src/components/UserOptions.vue +++ /dev/null @@ -1,87 +0,0 @@ -<template> - <v-toolbar-items> - <v-menu - bottom - offset-y - left - > - <template #activator="{ on }"> - <v-btn - id="user-options" - text - v-on="on" - > - <v-icon left> - account_circle - </v-icon> - {{ username }} ({{ userRole }})<v-icon>arrow_drop_down</v-icon> - </v-btn> - </template> - <v-list> - <v-list-item - v-if="!isStudent" - @click="showPasswordChangeDialog" - > - Change password - </v-list-item> - <v-list-item @click.capture.stop="$vuetify.theme.dark = !$vuetify.theme.dark"> - <v-list-item-content> - <v-list-item-title> - Dark mode (experimental) - </v-list-item-title> - </v-list-item-content> - <v-list-item-action> - <v-switch v-model="$vuetify.theme.dark" /> - </v-list-item-action> - </v-list-item> - <v-divider class="my-2" /> - <v-list-item @click="logout"> - <v-icon left> - exit_to_app - </v-icon> - Logout - </v-list-item> - </v-list> - </v-menu> - <component - :is="displayComponent" - v-if="displayComponent" - @hide="hideComponent" - /> - </v-toolbar-items> -</template> - -<script> -import PasswordChangeDialog from '@/components/PasswordChangeDialog' -import { Authentication } from '@/store/modules/authentication' -import { actions } from '@/store/actions' -export default { - name: 'UserOptions', - components: { PasswordChangeDialog }, - data () { - return { - displayComponent: null, - } - }, - computed: { - isStudent() { return Authentication.isStudent }, - username() { return Authentication.state.user.username }, - userRole() { return Authentication.state.user.role }, - }, - methods: { - hideComponent () { - this.displayComponent = null - }, - logout () { - actions.logout() - }, - showPasswordChangeDialog () { - this.displayComponent = PasswordChangeDialog - } - } -} -</script> - -<style scoped> - -</style> diff --git a/grady/frontend/src/components/export/DataExport.vue b/grady/frontend/src/components/export/DataExport.vue deleted file mode 100644 index 3cce92c401569f2fe0ef66920b0f898e7844ca7f..0000000000000000000000000000000000000000 --- a/grady/frontend/src/components/export/DataExport.vue +++ /dev/null @@ -1,116 +0,0 @@ -<template> - <v-dialog - v-model="exportDialog" - max-width="31vw" - @update:return-value="hide" - > - <v-card id="data-export-modal"> - <v-card-title class="title"> - Student Data Export - </v-card-title> - <v-card-text> - <div v-if="!mapFileLoaded"> - If you select a mapping file, the anonymized data - will be mapped back automatically and locally on your machine. - <v-row - - align="center" - > - <v-file-input - v-model="mapFile" - label="Map file" - accept="application/JSON" - /> - <span>Without the mapping, the data will still be obfuscated.</span> - </v-row> - </div> - <span> - <b>NOTE:</b> Mapping / setting passwords can take some time depending on course size. - </span> - <v-row> - <v-col cols="4"> - <v-tooltip top> - <template #activator="{ on }"> - <div v-on="on"> - <v-checkbox - v-model="setPasswords" - label="Set passwords" - /> - </div> - </template> - <span>Setting this will cause all student passwords - to be reset upon export. The new passwords will be contained in the - export file. - </span> - </v-tooltip> - </v-col> - <v-col - id="type-select" - cols="3" - offset="1" - > - <span>Export as <b>json</b> - </span> - </v-col> - </v-row> - <v-card-actions> - <v-btn - text - color="blue lighten-2" - @click="exportDialog = false" - > - close - </v-btn> - <v-spacer /> - <v-progress-circular - v-if="loading" - indeterminate - /> - <v-btn - v-else - id="export-data-download-btn" - text - outlined - @click="getExportFile('data')" - > - {{ mapFile || mapFileLoaded ? 'Download and apply mapping' : 'Download without mapping' }} - </v-btn> - </v-card-actions> - </v-card-text> - </v-card> - </v-dialog> -</template> - -<script lang="ts"> -import Component, { mixins } from 'vue-class-component' -import { getters } from '@/store/getters' -import ax, { StudentExportItem, fetchStudentExportData } from '@/api' -import { mutations as mut } from '@/store/mutations' -import { ExportType, exportMixin } from '@/components/mixins/exportMixin' - -@Component -export default class DataExport extends mixins(exportMixin) { - - get studentMap () { return getters.state.studentMap } - - applyMapping (studentExport: StudentExportItem[]) { - studentExport.forEach(student => { - if (this.studentMap[student.Matrikel]) { - student.Email = this.studentMap[student.Matrikel].email - student.Name = this.studentMap[student.Matrikel].name - student.Matrikel = this.studentMap[student.Matrikel].matrikelNo - } else { - this.$notify({ - title: `Unknown student: ${student.Name}`, - text: `Student ${student.Name} is missing in mapping file`, - type: 'error', - duration: -1 - }) - } - }) - } -} -</script> - -<style scoped> -</style> diff --git a/grady/frontend/src/components/export/ExportDialog.vue b/grady/frontend/src/components/export/ExportDialog.vue deleted file mode 100644 index 04708cf4aa53ab276b6c7108e84580b676292ae2..0000000000000000000000000000000000000000 --- a/grady/frontend/src/components/export/ExportDialog.vue +++ /dev/null @@ -1,95 +0,0 @@ -<template> - <div id="container"> - <v-menu offset-y> - <template #activator="{ on: menu }"> - <v-tooltip left> - <template #activator="{ on: tooltip }"> - <v-btn - id="export-btn" - slot="activator" - :icon="!corrected" - :text="!corrected" - :color="corrected ? 'success' : undefined" - v-on="{ ...tooltip, ...menu }" - > - <v-icon :left="corrected"> - file_download - </v-icon> - <span v-if="corrected"> - Export - </span> - </v-btn> - </template> - Export - <span - v-if="corrected" - id="corrected-tooltip" - >(All submissions have been corrected!)</span> - <span - v-else - id="uncorrected-tooltip" - >(UNCORRECTED submissions left! Export will be incomplete.)</span> - </v-tooltip> - </template> - <v-list> - <v-list-item - v-for="(item, i) in menuItems" - :id="'export-list' + i" - :key="i" - @click="item.action" - > - {{ item.display }} - </v-list-item> - </v-list> - </v-menu> - <component - :is="displayComponent" - v-if="displayComponent" - @hide="displayComponent = null" - /> - </div> -</template> - -<script lang="ts"> -import Vue from 'vue' -import Component from 'vue-class-component' -import DataExport from '@/components/export/DataExport.vue' -import InstanceExport from '@/components/export/InstanceExport.vue' -import { getters } from '@/store/getters' - -@Component({ - components: { DataExport, InstanceExport } -}) -export default class ExportDialog extends Vue { - displayComponent: any = null - - menuItems = [ - { - display: 'Export student scores', - action: () => { - this.setDisplayComponent(DataExport) - } - }, - { - display: 'Export whole instance data', - action: () => { this.setDisplayComponent(InstanceExport) } - } - ]; - - get corrected () { - return getters.corrected - } - - // apparently `this` is not the same when used within a - // closure when defining data and within a method - setDisplayComponent (component: any) { - this.displayComponent = component - } -} -</script> - -<style scoped> - #container { - display: inline; - } -</style> diff --git a/grady/frontend/src/components/export/InstanceExport.vue b/grady/frontend/src/components/export/InstanceExport.vue deleted file mode 100644 index 8d81c9f7cfd2b59bc72368f2f0ad40f0947d0105..0000000000000000000000000000000000000000 --- a/grady/frontend/src/components/export/InstanceExport.vue +++ /dev/null @@ -1,94 +0,0 @@ -<template> - <v-dialog - v-model="exportDialog" - max-width="31vw" - @update:return-value="hide" - > - <v-card id="instance-export-modal"> - <v-card-title class="title"> - Instance Data Export - </v-card-title> - <v-card-text> - <div v-if="!mapFileLoaded"> - If you select a mapping file, the anonymized data - will be mapped back automatically and locally on your machine. - <v-row - - align="center" - > - <v-file-input - v-model="mapFile" - label="Map file" - accept="application/JSON" - /> - <span>Without the mapping, the data will still be obfuscated.</span> - </v-row> - </div> - <span> - <b>NOTE:</b> Mapping can take some time depending on course size. - </span> - <v-card-actions> - <v-btn - text - color="blue lighten-2" - @click="exportDialog = false" - > - close - </v-btn> - <v-spacer /> - <v-progress-circular - v-if="loading" - indeterminate - /> - <v-btn - v-else - id="instance-export-dl" - text - outlined - @click="getExportFile('instance')" - > - {{ mapFile || mapFileLoaded ? 'Download and apply mapping' : 'Download without mapping' }} - </v-btn> - </v-card-actions> - </v-card-text> - </v-card> - </v-dialog> -</template> - -<script lang="ts"> -import Component, { mixins } from 'vue-class-component' -import { getters } from '@/store/getters' -import ax, { StudentExportItem, fetchStudentExportData, fetchInstanceExportData, InstanceExportData } from '@/api' -import { mutations as mut } from '@/store/mutations' -import { ExportType, exportMixin } from '@/components/mixins/exportMixin' - -@Component -export default class DataExport extends mixins(exportMixin) { - exportDialog = true - mapFile: File | null = null - exportType = ExportType.JSON // instance export is only available as JSON - loading = false - - get studentMap () { return getters.state.studentMap } - - applyMapping (instanceExport: InstanceExportData) { - instanceExport.students.forEach(student => { - if (this.studentMap[student.matrikelNo]) { - const anonMatrikelNo = student.matrikelNo - student.name = this.studentMap[anonMatrikelNo].name - student.matrikelNo = this.studentMap[anonMatrikelNo].matrikelNo - } else { - this.$notify({ - title: `Unknown student: ${student.name}`, - text: `Student ${student.name} is missing in mapping file`, - type: 'error', - duration: -1 - }) - } - }) - } -} -</script> - -<style scoped> -</style> diff --git a/grady/frontend/src/components/feedback_labels/FeedbackLabel.vue b/grady/frontend/src/components/feedback_labels/FeedbackLabel.vue deleted file mode 100644 index bf95efa29124ad4874393194f2e746b5cfba2b2c..0000000000000000000000000000000000000000 --- a/grady/frontend/src/components/feedback_labels/FeedbackLabel.vue +++ /dev/null @@ -1,38 +0,0 @@ -<template> - <v-tooltip top> - <template #activator="{ on }"> - <v-chip - :close="removable" - :color="colour" - v-on="on" - @click:close="onClose" - > - {{ name }} - </v-chip> - </template> - <span> {{ description }} </span> - </v-tooltip> -</template> - -<script lang="ts"> -import Vue from 'vue' -import Component from 'vue-class-component' -import { Prop } from 'vue-property-decorator' - -@Component -export default class FeedbackLabel extends Vue { - @Prop({ type: Number, required :true }) readonly pk!: number - @Prop({ type: String, required: true }) readonly name!: string - @Prop({ type: String, required: true }) readonly description!: string - @Prop({ type: String, required: true }) readonly colour!: string - @Prop({ type: Boolean, default: false }) readonly removable!: boolean - - onClose() { - this.$emit('remove-clicked', this.pk) - } -} -</script> - -<style> - -</style> diff --git a/grady/frontend/src/components/feedback_labels/FeedbackLabelForm.vue b/grady/frontend/src/components/feedback_labels/FeedbackLabelForm.vue deleted file mode 100644 index ec67b057e59032725fdeb1a8537689b330f6b6fc..0000000000000000000000000000000000000000 --- a/grady/frontend/src/components/feedback_labels/FeedbackLabelForm.vue +++ /dev/null @@ -1,175 +0,0 @@ -<template> - <div> - <v-text-field - id="label-name" - v-model="mutableName" - label="Name" - /> - <v-textarea - id="label-description" - v-model="mutableDescription" - label="Description" - placeholder="The description can be seen when hovering above the label" - auto-grow - /> - <v-color-picker - v-model="mutableColour" - show-swatches - hide-canvas - hide-inputs - hide-sliders - hide-mode-switch - :swatches="swatches" - /> - <v-btn - v-if="!is_update" - id="create-label-btn" - :loading="loading" - color="teal" - @click="createLabel" - > - Create - </v-btn> - <v-btn - v-else - id="update-label-btn" - color="teal" - :loading="loading" - @click="updateLabel" - > - Update - </v-btn> - </div> -</template> - -<script lang="ts"> -import Vue from 'vue' -import Component from 'vue-class-component' -import { Prop, Watch } from 'vue-property-decorator' -import * as api from '@/api' -import { FeedbackLabels } from '@/store/modules/feedback-labels' - -@Component -export default class FeedbackLabelForm extends Vue { - @Prop({ type: String, default: '' }) readonly name!: string - @Prop({ type: String, default: '' }) readonly description!: string - @Prop({ type: String, default: '#4D4D4D' }) readonly colour!: string - @Prop({ type: Number, required: false }) readonly pk!: number - @Prop({ type: Boolean, default: false }) readonly is_update!: boolean - - swatches = [['#4b4b4b', '#323232', '#000000'], - ['#969696', '#7d7d7d', '#646464'], - ['#fafafa', '#c8c8c8', '#afafaf'], - ['#ef4c3a', '#cf3015', '#9c0500'], - ['#f98f00', '#de7100', '#c04f00'], - ['#f7d800', '#f7c000', '#f69b00'], - ['#d7db00', '#adb800', '#7d8600'], - ['#a1d900', '#66b800', '#194d32'], - ['#66c8c6', '#16a2a2', '#0c777b'], - ['#71d4fa', '#0099dc', '#0060ae'], - ['#ab9efa', '#7962fa', '#633191'], - ['#f89efa', '#f527fa', '#a8149b']] - - mutableColour = this.colour - mutableName = this.name - mutableDescription = this.description - - loading = false - - @Watch('pk') - onPkChange() { this.resetFields() } - - resetFields () { - this.mutableName = this.name - this.mutableDescription = this.description - this.mutableColour = this.colour - } - - get label () { - return { - name: this.mutableName, - description: this.mutableDescription, - // @ts-ignore - colour: this.mutableColour.hex || this.mutableColour // hex may be undefined when colour comes from the updater - } - } - - get feedbackLabels () { - return FeedbackLabels.availableLabels - } - - async createLabel () { - this.loading = true - - const duplicate = this.feedbackLabels.find((val) => { - return val.name === this.label.name - }) - - if (duplicate) { - this.$notify({ - title: 'Label creation error', - text: 'A label with the same name already exists. ' + - 'You can, however, update the label', - type: 'error', - duration: -1 - }) - this.resetFields() - this.loading = false - return - } - - let res - try { - res = await api.createLabel(this.label) - this.notifySuccess() - } catch (ex) { - // user will be notified by the interceptor - this.resetFields() - this.loading = false - return - } - - FeedbackLabels.ADD_LABEL(res) - this.resetFields() - this.loading = false - } - - async updateLabel () { - this.loading = true - const label = { - ...this.label, - pk: this.pk, - } - - let res - try { - res = await api.updateLabel(label) - this.notifySuccess(true) - } catch (ex) { - // user will be notified by the interceptor - this.loading = false - return - } - - FeedbackLabels.UPDATE_LABEL(label) - this.$emit('label-updated', label.pk) - this.loading = false - } - - notifySuccess (updated = false) { - const msg = updated ? 'updated' : 'created' - - this.$notify({ - group: 'msg', - title: 'Success', - text: 'The label was <b>' + msg + '</b> successfully.', - type: 'success', - duration: 5 * 1e3, - }) - } -} -</script> - -<style> - -</style> diff --git a/grady/frontend/src/components/feedback_labels/FeedbackLabelList.vue b/grady/frontend/src/components/feedback_labels/FeedbackLabelList.vue deleted file mode 100644 index aad407c23efe7da70c5541401490b4c567de34ee..0000000000000000000000000000000000000000 --- a/grady/frontend/src/components/feedback_labels/FeedbackLabelList.vue +++ /dev/null @@ -1,36 +0,0 @@ -<template> - <div> - <div - v-for="label in labels" - :key="label.pk" - class="label" - > - <feedback-label - v-bind="label" - class="label" - /> - </div> - </div> -</template> - -<script lang="ts"> - -import FeedbackLabel from './FeedbackLabel.vue' -import { FeedbackLabels } from '@/store/modules/feedback-labels' - -export default { - components: { - FeedbackLabel - }, - computed: { - labels: () => { return FeedbackLabels.availableLabels }, - } -} -</script> - -<style scoped> -div.label { - display: inline-block; - margin: 0 8px 8px 0; -} -</style> diff --git a/grady/frontend/src/components/feedback_labels/FeedbackLabelTab.vue b/grady/frontend/src/components/feedback_labels/FeedbackLabelTab.vue deleted file mode 100644 index 93da029371763cc2983ee6fb96a7db62b4a1c5a4..0000000000000000000000000000000000000000 --- a/grady/frontend/src/components/feedback_labels/FeedbackLabelTab.vue +++ /dev/null @@ -1,115 +0,0 @@ -<template> - <v-card> - <v-toolbar - color="teal" - :dense="sidebar" - > - <v-app-bar-nav-icon> - <v-icon>label</v-icon> - </v-app-bar-nav-icon> - <v-toolbar-title - v-if="showDetail" - style="min-width: fit-content;" - > - Labels - </v-toolbar-title> - <v-spacer /> - <v-btn - icon - @click="refreshLabels" - > - <v-icon v-if="!updating"> - refresh - </v-icon> - <v-progress-circular - v-else - indeterminate - color="black" - size="20" - /> - </v-btn> - </v-toolbar> - <v-tabs - v-if="showDetail" - grow - color="black" - background-color="teal lighten-1" - > - <v-tab id="list-labels-section"> - List - </v-tab> - <v-tab id="create-label-section"> - Create - </v-tab> - <v-tab id="update-label-section"> - Update - </v-tab> - <v-tab-item> - <v-container> - <feedback-label-list /> - </v-container> - </v-tab-item> - <v-tab-item> - <v-container> - <feedback-label-form /> - </v-container> - </v-tab-item> - <v-tab-item> - <v-container> - <feedback-label-updater /> - </v-container> - </v-tab-item> - </v-tabs> - </v-card> -</template> - -<script lang="ts"> -import Vue from 'vue' -import Component from 'vue-class-component' -import { Prop } from 'vue-property-decorator' -import { getLabels } from '@/api' -import { FeedbackLabels } from '@/store/modules/feedback-labels' -import { UI } from '@/store/modules/ui' -import FeedbackLabelList from './FeedbackLabelList.vue' -import FeedbackLabelForm from './FeedbackLabelForm.vue' -import FeedbackLabelUpdater from './FeedbackLabelUpdater.vue' - -@Component({ - components: { - FeedbackLabelList, - FeedbackLabelForm, - FeedbackLabelUpdater, - } -}) -export default class FeedbackLabelsList extends Vue { - @Prop({type: Boolean, default: false}) sidebar!: boolean - - updating = false - timerId = -1 - - get showDetail () { - return !this.sidebar || (this.sidebar && !UI.state.sideBarCollapsed) - } - - // fetch labels once, then every 10 seconds - created () { - this.refreshLabels() - this.timerId = setInterval(this.refreshLabels, 10 * 1e3) - } - - destroyed () { - clearInterval(this.timerId) - } - - refreshLabels() { - this.updating = true - FeedbackLabels.getLabels().finally(() => { - this.updating = false - }) - } -} -</script> - -<style> - -</style> diff --git a/grady/frontend/src/components/feedback_labels/FeedbackLabelUpdater.vue b/grady/frontend/src/components/feedback_labels/FeedbackLabelUpdater.vue deleted file mode 100644 index b26e45af846c2da8ffa6408cc543ed42ede94ac6..0000000000000000000000000000000000000000 --- a/grady/frontend/src/components/feedback_labels/FeedbackLabelUpdater.vue +++ /dev/null @@ -1,70 +0,0 @@ -<template> - <div> - <v-autocomplete - id="label-update-autocomplete" - :items="feedbackLabels" - item-text="name" - item-value="pk" - append-icon="search" - placeholder="search for keywords" - @input="setLabel" - > - <template #item="{ item }"> - <div class="label-updater-item"> - <feedback-label-component v-bind="item" /> - </div> - </template> - </v-autocomplete> - <feedback-label-form - v-if="label.pk !== -1" - is_update - v-bind="currentLabel" - @label-updated="setLabel" - /> - </div> -</template> - -<script lang="ts"> -import Vue from 'vue' -import Component from 'vue-class-component' -import { FeedbackLabels } from '@/store/modules/feedback-labels' -import FeedbackLabelForm from './FeedbackLabelForm.vue' -import { FeedbackLabel } from '../../models' -import FeedbackLabelComponent from '@/components/feedback_labels/FeedbackLabel.vue' - -@Component({ - components: { - FeedbackLabelForm, - FeedbackLabelComponent, - } -}) -export default class FeedbackLabelUpdater extends Vue { - label: FeedbackLabel = { - pk: -1, - name: '', - description: '', - colour: '#4d4d4d', - } - loading = false - - get currentLabel () { return this.label } - - get feedbackLabels() { - return FeedbackLabels.availableLabels - } - - setLabel (pk: number) { - const label = this.feedbackLabels.find((val: FeedbackLabel) => { - return val.pk === pk - }) - - if (label !== undefined) { - this.label = label - } - } -} -</script> - -<style> - -</style> diff --git a/grady/frontend/src/components/feedback_labels/LabelSelector.vue b/grady/frontend/src/components/feedback_labels/LabelSelector.vue deleted file mode 100644 index ee88c72a0ce6dc6d2741dce543069b53c7bc241e..0000000000000000000000000000000000000000 --- a/grady/frontend/src/components/feedback_labels/LabelSelector.vue +++ /dev/null @@ -1,229 +0,0 @@ -<template> - <v-card> - <v-card-title>Assign labels</v-card-title> - <v-divider /> - <v-card-text> - <v-autocomplete - id="label-add-autocomplete" - :items="feedbackLabels" - item-text="name" - item-value="pk" - append-icon="search" - placeholder="search for keywords" - @keyup.enter.ctrl.exact="submitFeedback" - @input="addLabel" - > - <template #item="{ item }"> - <div class="label-adder-item"> - <feedback-label v-bind="item" /> - </div> - </template> - </v-autocomplete> - <v-row> - <v-col md="4"> - <div> - CURRENT LABELS - </div> - <feedback-label - v-for="label in unchangedMapped" - :key="label.pk" - removable - v-bind="label" - @remove-clicked="removeLabel" - /> - </v-col> - <v-col md="4"> - <div> - WILL BE REMOVED - </div> - <feedback-label - v-for="label in removedMapped" - :key="label.pk" - removable - v-bind="label" - @remove-clicked="addLabel" - /> - </v-col> - <v-col md="4"> - <div> - WILL BE ADDED - </div> - <feedback-label - v-for="label in addedMapped" - :key="label.pk" - removable - v-bind="label" - @remove-clicked="removeLabel" - /> - </v-col> - </v-row> - </v-card-text> - </v-card> -</template> - -<script lang="ts"> -import Vue from 'vue' -import Component from 'vue-class-component' -import { Prop } from 'vue-property-decorator' -import { FeedbackLabels } from '@/store/modules/feedback-labels' -import { SubmissionNotes } from '@/store/modules/submission-notes' -import FeedbackLabel from '@/components/feedback_labels/FeedbackLabel.vue' -import { FeedbackComment, SubmissionType } from '../../models' - -@Component({ - components: { - FeedbackLabel, - } -}) -export default class LabelSelector extends Vue { - @Prop({ type: String }) readonly lineNo!: string - @Prop({ type: Boolean, required: true }) readonly assignedToFeedback!: boolean - @Prop({ type: Array }) readonly labelsUnchanged!: number[] - @Prop({ type: Array }) readonly labelsAdded!: number[] - @Prop({ type: Array }) readonly labelsRemoved!: number[] - - get feedbackLabels () { - return FeedbackLabels.availableLabels - } - - get unchangedMapped() { - if (this.assignedToFeedback) { - return this.mapPksToLabelObj(this.unchangedFeedbackLabels()) - } else { - return this.mapPksToLabelObj(this.labelsUnchanged) - } - } - - get removedMapped() { - if (this.assignedToFeedback) { - return this.mapPksToLabelObj(this.removedFeedbackLabels()) - } else { - return this.mapPksToLabelObj(this.labelsRemoved) - } - } - - get addedMapped() { - if (this.assignedToFeedback) { - return this.mapPksToLabelObj(this.addedFeedbackLabels()) - } else { - return this.mapPksToLabelObj(this.labelsAdded) - } - } - - /** - * Returns an array of label pk's that have not changed from origFeedback to updatedFeedback - */ - unchangedFeedbackLabels() { - const labelsOrig = SubmissionNotes.state.origFeedback.labels - if (labelsOrig === undefined) return new Array() - - const labelsDeleted = this.removedFeedbackLabels() - const labelsAdded = this.addedFeedbackLabels() - - return labelsOrig.filter((label) => { - return !labelsAdded.includes(label) && !labelsDeleted.includes(label) - }) - } - - /** - * Returns an array of label pk's that have been removed in updatedFeedback - * but exist in origFeedback - */ - removedFeedbackLabels() { - if (!SubmissionNotes.state.changedLabels) return new Array() - - const labelsOrig = SubmissionNotes.state.origFeedback.labels - const labelsUpdated = SubmissionNotes.state.updatedFeedback.labels - - if (labelsOrig === undefined) return new Array() - - return labelsOrig.filter((label) => { - return !labelsUpdated.includes(label) - }) - } - - /** - * Returns an array of label pk's that have been added in updatedFeedback - * but do not exist in origFeedback - */ - addedFeedbackLabels() { - const labelsOrig = SubmissionNotes.state.origFeedback.labels - const labelsUpdated = SubmissionNotes.state.updatedFeedback.labels - - if (labelsOrig === undefined) return new Array() - - return labelsUpdated.filter((label) => { - return !labelsOrig.includes(label) - }) - } - - /** - * Maps label pk's to the objects stored in vuex store - */ - mapPksToLabelObj(pkArr: number[]): FeedbackLabel[] { - const mappedLabels = pkArr.map((val) => { - const label = FeedbackLabels.availableLabels.find((label) => { - return label.pk === val - }) - - if (!label) return - return { - pk: val, - name: label.name, - description: label.description, - colour: label.colour - } - }) - - return mappedLabels ? mappedLabels : new Array() - } - - /** - * Removes given label from the feedback or fires an event - * to remove the label from a comment - */ - removeLabel(pk: number) { - if (this.assignedToFeedback) { - if (!SubmissionNotes.state.changedLabels) { - SubmissionNotes.SET_FEEDBACK_LABELS([...SubmissionNotes.state.origFeedback.labels]) - } - - SubmissionNotes.REMOVE_FEEDBACK_LABEL(pk) - } else { - this.$emit('label-removed', pk) - } - } - - /** - * Adds the given label to the feedback or fires an event - * to add the label to a comment - * Calling this with an already added label will instead remove the label - */ - addLabel(pk: number) { - if (this.assignedToFeedback) { - if (!this.unchangedFeedbackLabels().includes(pk) && - !this.addedFeedbackLabels().includes(pk)) - { - if (!SubmissionNotes.state.changedLabels) { - SubmissionNotes.SET_FEEDBACK_LABELS([...SubmissionNotes.state.origFeedback.labels]) - } - - SubmissionNotes.ADD_FEEDBACK_LABEL(pk) - } - } else { - this.$emit('label-added', pk) - } - } - - /** - * Emits an event which tells the parent that - * the submit shortcut was pressed - */ - submitFeedback() { - this.$emit('submit-shortcut') - } -} -</script> - -<style> -</style> diff --git a/grady/frontend/src/components/feedback_list/FeedbackListHelpCard.vue b/grady/frontend/src/components/feedback_list/FeedbackListHelpCard.vue deleted file mode 100644 index 7487e5bc59c2e329686d128595d901fce777200e..0000000000000000000000000000000000000000 --- a/grady/frontend/src/components/feedback_list/FeedbackListHelpCard.vue +++ /dev/null @@ -1,58 +0,0 @@ -<template> - <v-row justify="center"> - <v-card - v-if="isReviewer" - class="mt-5" - > - <v-card-title class="title"> - This is the history of all the feedback! - </v-card-title> - <v-card-text> - To the left you see all the submissions everyone corrected including the score, final status, etc. You can do the following:<br><br> - <ol style="padding-left: 30px;"> - <li>click on one of the rows to see the submission, including the feedback.</li> - <li>sort the table via clicking on the table headers</li> - <li> - search the type names and also the <b>content</b> of the feedback that was written<br> - (e.g. you're looking for a feedback where someone mentioned a segmentation fault, just type it into the search!) - </li> - <li>filter by assigned labels</li> - <li>filter by the tutors that worked on a submission</li> - </ol> - </v-card-text> - </v-card> - <v-card v-else> - <v-card-title class="title"> - This is the history of your feedback! - </v-card-title> - <v-card-text> - To the left you see all the submissions you've corrected including the score, final status, etc. You can do the following:<br><br> - <ol style="padding-left: 30px;"> - <li>click on one of the rows tp see the submission, including your feedback and potentially a second tutor's feedback.</li> - <li>sort the table via clicking on the table headers</li> - <li> - search the type names and also the <b>content</b> of the feedback that you wrote<br> - (e.g. you're looking for a feedback where you mentioned a segmentation fault, just type it into the search!) - </li> - </ol> - </v-card-text> - </v-card> - </v-row> -</template> - -<script lang="ts"> -import Vue from 'vue' -import Component from 'vue-class-component' -import { Authentication } from '../../store/modules/authentication' - -@Component -export default class FeedbackListHelpCard extends Vue { - get isReviewer () { - return Authentication.isReviewer - } -} -</script> - -<style scoped> - -</style> diff --git a/grady/frontend/src/components/feedback_list/FeedbackSearchOptions.vue b/grady/frontend/src/components/feedback_list/FeedbackSearchOptions.vue deleted file mode 100644 index 8d518bc6a62b219f8d3d3e04f41745d807ca7663..0000000000000000000000000000000000000000 --- a/grady/frontend/src/components/feedback_list/FeedbackSearchOptions.vue +++ /dev/null @@ -1,192 +0,0 @@ -<template> - <v-container class="pt-0"> - <v-row> - <v-col class="py-0"> - <v-text-field - v-model="model.searchString" - append-icon="search" - label="Search" - single-line - hide-details - class="py-0 my-0" - @input="$emit('input', model)" - /> - </v-col> - </v-row> - <v-row> - <v-col class="pt-0"> - <v-checkbox - id="show-final-checkbox" - v-model="model.showFinal" - label="show final" - hide-details - @click="$emit('input', model)" - /> - </v-col> - <v-col class="pt-0"> - <v-checkbox - v-model="model.caseSensitive" - label="case sensitive" - hide-details - @click="$emit('input', model)" - /> - </v-col> - <v-col class="pt-0"> - <v-checkbox - v-model="model.useRegex" - hide-details - @click="$emit('input', model)" - > - <template #label> - use RegEx - <v-tooltip top> - <template #activator="{ on }"> - <a - href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp#character-classes" - target="_blank" - v-on="on" - > - <v-icon>help</v-icon> - </a> - </template> - <span>Go to RegEx documentation</span> - </v-tooltip> - </template> - </v-checkbox> - </v-col> - </v-row> - <v-row> - <v-col> - <v-select - v-model="model.filterByLabels" - label="Label" - :items="labels" - return-object - item-text="name" - multiple - hint="Filter by label" - persistent-hint - clearable - @change="$emit('input', model)" - /> - </v-col> - <v-col> - <v-select - v-model="model.filterByExcludingLabels" - label="Exclude label" - :items="labels" - item-text="name" - return-object - multiple - hint="Filter by excluding labels" - persistent-hint - clearable - @change="$emit('input', model)" - /> - </v-col> - </v-row> - <v-row> - <v-col - v-if="isReviewer" - md="6" - > - <v-select - v-model="model.filterByTutors" - label="Tutors" - :items="tutors" - item-text="username" - return-object - multiple - hint="Filter by tutors" - persistent-hint - clearable - @change="$emit('input', model)" - /> - </v-col> - <v-col - v-if="model.filterByTutors.length > 0" - md="6" - > - <v-select - v-model="model.filterByStage" - label="Stage" - :items="feedbackStages" - placeholder="All" - hint="Filter after initial feedback or validated" - persistent-hint - clearable - @change="$emit('input', model)" - /> - </v-col> - </v-row> - </v-container> -</template> - -<script lang="ts"> -import Vue, { PropType } from 'vue' -import Component from 'vue-class-component' -import { Authentication } from '@/store/modules/authentication' -import { TutorOverview } from '@/store/modules/tutor-overview' -import { FeedbackLabels } from '@/store/modules/feedback-labels' -import { Tutor, FeedbackLabel, FeedbackStageEnum, Exam } from '@/models' - -export type FeedbackSearchOptionsModel = { - searchString: string, - showFinal: boolean, - caseSensitive: boolean, - useRegex: boolean, - filterByExams: Exam[], - filterByTutors: Tutor[], - filterByStage: FeedbackStageEnum | undefined, - filterByLabels: FeedbackLabel[], - filterByExcludingLabels: FeedbackLabel[], -} - -const FeedbackSearchOptionsProps = Vue.extend({ - props: { - model: { - type: Object as PropType<FeedbackSearchOptionsModel>, - default: () => { - return { - searchString: '', - showFinal: true, - caseSensitive: false, - useRegex: false, - filterByExams: [], - filterByTutors: [], - filterByStage: undefined, - filterByLabels: [], - filterByExcludingLabels: [], - } - } - } - } -}) - -@Component -export default class FeedbackSearchOptions extends FeedbackSearchOptionsProps { - feedbackStages = Object.entries(FeedbackStageEnum).map(([key, value]) => ({text: key, value})) - - get tutors() { return TutorOverview.state.tutors } - get isReviewer() { return Authentication.isReviewer } - - get labels() { - return FeedbackLabels.state.labels - } - - loadTutors() { - if (this.tutors.length === 0 && this.isReviewer) { - TutorOverview.getTutors() - } - } - - created () { - this.loadTutors() - } -} -</script> - -<style scoped> - -</style> - diff --git a/grady/frontend/src/components/feedback_list/FeedbackTable.vue b/grady/frontend/src/components/feedback_list/FeedbackTable.vue deleted file mode 100644 index 311d6273bf3e83347da858f803d8ecf3e5aced85..0000000000000000000000000000000000000000 --- a/grady/frontend/src/components/feedback_list/FeedbackTable.vue +++ /dev/null @@ -1,203 +0,0 @@ -<template> - <v-card> - <v-card-title class="title"> - <span v-if="isTutor">Your</span><span>All</span> feedback history - </v-card-title> - <v-data-table - :headers="headers" - :items="filteredFeedback" - sort-by="student" - > - <template #top> - <feedback-search-options - v-model="searchOptions" - /> - </template> - <template #item="{ item }"> - <tr - class="feedback-row" - @click="showSubmission(item)" - > - <td>{{ item.ofSubmissionType.name }}</td> - <td v-if="exerciseMode"> - {{ item.ofStudent }} - </td> - <td>{{ item.score }}</td> - <td>{{ new Date(item.created).toLocaleString() }}</td> - <td>{{ new Date(item.modified).toLocaleString() }}</td> - <td> - <v-icon v-if="item.isFinal"> - check - </v-icon> - <v-icon v-else> - clear - </v-icon> - </td> - <td> - <v-btn - icon - :color="item.mark" - @click="changeMark(item.ofSubmission, item.mark)" - /> - </td> - </tr> - </template> - </v-data-table> - </v-card> -</template> - -<script lang="ts"> -import Vue from 'vue' -import { mapState, mapGetters } from 'vuex' -import Component from 'vue-class-component' -import { getObjectValueByPath } from '@/util/helpers' -import FeedbackSearchOptions, { FeedbackSearchOptionsModel } from '@/components/feedback_list/FeedbackSearchOptions.vue' -import { FeedbackTable as FeedbackModule, FeedbackHistoryItem } from '@/store/modules/feedback_list/feedback-table' -import { FeedbackStageEnum, Feedback, FeedbackLabel } from '@/models' -import { actions } from '@/store/actions' -import { getters } from '@/store/getters' -import { Authentication } from '../../store/modules/authentication' -import { ConfigModule } from '../../store/modules/config' -import SubmissionType from '../submission_type/SubmissionType.vue' -import ax, { fetchSubmissionType } from '@/api' -import { SubmissionNotes } from '@/store/modules/submission-notes' - -function extractLabelsFromFeedback(feedback: FeedbackHistoryItem): Set<number> { - let labels: Set<number> = new Set(feedback.labels) - - Object.values(feedback.feedbackLines || {}).forEach(comments => { - comments.forEach(comment => { - if (!comment.visibleToStudent) { - return - } - comment.labels.forEach(label => { - labels.add(label) - }) - }) - }) - - return labels -} - -@Component({ - components: { - FeedbackSearchOptions - } -}) -export default class FeedbackTable extends Vue { - get isTutor () { return Authentication.isTutor } - get exerciseMode () { return ConfigModule.state.config.instanceSettings.exerciseMode } - - get headers(): {text: string, value: string, align?: string}[] { - return [ - { text: 'Type', align: 'left', value: 'ofSubmissionType.name' }, - ...(this.exerciseMode ? [{ text: 'Student', value: 'ofStudent' }] : []), - { text: 'score', value: 'score' }, - { text: 'Created', value: 'created' }, - { text: 'Modified', value: 'modified', }, - { text: 'Final', value: 'final' }, - { text: 'Mark', value: 'mark' } - ] - } - - get feedback () { - return Object.values(FeedbackModule.state.feedbackHist) - } - - searchOptions: FeedbackSearchOptionsModel = { - searchString: '', - showFinal: true, - caseSensitive: false, - useRegex: false, - filterByExams: [], - filterByTutors: [], - filterByStage: undefined, - filterByLabels: [], - filterByExcludingLabels: [], - } - - get queryFoundInString(): (s: string) => boolean { - if (this.searchOptions.useRegex) { - const flags = this.searchOptions.caseSensitive ? 'u' : 'iu' - try { - const re = new RegExp(this.searchOptions.searchString , flags) - return s => re.test(s) - } catch { - return _ => true - } - } else { - if (this.searchOptions.caseSensitive) - return s => s.includes(this.searchOptions.searchString) - else - return s => s.toLowerCase().includes(this.searchOptions.searchString.toLowerCase()) - } - } - - queryFoundInFields(f: Feedback): boolean { - return f.ofSubmissionType.name !== undefined && this.queryFoundInString(f.ofSubmissionType.name) || - f.created !== undefined && this.queryFoundInString(f.created) || - f.modified !== undefined && this.queryFoundInString(f.modified) - } - - queryFoundInComments(feedback: Feedback): boolean { - return Object.values(feedback.feedbackLines ?? {}) - .some(line => line.map(comment => comment.text).some(this.queryFoundInString)) - } - - allLabelsFromFilterFoundOn(f: Feedback): boolean { - const fLabels = extractLabelsFromFeedback(f) - return this.searchOptions.filterByLabels.every(l => fLabels.has(l.pk)) - } - - noExcludedLabelFoundOn(f: Feedback): boolean { - const fLabels = extractLabelsFromFeedback(f) - return this.searchOptions.filterByExcludingLabels.every(l => !fLabels.has(l.pk)) - } - - // TODO: it is possible that a user is not assigned to the feedback, but still made a comment on it - // this happens when a reviewer adds a comment to a feedback that he has never corrected himself - // we could either ignore this case or add every user that has made a comment to a feedback - // to the list of associated users in the filteredTutorsContributedToFeedback method - - filteredTutorsContributedToFeedback(f: FeedbackHistoryItem): boolean { - if (this.searchOptions.filterByTutors.length === 0) - return true - - const stages = this.searchOptions.filterByStage ? [this.searchOptions.filterByStage] - : Object.values(FeedbackStageEnum) - const associatedTutors = stages.map(stage => f.history?.[stage]?.ofTutor).filter(x => !!x) - return this.searchOptions.filterByTutors.some(tutor => associatedTutors.includes(tutor.username)) - } - - feedbackIsForCurrentExam(f: Feedback): boolean { - return f.ofSubmissionType.examType.moduleReference === ConfigModule.state.config.currentExam - } - - get filteredFeedback() { - return this.feedback.filter(f => { - return (!f.isFinal || this.searchOptions.showFinal) && - (this.queryFoundInFields(f) || this.queryFoundInComments(f)) && - this.feedbackIsForCurrentExam(f) && - this.allLabelsFromFilterFoundOn(f) && - this.noExcludedLabelFoundOn(f) && - this.filteredTutorsContributedToFeedback(f) - }) - } - - showSubmission (feedback: Feedback) { - this.$router.push(`/feedback/${feedback.ofSubmission}`) - } - - changeMark(submissionPk: string, currColor: string) { - const colorArr = ['red lighten-2', 'blue lighten-2', 'green lighten-2', 'transparent'] - const newColor = colorArr[(colorArr.indexOf(currColor) + 1) % colorArr.length] - FeedbackModule.SET_MARK_COLOR({submissionPk, color: newColor}) - } -} -</script> - -<style scoped> - .feedback-row { - cursor: pointer; - } -</style> diff --git a/grady/frontend/src/components/instance_config/ConfigDialog.vue b/grady/frontend/src/components/instance_config/ConfigDialog.vue deleted file mode 100644 index 414f270b9f0e6efe84890c4014f6923a17884fef..0000000000000000000000000000000000000000 --- a/grady/frontend/src/components/instance_config/ConfigDialog.vue +++ /dev/null @@ -1,110 +0,0 @@ -<template> - <v-dialog - v-model="show" - width="50%" - > - <v-card> - <v-card-title class="title"> - Configure instance - </v-card-title> - <v-card-text> - <div> - In this section you can configure the running instance. - Any changes you make are immediately applied, but it is required that every user - logs out and in again to make sure that all users receive the new configuration. - </div> - <v-row> - <v-col - v-for="(setting, i) in Object.keys(instanceSettings)" - :key="i" - cols="6" - > - <v-checkbox - v-model="selected" - :label="snakeUpperCaseSetting(setting)" - :value="setting" - /> - </v-col> - </v-row> - </v-card-text> - <v-card-actions> - <v-btn - color="red" - @click="$emit('hide')" - > - Cancel - </v-btn> - <v-btn - @click="submitChange" - > - Change settings - </v-btn> - </v-card-actions> - </v-card> - </v-dialog> -</template> - -<script> -import { ConfigModule } from '@/store/modules/config' -import * as api from '@/api' - -export default { - name: 'ConfigDialog', - data() { - return { - loading: true, - show: true, - selected: [], - - // config fields that should be ignored entirely go here - ignoredFields: ['registrationPassword'] - } - }, - computed: { - instanceSettings: function () { - const filtered = Object.entries(ConfigModule.state.config.instanceSettings) - .filter(([key,]) => !this.ignoredFields.includes(key)) - return Object.fromEntries(filtered) - }, - }, - watch: { - show (val) { - if (!val) { - this.$emit('hide') - } - } - }, - mounted() { - ConfigModule.getConfig().then(() => { - this.loading = false - this.selected = Object.entries(this.instanceSettings) - .filter(([key, value]) => value) - .map(([key, value]) => key) - }) - }, - methods: { - submitChange() { - let conf = {} - - // initially set all settings to false, then set selected ones to true - for (const cur of Object.keys(this.instanceSettings)) { - conf = {...conf, [cur]: false} - } - for (const cur of this.selected) { - conf = {...conf, [cur]: true} - } - - this.$emit('hide') - api.patchInstanceSettings(conf) - ConfigModule.getConfig() - }, - snakeUpperCaseSetting(setting) { - // converts given string to from camelCase to uppercase snake case - return setting.split('').reduce((acc, curr) => { - return curr === curr.toUpperCase() ? acc + '_' + curr : acc + curr - }).toUpperCase() - } - } - -} -</script> diff --git a/grady/frontend/src/components/mixins/commentLabelSelector.ts b/grady/frontend/src/components/mixins/commentLabelSelector.ts deleted file mode 100644 index b37a2761289dd0293178d25c0fd9139766216e09..0000000000000000000000000000000000000000 --- a/grady/frontend/src/components/mixins/commentLabelSelector.ts +++ /dev/null @@ -1,132 +0,0 @@ -import Vue from 'vue' -import Component from 'vue-class-component' -import { Prop } from 'vue-property-decorator' -import { SubmissionNotes } from '@/store/modules/submission-notes' -import { FeedbackComment, FeedbackLabel } from '@/models' -import { FeedbackLabels } from '@/store/modules/feedback-labels' - -enum FeedbackType { - original = 'origFeedback', - updated = 'updatedFeedback', -} - -@Component -export default class commentLabelSelector extends Vue { - @Prop({ type: String, required: true }) readonly lineNo!: string - - /** - * Returns array of label pk's where feedbackType is - * either "origFeedback" or "updatedFeedback" - * - * Will return null when labels property does not exist on the requested state's comment - * This is the case when the labels have not been updated, as we don't want to have - * the labels field in the object if the labels have not changed. - */ - copyStateLabels(feedbackType: FeedbackType): number[] | null { - const currentLine = this.getFeedbackLine(feedbackType) - if (currentLine && currentLine.labels) { - return currentLine.labels - } else { - return null - } - } - - /** - * Gets the latest feedback line object for the current lineNo and the given feedbackType - * @param feedbackType The type to get the latest line from - */ - getFeedbackLine (feedbackType: FeedbackType): FeedbackComment | undefined { - - // helper used to determine the correct type to reduce redundancy - function isArray(val: FeedbackComment | FeedbackComment[]): val is FeedbackComment[] { - return (val as FeedbackComment[]).length !== undefined - } - - const stateLines = SubmissionNotes.state[feedbackType].feedbackLines - if (stateLines && Object.keys(stateLines).length > 0) { - let lines = stateLines[Number(this.lineNo)] - if (!lines) return undefined - - if (isArray(lines)) { - return lines.length > 0 ? lines[lines.length-1] : undefined - } else { - return lines - } - } - - return undefined - } - - getUnchangedLabels() { - const labelsOrig = this.copyStateLabels(FeedbackType.original) - if (labelsOrig === null || labelsOrig.length === 0) { - return new Array () - } - const removedLabels = this.getRemovedLabels() - const addedLabels = this.getAddedLabels() - - return labelsOrig.filter((val) => { - return !removedLabels.includes(val) && !addedLabels.includes(val) - }) - } - - getRemovedLabels() { - const currentLine = this.getFeedbackLine(FeedbackType.updated) - if (currentLine === undefined) return new Array() - - const labelsOrig = this.copyStateLabels(FeedbackType.original) - const labelsUpdated = this.copyStateLabels(FeedbackType.updated) - - if (labelsOrig === null || labelsUpdated === null) { - return new Array() - } - - return labelsOrig.filter((val) => { - return !labelsUpdated.includes(val) - }) - } - - getAddedLabels() { - const labelsOrig = this.copyStateLabels(FeedbackType.original) - const labelsUpdated = this.copyStateLabels(FeedbackType.updated) - - if (labelsUpdated === null) { - return new Array() - } - - if (labelsOrig === null) { - return labelsUpdated ? labelsUpdated : new Array() - } - - return labelsUpdated.filter((val) => { - return !labelsOrig.includes(val) - }) - } - - /** - * Maps label pk's to the objects stored in vuex store - */ - mapPksToLabelObj(pkArr: number[]): FeedbackLabel[] { - const mappedLabels = pkArr.map((val) => { - const label = FeedbackLabels.availableLabels.find((label) => { - return label.pk === val - }) - - if (!label) return undefined - return { - pk: val, - name: label.name, - description: label.description, - colour: label.colour - } - }).filter((val): val is FeedbackLabel => { - if (!val) { - return false - } - - return true - }) - - return mappedLabels - } -} diff --git a/grady/frontend/src/components/mixins/exportMixin.ts b/grady/frontend/src/components/mixins/exportMixin.ts deleted file mode 100644 index b68131f1929d5f404ea4b4b73f63f31b75fc60ff..0000000000000000000000000000000000000000 --- a/grady/frontend/src/components/mixins/exportMixin.ts +++ /dev/null @@ -1,100 +0,0 @@ -import Vue from 'vue' -import Component, { mixins } from 'vue-class-component' -import { fetchStudentExportData, StudentExportItem, InstanceExportData, fetchInstanceExportData } from '@/api' -import { getters } from '@/store/getters' -import { mutations as mut } from '@/store/mutations' -import { saveAs } from 'file-saver' - -let download = saveAs - -export enum ExportType { - JSON = 'application/json', -} - -export function mock(mockedDownload?: () => boolean) { - download = mockedDownload || saveAs -} - -@Component -export class exportMixin extends Vue { - exportDialog = true - mapFile: File | null = null - setPasswords = false - exportType = ExportType.JSON - loading = false - - get mapFileLoaded () { - return Object.keys(getters.state.studentMap).length > 0 - } - - async getExportFile (type: string) { - this.loading = true - - let studentData - if (type === 'data') { - studentData = await fetchStudentExportData({ setPasswords: this.setPasswords }) - } else if (type === 'instance') { - studentData = await fetchInstanceExportData() - } else { - throw new Error('Unsupported export type') - } - - if (this.mapFile || this.mapFileLoaded) { - this.getMappedExportFile(studentData) - } else { - this.optionalConvertAndCreatePopup(studentData) - } - } - - optionalConvertAndCreatePopup (studentData: StudentExportItem[] | InstanceExportData) { - const convertedData = JSON.stringify(studentData) - const filename = 'export.json' - download(new Blob([convertedData], { type: this.exportType }), filename) - this.loading = false - } - - async getMappedExportFile (studentData: StudentExportItem[] | InstanceExportData) { - if (!this.mapFile && !this.mapFileLoaded) { - throw new Error('Either mapFile must be selected or already loaded ' + - 'to call getMappedExportFile') - } - if (this.mapFile) { - await this.readMapFileAndCommit() - } - this.applyMapping(studentData) - this.optionalConvertAndCreatePopup(studentData) - } - - readMapFileAndCommit (): Promise<void> { - const fileReader = new FileReader() - return new Promise((resolve, reject) => { - fileReader.onload = event => { - // @ts-ignore typings of EventTarget seem to be wrong - const studentMap = JSON.parse(event.target.result) - mut.SET_STUDENT_MAP(studentMap) - resolve() - } - fileReader.onerror = () => { - fileReader.abort() - reject(new Error('Problem parsing input file.')) - } - - if (!this.mapFile) { - reject(new Error('Can only call' + - ' readMapFileAndCommit when mapFile is not undefined')) - } else { - fileReader.readAsText(this.mapFile) - } - }) - } - - hide () { - this.$emit('hide') - } - - showDialog () { - this.exportDialog = true - } - - applyMapping (exportData: StudentExportItem[] | InstanceExportData): void { throw new Error('Not implemented.') } -} diff --git a/grady/frontend/src/components/student/ExamInformation.vue b/grady/frontend/src/components/student/ExamInformation.vue deleted file mode 100644 index d1448b08964b828ae1cdae6b9df260651889306f..0000000000000000000000000000000000000000 --- a/grady/frontend/src/components/student/ExamInformation.vue +++ /dev/null @@ -1,40 +0,0 @@ -<template> - <table class="table table-info rounded exam-table"> - <tbody v-if="!exam"> - No exam information present - </tbody> - <tbody v-else> - <tr> - <th>Module</th> - <td>{{ exam.moduleReference }}</td> - </tr> - <tr> - <th>Pass score</th> - <td>{{ exam.passScore }}</td> - </tr> - <tr v-if="exam.passOnly"> - <th>Pass only exam!</th> - </tr> - <tr> - <th>Total score</th> - <td>{{ exam.totalScore }}</td> - </tr> - </tbody> - </table> -</template> - -<script lang="ts"> -import { Vue, Component, Prop } from 'vue-property-decorator' -import { Exam } from '@/models' - -@Component -export default class ExamInformation extends Vue { - @Prop(Object) exam!: Exam -} -</script> - -<style> -.exam-table { - width: 100% -} -</style> diff --git a/grady/frontend/src/components/student/SubmissionList.vue b/grady/frontend/src/components/student/SubmissionList.vue deleted file mode 100644 index 00615c7ac52070b8c82ddfc3a5c3303147c48714..0000000000000000000000000000000000000000 --- a/grady/frontend/src/components/student/SubmissionList.vue +++ /dev/null @@ -1,76 +0,0 @@ -<template> - <div class="row my-2 justify-content-center"> - <v-data-table - hide-default-footer - :headers="headers" - :items="submissions" - item-key="type.pk" - > - <template #item.feedback.score="{ item }"> - {{ item.feedback ? item.feedback.score : 'N/A' }} - </template> - <template #item.view="{ item }"> - <v-btn - :to="`/submission/${item.type.pk}`" - color="orange lighten-2" - > - <v-icon>chevron_right</v-icon> - </v-btn> - </template> - </v-data-table> - <v-alert color="info"> - You reached <b>{{ sumScore }}</b> of <b>{{ sumFullScore }}</b> possible points ({{ pointRatio }}%). - </v-alert> - </div> -</template> - -<script> -export default { - name: 'SubmissionList', - props: { - submissions: { - type: Array, - required: true - } - }, - data () { - return { - headers: [ - { - text: 'Task', - align: 'left', - value: 'type.name', - sortable: true - }, - { - text: 'Score', - align: 'right', - value: 'feedback.score' - }, - { - text: 'Maximum Score', - align: 'right', - value: 'type.fullScore' - }, - { - text: 'View', - align: 'center', - value: 'view', - sortable: false - } - ] - } - }, - computed: { - sumScore () { - return this.submissions.map(a => a.feedback && a.feedback.score).reduce((a, b) => a + b) || 0 - }, - sumFullScore () { - return this.submissions.map(a => a.type.fullScore).reduce((a, b) => a + b) - }, - pointRatio () { - return ((this.sumScore / this.sumFullScore) * 100).toFixed(2) - } - } -} -</script> diff --git a/grady/frontend/src/components/student_list/StudentList.vue b/grady/frontend/src/components/student_list/StudentList.vue deleted file mode 100644 index 40f8fcc45b0fc523faed16137ba9bcc3c21d2f85..0000000000000000000000000000000000000000 --- a/grady/frontend/src/components/student_list/StudentList.vue +++ /dev/null @@ -1,324 +0,0 @@ -<template> - <v-card> - <v-toolbar flat> - <v-toolbar-title> - Participants - </v-toolbar-title> - <v-spacer /> - <v-toolbar-items /> - <v-select - v-model="selectedGroup" - :items="groups" - item-text="name" - label="Group" - single-line - return-object - hide-details - clearable - flat - class="mr-6" - /> - <v-text-field - v-model="search" - append-icon="search" - label="Search" - single-line - hide-details - class="mr-6" - /> - <student-list-reverse-mapper /> - <v-btn - icon - @click="refresh" - > - <v-icon>refresh</v-icon> - </v-btn> - <student-list-menu /> - </v-toolbar> - <v-divider /> - <v-data-table - :headers="headers" - :items="studentListItems" - :search="search" - sort-by="name" - :loading="loading" - item-key="name" - show-expand - must-sort - > - <template #item="{ expand, isExpanded, item }"> - <tr> - <td> - <v-btn - small - icon - @click="expand(!isExpanded)" - > - <v-icon v-if="isExpanded"> - keyboard_arrow_up - </v-icon> - <v-icon v-else> - keyboard_arrow_down - </v-icon> - </v-btn> - </td> - <td> - {{ item.name }} - </td> - <td> - <v-tooltip top> - <template #activator="{ on }"> - <div v-on="on"> - <v-icon - v-if="item.isActive" - small - > - lock_open - </v-icon> - <v-icon - v-else - small - > - lock - </v-icon> - </div> - </template> - <span v-if="!item.isActive">Participant doesn't have access.</span> - <span v-else>Participant has access.</span> - </v-tooltip> - </td> - <td - v-for="type in submissionTypeHeaders" - :key="type.pk" - class="text-right" - > - <v-btn - v-if="item[type.pk]" - small - rounded - outlined - class="submission-button" - exact - :to="{name: 'submission-side-view', params: { - studentPk: item.pk, - submissionPk: item[type.pk].pk - }}" - :color="item[type.pk].final ? 'green darken-2' : 'grey'" - @click="showSubmissionDetails" - > - {{ item[type.pk].score }} - </v-btn> - <span v-else>N.A</span> - </td> - <td class="text-right"> - {{ item.total }} - </td> - </tr> - </template> - <template #expanded-item="{ headers, item }"> - <td :colspan="headers.length"> - <v-btn - v-if="isReviever" - @click="changeActiveStatus(item)" - > - {{ item.isActive ? 'Revoke access' : 'Grant access' }} - </v-btn> - <ul class="student-info-list"> - <li> - <b>Modul:</b> {{ item.exam }} - </li> - <li> - <b>MatrikelNr:</b> {{ item.matrikelNo }} - </li> - </ul> - </td> - </template> - </v-data-table> - </v-card> -</template> - -<script> -import { mapActions, mapState } from 'vuex' -import StudentListMenu from '@/components/student_list/StudentListMenu' -import StudentListReverseMapper from '@/components/student_list/StudentListReverseMapper' -import { changeActiveForUser, fetchUser } from '@/api' -import { getters } from '@/store/getters' -import { Authentication } from '@/store/modules/authentication' -import { ConfigModule } from '../../store/modules/config' -import * as api from '@/api' -import { Assignments } from '@/store/modules/assignments' - - -export default { - name: 'StudentList', - components: { - StudentListReverseMapper, - StudentListMenu }, - data () { - return { - loading: true, - search: '', - selectedGroup: null, - userData: [], - userMap: null - } - }, - computed: { - ...mapState([ - 'students' - ]), - isReviever() { - return Authentication.isReviewer - }, - submissionTypeHeaders () { - const subTypes = Object.values(getters.state.submissionTypes) - return subTypes - .filter(submissionType => { - return submissionType.examType.moduleReference === ConfigModule.state.config.currentExam - }) - .sort((a, b) => a.name.localeCompare(b.name)) - .map(type => { - return { - pk: type.pk, - text: type.name.substr(0, 5), - value: `${type.pk}.score`, - align: 'right' - } - }) - }, - headers () { - return [ - { - text: 'Name', - align: 'left', - value: 'name', - }, - { - text: 'Has Access', - align: 'left', - value: 'isActive', - }, - ...this.submissionTypeHeaders, - { - text: 'Total', - align: 'right', - value: 'total', - }, - ] - }, - studentListItems () { - if (!this.loading) { - let filteredStudents = this.students - if (this.selectedGroup !== null) { - filteredStudents = Object.values(filteredStudents).filter(student => { - let userGroups = this.userMap.get(student.userPk) - return userGroups.some(group => group.pk === this.selectedGroup.pk) - }) - } - return Object.values(filteredStudents).map(student => { - return { - pk: student.pk, - user: student.user, - userPk: student.userPk, - exam: student.exam, - name: student.name, - isActive: student.isActive, - matrikelNo: student.matrikelNo, - ...this.reduceArrToDict(student.submissions, 'type'), - total: this.sumSubmissionScores(student.submissions) - } - }) - } - - return [] - }, - groups () { - if (Authentication.isTutor) { - return Authentication.state.user.exerciseGroups.filter( group => { - return group.exam === null || group.exam.pk === ConfigModule.state.config.examId - }) - } - else if (Authentication.isReviewer) { - return Assignments.state.groups.filter( group => { - return group.exam === null || group.exam.pk === ConfigModule.state.config.examId - }) - } - else { - return [] - } - }, - }, - created () { - this.getUserData() - this.getStudents().then(() => { this.loading = false }) - const groups = Assignments.getGroups() - }, - methods: { - ...mapActions([ - 'getStudents' - ]), - reduceArrToDict (arr, key) { - return arr.reduce((acc, curr) => { - const keyInDict = curr[key] - acc[keyInDict] = curr - return acc - }, {}) - }, - changeActiveStatus (student) { - changeActiveForUser(student.userPk, !student.isActive).then(() => { - this.getStudents({ studentPks: [student.pk] }) - }).catch(() => { - this.$notify({ - title: 'Error', - text: `Unable to change active status of ${student.user}`, - type: 'error' - }) - }) - }, - sumSubmissionScores (submissions) { - submissions = submissions.filter(submission => { - var subType = Object.values(getters.state.submissionTypes).filter(submissionType => { - return submissionType.pk === submission.type - })[0] - return subType.examType.moduleReference === ConfigModule.state.config.currentExam - }) - return submissions.reduce((acc, curr) => { - if (curr.score) { - acc += curr.score - } - return acc - }, 0) - }, - refresh (opts = { silent: false }) { - if (!opts.silent) { - this.loading = true - } - this.getStudents().then(() => { this.loading = false }) - }, - showSubmissionDetails () { - this.$emit('detail-click') - }, - async getUserData() { - this.userMap = new Map() - this.userData = await api.fetchUsers() - var that = this // javascript this is not the same in forEach - this.userData.forEach(user => { - that.userMap.set(user.pk, user.exerciseGroups) - }) - } - }, -} -</script> - -<style scoped> - .submission-button { - min-width: 40px; - } - .student-info-list li { - display: inline; - margin-right: 20px; - } - .student-info-list { - display: inline; - } -</style> diff --git a/grady/frontend/src/components/student_list/StudentListHelpCard.vue b/grady/frontend/src/components/student_list/StudentListHelpCard.vue deleted file mode 100644 index a676d9c0fc1bdbfae95d62f5ddae1046b9e335d2..0000000000000000000000000000000000000000 --- a/grady/frontend/src/components/student_list/StudentListHelpCard.vue +++ /dev/null @@ -1,31 +0,0 @@ -<template> - <v-row justify="center"> - <v-card class="mt-5"> - <v-card-title class="title"> - This is the student overview page! - </v-card-title> - <v-card-text> - To the left you see all students as well as their scores - per task type. You can do the following:<br><br> - <ol style="padding-left: 30px;"> - <li>click the little arrow on the left to see additional student information (matrikel no., module, etc.)</li> - <li>click on a students score to see their submission including feedback, tests, etc.<br>(You can even create Feedback here!)</li> - <li>sort the table via clicking on the table headers</li> - <li>search for a student via the search bar</li> - </ol> - </v-card-text> - </v-card> - </v-row> -</template> - -<script> -export default { - name: 'StudentListHelpCard' -} -</script> - -<style scoped> - /* .mg-bottom { - margin-bottom: 25px; - } */ -</style> diff --git a/grady/frontend/src/components/student_list/StudentListMenu.vue b/grady/frontend/src/components/student_list/StudentListMenu.vue deleted file mode 100644 index e528cc9870b06c33fcbda3a658d5e7ab01b8a201..0000000000000000000000000000000000000000 --- a/grady/frontend/src/components/student_list/StudentListMenu.vue +++ /dev/null @@ -1,94 +0,0 @@ -<template> - <v-menu - v-if="isReviewer" - open-on-hover - bottom - offset-y - > - <template #activator="{ on }"> - <v-btn - icon - v-on="on" - > - <v-icon>menu</v-icon> - </v-btn> - </template> - <v-list> - <v-list-item - v-for="item in items" - :key="item.title" - @click="item.action" - > - <v-list-item-title>{{ item.title }}</v-list-item-title> - </v-list-item> - </v-list> - </v-menu> -</template> - -<script> -import { activateAllStudentAccess, - deactivateAllStudentAccess } from '@/api' -import { actions } from '@/store/actions' -import { Authentication } from '@/store/modules/authentication' - -export default { - name: 'StudentListMenu', - computed: { - studentsActive () { - const firstStudent = Object.values(this.$store.state.students)[0] - return firstStudent ? firstStudent.isActive === true : false - }, - isReviewer () { - return Authentication.isReviewer - }, - items () { - return [ - { - title: this.studentsActive - ? 'Remove participant access' - : 'Grant participant access', - action: this.changeStudentsAccess - } - ] - } - }, - methods: { - updateStudentData () { - actions.getStudents().catch(() => { - this.$notify({ - title: 'ERROR', - text: 'Unable to update student data!', - type: 'error' - }) - }) - }, - changeStudentsAccess () { - if (this.studentsActive) { - deactivateAllStudentAccess().then(() => { - this.updateStudentData() - }).catch(() => { - this.$notify({ - title: 'ERROR', - text: 'Unable to disable access', - type: 'error' - }) - }) - } else { - activateAllStudentAccess().then(() => { - this.updateStudentData() - }).catch(() => { - this.$notify({ - title: 'ERROR', - text: 'Unable to activate access', - type: 'error' - }) - }) - } - } - } -} -</script> - -<style scoped> - -</style> diff --git a/grady/frontend/src/components/student_list/StudentListReverseMapper.vue b/grady/frontend/src/components/student_list/StudentListReverseMapper.vue deleted file mode 100644 index 8fed96717969d5cc243c59d00b43645282a7d62d..0000000000000000000000000000000000000000 --- a/grady/frontend/src/components/student_list/StudentListReverseMapper.vue +++ /dev/null @@ -1,45 +0,0 @@ -<template> - <v-tooltip top> - <template #activator="{ on }"> - <div v-on="on"> - <v-file-input - v-model="file" - hide-input - prepend-icon="vpn_key" - accept="application/JSON" - @change="readMapFileAndApply" - /> - </div> - </template> - <span>Apply mapping</span> - </v-tooltip> -</template> - -<script> -export default { - name: 'StudentListReverseMapper', - data () { - return { - file: null, - fileReader: new FileReader() - } - }, - methods: { - readMapFileAndApply () { - this.fileReader.onload = event => { - const studentMap = JSON.parse(event.target.result) - this.reverseMapStudents(studentMap) - } - this.fileReader.readAsText(this.file) - }, - reverseMapStudents (studentMap) { - this.$store.commit('SET_STUDENT_MAP', studentMap) - this.$store.commit('SET_STUDENTS', Object.values(this.$store.state.students)) - } - } -} -</script> - -<style scoped> - -</style> diff --git a/grady/frontend/src/components/submission_notes/CorrectionHelpCard.vue b/grady/frontend/src/components/submission_notes/CorrectionHelpCard.vue deleted file mode 100644 index 0be45efe97d30fbbf616c525fd13d473644894fd..0000000000000000000000000000000000000000 --- a/grady/frontend/src/components/submission_notes/CorrectionHelpCard.vue +++ /dev/null @@ -1,37 +0,0 @@ -<template> - <v-card class="help-card"> - <v-card-title> - <v-icon>help_outline</v-icon> - <h3>Tips on using the correction interface</h3> - </v-card-title> - <v-card-text> - Never trade an ale. - The sea-dog leads with yellow fever, crush the captain's quarters until it waves.<br> - Ho-ho-ho! malaria of life.<br> - Halitosis, adventure, and yellow fever.<br> - The girl drinks with halitosis, pull the galley before it laughs.<br> - The moon fires with life, vandalize the bikini atoll before it travels.<br> - The tuna blows with fight, haul the freighter before it whines.<br> - The cannibal robs with hunger, fire the lighthouse until it whines.<br> - The captain loves with death, vandalize the lighthouse before it whines.<br> - The anchor loots with treasure, raid the freighter before it grows.<br> - The reef commands with endurance, view the quarter-deck until it whines.<br> - The scallywag loots with passion, crush the bikini atoll before it falls.<br> - The sea leads with treasure, ransack the brig until it dies.<br> - The parrot robs with desolation, view the seychelles before it screams.<br> - The warm anchor quirky blows the landlubber.<br> - </v-card-text> - </v-card> -</template> - -<script> -export default { - name: 'CorrectionHelpCard' -} -</script> - -<style scoped> - .help-card { - width: fit-content; - } -</style> diff --git a/grady/frontend/src/components/submission_notes/RouteChangeConfirmation.vue b/grady/frontend/src/components/submission_notes/RouteChangeConfirmation.vue deleted file mode 100644 index 9c89fcce0e1072478808e288d911b96b50f2907d..0000000000000000000000000000000000000000 --- a/grady/frontend/src/components/submission_notes/RouteChangeConfirmation.vue +++ /dev/null @@ -1,70 +0,0 @@ -<template> - <v-dialog - v-model="dialog" - max-width="30%" - > - <v-card class="text-center"> - <v-card-title class="title"> - Are you sure? - </v-card-title> - <v-card-text> - Not submitted feedback will be lost! - </v-card-text> - <v-card-actions> - <v-btn - text - outlined - color="red lighten-1" - @click="changeRoute" - > - Change page - </v-btn> - <v-btn - text - outlined - @click="dialog = false" - > - Stay here - </v-btn> - </v-card-actions> - </v-card> - </v-dialog> -</template> - -<script> -import { SubmissionNotes } from '@/store/modules/submission-notes' - -export default { - name: 'RouteChangeConfirmation', - props: { - nextRoute: { - type: Function, - default: null - } - }, - data () { - return { - dialog: false - } - }, - watch: { - nextRoute (newVal, oldVal) { - if (newVal !== oldVal && SubmissionNotes.workInProgress) { - this.dialog = true - } else { - this.nextRoute() - } - } - }, - methods: { - changeRoute () { - this.nextRoute() - this.dialog = false - } - } -} -</script> - -<style scoped> - -</style> diff --git a/grady/frontend/src/components/submission_notes/SubmissionCorrection.vue b/grady/frontend/src/components/submission_notes/SubmissionCorrection.vue deleted file mode 100644 index d3c9e73639fb13921bce4eb9bf69984fb9bc5587..0000000000000000000000000000000000000000 --- a/grady/frontend/src/components/submission_notes/SubmissionCorrection.vue +++ /dev/null @@ -1,257 +0,0 @@ -<template> - <div> - <base-annotated-submission> - <template #header> - <annotated-submission-top-toolbar - v-model="mathIsRendered" - :of-student="submissionObj && submissionObj.ofStudent" - :show-clipboard="true" - :show-correction-help="true" - :source-code-available="sourceCodeAvailable" - :submission="submission" - :submission-type="submission.type" - :feedback="feedback" - :is-markdown="isMarkdown" - /> - </template> - <template - id="sub-lines" - #table-content - > - <tr - v-for="(code, lineNo) in submission" - :id="`sub-line-${lineNo}`" - :key="`${submissionObj.pk}${lineNo}`" - > - <math-renderer :enabled="mathIsRendered"> - <submission-line - :hint="hasHiddenComment(lineNo)" - :code="code" - :line-no="lineNo" - @toggleEditor="toggleEditorOnLine(lineNo)" - > - <template v-if="showFeedback"> - <div v-if="origFeedback[lineNo]"> - <feedback-comment - v-for="(comment, index) in getSortedComments(lineNo)" - :key="index" - v-bind="comment" - :visible-to-student-bool="updatedFeedback[lineNo] ? false : comment.visibleToStudent" - :line-no="lineNo" - :deletable="comment.ofTutor === user || isReviewer" - @click.native="toggleEditorOnLine(lineNo, comment)" - /> - </div> - <feedback-comment - v-if="updatedFeedback[lineNo]" - v-bind="updatedFeedback[lineNo]" - :line-no="lineNo" - :deletable="true" - @click.native="toggleEditorOnLine(lineNo, updatedFeedback[lineNo])" - /> - </template> - <comment-form - v-if="showEditorOnLine[lineNo]" - :feedback="selectedComment[lineNo].text" - :line-no="lineNo" - @collapseFeedbackForm="toggleEditorOnLine(lineNo)" - /> - </submission-line> - </math-renderer> - </tr> - </template> - <template #labels> - <label-selector - id="feedback-label-selector" - :assigned-to-feedback="true" - class="mt-1 elevation-1" - /> - </template> - <template #footer> - <annotated-submission-bottom-toolbar - class="mt-1 elevation-1" - :loading="loading" - :full-score="submissionObj['fullScore']" - :skippable="assignment !== undefined" - :feedback="feedbackObj ? feedbackObj : {}" - @submitFeedback="submitFeedback" - /> - </template> - </base-annotated-submission> - </div> -</template> - -<script> -import { mapState, mapGetters } from 'vuex' -import CommentForm from '@/components/submission_notes/base/CommentForm.vue' -import FeedbackComment from '@/components/submission_notes/base/FeedbackComment.vue' -import AnnotatedSubmissionTopToolbar from '@/components/submission_notes/toolbars/AnnotatedSubmissionTopToolbar' -import AnnotatedSubmissionBottomToolbar from '@/components/submission_notes/toolbars/AnnotatedSubmissionBottomToolbar' -import BaseAnnotatedSubmission from '@/components/submission_notes/base/BaseAnnotatedSubmission' -import FeedbackLabel from '@/components/feedback_labels/FeedbackLabel.vue' -import { FeedbackLabels as Labels } from '@/store/modules/feedback-labels' -import LabelSelector from '@/components/feedback_labels/LabelSelector.vue' -import SubmissionLine from '@/components/submission_notes/base/SubmissionLine' -import { SubmissionNotes, subNotesEventBus } from '@/store/modules/submission-notes' -import { SubmissionType } from '@/models' -import { Authentication } from '@/store/modules/authentication' -import { actions } from '@/store/actions' -import { fetchFeedback } from '@/api' -import MathRenderer from '@/components/MathRenderer.vue' - -export default { - name: 'SubmissionCorrection', - components: { - SubmissionLine, - BaseAnnotatedSubmission, - AnnotatedSubmissionBottomToolbar, - AnnotatedSubmissionTopToolbar, - FeedbackComment, - LabelSelector, - CommentForm, - MathRenderer }, - props: { - assignment: { - default: () => {}, - type: Object - }, - // either pass in an assignment or a submission and feedback - submissionWithoutAssignment: { - default: () => {}, - type: Object - }, - feedback: { - default: () => {}, - type: Object - }, - ignoreHiddenState: { - type: Boolean, - default: false, - } - }, - data () { - return { - loading: false, - feedbackShortPollInterval: null, - mathIsRendered: true, - } - }, - computed: { - showEditorOnLine () { return SubmissionNotes.state.ui.showEditorOnLine }, - selectedComment () { return SubmissionNotes.state.ui.selectedCommentOnLine }, - origFeedback () { return SubmissionNotes.state.origFeedback.feedbackLines }, - updatedFeedback () { return SubmissionNotes.state.updatedFeedback.feedbackLines }, - showFeedback () { return SubmissionNotes.state.ui.showFeedback }, - - workInProgress () { return SubmissionNotes.workInProgress }, - - sourceCodeAvailable () { - return SubmissionNotes.state.submission.sourceCodeAvailable - }, - - isStudent () { return Authentication.isStudent }, - isTutor () { return Authentication.isTutor }, - isReviewer () { return Authentication.isReviewer }, - user () { return Authentication.state.user.username }, - submission () { - return SubmissionNotes.submission - }, - isMarkdown () { - const lang = SubmissionNotes.submissionType.programmingLanguage - return lang === SubmissionType.ProgrammingLanguageEnum.Markdown - }, - submissionObj () { - return this.assignment ? this.assignment.submission : this.submissionWithoutAssignment - }, - feedbackObj () { - return this.assignment ? this.assignment.feedback : this.feedback - } - }, - watch: { - assignment: function (newVar, oldVar) { - this.init() - }, - submissionWithoutAssignment: function () { - this.init() - }, - submission: function (oldVal, newVal) { - if (JSON.stringify(oldVal) !== JSON.stringify(newVal)) { - subNotesEventBus.$emit('submissionChanged') - } - } - }, - created () { - this.init() - this.shortPollOrigFeedback() - }, - beforeDestroy () { - clearInterval(this.feedbackShortPollInterval) - }, - methods: { - toggleEditorOnLine (lineNo, comment = '') { - SubmissionNotes.TOGGLE_EDITOR_ON_LINE({ lineNo, comment }) - }, - submitFeedback ({ isFinal }) { - this.loading = true - SubmissionNotes.submitFeedback({ - isFinal: isFinal - }).then(_ => { - SubmissionNotes.RESET_UPDATED_FEEDBACK() - this.$emit('feedbackCreated') - this.$emit('feedbackChanged') - SubmissionNotes.RESET_MARKED_COMMENTS_FOR_DELETE() - }).catch(err => { - // ignore trivial errors as those are handled - // by an interceptor - if (err.message.includes('Request failed')) return - - this.$notify({ - title: 'Feedback creation Error!', - text: err.message, - type: 'error', - duration: -1 - }) - }).finally(() => { - this.loading = false - }) - }, - shortPollOrigFeedback () { - this.feedbackShortPollInterval = setInterval(() => { - if (this.feedbackObj && this.feedbackObj.ofSubmission) { - fetchFeedback({ ofSubmission: this.feedbackObj.ofSubmission }).then(feedback => { - SubmissionNotes.SET_ORIG_FEEDBACK(feedback) - }) - } - }, 5e3) - }, - getSortedComments (lineNo) { - if (!this.origFeedback || (!this.origFeedback && !this.origFeedback[lineNo])) return new Array() - let feedback = [...this.origFeedback[lineNo]] - - return feedback.sort((a, b) => { - const da = new Date(a.modified) - const db = new Date(b.modified) - return da.getTime() - db.getTime() - }) - }, - hasHiddenComment (lineNo) { - const hasOrigComment = this.origFeedback && this.origFeedback[lineNo] - && this.origFeedback[lineNo].length > 0 - - const hasUpdatedComment = this.updatedFeedback && this.updatedFeedback[lineNo] - - return !this.showFeedback && (hasOrigComment || !!hasUpdatedComment) - }, - init () { - SubmissionNotes.RESET_STATE() - SubmissionNotes.SET_SUBMISSION(this.submissionObj) - SubmissionNotes.SET_ORIG_FEEDBACK(this.feedbackObj) - SubmissionNotes.SET_SHOW_FEEDBACK(this.ignoreHiddenState ? true : !SubmissionNotes.state.hasOrigFeedback) - } - } -} -</script> - -<style scoped> - -</style> diff --git a/grady/frontend/src/components/submission_notes/base/BaseAnnotatedSubmission.vue b/grady/frontend/src/components/submission_notes/base/BaseAnnotatedSubmission.vue deleted file mode 100644 index 1be4eb9c8b6ae4d4d70a0e33c2e9f66a6b688f5f..0000000000000000000000000000000000000000 --- a/grady/frontend/src/components/submission_notes/base/BaseAnnotatedSubmission.vue +++ /dev/null @@ -1,38 +0,0 @@ -<template> - <div> - <slot name="header" /> - <table - id="submission-table" - class="submission-table elevation-1" - :class="{latex: isMarkdown}" - > - <slot name="table-content" /> - </table> - <slot name="labels" /> - <slot name="footer" /> - </div> -</template> - -<script> -import { SubmissionNotes } from '@/store/modules/submission-notes' -import store from '@/store/store' -import { SubmissionType } from '@/models' -export default { - name: 'BaseAnnotatedSubmission', - computed: { - isMarkdown () { - const typePk = SubmissionNotes.state.submission.type - const type = store.state.submissionTypes[typePk] - return type && type.programmingLanguage === SubmissionType.ProgrammingLanguageEnum.Markdown - } - } -} -</script> - -<style scoped> - .submission-table { - table-layout: fixed; - border-collapse: collapse; - width: 100%; - } -</style> diff --git a/grady/frontend/src/components/submission_notes/base/CommentForm.vue b/grady/frontend/src/components/submission_notes/base/CommentForm.vue deleted file mode 100644 index f815936d3980f000310397fe9331b740fc9f8e06..0000000000000000000000000000000000000000 --- a/grady/frontend/src/components/submission_notes/base/CommentForm.vue +++ /dev/null @@ -1,154 +0,0 @@ -<template> - <v-container> - <v-row> - <v-col> - <v-textarea - v-model="currentFeedback" - name="feedback-input" - label="Please provide your feedback here" - rows="2" - outlined - autofocus - auto-grow - hide-details - @keyup.enter.ctrl.exact="submitFeedback" - @keyup.esc="collapseTextField" - /> - </v-col> - </v-row> - <v-row> - <v-col> - <label-selector - id="comment-label-selector" - :assigned-to-feedback="false" - :line-no="lineNo" - :labels-unchanged="labelsUnchanged" - :labels-added="labelsAdded" - :labels-removed="labelsRemoved" - @label-added="labelAdded" - @label-removed="labelRemoved" - @submit-shortcut="submitFeedback" - /> - </v-col> - </v-row> - <v-row> - <v-col> - <v-btn - id="submit-comment" - color="success" - @click="submitFeedback" - > - <v-icon>check</v-icon>Submit - </v-btn> - <v-btn - id="cancel-comment" - @click="collapseTextField" - > - <v-icon>cancel</v-icon>cancel - </v-btn> - </v-col> - </v-row> - </v-container> -</template> - -<script lang="ts"> -import Vue from 'vue' -import Component, { mixins } from 'vue-class-component' -import { Prop, Watch } from 'vue-property-decorator' -import { SubmissionNotes, subNotesEventBus } from '@/store/modules/submission-notes' -import LabelSelector from '@/components/feedback_labels/LabelSelector.vue' -import { FeedbackComment, SubmissionType } from '@/models' -import commentLabelSelector from '@/components/mixins/commentLabelSelector' - -@Component({ - components: { - LabelSelector - } -}) -export default class CommentForm extends mixins(commentLabelSelector) { - @Prop({ type: String, default: '' }) readonly feedback!: string - @Prop({ type: String, required: true }) readonly lineNo!: string - - currentFeedback = this.feedback - labelsUnchanged: number[] = this.getUnchangedLabels() - labelsAdded: number[] = this.getAddedLabels() - labelsRemoved: number[] = this.getRemovedLabels() - - selectInput (event: Event) { - if (event !== null) { - const target = event.target as HTMLTextAreaElement - target.select() - } - } - - collapseTextField () { - this.$emit('collapseFeedbackForm') - subNotesEventBus.$emit('submissionChanged') - } - - /** - * Adds label pk to the array of added labels - * or adds already removed labels to unchanged array - */ - labelAdded (pk: number) { - if (this.labelsRemoved.includes(pk)) { - this.labelsUnchanged.push(pk) - this.labelsRemoved = this.labelsRemoved.filter((val) => { - return val !== pk - }) - } else if (!this.labelsAdded.includes(pk) && - !this.labelsUnchanged.includes(pk)) - { - this.labelsAdded.push(pk) - } - } - - /** - * Adds label pk to the array of removed labels - * or removes already added labels from the list of added labels - */ - labelRemoved (pk: number) { - if (this.labelsAdded.includes(pk)) { - this.labelsAdded = this.labelsAdded.filter((val) => { - return val !== pk - }) - } else if (!this.labelsRemoved.includes(pk)) { - this.labelsRemoved.push(pk) - this.labelsUnchanged = this.labelsUnchanged.filter((val) => { - return val !== pk - }) - } - } - - submitFeedback () { - const text = this.currentFeedback - const labels = this.labelsUnchanged.concat(this.labelsAdded) - - if (text === '' && labels.length === 0) { - return this.collapseTextField() - } - - const payload: {lineNo: number, comment: Partial<FeedbackComment>} = { - lineNo: Number(this.lineNo), - comment: { - text: text, - labels: labels, - } - } - - if (this.labelsAdded.length === 0 && this.labelsRemoved.length === 0) { - delete payload.comment.labels - } - - SubmissionNotes.UPDATE_FEEDBACK_LINE(payload) - this.collapseTextField() - } -} - -</script> - -<style scoped> - v-text-field { - padding-top: 0px; - } -</style> diff --git a/grady/frontend/src/components/submission_notes/base/FeedbackComment.vue b/grady/frontend/src/components/submission_notes/base/FeedbackComment.vue deleted file mode 100644 index 4f6b1bec80002a5a7886701fc9b112f2c44a9320..0000000000000000000000000000000000000000 --- a/grady/frontend/src/components/submission_notes/base/FeedbackComment.vue +++ /dev/null @@ -1,340 +0,0 @@ -<template> - <div class="dialog-box"> - <div - v-if="commentDisplayable" - class="body elevation-1" - :style="{borderColor: borderColor}" - > - <span - class="tip tip-up" - :style="{borderBottomColor: borderColor}" - /> - <span - v-if="ofTutor" - class="of-tutor" - >Of tutor: {{ ofTutor }}</span> - <span class="comment-created">{{ parsedCreated }}</span> - <div - v-if="showVisibilityIcon" - class="visibility-icon" - > - <v-tooltip - v-if="visibleToStudentBool" - top - size="20px" - > - <template #activator="{ on }"> - <v-icon - size="20px" - v-on="on" - > - visibility - </v-icon> - </template> - <span>Will be visible to student</span> - </v-tooltip> - <v-tooltip - v-else - top - > - <template #activator="{ on }"> - <v-icon - size="20px" - v-on="on" - > - visibility_off - </v-icon> - </template> - <span>Won't be visible to student</span> - </v-tooltip> - </div> - <!-- eslint-disable-next-line vue/singleline-html-element-content-newline vue/max-attributes-per-line--> - <div :key="key" class="message">{{ text }}</div> - <v-btn - v-if="deletable" - text - icon - absolute - class="delete-button" - @click.stop="toggleDeleteComment" - > - <v-icon - v-if="!markedForDeletion.hasOwnProperty(pk)" - color="grey darken-1" - size="20px" - > - delete_forever - </v-icon> - <v-icon - v-else - size="20px" - > - restore - </v-icon> - </v-btn> - </div> - <v-row - v-if="showLabels && correctorView" - class="ml-2" - > - <v-col sm="4"> - <v-col sm="12"> - CURRENT LABELS - </v-col> - <feedback-label - v-for="label in unchangedLabels" - :key="label.pk" - removable - v-bind="label" - @remove-clicked="deleteAction" - /> - </v-col> - <v-col sm="4"> - <v-col sm="12"> - WILL BE REMOVED - </v-col> - <feedback-label - v-for="label in removedLabels" - :key="label.pk" - removable - v-bind="label" - @remove-clicked="deleteAction" - /> - </v-col> - <v-col sm="4"> - <v-col sm="12"> - WILL BE ADDED - </v-col> - <feedback-label - v-for="label in addedLabels" - :key="label.pk" - removable - v-bind="label" - @remove-clicked="deleteAction" - /> - </v-col> - </v-row> - <template - v-if="!correctorView" - row - wrap - align-center - > - <v-row - v-for="label in unchangedLabels" - :key="label.pk" - - - align="center" - > - <v-col sm="6"> - <feedback-label - v-bind="label" - /> - </v-col> - <v-col sm="6"> - <span><b>Description: </b>{{ label.description }}</span> - </v-col> - </v-row> - </template> - </div> -</template> - -<script> -import { mapState } from 'vuex' -import { UI } from '@/store/modules/ui' -import { SubmissionNotes, subNotesEventBus } from '@/store/modules/submission-notes' -import FeedbackLabel from '@/components/feedback_labels/FeedbackLabel.vue' -import { FeedbackLabels as Labels } from '@/store/modules/feedback-labels' -import commentLabelSelector from '@/components/mixins/commentLabelSelector' - -export default { - name: 'FeedbackComment', - components: { - FeedbackLabel, - }, - mixins: [ - commentLabelSelector, - ], - props: { - pk: { - default: '', - type: String, - required: false - }, - text: { - type: String, - required: true - }, - modified: { - default: '', - type: String, - required: false - }, - ofTutor: { - default: '', - type: String, - required: false - }, - lineNo: { - type: String, - required: true - }, - deletable: { - type: Boolean, - default: false - }, - visibleToStudentBool: { - type: Boolean, - default: true - }, - showVisibilityIcon: { - type: Boolean, - default: true - }, - correctorView: { - type: Boolean, - default: true - } - }, - data () { - return { - key: 0 - } - }, - computed: { - commentDisplayable () { return this.text !== '' }, - showLabels () { - return this.visibleToStudentBool && - (this.getUnchangedLabels().length > 0 || - this.getAddedLabels().length > 0 || - this.getRemovedLabels().length > 0) - }, - markedForDeletion () { return SubmissionNotes.state.commentsMarkedForDeletion }, - parsedCreated () { - if (this.modified) { - return new Date(this.modified).toLocaleString() - } else { - return 'Just now' - } - }, - borderColor () { - if (this.pk) { - return this.markedForDeletion.hasOwnProperty(this.pk) ? '#B5B5B5' : '#3D8FC1' - } - return 'orange' - }, - unchangedLabels() { - return this.mapPksToLabelObj(this.getUnchangedLabels()) - }, - addedLabels() { - return this.mapPksToLabelObj(this.getAddedLabels()) - }, - removedLabels() { - return this.mapPksToLabelObj(this.getRemovedLabels()) - } - }, - created() { - subNotesEventBus.$on('submissionChanged', () => { - this.key++ - }) - subNotesEventBus.$on('resetSubmission', () => { - this.key++ - }) - }, - methods: { - deleteAction (pk) { - let labels - const concated = this.getUnchangedLabels().concat(this.getAddedLabels()) - if (this.getUnchangedLabels().includes(pk)) { - labels = concated.filter((val) => { - return val !== pk - }) - } else if (this.getAddedLabels().includes(pk)) { - labels = concated.filter((val) => { - return val !== pk - }) - } else if (this.getRemovedLabels().includes(pk)) { - concated.push(pk) - labels = concated - } - - if (labels.length > 0 || SubmissionNotes.state.hasOrigFeedback || this.commentDisplayable) { - SubmissionNotes.UPDATE_FEEDBACK_LINE({ - lineNo: Number(this.lineNo), - comment: { - text: this.text || '', - labels: labels, - } - }) - } else { - SubmissionNotes.DELETE_FEEDBACK_LINE(Number(this.lineNo)) - } - }, - toggleDeleteComment () { - if (this.pk) { - if (!this.markedForDeletion.hasOwnProperty(this.pk)) { - SubmissionNotes.MARK_COMMENT_FOR_DELETION({ pk: this.pk }) - } else { - SubmissionNotes.UN_MARK_COMMENT_FOR_DELETION({ pk: this.pk }) - } - } - SubmissionNotes.DELETE_FEEDBACK_LINE(this.lineNo) - } - } -} -</script> - -<style scoped> - .tip { - width: 0px; - height: 0px; - position: absolute; - background: transparent; - border: 10px solid; - } - .tip-up { - top: -22px; /* Same as body margin top + border */ - left: 10px; - border-right-color: transparent; - border-left-color: transparent; - border-top-color: transparent; - } - .dialog-box .body { - cursor: pointer; - position: relative; - height: auto; - margin: 20px 10px 10px 10px; - padding: 5px; - border-radius: 0px; - border: 2px solid; - } - .body .message { - white-space: pre-line; - min-height: 30px; - border-radius: 3px; - font-size: 14px; - line-height: 1.5; - } - .delete-button { - bottom: -12px; - left: -42px; - } - .comment-created { - position: absolute; - font-size: 10px; - right: 4px; - top: -20px; - } - .of-tutor { - position: absolute; - font-size: 13px; - top: -20px; - left: 50px; - } - .visibility-icon { - position: absolute; - top: -4px; - left: -34px; - } -</style> diff --git a/grady/frontend/src/components/submission_notes/base/SubmissionLine.vue b/grady/frontend/src/components/submission_notes/base/SubmissionLine.vue deleted file mode 100644 index ee5537965cae1ba4517b851a916e0173e81643e2..0000000000000000000000000000000000000000 --- a/grady/frontend/src/components/submission_notes/base/SubmissionLine.vue +++ /dev/null @@ -1,90 +0,0 @@ -<template> - <div> - <td - :style="backgroundColor" - class="line-number-cell" - > - <v-btn - text - block - depressed - class="line-number-btn" - @click="toggleEditor" - > - {{ lineNo }} - </v-btn> - </td> - <td class="code-cell-content pl-2"> - <!-- eslint-disable-next-line --> - <span class="code-line" :key="key" v-html="code"/> - <slot /> - </td> - </div> -</template> - -<script> -import { subNotesEventBus } from '../../../store/modules/submission-notes' -export default { - name: 'SubmissionLine', - props: { - lineNo: { - type: String, - required: true - }, - code: { - type: String, - required: true - }, - codeLanguage: { - type: String, - default: 'lang-c' - }, - hint: { - type: Boolean, - default: false, - }, - }, - data () { - return { - key: 0 - } - }, - computed: { - backgroundColor() { - return this.hint ? 'background-color: #F44336;' : 'background-color: transparent;' - } - }, - created () { - subNotesEventBus.$on('resetSubmission', () => { - this.key++ - }) - }, - methods: { - toggleEditor () { - this.$emit('toggleEditor') - } - } -} -</script> - -<style scoped> - .line-number-cell { - vertical-align: top; - } - - .code-cell-content { - width: 100%; - } - - .code-line { - white-space: pre-wrap; - font-family: monospace; - } - - .line-number-btn { - height: fit-content; - min-width: 50px; - margin: 0; - border-radius: 0; - } -</style> diff --git a/grady/frontend/src/components/submission_notes/toolbars/AnnotatedSubmissionBottomToolbar.vue b/grady/frontend/src/components/submission_notes/toolbars/AnnotatedSubmissionBottomToolbar.vue deleted file mode 100644 index ac7879e92a7659c3f15f2641f36c82c3a233756e..0000000000000000000000000000000000000000 --- a/grady/frontend/src/components/submission_notes/toolbars/AnnotatedSubmissionBottomToolbar.vue +++ /dev/null @@ -1,227 +0,0 @@ -<template> - <v-card> - <v-card-text> - <v-form - ref="scoreForm" - v-model="scoreIsValid" - lazy-validation - @submit.prevent="submit" - > - <v-text-field - id="score-input" - v-model="score" - v-shortkey="'numeric'" - type="number" - step="0.5" - label="Score" - :suffix="`/${fullScore}`" - :rules="scoreRules" - min="0" - :max="fullScore" - @shortkey="handleKeypress" - /> - <div class="suggestion-chips"> - <v-chip - id="score-zero" - small - color="error" - outlined - @click="score=0" - > - 0 - </v-chip> - <v-chip - id="score-full" - small - color="success" - outlined - @click="score=fullScore" - > - {{ fullScore }} - </v-chip> - </div> - </v-form> - </v-card-text> - <v-divider /> - <v-card-actions> - <v-tooltip - v-if="showFinalCheckbox" - top - > - <template #activator="{ on }"> - <div v-on="on"> - <v-checkbox - v-model="isFinal" - label="Final" - class="final-checkbox" - hide-details - /> - </div> - </template> - <span>If unchecked this submission will be marked for review by the lecturer</span> - </v-tooltip> - <v-spacer /> - <v-tooltip - v-if="skippable" - top - > - <template #activator="{ on }"> - <v-btn - id="skip-submission" - text - v-on="on" - @click="skipSubmission" - > - Skip - </v-btn> - </template> - <span>Skip this submission</span> - </v-tooltip> - <v-tooltip top> - <template #activator="{ on }"> - <v-btn - id="submit-feedback" - color="primary" - :loading="loading" - :disabled="!scoreIsValid" - v-on="on" - @click="submit" - > - Submit - </v-btn> - </template> - <span>Submit and continue</span> - </v-tooltip> - </v-card-actions> - </v-card> -</template> - -<script> -import { SubmissionNotes } from '@/store/modules/submission-notes' -import { Authentication } from '@/store/modules/authentication' -import { Assignments } from '@/store/modules/assignments' -import { mapState } from 'vuex' - -export default { - name: 'AnnotatedSubmissionBottomToolbar', - props: { - fullScore: { - type: Number, - required: true - }, - loading: { - type: Boolean, - required: true - }, - skippable: { - type: Boolean, - default: false - }, - feedback: { - type: Object, - default: () => {} - } - }, - data () { - return { - scoreIsValid: true, - isFinal: this.initialFinalStatus(), - scoreRules: [ - score => score !== undefined || - 'Score is required.', - score => !isNaN(parseFloat(score)) || - 'Score must be a number.', - score => parseFloat(score) >= 0 && parseFloat(score) <= this.fullScore || - `Score must be between 0 and ${this.fullScore}.`, - score => parseFloat(score) === this.fullScore || this.hasFeedbackOrLabel || - 'Add a comment or label explaining why this submission doesn\'t get full score.' - ] - } - }, - computed: { - hasFeedbackOrLabel: function() { - return Object.keys(SubmissionNotes.state.updatedFeedback.feedbackLines).length > 0 || - SubmissionNotes.state.updatedFeedback.labels.length > 0 || - Object.keys(SubmissionNotes.state.origFeedback.feedbackLines).length > 0 || - SubmissionNotes.state.origFeedback.labels.length > 0 - }, - score: { - get: function () { - return SubmissionNotes.score - }, - set: function (score) { - SubmissionNotes.UPDATE_FEEDBACK_SCORE(Number(score)) - } - }, - showFinalCheckbox () { - // show always on feedback history and participants overview - if (this.$route.name !== 'correction') { - return true - } - - return !SubmissionNotes.isFeedbackCreation || - Authentication.isReviewer && !SubmissionNotes.isConflictResolution - } - }, - watch: { - feedback: { - handler: function (val) { - this.isFinal = this.initialFinalStatus() - }, - deep: true - }, - hasFeedbackOrLabel: function (newValue) { - if (this.score !== undefined) - this.$refs.scoreForm.validate() - } - }, - methods: { - initialFinalStatus () { - if (this.$route.name === 'correction') { - return !SubmissionNotes.isFeedbackCreation || Authentication.isReviewer - } else { - if (this.feedback.hasOwnProperty('isFinal') && !SubmissionNotes.isConflictResolution) { - return this.feedback.isFinal - } else { - return !SubmissionNotes.isFeedbackCreation || Authentication.isReviewer - } - } - }, - submit () { - if (this.$refs.scoreForm.validate()) - this.$emit('submitFeedback', { isFinal: this.isFinal }) - }, - skipSubmission () { - if (this.skippable) { - Assignments.skipAssignment().catch(() => { - this.$notify({ - title: 'Unable to skip submission', - type: 'error' - }) - }) - } else { - throw new Error('Can\'t skip submission when skippable is false for AnnotatedSubmissionBottomToolbar.') - } - }, - handleKeypress (event) { - // only handle keypress if nothing is focused - if (document.activeElement.tagName === 'BODY') { - this.score = event.key - const scoreInput = document.getElementById('score-input') - scoreInput.scrollIntoView() - scoreInput.focus() - } - } - } -} -</script> - -<style scoped> - .suggestion-chips { - margin: 0 -4px; - } - .final-checkbox { - margin: 0; - padding: 0; - } -</style> diff --git a/grady/frontend/src/components/submission_notes/toolbars/AnnotatedSubmissionTopToolbar.vue b/grady/frontend/src/components/submission_notes/toolbars/AnnotatedSubmissionTopToolbar.vue deleted file mode 100644 index 4f42298d67716667d7f9c13158e575d2527e1511..0000000000000000000000000000000000000000 --- a/grady/frontend/src/components/submission_notes/toolbars/AnnotatedSubmissionTopToolbar.vue +++ /dev/null @@ -1,239 +0,0 @@ -<template> - <v-toolbar - dense - > - <v-app-bar-nav-icon - v-if="showCorrectionHelp" - @click.stop="helpDialog=true" - > - <v-icon>help_outline</v-icon> - </v-app-bar-nav-icon> - <v-dialog - v-model="helpDialog" - scrollable - max-width="fit-content" - > - <correction-help-card /> - </v-dialog> - <span v-if="score < 0">Submission of {{ ofStudent }}</span> - <span - v-else - class="title" - > - Score: {{ score }} </span> - <v-spacer /> - <toggle-feedback-visibility-button /> - <div v-if="isMarkdown"> - <v-btn @click="$emit('input', !mathIsRendered)"> - {{ mathIsRendered ? 'Reset Math' : 'Render Math' }} - </v-btn> - </div> - <v-spacer /> - <v-tooltip - v-if="sourceCodeAvailable" - top - > - <template #activator="{ on }"> - <v-btn - icon - v-on="on" - @click="downloadSourceCode" - > - <v-icon> - cloud_download - </v-icon> - </v-btn> - </template> - <span>Download original source code (.ipynb, etc.)</span> - </v-tooltip> - <v-btn - v-if="notebookAvailable" - text - class="blue-grey lighten-2" - @click="showOriginalSubmission" - > - VIEW ORIGINAL SUBMISSION - </v-btn> - <v-tooltip top> - <template #activator="{ on }"> - <v-btn - v-if="showClipboard" - icon - v-on="on" - @click="copyToClipboard" - > - <v-icon>content_copy</v-icon> - </v-btn> - </template> - <span>{{ copyMessage }}</span> - </v-tooltip> - <v-tooltip - v-if="solutionHidden" - top - > - <template #activator="{ on }"> - <v-btn - icon - v-on="on" - @click="showSolution" - > - <v-icon> - keyboard_arrow_left - </v-icon> - </v-btn> - </template> - <span>Show Solution</span> - </v-tooltip> - - <v-dialog - v-model="originalSubmissionDialog" - fullscreen - hide-overlay - > - <v-card> - <v-toolbar - dark - color="#1a237e" - > - <v-btn - icon - dark - @click="originalSubmissionDialog = false" - > - <v-icon>close</v-icon> - </v-btn> - <v-toolbar-title>Original notebook</v-toolbar-title> - <v-spacer /> - </v-toolbar> - - <v-card-text> - <iframe - :srcdoc="originalSubmission" - class="origNotebookFrame" - /> - </v-card-text> - </v-card> - </v-dialog> - </v-toolbar> -</template> - -<script> -import CorrectionHelpCard from '@/components/submission_notes/CorrectionHelpCard' -import { mapState } from 'vuex' -import ToggleFeedbackVisibilityButton from '@/components/submission_notes/toolbars/ToggleFeedbackVisibilityButton' -import { SubmissionNotes, subNotesEventBus } from '@/store/modules/submission-notes' -import { StudentPage } from '@/store/modules/student-page' -import {fetchSubmissionSourceCode} from '@/api.ts' -import { fetchNotebookSubmissionAsHtml } from '@/api.ts' -import {saveAs} from 'file-saver' -import store from '../../../store/store' -import { SubmissionType } from '../../../models' -import Vue from 'vue' -import { UI } from '@/store/modules/ui' - -export default { - name: 'AnnotatedSubmissionTopToolbar', - components: { - ToggleFeedbackVisibilityButton, - CorrectionHelpCard }, - props: { - ofStudent: { - type: String, - default: 'Participant' - }, - showClipboard: { - type: Boolean, - default: false - }, - score: { - type: Number, - default: -1 - }, - showCorrectionHelp: { - type: Boolean, - default: false - }, - sourceCodeAvailable: { - type: Boolean, - default: false - }, - isMarkdown: { - type: Boolean, - default: false - }, - notebookAvailable: { - type: Boolean, - default: false - }, - submission: { - type: Object, - default: null - }, - submissionType: { - type: Object, - default: null - }, - feedback: { - type: Object, - default: null - }, - submissionLanguage: { - type: String, - default: null - }, - value: { - type: Boolean, - default: true - } - }, - data () { - return { - helpDialog: false, - copyMessage: 'Copy to clipboard', - originalSubmissionDialog: false, - originalSubmission: '', - } - }, - computed: { - solutionHidden () { - return UI.state.showSubmissionType === false - }, - mathIsRendered() { - return this.value - } - }, - methods: { - resetSubmission () { - subNotesEventBus.$emit('resetSubmission') - }, - async showOriginalSubmission () { - if (!this.originalSubmission) { - const notebook = await fetchNotebookSubmissionAsHtml(this.submission.pk) - this.originalSubmission = notebook - } - this.originalSubmissionDialog = true - }, - async downloadSourceCode () { - const data = await fetchSubmissionSourceCode(SubmissionNotes.state.submission.pk) - saveAs(new Blob([data.sourceCode], {type: 'application/json'}), 'notebook.ipynb') - }, - copyToClipboard () { - this.$clipboard(SubmissionNotes.state.submission.text) - this.copyMessage = 'Copied!' - setTimeout(() => { - this.copyMessage = 'Copy to clipboard' - }, 2500) - }, - showSolution () { - UI.SET_SHOW_SUBMISSIONTYPE(true) - } - } -} -</script> - -<style scoped> - .origNotebookFrame { - width: 100%; - min-height: 85vh; - } -</style> diff --git a/grady/frontend/src/components/submission_notes/toolbars/ToggleFeedbackVisibilityButton.vue b/grady/frontend/src/components/submission_notes/toolbars/ToggleFeedbackVisibilityButton.vue deleted file mode 100644 index 453a5ea8ca702d9ee9cea16587d01650da2f1992..0000000000000000000000000000000000000000 --- a/grady/frontend/src/components/submission_notes/toolbars/ToggleFeedbackVisibilityButton.vue +++ /dev/null @@ -1,39 +0,0 @@ -<template> - <v-btn - id="feedback-visibility-toggle" - text - color="info" - @click="showFeedback = !showFeedback" - > - <div v-if="showFeedback"> - Hide Feedback - </div> - <div v-else> - Show Feedback - </div> - </v-btn> -</template> - -<script lang="ts"> -import Vue from 'vue' -import { SubmissionNotes } from '@/store/modules/submission-notes' -import { createComputedGetterSetter } from '@/util/helpers' -import { getters } from '@/store/getters' -import Component from 'vue-class-component' - -@Component -export default class ToggleFeedbackVisibilityButton extends Vue { - get showFeedback () { - return getters.state.SubmissionNotes.ui.showFeedback - } - - set showFeedback (val) { - SubmissionNotes.SET_SHOW_FEEDBACK(val) - } -} -</script> - - -<style scoped> - -</style> diff --git a/grady/frontend/src/components/submission_type/SubmissionType.vue b/grady/frontend/src/components/submission_type/SubmissionType.vue deleted file mode 100644 index 3e845b98c303006363a162ddc5a5c84825e281e7..0000000000000000000000000000000000000000 --- a/grady/frontend/src/components/submission_type/SubmissionType.vue +++ /dev/null @@ -1,174 +0,0 @@ -<template> - <v-card id="submission-type"> - <v-toolbar> - <span class="title">{{ name }} - Full score: {{ fullScore }}</span> - <v-spacer /> - <v-btn - v-if="closeable" - icon - @click="close" - > - <v-icon>close</v-icon> - </v-btn> - </v-toolbar> - <v-expansion-panels - v-model="expanded" - multiple - accordion - > - <v-expansion-panel - v-for="(item, i) in typeItems" - :key="i" - > - <v-expansion-panel-header> - <b>{{ item.title }}</b> - <v-btn - v-if="item.title == 'Solution'" - color="info" - text - @click.stop="showSolutionComments = !showSolutionComments" - > - Toggle Comments - </v-btn> - </v-expansion-panel-header> - <v-expansion-panel-content - v-if="item.title === 'Description'" - class="type-description" - > - <math-renderer> - <!-- eslint-disable-next-line --> - <div class="description-content" v-html="item.text" /> - </math-renderer> - </v-expansion-panel-content> - <v-expansion-panel-content v-else-if="item.title === 'Solution'"> - <solution - :pk="pk" - :solution="solution" - :programming-language="programmingLanguage" - :solution-comments="solutionComments" - :show-solution-comments="showSolutionComments" - :editable="allowEditSolutionComments" - /> - </v-expansion-panel-content> - </v-expansion-panel> - </v-expansion-panels> - </v-card> -</template> - -<script lang="ts"> -import Vue from 'vue' -import Component from 'vue-class-component' -import { Prop, Watch } from 'vue-property-decorator' -import { highlight } from 'highlight.js' -import { UI } from '@/store/modules/ui' -import { SolutionComment } from '../../models' -import Solution from '@/components/submission_type/solution/Solution.vue' -import { Authentication } from '@/store/modules/authentication' -import MathRenderer from '@/components/MathRenderer.vue' - -@Component({ - components: { Solution, MathRenderer } -}) -export default class SubmissionType extends Vue { - @Prop({ - type: String, - required: true, - }) pk!: string - @Prop({ - type: String, - required: true - }) name!: string - @Prop({ - type: String, - required: true - }) description!: string - @Prop({ - type: String, - required: false, - default: '' - }) solution!: string - @Prop({ - type: Number, - required: true - }) fullScore!: number - @Prop({ - type: String, - default: 'c' - }) programmingLanguage!: string - @Prop({ - type: Boolean, - default: false - }) reverse!: boolean - @Prop({ - type: Object, - default: () => {return {}}, - }) solutionComments!: {[ofLine: number]: SolutionComment[]} - @Prop({ - type: Object, - default: function () { - return { - Description: true, - Solution: true - } - } - }) expandedByDefault!: {Description: boolean, Solution: boolean} - @Prop({ - type: Boolean, - default: true - }) closeable!: boolean - - expanded = [ - ...(this.expandedByDefault.Description ? [this.reverse ? 0 : 1] : []), - ...(this.expandedByDefault.Solution ? [this.reverse ? 1 : 0] : []) - ] - - showSolutionComments = true - - get allowEditSolutionComments () { - return Authentication.isTutorOrReviewer - } - - get typeItems () { - let items = [ - { - title: 'Description', - text: this.description - } - ] - if (this.solution) { - items.push({ - title: 'Solution', - text: this.solution - }) - } - if (this.reverse) { - return items.reverse() - } else { - return items - } - } - get highlightedSolution () { - return highlight(this.programmingLanguage, this.solution, true).value - } - - close() { - UI.SET_SHOW_SUBMISSIONTYPE(false) - } - - mounted () { - window.MathJax.typeset() - } -} -</script> - -<style> - .description-content pre { - overflow-x: auto; - } - - .v-expansion-panel { - /* Vuetify limits the height by default. We don't want that.*/ - max-height: initial; - } -</style> - diff --git a/grady/frontend/src/components/submission_type/SubmissionTypesOverview.vue b/grady/frontend/src/components/submission_type/SubmissionTypesOverview.vue deleted file mode 100644 index 64d8e385ab7f975f63b6ee54c8631a1ca4ac3986..0000000000000000000000000000000000000000 --- a/grady/frontend/src/components/submission_type/SubmissionTypesOverview.vue +++ /dev/null @@ -1,85 +0,0 @@ -<template> - <v-card> - <v-card-title class="title"> - Task types - </v-card-title> - <v-row> - <v-col cols="3"> - <v-list id="submission-types-list"> - <v-list-item - v-for="submissionType in sortedSubmissionTypes" - :key="submissionType.pk" - @click="selectedSubmissionType = submissionType" - > - <v-list-item-content> - {{ submissionType.name }} - </v-list-item-content> - </v-list-item> - </v-list> - </v-col> - <v-col cols="9"> - <v-row - v-if="!selectedSubmissionType" - justify="center" - > - <strong>Select a task type on the left to see the description and solution.</strong> - </v-row> - <submission-type - v-else - :closeable="false" - class="mr-2 mb-2" - v-bind="selectedSubmissionType" - /> - </v-col> - </v-row> - </v-card> -</template> - -<script> -import SubmissionType from '@/components/submission_type/SubmissionType' -import { ConfigModule } from '../../store/modules/config' -import store from '@/store/store' - -export default { - name: 'SubmissionTypesOverview', - components: { SubmissionType }, - data () { - return { - selectedSubmissionTypePk: null - } - }, - computed: { - submissionTypes () { - let types = Object.values(store.state.submissionTypes) - return types.filter(submissionType => { - return submissionType.examType.moduleReference === ConfigModule.state.config.currentExam - }) - }, - // needed to keep selectedSubmissionType reactive - selectedSubmissionType: { - get: function () { - return store.state.submissionTypes[this.selectedSubmissionTypePk] - }, - set: function (newSubType) { - this.selectedSubmissionTypePk = newSubType.pk - } - }, - sortedSubmissionTypes () { - return Object.values(this.submissionTypes).sort((t1, t2) => { - let lowerName1 = t1.name.toLowerCase() - let lowerName2 = t2.name.toLowerCase() - if (lowerName1 < lowerName2) { - return -1 - } else if (lowerName1 > lowerName2) { - return 1 - } - return 0 - }) - } - } -} -</script> - -<style scoped> - -</style> diff --git a/grady/frontend/src/components/submission_type/solution/Solution.vue b/grady/frontend/src/components/submission_type/solution/Solution.vue deleted file mode 100644 index 54e1ab256b92fb61fb12ce7d22e958e1764d57ea..0000000000000000000000000000000000000000 --- a/grady/frontend/src/components/submission_type/solution/Solution.vue +++ /dev/null @@ -1,219 +0,0 @@ -<template> - <table class="solution-table"> - <tr - v-for="(code, lineNo) in highlightedSolution" - :id="`solution-line-${lineNo}`" - :key="`${pk}:${lineNo}`" - > - <td - class="line-number-cell" - :style="backgroundColor(lineNo)" - > - <v-btn - text - block - depressed - class="line-number-btn" - @click="toggleEditor(lineNo)" - > - {{ lineNo }} - </v-btn> - </td> - <td class="code-cell-content pl-2"> - <!-- eslint-disable-next-line --> - <span class="code-line" v-html="code"/> - <template - v-if="solutionComments[lineNo] && solutionComments[lineNo].length && showSolutionComments" - > - <solution-comment - v-for="comment in solutionComments[lineNo]" - :key="comment.pk" - v-bind="comment" - @update-submission-type="updateSubmissionType" - @toggle-editor="toggleEditor(lineNo)" - @toggle-eidt-editor="toggleEditor(lineNo)" - /> - </template> - <template v-if="showEditorOnline[lineNo]"> - <v-textarea - v-model="editedSolutionComments[lineNo]" - name="solution-comment-input" - label="Here you can comment the solution. Other tutors will see those comments." - rows="2" - outlined - autofocus - auto-grow - hide-details - class="mx-2" - @keyup.enter.ctrl.exact="submitSolutionComment(lineNo)" - @keyup.esc="collapseTextField(lineNo)" - @focus="selectInput($event)" - /> - <v-btn - id="submit-comment" - color="success" - @click="submitSolutionComment(lineNo)" - > - <v-icon>check</v-icon>Submit - </v-btn> - <v-btn - id="cancel-comment" - @click="toggleEditor(lineNo)" - > - <v-icon>cancel</v-icon>cancel - </v-btn> - </template> - </td> - </tr> - </table> -</template> - -<script lang="ts"> - import { Vue, Component, Prop } from 'vue-property-decorator' - import { SolutionComment, FeedbackComment } from '../../../models' - import { highlight } from 'highlight.js' - import { syntaxPostProcess, objectifyArray } from '../../../util/helpers' - import SolutionCommentComponent from '@/components/submission_type/solution/SolutionComment.vue' - import * as api from '@/api' - import { actions } from '../../../store/actions' - - @Component({ - components: {'SolutionComment': SolutionCommentComponent} - }) - export default class Solution extends Vue { - @Prop({ - type: String, - required: true - }) - pk!: string - @Prop({ - type: String, - required: false, - default: '' - }) - solution!: string - @Prop({ - type: String, - default: 'c' - }) - programmingLanguage!: string - @Prop({ - type: Object, - default: {} - }) - solutionComments!: { [ofLine: number]: SolutionComment[] } - @Prop({ - type: Boolean, - default: true - }) - showSolutionComments!: boolean - @Prop({ - type: Boolean, - default: true - }) - editable!: boolean - - timer = 0 - showEditorOnline: {[ofLine: number]: boolean} = {} - editedSolutionComments: {[ofLine: number]: string} = {} - - get highlightedSolution() { - const highlighted = highlight(this.programmingLanguage, this.solution, true) - .value - const postprocessed = syntaxPostProcess(highlighted) - return postprocessed - .split('\n') - .reduce((acc: { [k: number]: string }, curr, index) => { - acc[index + 1] = curr - return acc - }, {}) - } - - get lineNoHint() { - if (this.showSolutionComments) { - // will return a falsy value if indexed with a line number - // meaning no hint will be displayed - return {} - } else { - // returning the solutionComments will return a truthy value - // if indexed with the line number where comments are located - return this.solutionComments - } - } - - backgroundColor(lineNo: number) { - if (this.lineNoHint[lineNo]) { - return 'backgroundColor: #64B5F6;' - } else { - 'backgroundColor: transparent;' - } - } - - selectInput (event: Event) { - if (event !== null) { - const target = event.target as HTMLTextAreaElement - target.select() - } - } - - toggleEditor(lineNo: number) { - if (this.editable) { - Vue.set(this.showEditorOnline, lineNo, !this.showEditorOnline[lineNo]) - } - } - - async submitSolutionComment(lineNo: number) { - const comment = { - text: this.editedSolutionComments[lineNo], - ofLine: lineNo, - ofSubmissionType: this.pk - } - await api.createSolutionComment(comment) - await actions.updateSubmissionType(this.pk) - this.toggleEditor(lineNo) - this.editedSolutionComments[lineNo] = '' - } - - updateSubmissionType() { - actions.updateSubmissionType(this.pk) - } - - mounted() { - this.timer = setInterval(() => { - actions.updateSubmissionType(this.pk) - }, 10 * 1e3) - } - - beforeDestroy() { - clearInterval(this.timer) - } - } -</script> - -<style scoped> - .solution-table { - table-layout: auto; - border-collapse: collapse; - width: 100%; - } - - .line-number-cell { - vertical-align: top - } - - .code-cell-content { - width: 100% - } - - .code-line { - white-space: pre-wrap; - font-family: monospace; - } - - .line-number-btn { - height: fit-content; - min-width: 50px; - margin: 0; - border-radius: 0px; - } -</style> diff --git a/grady/frontend/src/components/submission_type/solution/SolutionComment.vue b/grady/frontend/src/components/submission_type/solution/SolutionComment.vue deleted file mode 100644 index 34239c3ccf3da7f9400433f869a21c602cef1756..0000000000000000000000000000000000000000 --- a/grady/frontend/src/components/submission_type/solution/SolutionComment.vue +++ /dev/null @@ -1,238 +0,0 @@ -<template> - <div> - <div - class="dialog-box" - @click="$emit('toggle-editor')" - > - <div - class="body elevation-1" - :style="{borderColor: '#3D8FC1'}" - > - <span - class="tip tip-up" - :style="{borderBottomColor: '#3D8FC1'}" - /> - <span - v-if="ofUser" - class="of-user" - >Of user: {{ ofUser }}</span> - <span class="comment-created">{{ parsedCreated }}</span> - <div class="message"> - {{ text }} - </div> - <v-btn - v-if="deletable" - text - icon - absolute - class="delete-button" - @click.stop="deleteConfirmation = true" - > - <v-icon - color="grey darken-1" - size="20px" - > - delete_forever - </v-icon> - </v-btn> - <v-btn - v-if="editable" - text - icon - absolute - class="edit-button" - @click.stop="toggleEditing()" - > - <v-icon - color="grey darken-1" - size="20px" - > - edit - </v-icon> - </v-btn> - </div> - </div> - <template v-if="editing"> - <v-textarea - v-model="editedText" - name="solution-comment-edit" - label="Here you can edit your comment" - rows="2" - outlined - autofocus - auto-grow - hide-details - class="mx-2" - @keyup.enter.ctrl.exact="submitEdit" - @keyup.esc="editing = false" - @focus="selectInput($event)" - /> - <v-btn - id="submit-comment" - color="success" - @click="submitEdit" - > - <v-icon>check</v-icon>Submit - </v-btn> - <v-btn - id="cancel-comment" - @click="editing = false" - > - <v-icon>cancel</v-icon>cancel - </v-btn> - </template> - - <v-dialog - v-model="deleteConfirmation" - max-width="max-content" - > - <v-card - class="text-center pa-2" - > - <v-card-title class="title"> - Delete permanently? - </v-card-title> - <v-card-actions> - <v-btn - :id="`confirm-delete-comment`" - color="red lighten-1" - @click="deleteComment" - > - delete - </v-btn> - <v-btn @click="deleteConfirmation = false"> - cancel - </v-btn> - </v-card-actions> - </v-card> - </v-dialog> - </div> -</template> - -<script lang="ts"> -import {Vue, Component, Prop, Provide} from 'vue-property-decorator' -import { UI } from '@/store/modules/ui' -import { SubmissionNotes } from '@/store/modules/submission-notes' -import { Authentication } from '../../../store/modules/authentication' -import * as api from '@/api' -import { actions } from '@/store/actions' - -@Component -export default class SolutionComment extends Vue { - @Prop({ - type: Number, - required: true - }) pk!: number - @Prop({ - type: String, - required: true - }) text!: string - @Prop({ - type: String, - required: false - }) created?: string - @Prop({ - type: String, - required: true - }) ofUser!: string - @Prop({ - type: Number, - required: true - }) ofLine!: number - - editing: boolean = false - editedText: string = '' - deleteConfirmation: boolean = false - - get parsedCreated() { - if (this.created) { - return new Date(this.created).toLocaleString() - } else { - return 'Just now' - } - } - - get deletable() { - return Authentication.state.user.username === this.ofUser || Authentication.isReviewer - } - - get editable() { - return Authentication.state.user.username === this.ofUser - } - - toggleEditing() { - this.editing = !this.editing - this.editedText = this.text - } - - async deleteComment() { - await api.deleteSolutionComment(this.pk) - this.$emit('update-submission-type') - } - - async submitEdit() { - await api.patchSolutionComment({pk: this.pk, text: this.editedText}) - this.editing = false - this.$emit('update-submission-type') - } - - selectInput (event: Event) { - if (event !== null) { - const target = event.target as HTMLTextAreaElement - target.select() - } - } -} -</script> - -<style scoped> - .tip { - width: 0px; - height: 0px; - position: absolute; - background: transparent; - border: 10px solid; - } - .tip-up { - top: -22px; /* Same as body margin top + border */ - left: 10px; - border-right-color: transparent; - border-left-color: transparent; - border-top-color: transparent; - } - .dialog-box .body { - cursor: pointer; - position: relative; - height: auto; - margin: 20px 10px 10px 10px; - padding: 5px; - border-radius: 0px; - border: 2px solid; - } - .body .message { - min-height: 30px; - border-radius: 3px; - font-size: 14px; - line-height: 1.5; - } - .delete-button { - bottom: -12px; - left: -42px; - } - .edit-button { - bottom: 15px; - left: -42px; - } - .comment-created { - position: absolute; - font-size: 10px; - right: 4px; - top: -20px; - } - .of-user { - position: absolute; - font-size: 13px; - top: -20px; - left: 50px; - } -</style> diff --git a/grady/frontend/src/components/subscriptions/SubscriptionEnded.vue b/grady/frontend/src/components/subscriptions/SubscriptionEnded.vue deleted file mode 100644 index d3e6d667d6a194dbcf9fe22ab51834b08d3d56ba..0000000000000000000000000000000000000000 --- a/grady/frontend/src/components/subscriptions/SubscriptionEnded.vue +++ /dev/null @@ -1,43 +0,0 @@ -<template> - <v-card - id="subscription-ended" - class="mx-auto center-page" - > - <v-card-title class="title"> - No submissions left - </v-card-title> - <v-card-text> - All submissions of this type in the current stage have been corrected. If you've - been validating feedback or <br> - reviewing, new submissions might be available in the future. - If that is the case they will appear clickable in the sidebar again. - </v-card-text> - <v-card-actions class="text-center"> - <v-btn to="/home"> - Overview - </v-btn> - <v-btn to="/feedback"> - Feedback History - </v-btn> - </v-card-actions> - </v-card> -</template> - -<script lang="ts"> - -import Vue from 'vue' -import Component from 'vue-class-component' -import store from '@/store/store' - -@Component -export default class SubscriptionEnded extends Vue { -} - -</script> - -<style scoped> - .center-page { - width: fit-content; - top: 30vh; - } -</style> diff --git a/grady/frontend/src/components/subscriptions/SubscriptionForList.vue b/grady/frontend/src/components/subscriptions/SubscriptionForList.vue deleted file mode 100644 index 688f8add44d9e61d2875d6f6ddfc28004d13d94f..0000000000000000000000000000000000000000 --- a/grady/frontend/src/components/subscriptions/SubscriptionForList.vue +++ /dev/null @@ -1,74 +0,0 @@ -<template> - <v-list-item - exact - :to="correctionRoute" - style="width: 100%" - > - <!-- dynamically set css class depending on active --> - <v-list-item-content - :class="{'inactive-subscription': !active}" - class="mr-3 subscription" - > - {{ name }} - </v-list-item-content> - <v-list-item-action-text> - left: {{ available }} - </v-list-item-action-text> - </v-list-item> -</template> - -<script lang="ts"> -import Vue from 'vue' -import Component from 'vue-class-component' -import { Prop } from 'vue-property-decorator' -import { Assignment , FeedbackStageEnum } from '@/models' -import { Assignments } from '@/store/modules/assignments' - -@Component -export default class SubscriptionForList extends Vue { - @Prop({ type: String, required: true }) name!: string - @Prop({ type: String, required: true }) sub_type_pk!: string - - get active () { - return !!this.available - } - - get available () { - const stage = Assignments.state.assignmentCreation.stage - const sub_type = this.sub_type_pk - const forSubType = Assignments.state.submissionsLeft[sub_type] - const forStage = forSubType !== undefined ? forSubType[stage] : undefined - return forStage - } - - get correctionRoute() { - if (!this.active) - return undefined - - const group = Assignments.state.assignmentCreation.group - const group_pk = group !== undefined ? group.pk : undefined - - return { - name: 'correction', - params: { - sub_type: this.sub_type_pk, - stage: Assignments.state.assignmentCreation.stage, - group: group_pk || undefined, - } - } - } -} -</script> - -<style scoped> - .inactive-subscription { - cursor: default; - color: #B5B5B5; - } - - .subscription { - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - } -</style> diff --git a/grady/frontend/src/components/subscriptions/SubscriptionList.vue b/grady/frontend/src/components/subscriptions/SubscriptionList.vue deleted file mode 100644 index 9aff883b72d1ef9c104fe1f7816809a692eb2010..0000000000000000000000000000000000000000 --- a/grady/frontend/src/components/subscriptions/SubscriptionList.vue +++ /dev/null @@ -1,189 +0,0 @@ -<template> - <v-card name="subscription-list"> - <v-toolbar - color="teal" - :dense="sidebar" - > - <v-app-bar-nav-icon><v-icon>assignment</v-icon></v-app-bar-nav-icon> - <v-toolbar-title - v-if="!sidebar" - style="min-width: fit-content;" - > - Tasks - </v-toolbar-title> - <v-spacer /> - <v-select - v-model="selectedGroup" - :items="groups" - item-text="name" - return-object - hide-details - solo - flat - background-color="teal" - /> - <v-btn - icon - @click="getAvailableSubmissionCount(false)" - > - <v-icon v-if="!updating"> - refresh - </v-icon> - <v-progress-circular - v-else - indeterminate - color="black" - size="20" - /> - </v-btn> - </v-toolbar> - <v-tabs - v-if="showDetail" - v-model="selectedStage" - grow - color="black" - background-color="teal lighten-1" - > - <v-tab - v-for="(item, i) in stagesReadable" - :key="i" - > - {{ item }} - </v-tab> - <v-tab-item - v-for="(stage, i) in stages" - :key="i" - > - <subscriptions-for-stage - :id="`stage-${i}`" - :stage="stage" - /> - </v-tab-item> - </v-tabs> - </v-card> -</template> - -<script lang="ts"> -import Vue from 'vue' -import Component from 'vue-class-component' -import { Prop, Watch } from 'vue-property-decorator' -import { mapGetters, mapActions, mapState } from 'vuex' -import { UI } from '@/store/modules/ui' -import { actions } from '@/store/actions' -import SubscriptionForList from '@/components/subscriptions/SubscriptionForList.vue' -import SubscriptionsForStage from '@/components/subscriptions/SubscriptionsForStage.vue' -import { Assignments } from '@/store/modules/assignments' -import store from '../../store/store' -import { FeedbackStageEnum, Group } from '../../models' -import { Authentication } from '../../store/modules/authentication' -import { ConfigModule } from '../../store/modules/config' - -@Component({ - name: 'subscription-list', - components: { - SubscriptionsForStage, - SubscriptionForList, - }, -}) -export default class SubscriptionList extends Vue { - @Prop({type: Boolean, default: false}) sidebar!: boolean - - updating = false - timer = 0 - - get stages () { return Assignments.availableStages } - get stagesReadable () { return Assignments.availableStagesReadable } - get showDetail () { - return !this.sidebar || (this.sidebar && !UI.state.sideBarCollapsed) - } - get groups () { - return Assignments.state.groups.slice() - .filter(group => { - return group.exam === null || group.exam.pk === ConfigModule.state.config.examId - }) - .sort((a, b) => { - const matches_a = a.name.match(/(\d+)/) - const number_a = Number(matches_a === null ? 0 : matches_a[1]) - - const matches_b = b.name.match(/(\d+)/) - const number_b = Number(matches_b === null ? 0 : matches_b[1]) - - return (number_a<number_b?-1:(number_a>number_b?1:0)) - }) - } - - get selectedStage() { - const val = Assignments.state.assignmentCreation.stage - switch (val) { - case FeedbackStageEnum.Creation: return 0 - case FeedbackStageEnum.Validation: return 1 - case FeedbackStageEnum.Review: return 2 - default: - throw new Error(`Illegal value ${val} in get selectedStage`) - } - } - - set selectedStage(val) { - const map_number_to_stage = (val: number): FeedbackStageEnum => { - switch (val) { - case 0: return FeedbackStageEnum.Creation - case 1: return FeedbackStageEnum.Validation - case 2: return FeedbackStageEnum.Review - default: - throw new Error(`Illegal value ${val} in set selectedStage`) - } - } - Assignments.SET_CREATE_STAGE(map_number_to_stage(val)) - } - - get selectedGroup() { - return Assignments.state.assignmentCreation.group - } - - set selectedGroup(val: Group | undefined) { - if (val === undefined) { - throw new Error('Setting create group to undefined is not allowed') - } - Assignments.SET_CREATE_GROUP(val) - Assignments.getAvailableSubmissionCounts() - } - - - async getAvailableSubmissionCount (silent: boolean) { - if (silent === false) { - this.updating = true - } - await Assignments.getAvailableSubmissionCounts() - this.updating = false - } - - beforeDestroy() { - clearInterval(this.timer) - } - - created() { - const ownGroup = Authentication.state.user.exerciseGroups[0] - if (ownGroup !== undefined) { - this.selectedGroup = ownGroup - } - - const submissionTypes = actions.updateSubmissionTypes() - const groups = Assignments.getGroups() - Promise.all([submissionTypes, groups]).then(() => { - this.getAvailableSubmissionCount(false) - - this.timer = setInterval(() => { - this.getAvailableSubmissionCount(true) - }, 30 * 1e3) - }) - - Promise.all([submissionTypes]).then(() => { - Assignments.cleanAssignments() - }) - } -} -</script> - -<style scoped> - -</style> diff --git a/grady/frontend/src/components/subscriptions/SubscriptionsForStage.vue b/grady/frontend/src/components/subscriptions/SubscriptionsForStage.vue deleted file mode 100644 index e6ab066d02dbb2064ca7847ccc763b9b5828a683..0000000000000000000000000000000000000000 --- a/grady/frontend/src/components/subscriptions/SubscriptionsForStage.vue +++ /dev/null @@ -1,48 +0,0 @@ -<template> - <v-list :dense="dense"> - <div> - <div - v-for="subType in submissionTypes" - :key="subType.pk" - > - <subscription-for-list - :name="subType.name" - :sub_type_pk="subType.pk" - :available="1" - /> - </div> - </div> - </v-list> -</template> - -<script> -import SubscriptionForList from '@/components/subscriptions/SubscriptionForList' -import { Assignments } from '@/store/modules/assignments' -import store from '../../store/store' -import { ConfigModule } from '../../store/modules/config' -export default { - name: 'SubscriptionsForStage', - components: { - SubscriptionForList - }, - props: { - stage: { - type: String, - required: true - }, - dense: { - type: Boolean, - default: false - } - }, - computed: { - submissionTypes () { return Object.values(store.state.submissionTypes).filter(submissionType => { - return submissionType.examType.moduleReference === ConfigModule.state.config.currentExam - })} - } -} -</script> - -<style scoped> - -</style> diff --git a/grady/frontend/src/components/tutor_list/RoleSelect.vue b/grady/frontend/src/components/tutor_list/RoleSelect.vue deleted file mode 100644 index e5236334397af5a92d0f31d5d12678d35ff954f5..0000000000000000000000000000000000000000 --- a/grady/frontend/src/components/tutor_list/RoleSelect.vue +++ /dev/null @@ -1,48 +0,0 @@ -<template> - <v-select - v-model="value" - :items="roleOptions" - filled - dense - hide-details - :loading="loading" - :disabled="isForSelf" - @change="updateRole" - /> -</template> - -<script lang="ts"> -import Vue from 'vue' -import Component from 'vue-class-component' -import { Prop, Watch } from 'vue-property-decorator' -import { Tutor, UserAccount } from '@/models' -import { changeUserRole } from '@/api' -import { Authentication } from '@/store/modules/authentication' - -@Component -export default class RoleSelect extends Vue { - @Prop({ type: Object, required: true }) readonly tutor!: Tutor - - roleOptions = [UserAccount.RoleEnum.Reviewer, UserAccount.RoleEnum.Tutor] - value = this.tutor.role - previousValue = this.value - loading = false - - get isForSelf() { - return Authentication.state.user.pk === this.tutor.pk - } - - async updateRole(newRole: UserAccount.RoleEnum) { - this.loading = true - try { - await changeUserRole(this.tutor.pk, newRole) - this.previousValue = newRole - } catch (error) { - this.value = this.previousValue - } finally { - this.loading = false - } - } -} -</script> - diff --git a/grady/frontend/src/components/tutor_list/TutorList.vue b/grady/frontend/src/components/tutor_list/TutorList.vue deleted file mode 100644 index 229d0427469050c3f84a3cdb5e912f20d0acca63..0000000000000000000000000000000000000000 --- a/grady/frontend/src/components/tutor_list/TutorList.vue +++ /dev/null @@ -1,224 +0,0 @@ -<template> - <v-card> - <v-card-title class="title"> - Tutors - <v-spacer /> - <v-btn - icon - @click="refresh" - > - <v-icon>refresh</v-icon> - </v-btn> - </v-card-title> - <v-data-table - :headers="headers" - :items="tutors" - item-key="pk" - > - <template #item.reservedSubmissions="{ item }"> - {{ item.reservedSubmissions }} - <v-tooltip - v-if="item.reservedSubmissions" - top - > - <template #activator="{ on }"> - <v-icon - small - v-on="on" - @click="deleteAssignmentsOfTutor(item)" - > - clear - </v-icon> - </template> - <span>Free locked submissions</span> - </v-tooltip> - </template> - <template #item.exerciseGroups="{ item }"> - <v-select - v-model="item.exerciseGroups" - item-text="name" - item-value="pk" - :items="groups" - label="Set Groups" - single-line - return-object - multiple - chips - dense - hide-details - filled - @change="setExerciseGroups($event, item)" - /> - </template> - <template #item.isActive="{ item }"> - <v-btn - v-if="canRevokeAccess(item.username)" - icon - @click="changeActiveStatus(item)" - > - <v-tooltip top> - <template #activator="{ on }"> - <v-icon - v-if="item.isActive" - small - v-on="on" - > - lock_open - </v-icon> - <v-icon - v-else - small - v-on="on" - > - lock - </v-icon> - </template> - <span v-if="item.isActive">Revoke access</span> - <span v-else>Grant access</span> - </v-tooltip> - </v-btn> - </template> - <template #item.role="{ item }"> - <role-select :tutor="item" /> - </template> - </v-data-table> - </v-card> -</template> - -<script lang="ts"> -import Vue from 'vue' -import Component from 'vue-class-component' -import { changeActiveForUser, setGroups, fetchUserGroups, fetchUser } from '@/api' -import { actions } from '@/store/actions' -import { Authentication } from '@/store/modules/authentication' -import { TutorOverview } from '@/store/modules/tutor-overview' -import { Group, Tutor, UserAccount } from '@/models' -import { Assignments } from '@/store/modules/assignments' -import RoleSelect from './RoleSelect.vue' -import { ConfigModule } from '@/store/modules/config' - -@Component({ components: { RoleSelect } }) -export default class TutorList extends Vue { - headers = [ - { - text: 'Name', - align: 'left', - value: 'username' - }, - { - text: '# created', - align: 'right', - value: 'feedbackCreated' - }, - { - text: '# validated', - align: 'right', - value: 'feedbackValidated' - }, - { - text: '# locked submissions', - align: 'right', - value: 'reservedSubmissions' - }, - { - text: 'Exercise Groups', - align: 'right', - value: 'exerciseGroups' - }, - { - text: 'Has Access', - align: 'right', - value: 'isActive' - }, - { - text: 'Role', - value: 'role' - } - ] - - get tutors () { - var tlist = TutorOverview.state.tutors.map(tutor => { - var groups: Group[] = [] - this.userAccountGroups(tutor).then(function(value) { - groups = value // Success! - }, (reason) => { - this.$notify({ - title: 'Error', - text: `Unable to fetch tutors: ${reason}`, - type: 'error' - }) - return [] - }) - const reservedSubmissions = TutorOverview.state.activeAssignments[tutor.pk] - return { - ...tutor, - reservedSubmissions: reservedSubmissions ? reservedSubmissions.length : 0, - } - }) - return tlist - } - - get groups () { - return Assignments.state.groups.slice() - .filter(group => { - return group.exam === null || group.exam.pk === ConfigModule.state.config.examId - }) - .sort((a, b) => { - const matches_a = a.name.match(/(\d+)/) - const number_a = Number(matches_a === null ? 0 : matches_a[1]) - - const matches_b = b.name.match(/(\d+)/) - const number_b = Number(matches_b === null ? 0 : matches_b[1]) - - return (number_a<number_b?-1:(number_a>number_b?1:0)) - }) - } - - - async userAccountGroups(tutor: Tutor) { - const groups = await (await fetchUser(tutor.pk)).exerciseGroups - return groups - } - - changeActiveStatus (tutor: Tutor) { - changeActiveForUser(tutor.pk, !tutor.isActive).then(() => { - TutorOverview.getTutors() - }).catch(() => { - this.$notify({ - title: 'Error', - text: `Unable to change active status of ${tutor.username}`, - type: 'error' - }) - }) - } - - setExerciseGroups (groups: Group[], tutor: Tutor){ - setGroups(tutor.pk, groups).then(() => { - TutorOverview.getTutors() - }).catch(() => { - this.$notify({ - title: 'Error', - text: `Unable to change exercise-groups of ${tutor.username}`, - type: 'error' - }) - }) - } - - deleteAssignmentsOfTutor (tutor: Tutor) { - TutorOverview.deleteActiveAssignmentsOfTutor(tutor) - } - - refresh () { - TutorOverview.getTutors() - TutorOverview.getActiveAssignments() - } - - canRevokeAccess (username: string) { - return Authentication.state.user.username !== username - } -} -</script> - -<style scoped> - -</style> diff --git a/grady/frontend/src/main.ts b/grady/frontend/src/main.ts deleted file mode 100644 index ec119eaac3563274579c0192705f803e630c6351..0000000000000000000000000000000000000000 --- a/grady/frontend/src/main.ts +++ /dev/null @@ -1,38 +0,0 @@ - -import './class-component-hooks' - -import Vue from 'vue' -import store from './store/store' -import App from './App.vue' -import router from './router/index' -import Vuetify from 'vuetify' -import Notifications from 'vue-notification' -import Clipboard from 'v-clipboard' - -import 'vuetify/dist/vuetify.min.css' -import 'highlight.js/styles/atom-one-light.css' - -import '@/util/shortkeys' - -Vue.use(Vuetify) - -Vue.use(Clipboard) -Vue.use(Notifications) - -Vue.config.productionTip = false - -const el = process.env.NODE_ENV === 'test' ? undefined : '#app' - -const vuetify = new Vuetify({ - icons: { - iconfont: 'md', - }, -}) - -export default new Vue({ - vuetify, - el: el, - router: router, - store, - render: h => h(App) -}).$mount(el) diff --git a/grady/frontend/src/models.ts b/grady/frontend/src/models.ts deleted file mode 100644 index eb2d840d61c7913ce68343287832822c2b371a9d..0000000000000000000000000000000000000000 --- a/grady/frontend/src/models.ts +++ /dev/null @@ -1,922 +0,0 @@ -export interface Config { - timeDelta: number - version: string, - currentExam: string, - examId: string, - instanceSettings: { - [config: string]: boolean, - } -} - -export interface Group { - pk: string, - name: string, - exam: Exam -} - -export interface CreateAssignment { - submissionType: string - group?: string - stage: FeedbackStageEnum -} - -/** - * - * @export - * @interface Assignment - */ -export interface Assignment { - /** - * - * @type {string} - * @memberof Assignment - */ - pk: string - /** - * - * @type {string} - * @memberof Assignment - */ - submission?: string | SubmissionAssignment - /** - * - * @type {boolean} - * @memberof Assignment - */ - isDone?: boolean - /** - * - * @type {string} - * @memberof Assignment - */ - owner?: string - /** - * - * @type {string} - * @memberof Assignment - */ - stage?: FeedbackStageEnum - - ofTutor?: string - - feedback?: Feedback - -} - -export interface SubmissionAssignment { - text: string, - type: string - full_score: number, - tests: Test[] -} - -/** - * - * @export - * @interface Exam - */ -export interface Exam { - /** - * - * @type {string} - * @memberof Exam - */ - pk: string - /** - * - * @type {string} - * @memberof Exam - */ - moduleReference: string - /** - * - * @type {number} - * @memberof Exam - */ - totalScore: number - /** - * - * @type {number} - * @memberof Exam - */ - passScore: number - /** - * - * @type {boolean} - * @memberof Exam - */ - passOnly?: boolean -} - -/** - * - * @export - * @interface Feedback - */ -export interface Feedback { - /** - * - * @type {number} - * @memberof Feedback - */ - pk: number - /** - * - * @type {string} - * @memberof Feedback - */ - ofSubmission?: string - /** - * - * @type {boolean} - * @memberof Feedback - */ - ofStudent?: string - isFinal?: boolean - /** - * - * @type {number} - * @memberof Feedback - */ - score?: number - /** - * - * @type {Array<FeedbackComment>} - * @memberof Feedback - */ - feedbackLines?: {[lineNo: number]: FeedbackComment[]} - /** - * - * @type {Date} - * @memberof Feedback - */ - created?: string - /** - * - * @type {Date} - * @memberof Feedback - */ - modified?: string - /** - * - * @type {string} - * @memberof Feedback - */ - ofSubmissionType: SubmissionType - /** - * - * @type {SubmissionType} - * @memberof Feedback - */ - feedbackStageForUser?: string, - labels: number[], -} - -/** - * - * @export - * @interface CreateUpdateFeedback - */ -export interface CreateUpdateFeedback { - /** - * - * @type {number} - * @memberof Feedback - */ - pk: number - /** - * - * @type {string} - * @memberof Feedback - */ - ofSubmission?: string - /** - * - * @type {boolean} - * @memberof Feedback - */ - isFinal?: boolean - /** - * - * @type {number} - * @memberof Feedback - */ - score?: number - /** - * - * @type {Array<FeedbackComment>} - * @memberof Feedback - */ - feedbackLines: {[lineNo: number]: FeedbackComment} - /** - * - * @type {Date} - * @memberof Feedback - */ - created?: string - /** - * - * @type {string} - * @memberof Feedback - */ - ofSubmissionType?: string - /** - * - * @type {string} - * @memberof Feedback - */ - feedbackStageForUser?: string, - labels: number[], -} - -/** - * - * @export - * @Comment - */ -export interface FeedbackComment { - /** - * - * @type {string} - * @memberof FeedbackComment - */ - pk: string - /** - * - * @type {string} - * @memberof FeedbackComment - */ - text: string - /** - * - * @type {Date} - * @memberof FeedbackComment - */ - modified?: string - /** - * - * @type {string} - * @memberof FeedbackComment - */ - ofTutor?: string - /** - * - * @type {number} - * @memberof FeedbackComment - */ - ofLine?: number - /** - * - * @type {boolean} - * @memberof FeedbackComment - */ - visibleToStudent?: boolean - labels: number[] - updated?: boolean -} - -/** - * - * @export - * @interface FeedbackLabel - */ -export interface FeedbackLabel { - pk: number - name: string - description: string - colour: string -} - -/** - * - * @export - * @interface Credentials - */ -export interface Credentials { - /** - * - * @type {string} - * @memberof JSONWebToken - */ - username: string - /** - * - * @type {string} - * @memberof JSONWebToken - */ - password: string -} - -export interface JSONWebToken { - token: string -} - -export interface Statistics { - submissionsPerType: number, - submissionsPerStudent: number, - currentMeanScore: number, - submissionTypeProgress: Array<SubmissionTypeProgress> -} - -export interface LabelStatisticsForSubType { - /** Contains the count of the different labels under their pk */ - [label_pk: number]: number, - /** The pk of the corresponding SubmissionType */ - pk: string -} - -/** - * - * @export - * @interface StudentInfo - */ -export interface StudentInfo { - /** - * - * @type {string} - * @memberof StudentInfo - */ - pk: string - /** - * - * @type {string} - * @memberof StudentInfo - */ - name?: string - /** - * - * @type {string} - * @memberof StudentInfo - */ - user: string - /** - * - * @type {string} - * @memberof StudentInfo - */ - matrikelNo?: string - /** - * - * @type {Exam} - * @memberof StudentInfo - */ - exam: Exam - /** - * - * @type {Array<SubmissionList>} - * @memberof StudentInfo - */ - submissions: Array<SubmissionList> - /** - * - * @type {boolean} - * @memberof StudentInfo - */ - passesExam?: boolean -} - -/** - * - * @export - * @interface StudentInfoForListView - */ -export interface StudentInfoForListView { - /** - * - * @type {string} - * @memberof StudentInfoForListView - */ - pk: string - /** - * - * @type {string} - * @memberof StudentInfoForListView - */ - name?: string - /** - * - * @type {string} - * @memberof StudentInfoForListView - */ - user?: string - /** - * - * @type {string} - * @memberof StudentInfoForListView - */ - userPk?: string - /** - * - * @type {string} - * @memberof StudentInfoForListView - */ - exam?: string - /** - * - * @type {Array<SubmissionNoTextFields>} - * @memberof StudentInfoForListView - */ - submissions: Array<SubmissionNoTextFields> - /** - * - * @type {string} - * @memberof StudentInfoForListView - */ - matrikelNo?: string - /** - * - * @type {boolean} - * @memberof StudentInfoForListView - */ - passesExam?: boolean - /** - * - * @type {boolean} - * @memberof StudentInfoForListView - */ - isActive: boolean -} - -/** - * - * @export - * @interface Submission - */ -export interface Submission { - /** - * - * @type {string} - * @memberof Submission - */ - pk: string - /** - * - * @type {SubmissionType} - * @memberof Submission - */ - type: SubmissionType - /** - * - * @type {string} - * @memberof Submission - */ - text?: string - /** - * - * @type {VisibleCommentFeedback} - * @memberof Submission - */ - feedback: VisibleCommentFeedback - /** - * - * @type {Array<Test>} - * @memberof Submission - */ - tests: Array<Test>, - - sourceCodeAvailable: boolean -} - -/** - * - * @export - * @interface SubmissionList - */ -export interface SubmissionList { - /** - * - * @type {string} - * @memberof SubmissionList - */ - pk: string - /** - * - * @type {SubmissionTypeList} - * @memberof SubmissionList - */ - type: SubmissionTypeList - /** - * - * @type {Feedback} - * @memberof SubmissionList - */ - feedback: Feedback -} - -/** - * - * @export - * @interface SubmissionNoTextFields - */ -export interface SubmissionNoTextFields { - /** - * - * @type {string} - * @memberof SubmissionNoTextFields - */ - pk: string - /** - * - * @type {string} - * @memberof SubmissionNoTextFields - */ - type: string - /** - * - * @type {string} - * @memberof SubmissionNoTextFields - */ - score?: string - /** - * - * @type {string} - * @memberof SubmissionNoTextFields - */ - final?: string - /** - * - * @type {string} - * @memberof SubmissionNoTextFields - */ - fullScore?: string -} - -/** - * - * @export - * @interface SubmissionNoType - */ -export interface SubmissionNoType { - /** - * - * @type {string} - * @memberof SubmissionNoType - */ - pk: string - /** - * - * @type {string} - * @memberof SubmissionNoType - */ - type: string - /** - * - * @type {string} - * @memberof SubmissionNoType - */ - fullScore?: string - /** - * - * @type {string} - * @memberof SubmissionNoType - */ - text?: string - /** - * - * @type {Feedback} - * @memberof SubmissionNoType - */ - feedback?: Feedback - ofStudent?:string - /** - * - * @type {Array<Test>} - * @memberof SubmissionNoType - */ - tests: Array<Test>, - - sourceCodeAvailable: boolean -} - -/** - * - * @export - * @interface SubmissionType - */ -export interface SubmissionType { - /** - * - * @type {string} - * @memberof SubmissionType - */ - pk: string - /** - * - * @type {string} - * @memberof SubmissionType - */ - name: string - /** - * - * @type {number} - * @memberof SubmissionType - */ - examType: Exam - /** - * - * @type {Exam} - * @memberof SubmissionType - */ - fullScore?: number - /** - * - * @type {string} - * @memberof SubmissionType - */ - description: string - /** - * - * @type {string} - * @memberof SubmissionType - */ - solution?: string - /** - * - * @type {string} - * @memberof SubmissionType - */ - programmingLanguage?: SubmissionType.ProgrammingLanguageEnum - - solutionComments: {[ofLine: number]: SolutionComment[]} -} - -export interface AvailableSubmissionCounts { - [submissionType: string]: { - [stage: string]: number - } -} - -export interface SolutionComment { - pk: number, - created: string, - ofLine: number, - ofSubmissionType: string, - ofUser: string, - text: string -} - -/** - * @export - * @namespace SubmissionType - */ -export namespace SubmissionType { - /** - * @export - * @enum {string} - */ - export enum ProgrammingLanguageEnum { - C = 'c', - Java = 'java', - Markdown = 'markdown' - } -} - -/** - * - * @export - * @interface SubmissionTypeList - */ -export interface SubmissionTypeList { - /** - * - * @type {string} - * @memberof SubmissionTypeList - */ - pk: string - - /** - * - * @type {string} - * @memberof SubmissionTypeList - */ - name: string - /** - * - * @type {number} - * @memberof SubmissionTypeList - */ - fullScore?: number -} - -export interface SubmissionTypeProgress { - pk: string - name: string - feedbackFinal: number - feedbackInValidation: number - feedbackInConflict: number - submissionCount: number -} - - -/** - * @export - * @enum {string} - */ -export enum FeedbackStageEnum { - Creation = 'feedback-creation', - Validation = 'feedback-validation', - Review = 'feedback-review' -} - -/** - * - * @export - * @interface Test - */ -export interface Test { - /** - * - * @type {string} - * @memberof Test - */ - pk: string - /** - * - * @type {string} - * @memberof Test - */ - name: string - /** - * - * @type {string} - * @memberof Test - */ - label: string - /** - * - * @type {string} - * @memberof Test - */ - annotation: string -} - -/** - * - * @export - * @interface Tutor - */ -export interface Tutor { - /** - * - * @type {string} - * @memberof Tutor - */ - pk: string - /** - * - * @type {string} - * @memberof Tutor - */ - password?: string - /** - * Designates whether this user should be treated as active. Unselect this instead of deleting accounts. - * @type {boolean} - * @memberof Tutor - */ - isActive?: boolean - /** - * Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only. - * @type {string} - * @memberof Tutor - */ - username: string - /** - * - * @type {string} - * @memberof Tutor - */ - feedbackCreated?: string - /** - * - * @type {string} - * @memberof Tutor - */ - feedbackValidated?: string - /** - * - * @type {Group} - * @memberof Tutor - */ - exerciseGroups: Group[] - - /** - * @type {string} - * @memberof Tutor - */ - role: UserAccount.RoleEnum -} - -/** - * - * @export - * @interface UserAccount - */ -export interface UserAccount { - /** - * - * @type {string} - * @memberof UserAccount - */ - pk: string - /** - * Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only. - * @type {string} - * @memberof UserAccount - */ - username?: string - /** - * - * @type {string} - * @memberof UserAccount - */ - role?: UserAccount.RoleEnum - /** - * - * @type {boolean} - * @memberof UserAccount - */ - isAdmin?: boolean - /** - * - * @type {string} - * @memberof UserAccount - */ - password?: string - exerciseGroups: Group[] -} - -/** - * @export - * @namespace UserAccount - */ -export namespace UserAccount { - /** - * @export - * @enum {string} - */ - export enum RoleEnum { - Student = 'Student', - Tutor = 'Tutor', - Reviewer = 'Reviewer' - } -} - -/** - * - * @export - * @interface VisibleCommentFeedback - */ -export interface VisibleCommentFeedback { - /** - * - * @type {number} - * @memberof VisibleCommentFeedback - */ - pk: number - /** - * - * @type {string} - * @memberof VisibleCommentFeedback - */ - ofSubmission: string - /** - * - * @type {boolean} - * @memberof VisibleCommentFeedback - */ - isFinal?: boolean - /** - * - * @type {number} - * @memberof VisibleCommentFeedback - */ - score?: number - /** - * - * @type {string} - * @memberof VisibleCommentFeedback - */ - feedbackLines?: string - /** - * - * @type {Date} - * @memberof VisibleCommentFeedback - */ - created?: Date - /** - * - * @type {string} - * @memberof VisibleCommentFeedback - */ - ofSubmissionType?: string - - labels: number[] -} - -export interface GitlabRelease { - - tag_name: string - - description_html: string - -} diff --git a/grady/frontend/src/pages/ExamSelectionPage.vue b/grady/frontend/src/pages/ExamSelectionPage.vue deleted file mode 100644 index fcfc1e58bc9d11a159e02be3d8694035413d6a18..0000000000000000000000000000000000000000 --- a/grady/frontend/src/pages/ExamSelectionPage.vue +++ /dev/null @@ -1,121 +0,0 @@ -<template> - <v-container fill-height> - <v-app-bar - app - dense - fixed - dark - color="indigo darken-4" - class="grady-toolbar" - > - <router-link to="/home"> - <v-app-bar-title>Grady</v-app-bar-title> - </router-link> - <span class="pl-2 grady-speak">{{ gradySpeak }}</span> - <v-spacer /> - <v-divider vertical /> - <user-options /> - </v-app-bar> - <v-layout - align-center - justify-center - > - <v-card - class="mx-auto" - max-width="600" - min-width="500" - > - <v-card-title> - <h1>Select Exam<br></h1> - </v-card-title> - <v-card-text> - <p style="color:grey;"> - You can always come back and change your selection - </p> - </v-card-text> - <v-list> - <v-list-item - v-for="examType in examTypes" - id="listItem" - :key="examType.pk" - @click="selectExamType(examType)" - > - {{ examType.moduleReference }} - </v-list-item> - </v-list> - </v-card> - </v-layout> - </v-container> -</template> - -<script> -import { mapActions, mapState } from 'vuex' -import RegisterDialog from '@/components/RegisterDialog' -import { Authentication as Auth } from '@/store/modules/authentication' -import { ConfigModule } from '../store/modules/config' -import store from '@/store/store' -import { getters } from '@/store/getters' -import { actions } from '@/store/actions' -import ax, { fetchExamTypes } from '@/api' -import { Config } from '@/models' -import UserOptions from '@/components/UserOptions' - - -export default { - name: 'ExamSelection', - components: { UserOptions }, - data () { - return { - examTypes: [], - } - }, - computed: { - msg () { return Auth.state.message }, - userRole () { return Auth.state.user.role }, - gradySpeak () { return Auth.gradySpeak }, - }, - created () { - this.loadExamTypes() - }, - methods: { - selectExamType (examType) { - ConfigModule.SET_CURRENT_EXAM(examType.moduleReference) - ConfigModule.SET_CURRENT_EXAM_ID(examType.pk) - this.$router.push({ name: 'home' }) - }, - logout () { - actions.logout() - }, - async loadExamTypes () { - try { - const response = (await ax.get('/api/examtype/')).data - this.examTypes = response - if (this.examTypes.length === 0) { - this.$router.push({ name: 'home' }) - } - else if (this.examTypes.length === 1) { - this.selectExamType(this.examTypes[0]) - } - } catch (ex) { - console.log(ex) - } - }, - } -} -</script> - -<style scoped> - .v-btn { - margin: 0px; - } - - .btn-container { - display: flex; - flex-wrap: nowrap; - justify-content: space-around; - } - - .grady-toolbar { - font-weight: bold; - } -</style> diff --git a/grady/frontend/src/pages/LayoutSelector.vue b/grady/frontend/src/pages/LayoutSelector.vue deleted file mode 100644 index bb2e9d04ea1e7ccfc622c18b4647e4a85ef9f839..0000000000000000000000000000000000000000 --- a/grady/frontend/src/pages/LayoutSelector.vue +++ /dev/null @@ -1,58 +0,0 @@ -<template> - <div> - <component :is="layout" /> - <v-main class="main-content"> - <router-view /> - </v-main> - </div> -</template> - -<script> -import { mapGetters } from 'vuex' -import TutorLayout from '@/pages/tutor/TutorLayout' -import StudentLayout from '@/pages/student/StudentLayout' -import ReviewerLayout from '@/pages/reviewer/ReviewerLayout' -import { Authentication } from '@/store/modules/authentication' - -export default { - name: 'LayoutSelector', - components: { - ReviewerLayout, - StudentLayout, - TutorLayout }, - computed: { - isStudent () { return Authentication.isStudent }, - isTutor () { return Authentication.isTutor }, - isReviewer () { return Authentication.isReviewer }, - layout () { - if (this.isStudent) { - return 'student-layout' - } else if (this.isTutor) { - return 'tutor-layout' - } else if (this.isReviewer) { - return 'reviewer-layout' - } - - return undefined - } - } -} -</script> - -<style> - html { - /* Vuetify always shows the scrollbar by default. This disables it. */ - overflow-y: auto !important; - } -</style> - -<style scoped> - /* Move the scrollbar below the header so it doesn't jump around when no scrollbar is shown. */ - .main-content { - /* 48px is the vuetify header size. */ - height: calc(100vh - 48px); - margin-top: 48px; - padding-top: 0 !important; - overflow: auto; - } -</style> diff --git a/grady/frontend/src/pages/Login.vue b/grady/frontend/src/pages/Login.vue deleted file mode 100644 index 846f8c4d6e0eda0145aeda99a32bc87803dbf61a..0000000000000000000000000000000000000000 --- a/grady/frontend/src/pages/Login.vue +++ /dev/null @@ -1,158 +0,0 @@ -<template> - <v-container class="fill-height"> - <v-row - align="center" - justify="center" - > - <v-dialog - v-model="registerDialog" - class="pa-4" - scrollable - max-width="600" - > - <register-dialog @registered="registered($event)" /> - </v-dialog> - <v-col - cols="12" - sm="12" - md="10" - lg="7" - > - <img - src="https://grady.informatik.uni-goettingen.de/static/img/brand.svg" - class="grady-logo" - > - </v-col> - <v-divider - vertical - inset - class="ma-4" - /> - <v-col - class="text-center" - cols="8" - sm="6" - md="4" - lg="2" - > - <h2 class="pt-3"> - Log in - </h2> - <v-alert - :value="msg.length !== 0" - outlined - color="error" - transition="fade-transition" - > - {{ msg }} - </v-alert> - <p v-if="msg.length === 0"> - But I corrected them, sir. - </p> - <v-form - @submit.prevent="submit" - > - <v-text-field - id="username" - v-model="credentials.username" - label="Username" - required - autofocus - /> - <v-text-field - id="password" - v-model="credentials.password" - label="Password" - type="password" - required - /> - <v-row class="btn-container"> - <v-btn - id="register" - @click="registerDialog = true" - > - Register - </v-btn> - <v-btn - :loading="loading" - type="submit" - color="primary" - > - Access - </v-btn> - </v-row> - </v-form> - </v-col> - </v-row> - </v-container> -</template> - -<script> -import { mapActions, mapState } from 'vuex' -import RegisterDialog from '@/components/RegisterDialog' -import { Authentication as Auth } from '@/store/modules/authentication' -import { ConfigModule } from '../store/modules/config' - -export default { - name: 'GradyLogin', - components: { RegisterDialog }, - data () { - return { - credentials: { - username: '', - password: '' - }, - registerDialog: false, - loading: false - } - }, - computed: { - msg () { return Auth.state.message }, - userRole () { return Auth.state.user.role }, - }, - methods: { - submit () { - this.loading = true - Auth.getJWT(this.credentials).then(() => { - return Promise.all([ - Auth.getUser(), - ConfigModule.getConfig() - ]) - }).then(() => { - this.$router.push({ name: 'exam-selection' }) - this.loading = false - }).catch((err) => { - let msg = 'Login failed. Please try again.' - if (typeof err === 'string') { - msg = err - } - - Auth.SET_MESSAGE(msg) - this.loading = false - }) - }, - registered (credentials) { - this.registerDialog = false - this.credentials.username = credentials.username - this.credentials.password = credentials.password - Auth.SET_MESSAGE('Your account is being activated. Please wait.') - } - } -} -</script> - -<style scoped> - .v-btn { - margin: 0px; - } - - .btn-container { - display: flex; - flex-wrap: nowrap; - justify-content: space-around; - } - - .grady-logo { - width: 100%; - } -</style> diff --git a/grady/frontend/src/pages/PageNotFound.vue b/grady/frontend/src/pages/PageNotFound.vue deleted file mode 100644 index 4e8debf69a6116b625241edcadc82ab95623354d..0000000000000000000000000000000000000000 --- a/grady/frontend/src/pages/PageNotFound.vue +++ /dev/null @@ -1,46 +0,0 @@ -<template> - <v-container class="fill-height"> - <v-row - align="center" - justify="center" - > - <v-card - dark - width="80%" - height="80%" - > - <v-card-title style="font-size: 350%"> - The content you're requesting is not available in your country. - </v-card-title> - <v-divider class="px-5" /> - <v-col - cols="10" - offset="2" - > - <v-card-text class="no-content-text"> - <v-icon - size="200px" - color="deep-orange accent-4" - > - play_circle_outline - </v-icon> - <span style="font-size: xx-large">We're sorry about that ¯\_(ツ)_/¯</span> - </v-card-text> - </v-col> - </v-card> - </v-row> - </v-container> -</template> - -<script> -export default { - name: 'PageNotFound' -} -</script> - -<style scoped> - .no-content-text { - position: absolute; - top: 40%; - } -</style> diff --git a/grady/frontend/src/pages/StartPageSelector.vue b/grady/frontend/src/pages/StartPageSelector.vue deleted file mode 100644 index 85edbc664ee5e90a478fee7fbcfdac54cd9b46f1..0000000000000000000000000000000000000000 --- a/grady/frontend/src/pages/StartPageSelector.vue +++ /dev/null @@ -1,39 +0,0 @@ -<template> - <component :is="startPage" /> -</template> - -<script> -import { mapGetters } from 'vuex' -import TutorStartPage from '@/pages/tutor/TutorStartPage' -import StudentPage from '@/pages/student/StudentPage' -import ReviewerStartPage from '@/pages/reviewer/ReviewerStartPage' -import { Authentication } from '@/store/modules/authentication' -export default { - name: 'StartPageSelector', - components: { - ReviewerStartPage, - StudentPage, - TutorStartPage - }, - computed: { - isStudent () { return Authentication.isStudent }, - isTutor () { return Authentication.isTutor }, - isReviewer () { return Authentication.isReviewer }, - startPage () { - if (this.isStudent) { - return 'student-page' - } else if (this.isTutor) { - return 'tutor-start-page' - } else if (this.isReviewer) { - return 'reviewer-start-page' - } - - return undefined - } - } -} -</script> - -<style scoped> - -</style> diff --git a/grady/frontend/src/pages/Statistics.vue b/grady/frontend/src/pages/Statistics.vue deleted file mode 100644 index 52f71f03be0c1e7c3e3fae10ac5a09caf39ed160..0000000000000000000000000000000000000000 --- a/grady/frontend/src/pages/Statistics.vue +++ /dev/null @@ -1,29 +0,0 @@ -<template> - <v-container> - <v-row> - <v-col> - <label-statistics /> - </v-col> - <v-col> - <correction-statistics /> - </v-col> - </v-row> - </v-container> -</template> - -<script lang="ts"> -import Vue from 'vue' -import Component from 'vue-class-component' - -import CorrectionStatistics from '@/components/CorrectionStatistics.vue' -import LabelStatistics from '@/components/LabelStatistics.vue' - - -@Component({ - components: {CorrectionStatistics, LabelStatistics} -}) -export default class Statistics extends Vue { - - -} -</script> diff --git a/grady/frontend/src/pages/StudentSubmissionSideView.vue b/grady/frontend/src/pages/StudentSubmissionSideView.vue deleted file mode 100644 index ef863ba443264c41f50a408807bcf0d5192f0369..0000000000000000000000000000000000000000 --- a/grady/frontend/src/pages/StudentSubmissionSideView.vue +++ /dev/null @@ -1,109 +0,0 @@ -<template> - <div> - <route-change-confirmation :next-route="nextRoute" /> - <submission-correction - :submission-without-assignment="submission" - :feedback="submission.feedback" - :ignore-hidden-state="true" - @feedbackCreated="refresh" - @feedbackChanged="refresh" - /> - <submission-tests - :tests="submission.tests" - class="mt-4" - /> - <submission-type - :key="submissionType.pk" - v-bind="submissionType" - :reverse="true" - :expanded-by-default="{ Description: true, Solution: true }" - class="mt-1" - /> - </div> -</template> - -<script> -import store from '@/store/store' -import VueInstance from '@/main' -import SubmissionCorrection from '@/components/submission_notes/SubmissionCorrection' -import SubmissionTests from '@/components/SubmissionTests' -import SubmissionType from '@/components/submission_type/SubmissionType' -import RouteChangeConfirmation from '@/components/submission_notes/RouteChangeConfirmation' -import { actions } from '@/store/actions' - -function onRouteEnterOrUpdate (to, from, next) { - const toIsSubmissionSideView = to.matched.some(route => route.meta.submissionSideView) - if (toIsSubmissionSideView) { - let submission = store.state.submissions[to.params.submissionPk] - if (!submission) { - store.dispatch('getSubmissionFeedbackTest', { pk: to.params.submissionPk }).then(() => { - VueInstance.$nextTick(() => { - next() - }) - }).catch(() => { - VueInstance.$notify({ - title: 'Error', - text: 'Unable to fetch student data', - type: 'error' - }) - next(false) - }) - } else { - next() - } - } else { - next() - } -} - -export default { - name: 'StudentSubmissionSideView', - components: { - RouteChangeConfirmation, - SubmissionType, - SubmissionTests, - SubmissionCorrection }, - data () { - return { - nextRoute: null - } - }, - computed: { - submissionPk () { - return this.$route.params['submissionPk'] - }, - submission () { - return this.$store.state.submissions[this.submissionPk] - }, - submissionType () { - return this.$store.state.submissionTypes[this.submission.type] - } - }, - methods: { - refresh () { - this.$emit('refresh') - const studentPk = this.$route.params.studentPk - if (studentPk) { - actions.getStudents({ studentPks: [studentPk] }) - } - const submissionPk = this.$route.params.submissionPk - actions.getSubmissionFeedbackTest({ pk: submissionPk }) - } - }, - beforeRouteEnter (to, from, next) { - onRouteEnterOrUpdate(to, from, next) - }, - beforeRouteUpdate (to, from, next) { - this.nextRoute = () => { - onRouteEnterOrUpdate(to, from, next) - } - }, - beforeRouteLeave (to, from, next) { - this.nextRoute = next - } -} -</script> - -<style scoped> - -</style> diff --git a/grady/frontend/src/pages/SubscriptionWorkPage.vue b/grady/frontend/src/pages/SubscriptionWorkPage.vue deleted file mode 100644 index e3f6b1542c6ec2dbbe39bf9f6befbe07d1f2afe5..0000000000000000000000000000000000000000 --- a/grady/frontend/src/pages/SubscriptionWorkPage.vue +++ /dev/null @@ -1,124 +0,0 @@ -<template> - <two-pane-layout - ref="layout" - :show-right-pane="showSubmissionType" - > - <template #left> - <v-container> - <route-change-confirmation :next-route="nextRoute" /> - <submission-correction - :key="currentAssignment.pk" - :assignment="currentAssignment" - @feedbackCreated="startWorkOnNextAssignment" - /> - <submission-tests - :tests="submission.tests" - :expand="true" - /> - </v-container> - </template> - <template #right> - <submission-type - :key="submissionType.pk" - v-bind="submissionType" - :expanded-by-default="{ Description: true, Solution: true }" - /> - </template> - </two-pane-layout> -</template> - -<script lang="ts"> -import { Vue, Component, Watch } from 'vue-property-decorator' -import { Route, NavigationGuard } from 'vue-router' -import SubmissionCorrection from '@/components/submission_notes/SubmissionCorrection.vue' -import SubmissionType from '@/components/submission_type/SubmissionType.vue' -import store from '@/store/store' -import { SubmissionNotes } from '@/store/modules/submission-notes' -import SubmissionTests from '@/components/SubmissionTests.vue' -import { Assignments } from '@/store/modules/assignments' -import RouteChangeConfirmation from '@/components/submission_notes/RouteChangeConfirmation.vue' -import { getters } from '@/store/getters' -import { SubmissionAssignment } from '@/models' -import { UI } from '@/store/modules/ui' -import TwoPaneLayout from '@/components/TwoPaneLayout.vue' - -const onRouteEnterOrUpdate: NavigationGuard = function (to, from, next) { - Assignments.changeAssignment(to).then(() => { - if (from === to) { - return - } - next() - }) -} - -@Component({ - components: { - RouteChangeConfirmation, - SubmissionTests, - SubmissionType, - SubmissionCorrection, - TwoPaneLayout, - } -}) -export default class SubscriptionWorkPage extends Vue { - $refs!: { - layout: TwoPaneLayout - } - - subscriptionActive = false - nextRoute = () => {} - - get showSubmissionType () { - return UI.state.showSubmissionType - } - - get currentAssignment () { - return Assignments.state.currentAssignment - } - - get submission () { - return this.currentAssignment && this.currentAssignment.submission - } - - get submissionType () { - if (this.submission && (this.submission as SubmissionAssignment).type) { - return getters.state.submissionTypes[(this.submission as SubmissionAssignment).type] - } - } - - beforeRouteEnter (to: Route, from: Route, next: (to?: any) => void ) { - onRouteEnterOrUpdate(to, from, next) - } - - beforeRouteUpdate (this: SubscriptionWorkPage, to: Route, from: Route, next: (to?: any) => void) { - this.nextRoute = () => { - onRouteEnterOrUpdate(to, from, next) - } - } - - beforeRouteLeave (this: SubscriptionWorkPage, to: Route, from: Route, next: (to?: any) => void) { - if (to.name === 'correction-ended') { - next() - } else { - this.nextRoute = () => { - next() - Assignments.deleteCurrentAssignment() - } - } - } - - startWorkOnNextAssignment () { - Assignments.createNextAssignment().then(() => { - Assignments.getAvailableSubmissionCounts() - }).catch(() => { - Assignments.SET_CURRENT_ASSIGNMENT(undefined) - this.$router.replace({name: 'correction-ended'}) - }) - } - - @Watch('currentAssignment') - onCurrentAssignmentChanged() { - this.$refs.layout.leftPane().scrollTop = 0 - } -} -</script> diff --git a/grady/frontend/src/pages/base/FeedbackHistoryPage.vue b/grady/frontend/src/pages/base/FeedbackHistoryPage.vue deleted file mode 100644 index 313494d96e98c64c45708ec43324d53521713119..0000000000000000000000000000000000000000 --- a/grady/frontend/src/pages/base/FeedbackHistoryPage.vue +++ /dev/null @@ -1,35 +0,0 @@ -<template> - <two-pane-layout> - <template #left> - <router-view name="left" /> - </template> - <template #right> - <v-container> - <router-view - name="right" - @refresh="refresh" - /> - </v-container> - </template> - </two-pane-layout> -</template> - -<script lang="ts"> -import Vue from 'vue' -import Component from 'vue-class-component' -import { FeedbackTable } from '@/store/modules/feedback_list/feedback-table' -import TwoPaneLayout from '@/components/TwoPaneLayout.vue' - -@Component({ - components: { TwoPaneLayout } -}) -export default class FeedbackHistoryPage extends Vue { - refresh () { - FeedbackTable.getFeedbackHistory() - } - - created () { - FeedbackTable.getFeedbackHistory() - } -} -</script> diff --git a/grady/frontend/src/pages/base/TutorReviewerBaseLayout.vue b/grady/frontend/src/pages/base/TutorReviewerBaseLayout.vue deleted file mode 100644 index 8016a37ae37ba77ed5016e3118c09da359d87474..0000000000000000000000000000000000000000 --- a/grady/frontend/src/pages/base/TutorReviewerBaseLayout.vue +++ /dev/null @@ -1,79 +0,0 @@ -<template> - <base-layout> - <template #header> - Grady - </template> - - <template #sidebar-content> - <v-list dense> - <v-list-item - v-for="(item, i) in generalNavItems" - :key="i" - :to="item.route" - > - <v-list-item-action> - <v-icon>{{ item.icon }}</v-icon> - </v-list-item-action> - <v-list-item-content> - <v-list-item-title :id="item.tagId"> - {{ item.name }} - </v-list-item-title> - </v-list-item-content> - </v-list-item> - </v-list> - <v-divider /> - <slot name="above-subscriptions" /> - <subscription-list - v-if="!mini" - :sidebar="true" - /> - <feedback-label-tab v-if="!mini" /> - <slot name="below-subscriptions" /> - </template> - </base-layout> -</template> - -<script> -import { UI } from '@/store/modules/ui' -import BaseLayout from '@/components/BaseLayout' -import SubscriptionList from '@/components/subscriptions/SubscriptionList' -import FeedbackLabelTab from '@/components/feedback_labels/FeedbackLabelTab.vue' - -export default { - name: 'TutorReviewerBaseLayout', - components: { - SubscriptionList, - FeedbackLabelTab, - BaseLayout }, - data () { - return { - generalNavItems: [ - { - name: 'Overview', - icon: 'home', - route: '/home', - tagId: 'overview' - }, - { - name: 'Feedback History', - icon: 'feedback', - route: '/feedback', - tagId: 'feedback' - }, - { - name: 'Statistics', - icon: 'bar_chart', - route: '/statistics', - tagId: 'statistics' - } - ] - } - }, - computed: { - mini () { return UI.state.sideBarCollapsed }, - } -} -</script> - -<style scoped> -</style> diff --git a/grady/frontend/src/pages/reviewer/ReviewerLayout.vue b/grady/frontend/src/pages/reviewer/ReviewerLayout.vue deleted file mode 100644 index 18767de26610bc970ddd22661a269fd2b6176bb0..0000000000000000000000000000000000000000 --- a/grady/frontend/src/pages/reviewer/ReviewerLayout.vue +++ /dev/null @@ -1,52 +0,0 @@ -<template> - <tutor-reviewer-base-layout> - <template #above-subscriptions> - <v-list - dense - > - <v-list-item - v-for="(item, i) in subGeneralNavItems" - :key="i" - :to="item.route" - > - <v-list-item-action> - <v-icon>{{ item.icon }}</v-icon> - </v-list-item-action> - <v-list-item-content> - <v-list-item-title> - {{ item.name }} - </v-list-item-title> - </v-list-item-content> - </v-list-item> - </v-list> - </template> - </tutor-reviewer-base-layout> -</template> - -<script> -import TutorReviewerBaseLayout from '@/pages/base/TutorReviewerBaseLayout' - -export default { - name: 'ReviewerLayout', - components: { TutorReviewerBaseLayout }, - data () { - return { - subGeneralNavItems: [ - { - name: 'Participants', - route: '/participant-overview', - icon: 'people' - }, - { - name: 'Tutors', - route: { name: 'tutor-overview' }, - icon: 'people' - } - ] - } - } -} -</script> - -<style scoped> -</style> diff --git a/grady/frontend/src/pages/reviewer/ReviewerStartPage.vue b/grady/frontend/src/pages/reviewer/ReviewerStartPage.vue deleted file mode 100644 index b902a3d3e4e87d1e4ee13a3ed92aeefa26239df2..0000000000000000000000000000000000000000 --- a/grady/frontend/src/pages/reviewer/ReviewerStartPage.vue +++ /dev/null @@ -1,93 +0,0 @@ -<template> - <v-container v-if="dataLoaded"> - <v-row> - <v-col - lg="6" - md="12" - > - <change-log /> - </v-col> - <v-col - lg="6" - md="12" - > - <correction-statistics /> - </v-col> - <v-col> - <SubmissionTypesOverview /> - </v-col> - </v-row> - </v-container> - <v-row - v-else - justify="center" - class="mt-4 pt-4" - > - <import-dialog - v-if="showImportDialog" - @hide="showImportDialog = false" - @imported="importDone" - /> - <v-card class="import-card"> - <v-card-title class="title"> - Import data - </v-card-title> - <v-card-text> - It looks like this instance doesn't contain any data. - Would you like to import some? - </v-card-text> - <v-card-actions class="justify-center"> - <v-btn - class="info" - @click="showImportDialog = true" - > - Import data - </v-btn> - </v-card-actions> - </v-card> - </v-row> -</template> - -<script> -import CorrectionStatistics from '@/components/CorrectionStatistics' -import ImportDialog from '@/components/ImportDialog' -import ChangeLog from '@/components/ChangeLog' -import SubmissionTypesOverview from '@/components/submission_type/SubmissionTypesOverview' -import { getters } from '../../store/getters' -import { Assignments } from '@/store/modules/assignments' - -export default { - name: 'ReviewerStartPage', - name: 'reviewer-start-page', - components: { - ImportDialog, - SubmissionTypesOverview, - ChangeLog, - CorrectionStatistics }, - data: () => { - return { - showImportDialog: false, - dataImported: false - } - }, - computed: { - dataLoaded () { - return Object.keys(getters.state.submissionTypes).length !== 0 || this.dataImported - } - }, - methods: { - importDone() { - this.dataImported = true - Assignments.RESET_STATE() - } - } -} -</script> - -<style scoped> - -.import-card { - width: 30%; -} - -</style> diff --git a/grady/frontend/src/pages/reviewer/StudentOverviewPage.vue b/grady/frontend/src/pages/reviewer/StudentOverviewPage.vue deleted file mode 100644 index f062dce51d3d62916cffd0aacb71258dabed25d9..0000000000000000000000000000000000000000 --- a/grady/frontend/src/pages/reviewer/StudentOverviewPage.vue +++ /dev/null @@ -1,74 +0,0 @@ -<template> - <v-container> - <v-row v-if="this.$vuetify.breakpoint.xl"> - <v-col md="6"> - <student-list /> - </v-col> - <v-col - md="6" - class="right-view" - > - <router-view /> - </v-col> - </v-row> - <v-row v-else> - <v-col> - <student-list @detail-click="openDialog" /> - </v-col> - <v-dialog - v-model="dialog" - fullscreen - hide-overlay - > - <v-card> - <v-toolbar - dark - color="#1a237e" - > - <v-btn - icon - dark - @click="dialog = false" - > - <v-icon>close</v-icon> - </v-btn> - <v-toolbar-title>Submission details</v-toolbar-title> - <v-spacer /> - </v-toolbar> - <v-card-text> - <router-view @refresh="dialog = false" /> - </v-card-text> - </v-card> - </v-dialog> - </v-row> - </v-container> -</template> - -<script> -import StudentList from '@/components/student_list/StudentList' -import StudentListHelpCard from '@/components/student_list/StudentListHelpCard' - -export default { - name: 'StudentOverviewPage', - components: { StudentList }, - data: () => { - return { - dialog: false - } - }, - methods: { - openDialog () { - this.dialog = true - } - } -} -</script> - -<style scoped> - .right-view { - position: sticky; - top: 80px; - overflow-y: scroll; - height: 90vh; - } -</style> diff --git a/grady/frontend/src/pages/reviewer/TutorOverviewPage.vue b/grady/frontend/src/pages/reviewer/TutorOverviewPage.vue deleted file mode 100644 index b0b98e30a4604bb419e472f5ba96a4b0eaebc35e..0000000000000000000000000000000000000000 --- a/grady/frontend/src/pages/reviewer/TutorOverviewPage.vue +++ /dev/null @@ -1,24 +0,0 @@ -<template> - <tutor-list class="ma-2 elevation-1" /> -</template> - -<script> -import store from '@/store/store' -import TutorList from '@/components/tutor_list/TutorList' -import { actions } from '@/store/actions' -import { TutorOverview } from '@/store/modules/tutor-overview' - -export default { - name: 'TutorOverviewPage', - components: { TutorList }, - beforeRouteEnter (to, from, next) { - TutorOverview.getTutors() - TutorOverview.getActiveAssignments() - next() - } -} -</script> - -<style scoped> - -</style> diff --git a/grady/frontend/src/pages/student/StudentLayout.vue b/grady/frontend/src/pages/student/StudentLayout.vue deleted file mode 100644 index b11687b536fabbcf5dcd5b05f48daa2b91dc9ae7..0000000000000000000000000000000000000000 --- a/grady/frontend/src/pages/student/StudentLayout.vue +++ /dev/null @@ -1,95 +0,0 @@ -<template> - <base-layout> - <template #sidebar-content> - <v-list dense> - <v-list-item - v-for="(item, i) in generalNavItems" - :key="i" - exact - :to="item.route" - > - <v-list-item-action> - <v-icon>{{ item.icon }}</v-icon> - </v-list-item-action> - <v-list-item-content> - <v-list-item-title> - {{ item.name }} - </v-list-item-title> - </v-list-item-content> - </v-list-item> - - <v-divider /> - - <exam-information - v-if="!mini" - :exam="exam" - class="elevation-1 exam-info ma-1" - /> - <v-list-item - v-for="item in submissionNavItems" - :key="item.route" - exact - :to="item.route" - > - <v-list-item-action> - <v-icon v-if="!visited[item.id]"> - assignment - </v-icon> - <v-icon v-else> - check - </v-icon> - </v-list-item-action> - <v-list-item-content> - <v-list-item-title> - {{ item.name }} - </v-list-item-title> - </v-list-item-content> - </v-list-item> - </v-list> - </template> - </base-layout> -</template> - -<script> -import { UI } from '@/store/modules/ui' -import BaseLayout from '@/components/BaseLayout' -import ExamInformation from '@/components/student/ExamInformation' -import { StudentPage } from '@/store/modules/student-page' -export default { - name: 'StudentLayout', - components: { BaseLayout, ExamInformation }, - data () { - return { - generalNavItems: [ - { - name: 'Overview', - icon: 'home', - route: '/home' - } - ] - } - }, - computed: { - submissions () { return StudentPage.state.submissionsForList }, - exam () { return StudentPage.state.exam }, - visited () { return StudentPage.state.visited }, - moduleReference () { return this.exam ? this.exam.moduleReference : 'No exam information' }, - - mini () { return UI.state.sideBarCollapsed }, - - submissionNavItems () { - return this.submissions.map((sub, index) => { - return { - name: sub.type.name, - id: sub.type.pk, - route: `/submission/${sub.type.pk}` - } - }) - } - } -} -</script> - -<style scoped> - -</style> diff --git a/grady/frontend/src/pages/student/StudentPage.vue b/grady/frontend/src/pages/student/StudentPage.vue deleted file mode 100644 index a9b289a1c0f58ef5c687d1714726a909486e4037..0000000000000000000000000000000000000000 --- a/grady/frontend/src/pages/student/StudentPage.vue +++ /dev/null @@ -1,47 +0,0 @@ -<template> - <v-container fluid> - <v-row - class="center" - justify - > - <template v-if="loaded"> - <v-col - class="mt-5" - md="10" - offset="1" - > - <h2>Your submissions:</h2> - <submission-list :submissions="submissions" /> - </v-col> - </template> - </v-row> - </v-container> -</template> - -<script> -import SubmissionList from '@/components/student/SubmissionList.vue' -import { StudentPage } from '@/store/modules/student-page' -import { FeedbackLabels } from '@/store/modules/feedback-labels' - -export default { - name: 'StudentPage', - components: { - SubmissionList - }, - computed: { - submissions () { return StudentPage.state.submissionsForList }, - loaded () { return StudentPage.state.loaded } - }, - created: function () { - if (!this.loaded) { - StudentPage.getStudentData().then(() => { - FeedbackLabels.getLabels() - StudentPage.getStudentSubmissions() - }) - } - } -} -</script> - -<style scoped> -</style> diff --git a/grady/frontend/src/pages/student/StudentSubmissionPage.vue b/grady/frontend/src/pages/student/StudentSubmissionPage.vue deleted file mode 100644 index fb800b4cd9b3503720e6285fa1d4efb9883b70f5..0000000000000000000000000000000000000000 --- a/grady/frontend/src/pages/student/StudentSubmissionPage.vue +++ /dev/null @@ -1,195 +0,0 @@ -<template> - <v-container> - <v-row v-if="!feedback"> - <v-col> - <v-alert type="info"> - This submission hasn't been corrected due to this being a pass only exam. - </v-alert> - </v-col> - </v-row> - <v-row v-if="feedback && !feedback.isFinal"> - <v-col> - <v-alert type="info"> - This feedback is not final! Changes will likely occur! - </v-alert> - </v-col> - </v-row> - <v-row> - <v-col :md="solutionHidden ? 12 : 6"> - <base-annotated-submission> - <template #header> - <annotated-submission-top-toolbar - v-if="feedback" - v-model="mathIsRendered" - :score="feedback.score" - :notebook-available="notebookAvailable" - :submission="submission" - :submission-type="submissionType" - :feedback="feedback" - :is-markdown="isMarkdown" - /> - </template> - <template #table-content> - <tr - v-for="(code, lineNo) in submissionText" - :key="lineNo" - > - <math-renderer :enabled="mathIsRendered"> - <submission-line - :code="code" - :line-no="lineNo" - > - <template v-if="feedback"> - <template v-for="(comment, index) in feedback.feedbackLines[lineNo]"> - <feedback-comment - v-if="showFeedback" - :key="comment.pk + index" - v-bind="comment" - :line-no="lineNo" - :show-visibility-icon="false" - :corrector-view="false" - /> - </template> - </template> - </submission-line> - </math-renderer> - </tr> - </template> - </base-annotated-submission> - <v-card> - <v-card-title>Labels:</v-card-title> - <v-card-text> - <v-row - v-for="label in mappedLabels" - :key="'global' + label.pk" - align="center" - > - <v-col sm="6"> - <feedback-label - v-bind="label" - /> - </v-col> - <v-col sm="6"> - <span><b>Description: </b>{{ label.description }}</span> - </v-col> - </v-row> - </v-card-text> - </v-card> - <submission-tests - :tests="tests" - :expand="true" - class="mt-3" - /> - </v-col> - <v-col - class="pl-3" - lg="6" - md="12" - > - <submission-type - v-bind="submissionType" - /> - </v-col> - </v-row> - </v-container> -</template> - -<script> -import { mapState, mapGetters } from 'vuex' -import AnnotatedSubmission from '@/components/submission_notes/SubmissionCorrection' -import SubmissionType from '@/components/submission_type/SubmissionType' -import BaseAnnotatedSubmission from '@/components/submission_notes/base/BaseAnnotatedSubmission' -import AnnotatedSubmissionTopToolbar from '@/components/submission_notes/toolbars/AnnotatedSubmissionTopToolbar' -import SubmissionLine from '@/components/submission_notes/base/SubmissionLine' -import FeedbackComment from '@/components/submission_notes/base/FeedbackComment' -import { StudentPage } from '@/store/modules/student-page' -import { SubmissionNotes } from '@/store/modules/submission-notes' -import SubmissionTests from '@/components/SubmissionTests' -import { FeedbackLabels } from '@/store/modules/feedback-labels' -import FeedbackLabel from '@/components/feedback_labels/FeedbackLabel.vue' -import { fetchNotebookSubmissionAsHtml } from '@/api.ts' -import store from '@/store/store' -import { SubmissionType as SubType } from '@/models' -import { UI } from '@/store/modules/ui' -import MathRenderer from '@/components/MathRenderer.vue' - -export default { - name: 'StudentSubmissionPage', - components: { - SubmissionTests, - FeedbackComment, - SubmissionLine, - BaseAnnotatedSubmission, - AnnotatedSubmissionTopToolbar, - FeedbackLabel, - SubmissionType, - MathRenderer }, - data () { - return { - originalSubmissionDialog: false, - originalSubmission: '', - mathIsRendered: false, - } - }, - computed: { - id: function () { - return this.$route.params.id - }, - isMarkdown () { - const typePk = SubmissionNotes.state.submission.type - const type = store.state.submissionTypes[typePk] - return type && type.programmingLanguage === SubType.ProgrammingLanguageEnum.Markdown - }, - submissionText () { return SubmissionNotes.submission }, - tests () { return SubmissionNotes.state.submission.tests }, - showFeedback: function (state) { return SubmissionNotes.state.ui.showFeedback }, - submission () { return StudentPage.state.submissionData[this.id] }, - submissionType () { return StudentPage.state.submissionData[this.id].type }, - feedback () { return StudentPage.state.submissionData[this.$route.params.id].feedback }, - mappedLabels () { - if (!this.feedback) { - return [] - } - return this.feedback.labels.map(entry => { - return FeedbackLabels.state.labels.find(label => { - return label.pk === entry - }) - }) - }, - notebookAvailable () { - return this.submission.sourceCodeAvailable - }, - solutionHidden () { - return UI.state.showSubmissionType === false - } - }, - mounted () { - this.onRouteMountOrUpdate(this.id) - }, - methods: { - onRouteMountOrUpdate (routeId) { - StudentPage.SET_VISITED({ index: routeId, visited: true }) - let submission = {...StudentPage.state.submissionData[routeId]} - submission.type = submission.type.pk - SubmissionNotes.SET_SUBMISSION(submission) - this.mathIsRendered = true - }, - }, - beforeRouteUpdate (to, from, next) { - this.onRouteMountOrUpdate(to.params.id) - next() - } -} -</script> - - -<style scoped> -.origNotebookFrame { - width: 100%; - height: 800px; -} - -.v-alert { - margin: 0; -} -</style> diff --git a/grady/frontend/src/pages/tutor/TutorLayout.vue b/grady/frontend/src/pages/tutor/TutorLayout.vue deleted file mode 100644 index fbfd73af925940e754d9f99799fab61b5174efac..0000000000000000000000000000000000000000 --- a/grady/frontend/src/pages/tutor/TutorLayout.vue +++ /dev/null @@ -1,37 +0,0 @@ -<template> - <tutor-reviewer-base-layout> - <template #above-subscriptions> - <v-list - v-if="isInExerciseMode" - dense - > - <v-list-item :to="'/participant-overview'"> - <v-list-item-action> - <v-icon> people </v-icon> - </v-list-item-action> - <v-list-item-content> - <v-list-item-title> - {{ "Participants" }} - </v-list-item-title> - </v-list-item-content> - </v-list-item> - </v-list> - </template> - </tutor-reviewer-base-layout> -</template> - -<script> - -import TutorReviewerBaseLayout from '@/pages/base/TutorReviewerBaseLayout' -import { ConfigModule } from '@/store/modules/config' - -export default { - name: 'TutorLayout', - components: { - TutorReviewerBaseLayout - }, - computed: { - isInExerciseMode: () => { return ConfigModule.state.config.instanceSettings['exerciseMode'] } - } -} -</script> diff --git a/grady/frontend/src/pages/tutor/TutorStartPage.vue b/grady/frontend/src/pages/tutor/TutorStartPage.vue deleted file mode 100644 index 26c458b84dbb24705d1f5533fcdbaba19387ea7a..0000000000000000000000000000000000000000 --- a/grady/frontend/src/pages/tutor/TutorStartPage.vue +++ /dev/null @@ -1,39 +0,0 @@ -<template> - <v-container> - <v-row> - <v-col - lg="6" - md="12" - > - <change-log /> - </v-col> - <v-col - lg="6" - md="12" - > - <correction-statistics /> - </v-col> - <v-col> - <SubmissionTypesOverview /> - </v-col> - </v-row> - </v-container> -</template> - -<script> -import ChangeLog from '@/components/ChangeLog' -import CorrectionStatistics from '@/components/CorrectionStatistics' -import SubmissionTypesOverview from '@/components/submission_type/SubmissionTypesOverview' - -export default { - name: 'TutorStartPage', - components: { - SubmissionTypesOverview, - CorrectionStatistics, - ChangeLog } -} -</script> - -<style scoped> - -</style> diff --git a/grady/frontend/src/router/index.ts b/grady/frontend/src/router/index.ts deleted file mode 100644 index df44c88cdfefd40ad31c77a1654a514ee79afa67..0000000000000000000000000000000000000000 --- a/grady/frontend/src/router/index.ts +++ /dev/null @@ -1,191 +0,0 @@ -import Vue from 'vue' -import Router, { RawLocation, Route, NavigationGuard } from 'vue-router' -import Login from '@/pages/Login.vue' -import ExamSelection from '@/pages/ExamSelectionPage.vue' -import StudentSubmissionPage from '@/pages/student/StudentSubmissionPage.vue' -import StudentOverviewPage from '@/pages/reviewer/StudentOverviewPage.vue' -import TutorOverviewPage from '@/pages/reviewer/TutorOverviewPage.vue' -import SubscriptionWorkPage from '@/pages/SubscriptionWorkPage.vue' -import SubscriptionEnded from '@/components/subscriptions/SubscriptionEnded.vue' -import PageNotFound from '@/pages/PageNotFound.vue' -import StartPageSelector from '@/pages/StartPageSelector.vue' -import Statistics from '@/pages/Statistics.vue' -import LayoutSelector from '@/pages/LayoutSelector.vue' -import StudentSubmissionSideView from '@/pages/StudentSubmissionSideView.vue' -import StudentListHelpCard from '@/components/student_list/StudentListHelpCard.vue' -import FeedbackHistoryPage from '@/pages/base/FeedbackHistoryPage.vue' -import FeedbackTable from '@/components/feedback_list/FeedbackTable.vue' -import FeedbackListHelpCard from '@/components/feedback_list/FeedbackListHelpCard.vue' -import VueInstance from '@/main' -import { Authentication } from '@/store/modules/authentication' -import { ConfigModule } from '@/store/modules/config' - -Vue.use(Router) - -type rerouteFunc = (to?: RawLocation | false | ((vm: Vue) => any) | void) => void - -function denyAccess (next: rerouteFunc, redirect: Route) { - next(redirect.path) - VueInstance.$notify({ - title: 'Access denied', - text: 'You don\'t have permission to view this.', - type: 'error' - }) -} - -let tutorOrReviewerOnly: NavigationGuard = function (to, from, next) { - if (Authentication.isTutorOrReviewer) { - next() - } else { - denyAccess(next, from) - } -} - -let reviewerOnly: NavigationGuard = function (to, from, next) { - if (Authentication.isReviewer) { - next() - } else { - denyAccess(next, from) - } -} - -const reviewerOrTutorInExerciseMode: NavigationGuard = function (to, from, next) { - if (Authentication.isReviewer) { - next() - } else if (Authentication.isTutor && ConfigModule.state.config.instanceSettings.exerciseMode) { - next() - } else { - denyAccess(next, from) - } -} - -let studentOnly: NavigationGuard = function (to, from, next) { - if (Authentication.isStudent) { - next() - } else { - next(false) - } -} - -let checkLoggedIn: NavigationGuard = function (to, from, next) { - if (Authentication.isLoggedIn) { - next() - } else { - next('/login/') - } -} - -const router = new Router({ - routes: [ - { - path: '/login/', - name: 'login', - component: Login - }, - { - path: '/exam_selection/', - name: 'exam-selection', - beforeEnter: checkLoggedIn, - component: ExamSelection - }, - { - path: '', - redirect: 'home', - beforeEnter: checkLoggedIn, - component: LayoutSelector, - children: [ - { - path: 'home', - name: 'home', - component: StartPageSelector - }, - { - path: 'correction/:sub_type/:stage/:group?', - name: 'correction', - beforeEnter: tutorOrReviewerOnly, - component: SubscriptionWorkPage - }, - { - path: 'correction/ended', - name: 'correction-ended', - component: SubscriptionEnded - }, - { - path: 'statistics', - name: 'statistics', - component: Statistics - }, - { - path: 'feedback', - beforeEnter: tutorOrReviewerOnly, - component: FeedbackHistoryPage, - children: [ - { - path: '', - name: 'feedback', - components: { - left: FeedbackTable, - right: FeedbackListHelpCard - } - }, - { - path: ':submissionPk', - components: { - left: FeedbackTable, - right: StudentSubmissionSideView - }, - meta: { - submissionSideView: true - } - }, - { - path: ':id/detail', - components: { - left: FeedbackTable, - right: PageNotFound - } - } - ] - }, - { - path: 'participant-overview', - beforeEnter: reviewerOrTutorInExerciseMode, - component: StudentOverviewPage, - children: [ - { - path: '', - name: 'participant-overview', - component: StudentListHelpCard - }, - { - path: 'participant/:studentPk/submission/:submissionPk', - name: 'submission-side-view', - component: StudentSubmissionSideView, - meta: { - submissionSideView: true - } - } - ] - }, - { - path: 'tutor-overview', - name: 'tutor-overview', - beforeEnter: reviewerOnly, - component: TutorOverviewPage - }, - { - path: 'submission/:id', - beforeEnter: studentOnly, - component: StudentSubmissionPage - } - ] - }, - { - path: '*', - name: 'page-not-found', - component: PageNotFound - } - ] -}) - -export default router diff --git a/grady/frontend/src/shims-tsx.d.ts b/grady/frontend/src/shims-tsx.d.ts deleted file mode 100644 index cbc02136cbc4d325e1c4eff0a000f52886ea555e..0000000000000000000000000000000000000000 --- a/grady/frontend/src/shims-tsx.d.ts +++ /dev/null @@ -1,14 +0,0 @@ -import Vue, { VNode } from 'vue' - -declare global { - namespace JSX { - // tslint:disable no-empty-interface - interface Element extends VNode {} - // tslint:disable no-empty-interface - interface ElementClass extends Vue {} - interface IntrinsicElements { - [elem: string]: any - } - } - interface Window { MathJax: any; } -} diff --git a/grady/frontend/src/shims-vue.d.ts b/grady/frontend/src/shims-vue.d.ts deleted file mode 100644 index d9f24faa42e74d0f178759f8f085a0541db6cc7c..0000000000000000000000000000000000000000 --- a/grady/frontend/src/shims-vue.d.ts +++ /dev/null @@ -1,4 +0,0 @@ -declare module '*.vue' { - import Vue from 'vue' - export default Vue -} diff --git a/grady/frontend/src/store/actions.ts b/grady/frontend/src/store/actions.ts deleted file mode 100644 index 68297e518382cc274284f601213e574c25dfa41e..0000000000000000000000000000000000000000 --- a/grady/frontend/src/store/actions.ts +++ /dev/null @@ -1,103 +0,0 @@ -import { ActionContext } from 'vuex' -import { BareActionContext, getStoreBuilder } from 'vuex-typex' - -import { mutations as mut } from './mutations' -import { Authentication } from '@/store/modules/authentication' -import { SubmissionNotes } from '@/store/modules/submission-notes' -import * as api from '@/api' -import router from '@/router/index' -import { RootState } from '@/store/store' -import { FeedbackTable } from '@/store/modules/feedback_list/feedback-table' -import { Assignments } from '@/store/modules/assignments' -import { TutorOverview } from './modules/tutor-overview' -import { StudentPage } from './modules/student-page' -import { ConfigModule } from './modules/config' - -async function getExamTypes (context: BareActionContext<RootState, RootState>) { - const examTypes = await api.fetchExamTypes() - mut.SET_EXAM_TYPES(examTypes) -} -async function updateSubmissionTypes (){ - const submissionTypes = await api.fetchSubmissionTypes() - submissionTypes.forEach(type => { - mut.UPDATE_SUBMISSION_TYPE(type) - }) -} - -async function updateSubmissionType ( - context: BareActionContext<RootState, RootState>, - pk: string -) { - const submissionType = await api.fetchSubmissionType(pk) - mut.UPDATE_SUBMISSION_TYPE(submissionType) -} - -async function getStudents ( - context: BareActionContext<RootState, RootState>, - opt: { studentPks: Array<string>} = { - studentPks: [] - } -) { - if (opt.studentPks.length === 0) { - const students = await api.fetchAllStudents() - mut.SET_STUDENTS(students) - return students - } else { - const students = await Promise.all( - opt.studentPks.map((pk: string) => - api.fetchStudent({ pk }) - ) - ) - students.forEach(student => mut.SET_STUDENT(student)) - return students - } -} -async function getSubmissionFeedbackTest ( - context: BareActionContext<RootState, RootState>, - submissionPkObj: { pk: string } -) { - const submission = await api.fetchSubmissionFeedbackTests(submissionPkObj) - mut.SET_SUBMISSION(submission) -} -async function getStatistics () { - const statistics = await api.fetchStatistics(ConfigModule.state.config.examId) - mut.SET_STATISTICS(statistics) -} - -function resetState ({ message }: {message: string}) { - FeedbackTable.RESET_STATE() - Assignments.RESET_STATE() - SubmissionNotes.RESET_STATE() - StudentPage.RESET_STATE() - Authentication.RESET_STATE() - Authentication.SET_MESSAGE(message) - TutorOverview.RESET_STATE() - mut.RESET_STATE() -} - -function logout ( - context: BareActionContext<RootState, RootState>, - message = '' -) { - if (Authentication.isStudent && !ConfigModule.state.config.instanceSettings.exerciseMode) { - Authentication.deactivateUserAccount() - } - if (Authentication.isTutorOrReviewer) { - Assignments.cleanAssignments() - } - router.push({ name: 'login' }, () => { - resetState({ message }) - }) -} - -const mb = getStoreBuilder<RootState>() - -export const actions = { - updateSubmissionTypes: mb.dispatch(updateSubmissionTypes), - updateSubmissionType: mb.dispatch(updateSubmissionType), - getExamTypes: mb.dispatch(getExamTypes), - getStudents: mb.dispatch(getStudents), - getSubmissionFeedbackTest: mb.dispatch(getSubmissionFeedbackTest), - getStatistics: mb.dispatch(getStatistics), - logout: mb.dispatch(logout) -} diff --git a/grady/frontend/src/store/getters.ts b/grady/frontend/src/store/getters.ts deleted file mode 100644 index 2ea338f6e1bd32226e6a12491d6abcc4d3695701..0000000000000000000000000000000000000000 --- a/grady/frontend/src/store/getters.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { RootState } from '@/store/store' -import { getStoreBuilder } from 'vuex-typex' - -const mb = getStoreBuilder<RootState>() - -const stateGetter = mb.state() - -const correctedGetter = mb.read(function corrected (state) { - const progresses = state.statistics.submissionTypeProgress - return progresses.length > 0 && progresses.every(progress => { - return progress.feedbackFinal === progress.submissionCount - }) -}) -const submissionGetter = mb.read(function submission (state) { - return (pk: string) => { - return state.submissions[pk] - } -}) -const submissionTypeGetter = mb.read(function submissionType (state) { - return (pk: string) => { - return state.submissionTypes[pk] - } -}) - -export const getters = { - get state () { return stateGetter() }, - get corrected () { return correctedGetter() }, - get submission () { return submissionGetter() }, - get submissionType () { return submissionTypeGetter() } -} diff --git a/grady/frontend/src/store/grady_speak.ts b/grady/frontend/src/store/grady_speak.ts deleted file mode 100644 index 6ae7abba064d4c3f07922ad004073bea8baacbfc..0000000000000000000000000000000000000000 --- a/grady/frontend/src/store/grady_speak.ts +++ /dev/null @@ -1,25 +0,0 @@ -const gradySays = [ - 'Now let\'s see if we can improve this with a little water, sir.', - 'Won\'t keep you a moment, sir.', - 'Grady, sir. Delbert Grady.', - 'Yes, sir.', - 'That\'s right, sir.', - 'Why no, sir. I don\'t believe so.', - 'Ah ha, it\'s coming off now, sir.', - 'Why no, sir. I don\'t believe so.', - 'Yes, sir. I have a wife and two daughters, sir.', - 'Oh, they\'re somewhere around. I\'m not quite sure at the moment, sir.', - 'That\'s strange, sir. I don\'t have any recollection of that at all.', - 'I\'m sorry to differ with you, sir, but you are the caretaker.', - 'You have always been the caretaker, I should know, sir.', - 'I\'ve always been here.', - 'Indeed, he is, Mr. Torrance. A very willful boy. ', - 'A rather naughty boy, if I may be so bold, sir.', - 'Perhaps they need a good talking to, if you don\'t mind my saying so. Perhaps a bit more.', - 'My girls, sir, they didn\'t care for the Overlook at first.', - 'One of them actually stole a packet of matches and tried to burn it down.', - 'But I corrected them, sir.', - 'And when my wife tried to prevent me from doing my duty... I corrected her.' -] - -export default gradySays diff --git a/grady/frontend/src/store/modules/assignments.ts b/grady/frontend/src/store/modules/assignments.ts deleted file mode 100644 index d50399426573684067e4f4ddf464e7d65eb5430e..0000000000000000000000000000000000000000 --- a/grady/frontend/src/store/modules/assignments.ts +++ /dev/null @@ -1,193 +0,0 @@ -import Vue from 'vue' -import * as api from '@/api' -import { cartesian, flatten, once } from '@/util/helpers' -import { Assignment, FeedbackStageEnum, CreateAssignment, AvailableSubmissionCounts, Group} from '@/models' -import { RootState } from '@/store/store' -import { Authentication } from '@/store/modules/authentication' -import { getStoreBuilder, BareActionContext } from 'vuex-typex' -import router from '@/router' -import { Route } from 'vue-router' - -export interface AssignmentsState { - currentAssignment?: Assignment - assignmentCreation: { - submissionType?: string - stage: FeedbackStageEnum - group?: Group - }, - submissionsLeft: AvailableSubmissionCounts, - groups: Group[], - loading: boolean -} - -function initialState (): AssignmentsState { - return { - currentAssignment: undefined, - loading: false, - assignmentCreation: { - stage: FeedbackStageEnum.Creation, - group: undefined, - submissionType: undefined - }, - submissionsLeft: {}, - groups: [] - } -} - -const mb = getStoreBuilder<RootState>().module('Assignments', initialState()) - -const stateGetter = mb.state() - - -const availableStagesGetter = mb.read(function availableStages (state, getters) { - let stages = [FeedbackStageEnum.Creation, FeedbackStageEnum.Validation] - if (Authentication.isReviewer) { - stages.push(FeedbackStageEnum.Review) - } - return stages -}) - -const availableStagesReadableGetter = mb.read(function availableStagesReadable (state, getters) { - let stages = ['initial', 'validate'] - if (Authentication.isReviewer) { - stages.push('review') - } - return stages -}) - -const availableSubmissionTypeQueryKeysGetter = mb.read(function availableSubmissionTypeQueryKeys (state, getters, rootState) { - return Object.values(rootState.submissionTypes).map((subType: any) => subType.pk) -}) - -const availableExamTypeQueryKeysGetter = mb.read(function availableExamTypeQueryKeys (state, getters, rootState) { - return Object.values(rootState.examTypes).map((examType: any) => examType.pk) -}) - - -function SET_CURRENT_ASSIGNMENT (state: AssignmentsState, assignment?: Assignment): void { - state.currentAssignment = assignment -} - -function SET_CREATE_SUBMISSION_TYPE (state: AssignmentsState, submissionType: string): void { - state.assignmentCreation.submissionType = submissionType -} - -function SET_CREATE_STAGE (state: AssignmentsState, stage: FeedbackStageEnum): void { - state.assignmentCreation.stage = stage -} - -function SET_CREATE_GROUP (state: AssignmentsState, group: Group): void { - state.assignmentCreation.group = group -} - -function SET_SUBMISSION_LEFT (state: AssignmentsState, availableSubmissions: AvailableSubmissionCounts): void { - state.submissionsLeft = availableSubmissions -} - -function SET_GROUPS (state: AssignmentsState, groups: Group[]): void { - state.groups = groups -} - -function UPDATE_CREATE_PARAMETERS_FROM_URL(state: AssignmentsState, route: Route) { - const submissionType = route.params['sub_type'] - const stage = route.params['stage'] as FeedbackStageEnum - const group_par = route.params['group'] - - state.assignmentCreation.submissionType = submissionType - state.assignmentCreation.stage = stage - const group = state.groups.find((group) => group.pk === group_par) - if (group === undefined && state.groups.length > 0) { - throw new Error(`Group ${group_par} appeared in parameter but not available in ${state.groups}`) - } - state.assignmentCreation.group = group -} - -function RESET_STATE (state: AssignmentsState): void { - Object.assign(state, initialState()) -} - -async function createNextAssignment({ state }: BareActionContext<AssignmentsState, RootState>) { - const createAssignment = state.assignmentCreation - if (createAssignment.submissionType === undefined ) { - throw new Error('SET_CREATE_SUBMISSION_TYPE needs to be called before createNextAssignment') - } - - const data = { - stage: createAssignment.stage, - submissionType: createAssignment.submissionType!, - group: createAssignment.group !== undefined ? createAssignment.group.pk : undefined - } - - Assignments.SET_CURRENT_ASSIGNMENT(await api.createAssignment(data)) -} - -async function cleanAssignments -({ state }: BareActionContext<AssignmentsState, RootState>) { - await api.releaseUndoneAssignments() -} - -async function changeAssignment -({ state }: BareActionContext<AssignmentsState, RootState>, route: Route) { - Assignments.UPDATE_CREATE_PARAMETERS_FROM_URL(route) - if (state.currentAssignment) { - await Assignments.deleteCurrentAssignment() - } - await Assignments.createNextAssignment() -} - -async function skipAssignment ({ state }: BareActionContext<AssignmentsState, RootState>) { - if (!state.currentAssignment) { - throw new Error('skipAssignment can only be called with active assignment') - } - - const oldAssignment = state.currentAssignment - await Assignments.createNextAssignment() - await api.deleteAssignment({assignment: oldAssignment }) - -} - -async function deleteCurrentAssignment ({ state }: BareActionContext<AssignmentsState - , RootState>) { - if (!state.currentAssignment) { - throw new Error('No active assignment to delete') - } - await api.deleteAssignment({assignment: state.currentAssignment}) - Assignments.SET_CURRENT_ASSIGNMENT(undefined) -} - -async function getAvailableSubmissionCounts({ state }: BareActionContext<AssignmentsState, RootState>) { - const counts = await api.fetchAvailableSubmissionCounts(state.assignmentCreation.group) - Assignments.SET_SUBMISSION_LEFT(counts) -} - -async function getGroups() { - const groups = await api.fetchGroups() - Assignments.SET_GROUPS(groups) -} - - -export const Assignments = { - get state () { return stateGetter() }, - get availableStages () { return availableStagesGetter() }, - get availableStagesReadable () { return availableStagesReadableGetter() }, - get availableSubmissionTypeQueryKeys () { return availableSubmissionTypeQueryKeysGetter() }, - get availableExamTypeQueryKeys () { return availableExamTypeQueryKeysGetter() }, - - SET_CURRENT_ASSIGNMENT: mb.commit(SET_CURRENT_ASSIGNMENT), - SET_CREATE_SUBMISSION_TYPE: mb.commit(SET_CREATE_SUBMISSION_TYPE), - SET_CREATE_STAGE: mb.commit(SET_CREATE_STAGE), - SET_CREATE_GROUP: mb.commit(SET_CREATE_GROUP), - SET_SUBMISSION_LEFT: mb.commit(SET_SUBMISSION_LEFT), - SET_GROUPS: mb.commit(SET_GROUPS), - UPDATE_CREATE_PARAMETERS_FROM_URL: mb.commit(UPDATE_CREATE_PARAMETERS_FROM_URL), - RESET_STATE: mb.commit(RESET_STATE), - - - cleanAssignments: mb.dispatch(cleanAssignments), - changeAssignment: mb.dispatch(changeAssignment), - createNextAssignment: mb.dispatch(createNextAssignment), - skipAssignment: mb.dispatch(skipAssignment), - deleteCurrentAssignment: mb.dispatch(deleteCurrentAssignment), - getAvailableSubmissionCounts: mb.dispatch(getAvailableSubmissionCounts), - getGroups: mb.dispatch(getGroups) -} diff --git a/grady/frontend/src/store/modules/authentication.ts b/grady/frontend/src/store/modules/authentication.ts deleted file mode 100644 index 9444cdb284d066879acea0c889b12e98fc9b2322..0000000000000000000000000000000000000000 --- a/grady/frontend/src/store/modules/authentication.ts +++ /dev/null @@ -1,143 +0,0 @@ -import * as api from '@/api' -import gradySays from '../grady_speak' -import { BareActionContext, getStoreBuilder } from 'vuex-typex' -import { UserAccount } from '@/models' -import { RootState } from '@/store/store' - -export interface Credentials { - username: string, - password: string -} - -export interface AuthState { - token: string, - lastTokenRefreshTry: number, - refreshingToken: boolean, - message: string, - user: UserAccount -} -function initialState (): AuthState { - return { - token: '', - lastTokenRefreshTry: Date.now(), - refreshingToken: false, - message: '', - user: { - pk: '', - username: '', - isAdmin: false, - exerciseGroups: [] - } - } -} - -const mb = getStoreBuilder<RootState>().module('Authentication', initialState()) - -const stateGetter = mb.state() - -const gradySpeakGetter = mb.read(function gradySpeak () { - return gradySays[Math.floor(Math.random() * gradySays.length)] -}) -const isStudentGetter = mb.read(function isStudent (state: AuthState) { - return state.user.role === UserAccount.RoleEnum.Student -}) -const isTutorGetter = mb.read(function isTutor (state: AuthState) { - return state.user.role === UserAccount.RoleEnum.Tutor -}) -const isReviewerGetter = mb.read(function isReviewer (state: AuthState) { - return state.user.role === UserAccount.RoleEnum.Reviewer -}) -const isTutorOrReviewerGetter = mb.read(function isTutorOrReviewer (state: AuthState, getters) { - return getters.isTutor || getters.isReviewer -}) -const isLoggedInGetter = mb.read(function isLoggedIn (state: AuthState) { - return !!state.token -}) - -function SET_MESSAGE (state: AuthState, message: string) { - state.message = message -} -function SET_JWT_TOKEN (state: AuthState, token: string) { - api.default.defaults.headers['Authorization'] = `JWT ${token}` - state.token = token -} -function SET_USER (state: AuthState, user: UserAccount) { - state.user = user -} -function SET_REFRESHING_TOKEN (state: AuthState, refreshing: boolean) { - state.refreshingToken = refreshing -} -function SET_LAST_TOKEN_REFRESH_TRY (state: AuthState) { - state.lastTokenRefreshTry = Date.now() -} -function RESET_STATE (state: AuthState) { - Object.assign(state, initialState()) -} - -async function getJWT (context: BareActionContext<AuthState, RootState>, credentials: Credentials) { - try { - const token = await api.fetchJWT(credentials) - Authentication.SET_JWT_TOKEN(token.token) - } catch (error: any) { - let errorMsg - if (!error.response) { - errorMsg = 'Cannot reach server.' - } else if (error.response.status === 400) { - errorMsg = 'Unable to log in with provided credentials.' - } else if (error.response.status === 429) { - errorMsg = error.response.data.detail - } - Authentication.SET_MESSAGE(errorMsg) - throw errorMsg - } finally { - Authentication.SET_LAST_TOKEN_REFRESH_TRY() - } -} -async function refreshJWT ({ state }: BareActionContext<AuthState, RootState>) { - Authentication.SET_REFRESHING_TOKEN(true) - try { - const token = await api.refreshJWT(state.token) - Authentication.SET_JWT_TOKEN(token.token) - } finally { - Authentication.SET_REFRESHING_TOKEN(false) - Authentication.SET_LAST_TOKEN_REFRESH_TRY() - } -} -async function getUser () { - try { - const user = await api.getOwnUser() - Authentication.SET_USER(user) - } catch (err) { - Authentication.SET_MESSAGE('Unable to fetch user.') - } -} - -/** - * Deactivates the current user's account. - * They will not be able to login again until activated again. - */ -async function deactivateUserAccount ({ state }: BareActionContext<AuthState, RootState>) { - api.changeActiveForUser(state.user.pk, false) -} - -export const Authentication = { - get state () { return stateGetter() }, - get gradySpeak () { return gradySpeakGetter() }, - get isStudent () { return isStudentGetter() }, - get isTutor () { return isTutorGetter() }, - get isReviewer () { return isReviewerGetter() }, - get isTutorOrReviewer () { return isTutorOrReviewerGetter() }, - get isLoggedIn () { return isLoggedInGetter() }, - - SET_MESSAGE: mb.commit(SET_MESSAGE), - SET_JWT_TOKEN: mb.commit(SET_JWT_TOKEN), - SET_USER: mb.commit(SET_USER), - SET_REFRESHING_TOKEN: mb.commit(SET_REFRESHING_TOKEN), - SET_LAST_TOKEN_REFRESH_TRY: mb.commit(SET_LAST_TOKEN_REFRESH_TRY), - RESET_STATE: mb.commit(RESET_STATE), - - getJWT: mb.dispatch(getJWT), - refreshJWT: mb.dispatch(refreshJWT), - getUser: mb.dispatch(getUser), - deactivateUserAccount: mb.dispatch(deactivateUserAccount), -} diff --git a/grady/frontend/src/store/modules/config.ts b/grady/frontend/src/store/modules/config.ts deleted file mode 100644 index 8f29aaa177db330db9800f4bbe78aa7249eca73e..0000000000000000000000000000000000000000 --- a/grady/frontend/src/store/modules/config.ts +++ /dev/null @@ -1,61 +0,0 @@ -import { getStoreBuilder } from 'vuex-typex' -import { RootState } from '@/store/store' -import { Config } from '@/models' -import * as api from '@/api' - -export interface ConfigState { - config: Config -} - -function initialState (): ConfigState { - return { - config: { - timeDelta: 0, - currentExam: '', - examId: '', - version: '', - instanceSettings: { - exerciseMode: false, - singleCorrection: false, - stopOnPass: false, - showSolutionToStudents: false, - } - } - } -} - -const mb = getStoreBuilder<RootState>().module('ConfigModule', initialState()) - -const stateGetter = mb.state() - -function SET_CONFIG (state: ConfigState, config: Config) { - let exam_tmp = state.config.currentExam - let examId_tmp = state.config.examId - state.config = config - state.config.currentExam = exam_tmp - state.config.examId = examId_tmp -} - -function SET_CURRENT_EXAM (state: ConfigState, exam: string) { - state.config.currentExam = exam -} - -function SET_CURRENT_EXAM_ID (state: ConfigState, pk: string) { - state.config.examId = pk -} - -async function getConfig() { - const config = await api.fetchConfig() - ConfigModule.SET_CONFIG(config) -} - - -export const ConfigModule = { - get state () { return stateGetter() }, - - SET_CONFIG: mb.commit(SET_CONFIG), - SET_CURRENT_EXAM: mb.commit(SET_CURRENT_EXAM), - SET_CURRENT_EXAM_ID: mb.commit(SET_CURRENT_EXAM_ID), - - getConfig: mb.dispatch(getConfig) -} diff --git a/grady/frontend/src/store/modules/feedback-labels.ts b/grady/frontend/src/store/modules/feedback-labels.ts deleted file mode 100644 index ebf22ed8cfd8b5a04f08490e8691eb94c582d329..0000000000000000000000000000000000000000 --- a/grady/frontend/src/store/modules/feedback-labels.ts +++ /dev/null @@ -1,60 +0,0 @@ -import { FeedbackLabel } from '@/models' -import { getStoreBuilder } from 'vuex-typex' -import { RootState } from '../store' -import * as api from '@/api' -import Vue from 'vue' - -export interface FeedbackLabelsState { - labels: FeedbackLabel[] -} - -function initialState(): FeedbackLabelsState { - return { - labels: [] - } -} - -const mb = getStoreBuilder<RootState>().module('FeedbackLabels', initialState()) - -const stateGetter = mb.state() - -const availableLabelsGetter = mb.read(function labels(state) { - return state.labels -}) - -function SET_LABELS(state: FeedbackLabelsState, labels: FeedbackLabel[]) { - state.labels = labels -} - -function ADD_LABEL(state: FeedbackLabelsState, label: FeedbackLabel) { - state.labels.push(label) -} - -function REMOVE_LABEL(state: FeedbackLabelsState, label: FeedbackLabel) { - state.labels = state.labels.filter((val) => { - return val.pk !== label.pk - }) -} - -function UPDATE_LABEL(state: FeedbackLabelsState, label: FeedbackLabel) { - REMOVE_LABEL(state, label) - ADD_LABEL(state, label) -} - -async function getLabels() { - const labels = await api.getLabels() - FeedbackLabels.SET_LABELS(labels) -} - -export const FeedbackLabels = { - get state() { return stateGetter() }, - get availableLabels() { return availableLabelsGetter() }, - - SET_LABELS: mb.commit(SET_LABELS), - ADD_LABEL: mb.commit(ADD_LABEL), - REMOVE_LABEL: mb.commit(REMOVE_LABEL), - UPDATE_LABEL: mb.commit(UPDATE_LABEL), - - getLabels: mb.dispatch(getLabels) -} - diff --git a/grady/frontend/src/store/modules/feedback_list/feedback-table.ts b/grady/frontend/src/store/modules/feedback_list/feedback-table.ts deleted file mode 100644 index 3c11588631d470bd08fd18a54ccc0e93f5ce51ef..0000000000000000000000000000000000000000 --- a/grady/frontend/src/store/modules/feedback_list/feedback-table.ts +++ /dev/null @@ -1,108 +0,0 @@ -import { fetchAllFeedback, fetchAllAssignments } from '@/api' -import { objectifyArray } from '@/util/helpers' -import { Assignment, Feedback, FeedbackStageEnum, SubmissionType } from '@/models' -import { RootState } from '@/store/store' -import { getters } from '@/store/getters' -import { getStoreBuilder, BareActionContext } from 'vuex-typex' -import { Authentication } from '@/store/modules/authentication' - -export interface FeedbackHistoryItem extends Feedback { - history?: { - [key in FeedbackStageEnum]?: { - ofTutor: string - isDone: boolean - } - } - mark?: string // not the grade, but the color of the highlighting tool on feedbackHist page -} - -export interface FeedbackTableState { - feedbackHist: {[submissionPk: string]: FeedbackHistoryItem} -} - -function initialState (): FeedbackTableState { - return { - feedbackHist: {} - } -} - -const mb = getStoreBuilder<RootState>().module('FeedbackTable', initialState()) - -const stateGetter = mb.state() - -function SET_FEEDBACK_HISTORY (state: FeedbackTableState, val: Array<Feedback>) { - let feedbackList: FeedbackHistoryItem[] = val.map(feedback => { - return { - ...feedback, - mark: 'transparent', - } - }) - state.feedbackHist = objectifyArray(feedbackList, 'ofSubmission') -} -function ADD_ASSIGNMENTS_INFO (state: FeedbackTableState, assignments: Array<Assignment>) { - const doneAssignments = assignments.filter(assignment => assignment.isDone) - for (const assignment of doneAssignments) { - if (!assignment.submission || !assignment.stage) { - throw Error() - } - const feedback = state.feedbackHist[assignment.submission as string] - feedback.history = { - ...feedback.history, - [assignment.stage]: { - ofTutor: assignment.ofTutor, - isDone: assignment.isDone - } - } - } -} -function SET_FEEDBACK_OF_SUBMISSION_TYPE (state: FeedbackTableState, { feedback, type }: -{feedback: Feedback, type: SubmissionType}) { - if (!feedback.ofSubmission) { - throw new Error('Feedback must have ofSubmission present') - } - state.feedbackHist[feedback.ofSubmission].ofSubmissionType = type -} -function SET_MARK_COLOR (state: FeedbackTableState, {submissionPk, color}: -{submissionPk: string, color: string}) { - state.feedbackHist[submissionPk].mark=color -} -function RESET_STATE (state: FeedbackTableState) { Object.assign(state, initialState()) } - -function mapFeedbackHistExam ({ state }: BareActionContext<FeedbackTableState, RootState>) { - for (const feedback of Object.values(state.feedbackHist)) { - const type = getters.state.examTypes - } -} - -function mapFeedbackHistOfSubmissionType ({ state }: BareActionContext<FeedbackTableState, RootState>) { - for (const feedback of Object.values(state.feedbackHist)) { - const type = getters.submissionType((feedback as any).ofSubmissionType) - FeedbackTable.SET_FEEDBACK_OF_SUBMISSION_TYPE({ feedback, type }) - } -} -async function getFeedbackHistory () { - let data: [Promise<Feedback[]>, Promise<Assignment[]> | undefined] = - [fetchAllFeedback(), Authentication.isReviewer ? fetchAllAssignments() : undefined] - - Promise.all<Feedback[], Assignment[] | undefined>(data) - .then(([feedbacks, assignments]: [Feedback[], Assignment[]?]) => { - FeedbackTable.SET_FEEDBACK_HISTORY(feedbacks) - FeedbackTable.mapFeedbackHistOfSubmissionType() - if (assignments) { - FeedbackTable.ADD_ASSIGNMENTS_INFO(assignments) - } - }) -} - -export const FeedbackTable = { - get state () { return stateGetter() }, - - SET_FEEDBACK_HISTORY: mb.commit(SET_FEEDBACK_HISTORY), - ADD_ASSIGNMENTS_INFO: mb.commit(ADD_ASSIGNMENTS_INFO), - SET_FEEDBACK_OF_SUBMISSION_TYPE: mb.commit(SET_FEEDBACK_OF_SUBMISSION_TYPE), - SET_MARK_COLOR: mb.commit(SET_MARK_COLOR), - RESET_STATE: mb.commit(RESET_STATE), - - mapFeedbackHistOfSubmissionType: mb.dispatch(mapFeedbackHistOfSubmissionType), - getFeedbackHistory: mb.dispatch(getFeedbackHistory) -} diff --git a/grady/frontend/src/store/modules/student-page.ts b/grady/frontend/src/store/modules/student-page.ts deleted file mode 100644 index 03bf04902f3d6808a607e3bc4092831437f9787e..0000000000000000000000000000000000000000 --- a/grady/frontend/src/store/modules/student-page.ts +++ /dev/null @@ -1,92 +0,0 @@ -import { fetchStudentSelfData, fetchStudentSubmissions } from '@/api' -import { Exam, Submission, SubmissionList } from '@/models' -import { RootState } from '@/store/store' -import { Module } from 'vuex' -import { getStoreBuilder } from 'vuex-typex' -import { mutations } from '../mutations' - -export interface StudentPageState { - studentName: string - exam?: Exam - submissionsForList: Array<SubmissionList> - submissionData: {[typePk: string]: Submission} - visited: {[typePk: string]: boolean} - loaded: boolean -} - -function initialState (): StudentPageState { - return { - studentName: '', - exam: undefined, - submissionsForList: [], - submissionData: {}, - visited: {}, - loaded: false - } -} - -const mb = getStoreBuilder<RootState>().module('SutdenPage', initialState()) - -const stateGetter = mb.state() - -function SET_STUDENT_NAME (state: StudentPageState, name: string) { - state.studentName = name -} -function SET_EXAM (state: StudentPageState, exam: Exam) { - state.exam = exam -} -function SET_SUBMISSIONS_FOR_LIST (state: StudentPageState, submissions: SubmissionList[]) { - state.submissionsForList = submissions -} -/** - * Reduces the array submissionData returned by the /api/student-submissions - * into an object where the keys are the SubmissionType id's and the values - * the former array elements. This is done to have direct access to the data - * via the SubmissionType id. - */ -function SET_FULL_SUBMISSION_DATA (state: StudentPageState, submissionData: Array<Submission>) { - state.submissionData = submissionData.reduce((acc: {[pk: string]: Submission}, cur) => { - acc[cur.type.pk] = cur - return acc - }, {}) -} -function SET_VISITED (state: StudentPageState, visited: {index: string, visited: boolean}) { - state.visited = { ...state.visited, [visited.index]: visited.visited } -} -function SET_LOADED (state: StudentPageState, loaded: boolean) { - state.loaded = loaded -} -function RESET_STATE (state: StudentPageState) { - Object.assign(state, initialState()) -} - -async function getStudentData () { - const studentData = await fetchStudentSelfData() - StudentPage.SET_STUDENT_NAME(studentData.name || '') - StudentPage.SET_EXAM(studentData.exam) - StudentPage.SET_SUBMISSIONS_FOR_LIST(studentData.submissions) - StudentPage.SET_LOADED(true) -} - -async function getStudentSubmissions () { - const submissions = await fetchStudentSubmissions() - StudentPage.SET_FULL_SUBMISSION_DATA(submissions) - for (const submission of submissions) { - mutations.UPDATE_SUBMISSION_TYPE(submission.type) - } -} - -export const StudentPage = { - get state () { return stateGetter() }, - - SET_STUDENT_NAME: mb.commit(SET_STUDENT_NAME), - SET_EXAM: mb.commit(SET_EXAM), - SET_SUBMISSIONS_FOR_LIST: mb.commit(SET_SUBMISSIONS_FOR_LIST), - SET_FULL_SUBMISSION_DATA: mb.commit(SET_FULL_SUBMISSION_DATA), - SET_VISITED: mb.commit(SET_VISITED), - SET_LOADED: mb.commit(SET_LOADED), - RESET_STATE: mb.commit(RESET_STATE), - - getStudentData: mb.dispatch(getStudentData), - getStudentSubmissions: mb.dispatch(getStudentSubmissions) -} diff --git a/grady/frontend/src/store/modules/submission-notes.ts b/grady/frontend/src/store/modules/submission-notes.ts deleted file mode 100644 index dfac0cc68ea841a80fb693a5f4df0d0a60502a7b..0000000000000000000000000000000000000000 --- a/grady/frontend/src/store/modules/submission-notes.ts +++ /dev/null @@ -1,266 +0,0 @@ -import Vue from 'vue' -import * as hljs from 'highlight.js' -import * as api from '@/api' -import { Feedback, FeedbackComment, SubmissionNoType, CreateUpdateFeedback, SubmissionType } from '@/models' -import { RootState } from '@/store/store' -import { getStoreBuilder, BareActionContext } from 'vuex-typex' -import { syntaxPostProcess } from '@/util/helpers' -import { AxiosResponse } from 'axios' -import { Assignments } from './assignments' - -export const subNotesEventBus = new Vue() - -export interface SubmissionNotesState { - submission: SubmissionNoType - ui: { - showEditorOnLine: { [lineNo: number]: boolean } - selectedCommentOnLine: { [lineNo: number]: FeedbackComment } - showFeedback: boolean - }, - hasOrigFeedback: boolean - origFeedback: Feedback - updatedFeedback: CreateUpdateFeedback - commentsMarkedForDeletion: { [pk: string]: FeedbackComment } - changedLabels: boolean -} - -function initialState (): SubmissionNotesState { - return { - submission: { - text: '', - pk: '', - type: '', - tests: [], - sourceCodeAvailable: false - }, - ui: { - showEditorOnLine: {}, - selectedCommentOnLine: {}, - showFeedback: true - }, - hasOrigFeedback: false, - origFeedback: { - pk: 0, - ofSubmissionType: { - pk: '', - name: '', - examType: { - pk: '', - moduleReference: '', - totalScore: 0, - passScore: 0 - }, - description: '', - solutionComments: {} - }, - score: undefined, - isFinal: false, - feedbackLines: {}, - labels: [], - }, - updatedFeedback: { - pk: 0, - score: undefined, - feedbackLines: {}, - labels: [], - }, - commentsMarkedForDeletion: {}, - changedLabels: false - } -} - -const mb = getStoreBuilder<RootState>().module('SubmissionNotes', initialState()) - -const stateGetter = mb.state() - -const submissionTypeGetter = mb.read(function submissionType(state, getters, rootState) { - return rootState.submissionTypes[state.submission.type] -}) -// highlight the submission the reduce the string -// submission.text into an object where the keys are the -// line indexes starting at one and the values the corresponding submission line -// this makes iterating over the submission much more pleasant -const submissionGetter = mb.read(function submission(state, getters) { - const language = getters.submissionType - ? getters.submissionType.programmingLanguage - : 'c' - let highlighted = state.submission.text || '' - if (language !== SubmissionType.ProgrammingLanguageEnum.Markdown) { - highlighted = hljs.highlight(language, highlighted, true).value - } else if (language === SubmissionType.ProgrammingLanguageEnum.Markdown) { - highlighted = hljs.highlight('plaintext', highlighted, true).value - } - // const highlighted = state.submission.text || '' - const postProcessed = syntaxPostProcess(highlighted) - const splitted = postProcessed.split('\n').reduce((acc: { [k: number]: string }, cur, index) => { - acc[index + 1] = cur - return acc - }, {}) - return splitted -}) -const scoreGetter = mb.read(function score(state) { - return state.updatedFeedback.score !== undefined ? state.updatedFeedback.score : state.origFeedback.score -}) -const workInProgressGetter = mb.read(function workInProgress(state) { - const openEditor = Object.values(state.ui.showEditorOnLine).reduce((acc, curr) => acc || curr, false) - const feedbackWritten = Object.entries(state.updatedFeedback.feedbackLines || {}).length > 0 - return openEditor || feedbackWritten || state.changedLabels -}) -const isFeedbackCreationGetter = mb.read(function isFeedbackCreation(state) { - return !state.origFeedback['feedbackStageForUser'] || - state.origFeedback['feedbackStageForUser'] === 'feedback-creation' -}) - -/** - * Getter function to determine if the current stage is feedback review / conflict resolution. - */ -const isConflictResolution = mb.read(function isConflictResolution(state) { - return state.origFeedback['feedbackStageForUser'] && - state.origFeedback['feedbackStageForUser'] === 'feedback-review' -}) - -function SET_SUBMISSION(state: SubmissionNotesState, submission: SubmissionNoType) { - state.submission = submission - if (submission.feedback !== undefined) { - SET_ORIG_FEEDBACK(state, submission.feedback) - } -} -function SET_ORIG_FEEDBACK(state: SubmissionNotesState, feedback: Feedback) { - if (feedback) { - state.origFeedback = feedback - state.hasOrigFeedback = true - } -} -function SET_SHOW_FEEDBACK(state: SubmissionNotesState, val: boolean) { - state.ui.showFeedback = val -} -function UPDATE_FEEDBACK_LINE(state: SubmissionNotesState, feedback: { lineNo: number, comment: Partial<FeedbackComment> }) { - // explicit .toString() on lineNo is necessary because of Vue.set typings - if (state.updatedFeedback.feedbackLines) { - Vue.set(state.updatedFeedback.feedbackLines, feedback.lineNo.toString(), feedback.comment) - } -} -function SET_FEEDBACK_LABELS(state: SubmissionNotesState, labels: number[]) { - state.changedLabels = true - state.updatedFeedback.labels = labels -} -function ADD_FEEDBACK_LABEL(state: SubmissionNotesState, label: number) { - state.changedLabels = true - state.updatedFeedback.labels.push(label) -} -function REMOVE_FEEDBACK_LABEL(state: SubmissionNotesState, label: number) { - state.changedLabels = true - const tmp = state.updatedFeedback.labels.filter((val) => { - return val !== label - }) - state.updatedFeedback.labels = tmp -} -function UPDATE_FEEDBACK_SCORE(state: SubmissionNotesState, score: number) { - state.updatedFeedback.score = score -} -function DELETE_FEEDBACK_LINE(state: SubmissionNotesState, lineNo: number) { - if (state.updatedFeedback.feedbackLines) { - // Vue dosn't like objects that are indexed with numbers... - Vue.delete(state.updatedFeedback.feedbackLines, lineNo as unknown as string) - } -} -function TOGGLE_EDITOR_ON_LINE(state: SubmissionNotesState, { lineNo, comment }: { lineNo: number, comment: FeedbackComment }) { - Vue.set(state.ui.selectedCommentOnLine, lineNo as unknown as string, comment) - Vue.set(state.ui.showEditorOnLine, lineNo as unknown as string, !state.ui.showEditorOnLine[lineNo]) -} -function MARK_COMMENT_FOR_DELETION(state: SubmissionNotesState, comment: FeedbackComment) { - Vue.set(state.commentsMarkedForDeletion, comment.pk, comment) -} -function UN_MARK_COMMENT_FOR_DELETION(state: SubmissionNotesState, comment: FeedbackComment) { - Vue.delete(state.commentsMarkedForDeletion, comment.pk) -} -function RESET_MARKED_COMMENTS_FOR_DELETE(state: SubmissionNotesState) { - state.commentsMarkedForDeletion = {} -} -function RESET_UPDATED_FEEDBACK(state: SubmissionNotesState) { - state.updatedFeedback = initialState().updatedFeedback -} -function RESET_STATE(state: SubmissionNotesState) { - Object.assign(state, initialState()) -} - -async function deleteComments({ state }: BareActionContext<SubmissionNotesState, RootState>) { - return Promise.all( - Object.values(state.commentsMarkedForDeletion).map(comment => { - return api.deleteComment(comment) - }) - ) -} -async function submitFeedback( -{ state }: BareActionContext<SubmissionNotesState, RootState>, -{ isFinal = false}): -Promise<AxiosResponse<void>[]> { - - let feedback: Partial<CreateUpdateFeedback> = { - isFinal: isFinal, - ofSubmission: state.submission.pk, - ofSubmissionType: state.submission.type, - feedbackLines: {}, - labels: state.updatedFeedback.labels - } - - // omit labels for the request - if (!state.changedLabels) { - delete feedback.labels - } - - if (state.updatedFeedback.score !== undefined) { - feedback.score = state.updatedFeedback.score - } else { - feedback.score = state.origFeedback.score - } - - // set the comments for the feedback lines accordingly - for (const key of Object.keys(state.updatedFeedback.feedbackLines)) { - const numKey = Number(key) - - numKey && feedback.feedbackLines - && (feedback.feedbackLines[numKey] = state.updatedFeedback.feedbackLines[numKey]) - } - - const assignment = Assignments.state.currentAssignment - if (assignment) { - await api.submitFeedbackForAssignment({ feedback , assignment}) - } else if (state.hasOrigFeedback) { - feedback.pk = state.origFeedback.pk - await api.submitUpdatedFeedback({ feedback } as { feedback: CreateUpdateFeedback }) - } else { - await api.submitFeedback({feedback} as { feedback: CreateUpdateFeedback }) - } - // delete those comments that have been marked for deletion - return SubmissionNotes.deleteComments() -} - -export const SubmissionNotes = { - get state() { return stateGetter() }, - get submissionType() { return submissionTypeGetter() }, - get submission() { return submissionGetter() }, - get score() { return scoreGetter() }, - get workInProgress() { return workInProgressGetter() }, - get isFeedbackCreation() { return isFeedbackCreationGetter() }, - get isConflictResolution() { return isFeedbackCreationGetter() }, - - SET_SUBMISSION: mb.commit(SET_SUBMISSION), - SET_ORIG_FEEDBACK: mb.commit(SET_ORIG_FEEDBACK), - SET_SHOW_FEEDBACK: mb.commit(SET_SHOW_FEEDBACK), - SET_FEEDBACK_LABELS: mb.commit(SET_FEEDBACK_LABELS), - ADD_FEEDBACK_LABEL: mb.commit(ADD_FEEDBACK_LABEL), - REMOVE_FEEDBACK_LABEL: mb.commit(REMOVE_FEEDBACK_LABEL), - UPDATE_FEEDBACK_LINE: mb.commit(UPDATE_FEEDBACK_LINE), - UPDATE_FEEDBACK_SCORE: mb.commit(UPDATE_FEEDBACK_SCORE), - DELETE_FEEDBACK_LINE: mb.commit(DELETE_FEEDBACK_LINE), - TOGGLE_EDITOR_ON_LINE: mb.commit(TOGGLE_EDITOR_ON_LINE), - MARK_COMMENT_FOR_DELETION: mb.commit(MARK_COMMENT_FOR_DELETION), - UN_MARK_COMMENT_FOR_DELETION: mb.commit(UN_MARK_COMMENT_FOR_DELETION), - RESET_MARKED_COMMENTS_FOR_DELETE: mb.commit(RESET_MARKED_COMMENTS_FOR_DELETE), - RESET_UPDATED_FEEDBACK: mb.commit(RESET_UPDATED_FEEDBACK), - RESET_STATE: mb.commit(RESET_STATE), - - deleteComments: mb.dispatch(deleteComments), - submitFeedback: mb.dispatch(submitFeedback) -} diff --git a/grady/frontend/src/store/modules/tutor-overview.ts b/grady/frontend/src/store/modules/tutor-overview.ts deleted file mode 100644 index 6e562e49de0ca8ab5aa00bab9cd2b4d6a7b8b459..0000000000000000000000000000000000000000 --- a/grady/frontend/src/store/modules/tutor-overview.ts +++ /dev/null @@ -1,71 +0,0 @@ -import { fetchAllTutors, fetchActiveAssignments, deleteAssignment } from '@/api' -import { Tutor, Assignment } from '@/models' -import { RootState } from '../store' -import { getStoreBuilder, BareActionContext } from 'vuex-typex' -import { objectifyArray } from '@/util/helpers' - -export interface TutorOverviewState { - tutors: Tutor[], - activeAssignments: {[ownerName: string]: Assignment[]} -} - -function initialState (): TutorOverviewState { - return { - tutors: [], - activeAssignments: {} - } -} - -type Context = BareActionContext<TutorOverviewState, RootState> - -const mb = getStoreBuilder<RootState>().module('TutorOverview', initialState()) - -const stateGetter = mb.state() - -function SET_TUTORS (state: TutorOverviewState, tutors: Tutor[]) { - state.tutors = tutors -} - -function SET_ASSIGNMENTS (state: TutorOverviewState, assignments: Assignment[]) { - state.activeAssignments = assignments.reduce((acc: {[ownerName: string]: Assignment[]}, curr) => { - if (!curr.owner) { - throw new Error('Assignments must have owner information') - } - acc[curr.owner] ? acc[curr.owner].push(curr) : acc[curr.owner] = [curr] - return acc - }, {}) -} - -function RESET_STATE (state: TutorOverviewState) { - Object.assign(state, initialState()) -} - -async function getTutors () { - const tutors = await fetchAllTutors() - TutorOverview.SET_TUTORS(tutors) -} - -async function getActiveAssignments () { - const assignments = await fetchActiveAssignments() - TutorOverview.SET_ASSIGNMENTS(assignments) -} - -async function deleteActiveAssignmentsOfTutor ({ state }: Context, tutor: Tutor) { - const assignments = state.activeAssignments[tutor.pk] - const promises = assignments.map(assignment => { return deleteAssignment({ assignment }) }) - Promise.all(promises).finally(() => { - TutorOverview.getActiveAssignments() - }) -} - -export const TutorOverview = { - get state () { return stateGetter() }, - - SET_TUTORS: mb.commit(SET_TUTORS), - SET_ASSIGNMENTS: mb.commit(SET_ASSIGNMENTS), - RESET_STATE: mb.commit(RESET_STATE), - - getTutors: mb.dispatch(getTutors), - getActiveAssignments: mb.dispatch(getActiveAssignments), - deleteActiveAssignmentsOfTutor: mb.dispatch(deleteActiveAssignmentsOfTutor) -} diff --git a/grady/frontend/src/store/modules/ui.ts b/grady/frontend/src/store/modules/ui.ts deleted file mode 100644 index 7e3849be84ff6d04033ff6aa84f45e1c05a8f67b..0000000000000000000000000000000000000000 --- a/grady/frontend/src/store/modules/ui.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { getStoreBuilder } from 'vuex-typex' -import { RootState } from '@/store/store' - -export interface UIState { - sideBarCollapsed: boolean - showJumbotron: boolean, - showSubmissionType: boolean, -} - -function initialState (): UIState { - return { - sideBarCollapsed: false, - showJumbotron: true, - showSubmissionType: true, - } -} - -const mb = getStoreBuilder<RootState>().module('UI', initialState()) - -const stateGetter = mb.state() - -function SET_SIDEBAR_COLLAPSED (state: UIState, collapsed: boolean) { - state.sideBarCollapsed = collapsed -} -function SET_SHOW_JUMBOTRON (state: UIState, val: boolean) { - state.showJumbotron = val -} -function SET_SHOW_SUBMISSIONTYPE (state: UIState, val: boolean) { - state.showSubmissionType = val -} - -export const UI = { - get state () { return stateGetter() }, - - SET_SIDEBAR_COLLAPSED: mb.commit(SET_SIDEBAR_COLLAPSED), - SET_SHOW_JUMBOTRON: mb.commit(SET_SHOW_JUMBOTRON), - SET_SHOW_SUBMISSIONTYPE: mb.commit(SET_SHOW_SUBMISSIONTYPE), -} diff --git a/grady/frontend/src/store/mutations.ts b/grady/frontend/src/store/mutations.ts deleted file mode 100644 index 8be94088c9f129e3d4cf69e99954be7af45ed7a0..0000000000000000000000000000000000000000 --- a/grady/frontend/src/store/mutations.ts +++ /dev/null @@ -1,85 +0,0 @@ -import Vue from 'vue' -import { getStoreBuilder } from 'vuex-typex' - -import { initialState, RootState } from '@/store/store' -import { Exam, Statistics, StudentInfoForListView, SubmissionNoType, SubmissionType} from '@/models' - -export const mb = getStoreBuilder<RootState>() - -function SET_EXAM_TYPES (state: RootState, examTypes: Array<Exam>) { - state.examTypes = examTypes.reduce((acc: {[pk: string]: Exam}, curr) => { - acc[curr.pk] = curr - return acc - }, {}) -} -function SET_STUDENTS (state: RootState, students: Array<StudentInfoForListView>) { - state.students = students.reduce((acc: {[pk: string]: StudentInfoForListView}, curr) => { - acc[curr.pk] = mapStudent(curr, state.studentMap) - return acc - }, {}) -} -function SET_STUDENT (state: RootState, student: StudentInfoForListView) { - Vue.set(state.students, student.pk, mapStudent({ - ...state.students[student.pk], - ...student - }, state.studentMap)) -} -// TODO proper types for student map -export interface StudentMap { - [pseudoMatrikelNo: string]: { - matrikelNo: string, - name: string, - email: string - } -} -function SET_STUDENT_MAP (state: RootState, map: StudentMap) { - state.studentMap = map -} -function SET_SUBMISSION (state: RootState, submission: SubmissionNoType) { - Vue.set(state.submissions, submission.pk, submission) -} -function SET_STATISTICS (state: RootState, statistics: Statistics) { - state.statistics = { - ...state.statistics, - ...statistics - } -} -function UPDATE_SUBMISSION_TYPE (state: RootState, submissionType: SubmissionType) { - const updatedSubmissionType = { - ...state.submissionTypes[submissionType.pk], - ...submissionType - } - Vue.set(state.submissionTypes, submissionType.pk, updatedSubmissionType) -} -// this func is being exported to use it's name in the latInteractionPlugin -export function SET_LAST_INTERACTION (state: RootState) { - state.lastAppInteraction = Date.now() -} -function RESET_STATE (state: RootState) { - Object.assign(state, initialState()) -} - -function mapStudent (student: StudentInfoForListView, map: any) { - if (Object.keys(map).length > 0) { - if (!student.matrikelNo) { - throw Error('Student objects need matrikelNo key in order to apply mapping') - } - return { - ...student, - ...map[student.matrikelNo] - } - } - return student -} - -export const mutations = { - SET_LAST_INTERACTION: mb.commit(SET_LAST_INTERACTION), - SET_EXAM_TYPES: mb.commit(SET_EXAM_TYPES), - SET_STUDENTS: mb.commit(SET_STUDENTS), - SET_STUDENT: mb.commit(SET_STUDENT), - SET_STUDENT_MAP: mb.commit(SET_STUDENT_MAP), - SET_SUBMISSION: mb.commit(SET_SUBMISSION), - SET_STATISTICS: mb.commit(SET_STATISTICS), - UPDATE_SUBMISSION_TYPE: mb.commit(UPDATE_SUBMISSION_TYPE), - RESET_STATE: mb.commit(RESET_STATE) -} diff --git a/grady/frontend/src/store/store.ts b/grady/frontend/src/store/store.ts deleted file mode 100644 index 32f7c91541b4c357944352678e7e40766e06df1b..0000000000000000000000000000000000000000 --- a/grady/frontend/src/store/store.ts +++ /dev/null @@ -1,94 +0,0 @@ -import Vuex, { Plugin } from 'vuex' -import Vue from 'vue' -import { getStoreBuilder } from 'vuex-typex' - -// @ts-ignore -import './modules/ui' -// @ts-ignore -import './modules/authentication' -// @ts-ignore -import './modules/feedback_list/feedback-table' -// @ts-ignore -import './modules/assignments' -// @ts-ignore -import './modules/submission-notes' -// @ts-ignore -import './modules/student-page' -// @ts-ignore -import './modules/tutor-overview' -// @ts-ignore -import './modules/config' - -import './mutations' -import './actions' -import './getters' - -import { UIState } from './modules/ui' -import { AuthState } from './modules/authentication' -import { AssignmentsState } from './modules/assignments' -import { FeedbackTableState } from './modules/feedback_list/feedback-table' -import { SubmissionNotesState } from './modules/submission-notes' -import { StudentPageState } from './modules/student-page' -import { TutorOverviewState } from './modules/tutor-overview' - -import { - Exam, - Statistics, - StudentInfoForListView, - SubmissionNoType, - SubmissionType, -} from '@/models' -import { FeedbackLabelsState } from './modules/feedback-labels' -import { ConfigState } from './modules/config' -import { StudentMap } from './mutations' - -Vue.use(Vuex) - -export interface RootInitialState { - lastAppInteraction: number - examTypes: {[pk: string]: Exam} - submissionTypes: {[pk: string]: SubmissionType} - submissions: {[pk: string]: SubmissionNoType} - students: {[pk: string]: StudentInfoForListView} - studentMap: StudentMap // is used to map obfuscated student data back to the original - statistics: Statistics -} - -export interface RootState extends RootInitialState{ - UI: UIState, - Authentication: AuthState, - FeedbackTable: FeedbackTableState, - Assignments: AssignmentsState, - SubmissionNotes: SubmissionNotesState, - StudentPage: StudentPageState, - TutorOverview: TutorOverviewState, - FeedbackLabels: FeedbackLabelsState - ConfigModule: ConfigState -} - -export function initialState (): RootInitialState { - return { - lastAppInteraction: Date.now(), - examTypes: {}, - submissionTypes: {}, - submissions: {}, - students: {}, - studentMap: {}, // is used to map obfuscated student data back to the original - statistics: { - submissionsPerType: 0, - submissionsPerStudent: 0, - currentMeanScore: 0, - submissionTypeProgress: [] - } - } -} - -export const persistedStateKey = 'grady' - -const store = getStoreBuilder<RootState>().vuexStore({ - strict: process.env.NODE_ENV === 'development', - // TODO is there a better way than casting the initialState ? - state: initialState() as RootState -}) - -export default store diff --git a/grady/frontend/src/util/form-rules.ts b/grady/frontend/src/util/form-rules.ts deleted file mode 100644 index 7eb32321fe1f9572d1445a5f66eb7d00fb5fa8f5..0000000000000000000000000000000000000000 --- a/grady/frontend/src/util/form-rules.ts +++ /dev/null @@ -1,5 +0,0 @@ -type Rule = (value: unknown) => true | string - -export const required: Rule = function (v) { - return !!v || 'This field is required.' -} diff --git a/grady/frontend/src/util/helpers.ts b/grady/frontend/src/util/helpers.ts deleted file mode 100644 index 314db84fe5bee5352ea3614e094f245e794aafd6..0000000000000000000000000000000000000000 --- a/grady/frontend/src/util/helpers.ts +++ /dev/null @@ -1,173 +0,0 @@ -import { AxiosError, AxiosResponse } from 'axios' -import { Dispatch } from 'vuex' -import { MutationHandler } from 'vuex-typex' - -export function nameSpacer (namespace: string) { - return function (commitType: string) { - return namespace + commitType - } -} - -export function getObjectValueByPath (obj: any, path: string): any { - // credit: http://stackoverflow.com/questions/6491463/accessing-nested-javascript-objects-with-string-key#comment55278413_6491621 - if (!path || path.constructor !== String) return - path = path.replace(/\[(\w+)\]/g, '.$1') // convert indexes to properties - path = path.replace(/^\./, '') // strip a leading dot - const a = path.split('.') - for (let i = 0, n = a.length; i < n; ++i) { - const k = a[i] - if (obj instanceof Object && k in obj) { - obj = obj[k] - } else { - return - } - } - return obj -} - -interface GetSetPair<P> { - get: () => any, - set: (val: P) => void -} - -/** - * Use this method to generate a computed property accessing the store for a Vue instance. - * The get method will return the value at this.$store.state.<path>. - * The set method will commit the passed value as payload for the specified mutation - * @param path to the store variable/object being returned - * @param mutation name of mutation type - * @param namespace to prepend the mutation type with - * @returns {*} - */ -export function createComputedGetterSetter<P> ( - { path, mutation, namespace }: - {path: string, mutation: string | ((payload?: P) => void), namespace:string}): GetSetPair<P> { - return { - get (): any { - return getObjectValueByPath((this as any).$store.state, path) - }, - set (val: P): void { - if (typeof mutation === 'string') { - (this as any).$store.commit(`${namespace ? namespace + '/' : ''}${mutation}`, val) - } else { - mutation(val) - } - } - } -} - -interface StateMapperItem { - name: string, - mutation: string, - path?: string -} - -interface MappedState { - [key: string]: GetSetPair<any> -} - -/** - * Returns an object of generated computed getter/setter pairs. - * Can be used to quickly bind a stores state and corresponding setters to a vue component - * @param namespace optional namespace of mutations - * @param pathPrefix if set, all items path will be prepended by the path prefix - * @param items array that contains objects {name, path, mutation} - */ -export function mapStateToComputedGetterSetter ( - { namespace = '', pathPrefix = '', items = [] }: - {namespace: string, pathPrefix: string, items: StateMapperItem[]}): MappedState { - return items.reduce((acc: MappedState, curr) => { - // if no path is give, use name - const itemPath = curr.path || curr.name - const path = pathPrefix ? `${pathPrefix}.${itemPath}` : itemPath - acc[curr.name] = createComputedGetterSetter({ mutation: curr.mutation, path, namespace }) - return acc - }, {}) -} - -// thanks to rsp -// https://stackoverflow.com/questions/12303989/cartesian-product-of-multiple-arrays-in-javascript/43053803#43053803 -function cartesianHelper (a: Array<any>, b: Array<any>): Array<Array<any>> { - return ([] as Array<any>).concat(...a.map((a: any) => b.map((b: any) => [].concat(a, b)))) -} -export function cartesian (a: Array<any>, b?: Array<any>, ...c: Array<Array<any>>): Array<Array<any>> { - return b ? cartesian(cartesianHelper(a, b), ...c) : a -} - -// flatten an array -export function flatten (list: any[]): any[] { - return list.reduce( - (a, b) => a.concat(Array.isArray(b) ? flatten(b) : b), [] - ) -} - -export function objectifyArray<T, P extends keyof T> (arr: T[], key: P): {[index: string]: T} { - return arr.reduce((acc: any, curr) => { - acc[curr[key]] = curr - return acc - }, {}) -} - -interface OnceFunc { - (): any - reset: () => void -} - -export function once (fn: Function, context?: object): OnceFunc { - let result: any - let wrapped = function (this: any) { - if (!result) { - result = fn.apply(context || this, arguments) - } - return result - } as OnceFunc - wrapped.reset = function () { result = undefined } - return wrapped -} - -export function syntaxPostProcess (code: string): string { - const spanPrefix = '<span class="hljs-comment">' - const spanSuffix = '</span>' - - code = code.replace(/(<span class="hljs-comment">)([\s\S]*?)(<\/span>)/gim, (match, p1, p2, p3) => { - const splitted = p2.split(/\n/) - for (let i = 0; i < splitted.length; i++) { - splitted[i] = spanPrefix + splitted[i] + spanSuffix - } - - return splitted.join('\n') - }) - return code -} - -export function parseBlacklist (blacklist: Array<string>): string { - return blacklist.reduce((acc, curr) => { - return acc + '|' + curr - }) -} - -export function parseErrorNotification (response: AxiosResponse): string { - if (!response.data || Object.keys(response.data).length === 0) { - return 'There is no useful error data. Please ask the staff for help.' - } else { - let msg = '<ul>' - function pickRecursive(obj: any) { - if (obj instanceof Object) { - for (let k of Object.keys(obj)) { - pickRecursive(obj[k]) - } - } else { - msg += '<li>' + obj + '</li>' - } - } - pickRecursive(response.data) - msg += '</ul>' - - if (response.status === 404) { - msg += '<br/>If you experience unusual behaviour, finish all unfinished work and relog.' + - ' If not, this is probably not a critical error.' - } - - return msg - } -} diff --git a/grady/frontend/src/util/interceptor.ts b/grady/frontend/src/util/interceptor.ts deleted file mode 100644 index 109706fe7f99bde48f0c5d7f420d3d6a80ce08ec..0000000000000000000000000000000000000000 --- a/grady/frontend/src/util/interceptor.ts +++ /dev/null @@ -1,23 +0,0 @@ -import instance from '@/main' -import { parseErrorNotification, parseBlacklist } from '@/util/helpers' - - -const errorUrlBlacklist = [ - '/api/get-token/', - '/api/.*/change_password/', - '/api/corrector/register/', - '/api/assignment/' -] -const blackListRegExp = new RegExp(parseBlacklist(errorUrlBlacklist), 'g') - -export function errorInterceptor (error: any): any { - if (!error.response.request.responseURL.match(blackListRegExp)) { - instance.$notify({ - title: 'Request failed.', - text: parseErrorNotification(error.response), - type: 'error', - duration: -1 - }) - } - return Promise.reject(error) -} diff --git a/grady/frontend/src/util/shortkeys.ts b/grady/frontend/src/util/shortkeys.ts deleted file mode 100644 index 996c04d279b3308f4e14ad0c30c832ba9dd11942..0000000000000000000000000000000000000000 --- a/grady/frontend/src/util/shortkeys.ts +++ /dev/null @@ -1,26 +0,0 @@ -import Vue from 'vue' - -const shortkeyTypes = { - numeric: (key: string) => { return Number(key) >= 0 && Number(key) <= 9 } -} - -const handlerFunc = (el: any, bind: any) => { - return (event: KeyboardEvent) => { - // handle numeric key press - if (bind.value === 'numeric' && shortkeyTypes.numeric(event.key)) { - const e = new KeyboardEvent('shortkey', { bubbles: false, key: event.key }) - el.dispatchEvent(e) - } - } -} - -// add the v-shortkey directive to Vue -// usage: <tag v-shortkey="<shortkeyType>" @shortkey="<handlerFunc>"></tag> -Vue.directive('shortkey', { - bind: (el, bind) => { - window.addEventListener('keypress', handlerFunc(el, bind)) - }, - unbind: (el, bind) => { - window.removeEventListener('keypress', handlerFunc(el, bind)) - } -}) \ No newline at end of file diff --git a/grady/frontend/tsconfig.json b/grady/frontend/tsconfig.json deleted file mode 100644 index 8e57f591ec8c5c3879e6c66c8112470e37a7615f..0000000000000000000000000000000000000000 --- a/grady/frontend/tsconfig.json +++ /dev/null @@ -1,42 +0,0 @@ -{ - "compilerOptions": { - "target": "es2018", - "module": "esnext", - "strict": true, - "jsx": "preserve", - "importHelpers": true, - "moduleResolution": "node", - "experimentalDecorators": true, - "esModuleInterop": true, - "sourceMap": true, - "baseUrl": ".", - "types": [ - "webpack-env", - "mocha", - "chai" - ], - "paths": { - "@/*": [ - "src/*" - ] - }, - "lib": [ - "es2017", - "es2018.promise", - "dom", - "dom.iterable", - "scripthost" - ] - }, - "include": [ - "@types/", - "src/**/*.ts", - "src/**/*.tsx", - "src/**/*.vue", - "tests/**/*.ts", - "tests/**/*.tsx" - ], - "exclude": [ - "node_modules" - ] -} diff --git a/grady/frontend/vue.config.js b/grady/frontend/vue.config.js deleted file mode 100644 index 74cd12131786660b22cb1449c25af83d85e61e76..0000000000000000000000000000000000000000 --- a/grady/frontend/vue.config.js +++ /dev/null @@ -1,23 +0,0 @@ -const path = require('path') - -const projectRoot = path.resolve(__dirname) - -module.exports = { - assetsDir: 'static', - devServer: { - allowedHosts: ['localhost'], - host: 'localhost' - }, - configureWebpack: config => { - config.resolve.alias['@'] = `${projectRoot}/src` - - if (process.env.NODE_ENV === 'development') { - config.devtool = 'source-map' - } - - // keep_fnames ist set to true because vuex-typex is dependant on the function names - if (process.env.NODE_ENV === 'production') { - config.optimization.minimizer[0].options.terserOptions.keep_fnames = true - } - } -} diff --git a/grady/frontend/yarn.lock b/grady/frontend/yarn.lock deleted file mode 100644 index f13a22aaa8371dfae0b9d57a0026cc1740f52280..0000000000000000000000000000000000000000 --- a/grady/frontend/yarn.lock +++ /dev/null @@ -1,8283 +0,0 @@ -# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. -# yarn lockfile v1 - - -"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.16.0", "@babel/code-frame@^7.8.3": - version "7.16.0" - resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.16.0.tgz#0dfc80309beec8411e65e706461c408b0bb9b431" - integrity sha512-IF4EOMEV+bfYwOmNxGzSnjR2EmQod7f1UXOpZM3l4i4o4QNwzjtJAu/HxdjHq0aYBvdqMuQEY1eg0nqW9ZPORA== - dependencies: - "@babel/highlight" "^7.16.0" - -"@babel/generator@^7.16.0": - version "7.16.0" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.16.0.tgz#d40f3d1d5075e62d3500bccb67f3daa8a95265b2" - integrity sha512-RR8hUCfRQn9j9RPKEVXo9LiwoxLPYn6hNZlvUOR8tSnaxlD0p0+la00ZP9/SnRt6HchKr+X0fO2r8vrETiJGew== - dependencies: - "@babel/types" "^7.16.0" - jsesc "^2.5.1" - source-map "^0.5.0" - -"@babel/helper-function-name@^7.16.0": - version "7.16.0" - resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.16.0.tgz#b7dd0797d00bbfee4f07e9c4ea5b0e30c8bb1481" - integrity sha512-BZh4mEk1xi2h4HFjWUXRQX5AEx4rvaZxHgax9gcjdLWdkjsY7MKt5p0otjsg5noXw+pB+clMCjw+aEVYADMjog== - dependencies: - "@babel/helper-get-function-arity" "^7.16.0" - "@babel/template" "^7.16.0" - "@babel/types" "^7.16.0" - -"@babel/helper-get-function-arity@^7.16.0": - version "7.16.0" - resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.16.0.tgz#0088c7486b29a9cb5d948b1a1de46db66e089cfa" - integrity sha512-ASCquNcywC1NkYh/z7Cgp3w31YW8aojjYIlNg4VeJiHkqyP4AzIvr4qx7pYDb4/s8YcsZWqqOSxgkvjUz1kpDQ== - dependencies: - "@babel/types" "^7.16.0" - -"@babel/helper-hoist-variables@^7.16.0": - version "7.16.0" - resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.16.0.tgz#4c9023c2f1def7e28ff46fc1dbcd36a39beaa81a" - integrity sha512-1AZlpazjUR0EQZQv3sgRNfM9mEVWPK3M6vlalczA+EECcPz3XPh6VplbErL5UoMpChhSck5wAJHthlj1bYpcmg== - dependencies: - "@babel/types" "^7.16.0" - -"@babel/helper-split-export-declaration@^7.16.0": - version "7.16.0" - resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.16.0.tgz#29672f43663e936df370aaeb22beddb3baec7438" - integrity sha512-0YMMRpuDFNGTHNRiiqJX19GjNXA4H0E8jZ2ibccfSxaCogbm3am5WN/2nQNj0YnQwGWM1J06GOcQ2qnh3+0paw== - dependencies: - "@babel/types" "^7.16.0" - -"@babel/helper-validator-identifier@^7.15.7": - version "7.15.7" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.15.7.tgz#220df993bfe904a4a6b02ab4f3385a5ebf6e2389" - integrity sha512-K4JvCtQqad9OY2+yTU8w+E82ywk/fe+ELNlt1G8z3bVGlZfn/hOcQQsUhGhW/N+tb3fxK800wLtKOE/aM0m72w== - -"@babel/highlight@^7.16.0": - version "7.16.0" - resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.16.0.tgz#6ceb32b2ca4b8f5f361fb7fd821e3fddf4a1725a" - integrity sha512-t8MH41kUQylBtu2+4IQA3atqevA2lRgqA2wyVB/YiWmsDSuylZZuXOUy9ric30hfzauEFfdsuk/eXTRrGrfd0g== - dependencies: - "@babel/helper-validator-identifier" "^7.15.7" - chalk "^2.0.0" - js-tokens "^4.0.0" - -"@babel/parser@^7.16.0", "@babel/parser@^7.7.0": - version "7.16.2" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.16.2.tgz#3723cd5c8d8773eef96ce57ea1d9b7faaccd12ac" - integrity sha512-RUVpT0G2h6rOZwqLDTrKk7ksNv7YpAilTnYe1/Q+eDjxEceRMKVWbCsX7t8h6C1qCFi/1Y8WZjcEPBAFG27GPw== - -"@babel/template@^7.16.0": - version "7.16.0" - resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.16.0.tgz#d16a35ebf4cd74e202083356fab21dd89363ddd6" - integrity sha512-MnZdpFD/ZdYhXwiunMqqgyZyucaYsbL0IrjoGjaVhGilz+x8YB++kRfygSOIj1yOtWKPlx7NBp+9I1RQSgsd5A== - dependencies: - "@babel/code-frame" "^7.16.0" - "@babel/parser" "^7.16.0" - "@babel/types" "^7.16.0" - -"@babel/traverse@^7.7.0": - version "7.16.0" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.16.0.tgz#965df6c6bfc0a958c1e739284d3c9fa4a6e3c45b" - integrity sha512-qQ84jIs1aRQxaGaxSysII9TuDaguZ5yVrEuC0BN2vcPlalwfLovVmCjbFDPECPXcYM/wLvNFfp8uDOliLxIoUQ== - dependencies: - "@babel/code-frame" "^7.16.0" - "@babel/generator" "^7.16.0" - "@babel/helper-function-name" "^7.16.0" - "@babel/helper-hoist-variables" "^7.16.0" - "@babel/helper-split-export-declaration" "^7.16.0" - "@babel/parser" "^7.16.0" - "@babel/types" "^7.16.0" - debug "^4.1.0" - globals "^11.1.0" - -"@babel/types@^7.16.0", "@babel/types@^7.7.0": - version "7.16.0" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.16.0.tgz#db3b313804f96aadd0b776c4823e127ad67289ba" - integrity sha512-PJgg/k3SdLsGb3hhisFvtLOw5ts113klrpLuIPtCJIU+BB24fqq6lf8RWqKJEjzqXR9AEH1rIb5XTqwBHB+kQg== - dependencies: - "@babel/helper-validator-identifier" "^7.15.7" - to-fast-properties "^2.0.0" - -"@hapi/address@2.x.x": - version "2.1.4" - resolved "https://registry.yarnpkg.com/@hapi/address/-/address-2.1.4.tgz#5d67ed43f3fd41a69d4b9ff7b56e7c0d1d0a81e5" - integrity sha512-QD1PhQk+s31P1ixsX0H0Suoupp3VMXzIVMSwobR3F3MSUO2YCV0B7xqLcUw/Bh8yuvd3LhpyqLQWTNcRmp6IdQ== - -"@hapi/bourne@1.x.x": - version "1.3.2" - resolved "https://registry.yarnpkg.com/@hapi/bourne/-/bourne-1.3.2.tgz#0a7095adea067243ce3283e1b56b8a8f453b242a" - integrity sha512-1dVNHT76Uu5N3eJNTYcvxee+jzX4Z9lfciqRRHCU27ihbUcYi+iSc2iml5Ke1LXe1SyJCLA0+14Jh4tXJgOppA== - -"@hapi/hoek@8.x.x", "@hapi/hoek@^8.3.0": - version "8.5.1" - resolved "https://registry.yarnpkg.com/@hapi/hoek/-/hoek-8.5.1.tgz#fde96064ca446dec8c55a8c2f130957b070c6e06" - integrity sha512-yN7kbciD87WzLGc5539Tn0sApjyiGHAJgKvG9W8C7O+6c7qmoQMfVs0W4bX17eqz6C78QJqqFrtgdK5EWf6Qow== - -"@hapi/joi@^15.0.1": - version "15.1.1" - resolved "https://registry.yarnpkg.com/@hapi/joi/-/joi-15.1.1.tgz#c675b8a71296f02833f8d6d243b34c57b8ce19d7" - integrity sha512-entf8ZMOK8sc+8YfeOlM8pCfg3b5+WZIKBfUaaJT8UsjAAPjartzxIYm3TIbjvA4u+u++KbcXD38k682nVHDAQ== - dependencies: - "@hapi/address" "2.x.x" - "@hapi/bourne" "1.x.x" - "@hapi/hoek" "8.x.x" - "@hapi/topo" "3.x.x" - -"@hapi/topo@3.x.x": - version "3.1.6" - resolved "https://registry.yarnpkg.com/@hapi/topo/-/topo-3.1.6.tgz#68d935fa3eae7fdd5ab0d7f953f3205d8b2bfc29" - integrity sha512-tAag0jEcjwH+P2quUfipd7liWCNX2F8NvYjQp2wtInsZxnMlypdw0FtAOLxtvvkO+GSRRbmNi8m/5y42PQJYCQ== - dependencies: - "@hapi/hoek" "^8.3.0" - -"@intervolga/optimize-cssnano-plugin@^1.0.5": - version "1.0.6" - resolved "https://registry.yarnpkg.com/@intervolga/optimize-cssnano-plugin/-/optimize-cssnano-plugin-1.0.6.tgz#be7c7846128b88f6a9b1d1261a0ad06eb5c0fdf8" - integrity sha512-zN69TnSr0viRSU6cEDIcuPcP67QcpQ6uHACg58FiN9PDrU6SLyGW3MR4tiISbYxy1kDWAVPwD+XwQTWE5cigAA== - dependencies: - cssnano "^4.0.0" - cssnano-preset-default "^4.0.0" - postcss "^7.0.0" - -"@mrmlnc/readdir-enhanced@^2.2.1": - version "2.2.1" - resolved "https://registry.yarnpkg.com/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz#524af240d1a360527b730475ecfa1344aa540dde" - integrity sha512-bPHp6Ji8b41szTOcaP63VlnbbO5Ny6dwAATtY6JTjh5N2OLrb5Qk/Th5cRkRQhkWCt+EJsYrNB0MiL+Gpn6e3g== - dependencies: - call-me-maybe "^1.0.1" - glob-to-regexp "^0.3.0" - -"@nodelib/fs.scandir@2.1.5": - version "2.1.5" - resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" - integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g== - dependencies: - "@nodelib/fs.stat" "2.0.5" - run-parallel "^1.1.9" - -"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2": - version "2.0.5" - resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b" - integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== - -"@nodelib/fs.stat@^1.1.2": - version "1.1.3" - resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-1.1.3.tgz#2b5a3ab3f918cca48a8c754c08168e3f03eba61b" - integrity sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw== - -"@nodelib/fs.walk@^1.2.3": - version "1.2.8" - resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a" - integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg== - dependencies: - "@nodelib/fs.scandir" "2.1.5" - fastq "^1.6.0" - -"@soda/friendly-errors-webpack-plugin@^1.7.1": - version "1.8.0" - resolved "https://registry.yarnpkg.com/@soda/friendly-errors-webpack-plugin/-/friendly-errors-webpack-plugin-1.8.0.tgz#84751d82a93019d5c92c0cf0e45ac59087cd2240" - integrity sha512-RLotfx6k1+nfLacwNCenj7VnTMPxVwYKoGOcffMFoJDKM8tXzBiCN0hMHFJNnoAojduYAsxuiMm0EOMixgiRow== - dependencies: - chalk "^2.4.2" - error-stack-parser "^2.0.2" - string-width "^2.0.0" - strip-ansi "^5" - -"@types/eslint-visitor-keys@^1.0.0": - version "1.0.0" - resolved "https://registry.yarnpkg.com/@types/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz#1ee30d79544ca84d68d4b3cdb0af4f205663dd2d" - integrity sha512-OCutwjDZ4aFS6PB1UZ988C4YgwlBHJd6wCeQqaLdmadZ/7e+w79+hbMUFC1QXDNCmdyoRfAFdm0RypzwR+Qpag== - -"@types/file-saver@^2.0.1": - version "2.0.3" - resolved "https://registry.yarnpkg.com/@types/file-saver/-/file-saver-2.0.3.tgz#b734c4f5a04d20615eaed3dc106e2ab321082009" - integrity sha512-MBIou8pd/41jkff7s97B47bc9+p0BszqqDJsO51yDm49uUxeKzrfuNl5fSLC6BpLEWKA8zlwyqALVmXrFwoBHQ== - -"@types/glob@^7.1.1": - version "7.2.0" - resolved "https://registry.yarnpkg.com/@types/glob/-/glob-7.2.0.tgz#bc1b5bf3aa92f25bd5dd39f35c57361bdce5b2eb" - integrity sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA== - dependencies: - "@types/minimatch" "*" - "@types/node" "*" - -"@types/highlight.js@^9.12.3": - version "9.12.4" - resolved "https://registry.yarnpkg.com/@types/highlight.js/-/highlight.js-9.12.4.tgz#8c3496bd1b50cc04aeefd691140aa571d4dbfa34" - integrity sha512-t2szdkwmg2JJyuCM20e8kR2X59WCE5Zkl4bzm1u1Oukjm79zpbiAv+QjnwLnuuV0WHEcX2NgUItu0pAMKuOPww== - -"@types/json-schema@^7.0.3", "@types/json-schema@^7.0.4", "@types/json-schema@^7.0.5", "@types/json-schema@^7.0.7": - version "7.0.9" - resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.9.tgz#97edc9037ea0c38585320b28964dde3b39e4660d" - integrity sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ== - -"@types/minimatch@*": - version "3.0.5" - resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.5.tgz#1001cc5e6a3704b83c236027e77f2f58ea010f40" - integrity sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ== - -"@types/node@*": - version "16.11.7" - resolved "https://registry.yarnpkg.com/@types/node/-/node-16.11.7.tgz#36820945061326978c42a01e56b61cd223dfdc42" - integrity sha512-QB5D2sqfSjCmTuWcBWyJ+/44bcjO7VbjSbOE0ucoVbAsSNQc4Lt6QkgkVXkTDwkL4z/beecZNDvVX15D4P8Jbw== - -"@types/normalize-package-data@^2.4.0": - version "2.4.1" - resolved "https://registry.yarnpkg.com/@types/normalize-package-data/-/normalize-package-data-2.4.1.tgz#d3357479a0fdfdd5907fe67e17e0a85c906e1301" - integrity sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw== - -"@types/parse-json@^4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.0.tgz#2f8bb441434d163b35fb8ffdccd7138927ffb8c0" - integrity sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA== - -"@types/q@^1.5.1": - version "1.5.5" - resolved "https://registry.yarnpkg.com/@types/q/-/q-1.5.5.tgz#75a2a8e7d8ab4b230414505d92335d1dcb53a6df" - integrity sha512-L28j2FcJfSZOnL1WBjDYp2vUHCeIFlyYI/53EwD/rKUBQ7MtUUfbQWiyKJGpcnv4/WgrhWsFKrcPstcAt/J0tQ== - -"@types/webpack-env@^1.15.2": - version "1.16.3" - resolved "https://registry.yarnpkg.com/@types/webpack-env/-/webpack-env-1.16.3.tgz#b776327a73e561b71e7881d0cd6d34a1424db86a" - integrity sha512-9gtOPPkfyNoEqCQgx4qJKkuNm/x0R2hKR7fdl7zvTJyHnIisuE/LfvXOsYWL0o3qq6uiBnKZNNNzi3l0y/X+xw== - -"@typescript-eslint/eslint-plugin@^1.1.0": - version "1.13.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-1.13.0.tgz#22fed9b16ddfeb402fd7bcde56307820f6ebc49f" - integrity sha512-WQHCozMnuNADiqMtsNzp96FNox5sOVpU8Xt4meaT4em8lOG1SrOv92/mUbEHQVh90sldKSfcOc/I0FOb/14G1g== - dependencies: - "@typescript-eslint/experimental-utils" "1.13.0" - eslint-utils "^1.3.1" - functional-red-black-tree "^1.0.1" - regexpp "^2.0.1" - tsutils "^3.7.0" - -"@typescript-eslint/eslint-plugin@^4.13.0": - version "4.33.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.33.0.tgz#c24dc7c8069c7706bc40d99f6fa87edcb2005276" - integrity sha512-aINiAxGVdOl1eJyVjaWn/YcVAq4Gi/Yo35qHGCnqbWVz61g39D0h23veY/MA0rFFGfxK7TySg2uwDeNv+JgVpg== - dependencies: - "@typescript-eslint/experimental-utils" "4.33.0" - "@typescript-eslint/scope-manager" "4.33.0" - debug "^4.3.1" - functional-red-black-tree "^1.0.1" - ignore "^5.1.8" - regexpp "^3.1.0" - semver "^7.3.5" - tsutils "^3.21.0" - -"@typescript-eslint/experimental-utils@1.13.0": - version "1.13.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-1.13.0.tgz#b08c60d780c0067de2fb44b04b432f540138301e" - integrity sha512-zmpS6SyqG4ZF64ffaJ6uah6tWWWgZ8m+c54XXgwFtUv0jNz8aJAVx8chMCvnk7yl6xwn8d+d96+tWp7fXzTuDg== - dependencies: - "@types/json-schema" "^7.0.3" - "@typescript-eslint/typescript-estree" "1.13.0" - eslint-scope "^4.0.0" - -"@typescript-eslint/experimental-utils@4.33.0": - version "4.33.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-4.33.0.tgz#6f2a786a4209fa2222989e9380b5331b2810f7fd" - integrity sha512-zeQjOoES5JFjTnAhI5QY7ZviczMzDptls15GFsI6jyUOq0kOf9+WonkhtlIhh0RgHRnqj5gdNxW5j1EvAyYg6Q== - dependencies: - "@types/json-schema" "^7.0.7" - "@typescript-eslint/scope-manager" "4.33.0" - "@typescript-eslint/types" "4.33.0" - "@typescript-eslint/typescript-estree" "4.33.0" - eslint-scope "^5.1.1" - eslint-utils "^3.0.0" - -"@typescript-eslint/parser@^1.1.0": - version "1.13.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-1.13.0.tgz#61ac7811ea52791c47dc9fd4dd4a184fae9ac355" - integrity sha512-ITMBs52PCPgLb2nGPoeT4iU3HdQZHcPaZVw+7CsFagRJHUhyeTgorEwHXhFf3e7Evzi8oujKNpHc8TONth8AdQ== - dependencies: - "@types/eslint-visitor-keys" "^1.0.0" - "@typescript-eslint/experimental-utils" "1.13.0" - "@typescript-eslint/typescript-estree" "1.13.0" - eslint-visitor-keys "^1.0.0" - -"@typescript-eslint/parser@^4.13.0": - version "4.33.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-4.33.0.tgz#dfe797570d9694e560528d18eecad86c8c744899" - integrity sha512-ZohdsbXadjGBSK0/r+d87X0SBmKzOq4/S5nzK6SBgJspFo9/CUDJ7hjayuze+JK7CZQLDMroqytp7pOcFKTxZA== - dependencies: - "@typescript-eslint/scope-manager" "4.33.0" - "@typescript-eslint/types" "4.33.0" - "@typescript-eslint/typescript-estree" "4.33.0" - debug "^4.3.1" - -"@typescript-eslint/scope-manager@4.33.0": - version "4.33.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-4.33.0.tgz#d38e49280d983e8772e29121cf8c6e9221f280a3" - integrity sha512-5IfJHpgTsTZuONKbODctL4kKuQje/bzBRkwHE8UOZ4f89Zeddg+EGZs8PD8NcN4LdM3ygHWYB3ukPAYjvl/qbQ== - dependencies: - "@typescript-eslint/types" "4.33.0" - "@typescript-eslint/visitor-keys" "4.33.0" - -"@typescript-eslint/types@4.33.0": - version "4.33.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.33.0.tgz#a1e59036a3b53ae8430ceebf2a919dc7f9af6d72" - integrity sha512-zKp7CjQzLQImXEpLt2BUw1tvOMPfNoTAfb8l51evhYbOEEzdWyQNmHWWGPR6hwKJDAi+1VXSBmnhL9kyVTTOuQ== - -"@typescript-eslint/typescript-estree@1.13.0": - version "1.13.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-1.13.0.tgz#8140f17d0f60c03619798f1d628b8434913dc32e" - integrity sha512-b5rCmd2e6DCC6tCTN9GSUAuxdYwCM/k/2wdjHGrIRGPSJotWMCe/dGpi66u42bhuh8q3QBzqM4TMA1GUUCJvdw== - dependencies: - lodash.unescape "4.0.1" - semver "5.5.0" - -"@typescript-eslint/typescript-estree@4.33.0": - version "4.33.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-4.33.0.tgz#0dfb51c2908f68c5c08d82aefeaf166a17c24609" - integrity sha512-rkWRY1MPFzjwnEVHsxGemDzqqddw2QbTJlICPD9p9I9LfsO8fdmfQPOX3uKfUaGRDFJbfrtm/sXhVXN4E+bzCA== - dependencies: - "@typescript-eslint/types" "4.33.0" - "@typescript-eslint/visitor-keys" "4.33.0" - debug "^4.3.1" - globby "^11.0.3" - is-glob "^4.0.1" - semver "^7.3.5" - tsutils "^3.21.0" - -"@typescript-eslint/visitor-keys@4.33.0": - version "4.33.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-4.33.0.tgz#2a22f77a41604289b7a186586e9ec48ca92ef1dd" - integrity sha512-uqi/2aSz9g2ftcHWf8uLPJA70rUv6yuMW5Bohw+bwcuzaxQIHaKFZCKGoGXIrc9vkTJ3+0txM73K0Hq3d5wgIg== - dependencies: - "@typescript-eslint/types" "4.33.0" - eslint-visitor-keys "^2.0.0" - -"@vue/cli-overlay@^3.12.1": - version "3.12.1" - resolved "https://registry.yarnpkg.com/@vue/cli-overlay/-/cli-overlay-3.12.1.tgz#bdfde8f7123561ab06e4e4c60b854cc5092f5ab1" - integrity sha512-Bym92EN+lj+cNRN2ozbYyH+V8DMXWGbCDUk+hiJ4EYDBZfBkZKvalk1/mOBFwyxiopnnbOEBAAhL/UuMQ1xARg== - -"@vue/cli-plugin-eslint@^3.11.0": - version "3.12.1" - resolved "https://registry.yarnpkg.com/@vue/cli-plugin-eslint/-/cli-plugin-eslint-3.12.1.tgz#302c463867f38e790bb996eafdf7159c782dc8cf" - integrity sha512-tVTZlEZsy3sQbO4LLWFK11yzlWwqVAqaM+IY+BeWHITBzEJKh2KmouG+x6x/reXiU3qROsMJ4Ej3Hs8buSMWyQ== - dependencies: - "@vue/cli-shared-utils" "^3.12.1" - babel-eslint "^10.0.1" - eslint-loader "^2.1.2" - globby "^9.2.0" - webpack "^4.0.0" - yorkie "^2.0.0" - optionalDependencies: - eslint "^4.19.1" - eslint-plugin-vue "^4.7.1" - -"@vue/cli-plugin-typescript@^4.5.10": - version "4.5.15" - resolved "https://registry.yarnpkg.com/@vue/cli-plugin-typescript/-/cli-plugin-typescript-4.5.15.tgz#14ba0ddcf3b94e73148ff84ac904fbc5346c14d1" - integrity sha512-g2HDBwWBboTzNvVrS+w4Ctl7CCErboTlx7PyQrXgY+7uGdPVUT9PWuv4DjaZhosSk7WI3qSIpruCBIkdHX5bwQ== - dependencies: - "@types/webpack-env" "^1.15.2" - "@vue/cli-shared-utils" "^4.5.15" - cache-loader "^4.1.0" - fork-ts-checker-webpack-plugin "^3.1.1" - globby "^9.2.0" - thread-loader "^2.1.3" - ts-loader "^6.2.2" - tslint "^5.20.1" - webpack "^4.0.0" - yorkie "^2.0.0" - optionalDependencies: - fork-ts-checker-webpack-plugin-v5 "npm:fork-ts-checker-webpack-plugin@^5.0.11" - -"@vue/cli-service@^3.11.0": - version "3.12.1" - resolved "https://registry.yarnpkg.com/@vue/cli-service/-/cli-service-3.12.1.tgz#13220b1c189254e7c003390df329086f9b6e77e6" - integrity sha512-PDxNrTGnSKzeV1ruFlsRIAO8JcPizwT0EJXq9GeyooU+p+sOkv7aKkCBJQVYNjZapD1NOGWx6CvAAC/wAW+gew== - dependencies: - "@intervolga/optimize-cssnano-plugin" "^1.0.5" - "@soda/friendly-errors-webpack-plugin" "^1.7.1" - "@vue/cli-overlay" "^3.12.1" - "@vue/cli-shared-utils" "^3.12.1" - "@vue/component-compiler-utils" "^3.0.0" - "@vue/preload-webpack-plugin" "^1.1.0" - "@vue/web-component-wrapper" "^1.2.0" - acorn "^6.1.1" - acorn-walk "^6.1.1" - address "^1.0.3" - autoprefixer "^9.5.1" - browserslist "^4.5.4" - cache-loader "^2.0.1" - case-sensitive-paths-webpack-plugin "^2.2.0" - chalk "^2.4.2" - cli-highlight "^2.1.0" - clipboardy "^2.0.0" - cliui "^5.0.0" - copy-webpack-plugin "^4.6.0" - css-loader "^1.0.1" - cssnano "^4.1.10" - current-script-polyfill "^1.0.0" - debug "^4.1.1" - default-gateway "^5.0.2" - dotenv "^7.0.0" - dotenv-expand "^5.1.0" - escape-string-regexp "^1.0.5" - file-loader "^3.0.1" - fs-extra "^7.0.1" - globby "^9.2.0" - hash-sum "^1.0.2" - html-webpack-plugin "^3.2.0" - launch-editor-middleware "^2.2.1" - lodash.defaultsdeep "^4.6.1" - lodash.mapvalues "^4.6.0" - lodash.transform "^4.6.0" - mini-css-extract-plugin "^0.8.0" - minimist "^1.2.0" - ora "^3.4.0" - portfinder "^1.0.20" - postcss-loader "^3.0.0" - read-pkg "^5.0.0" - semver "^6.0.0" - slash "^2.0.0" - source-map-url "^0.4.0" - ssri "^6.0.1" - string.prototype.padend "^3.0.0" - terser-webpack-plugin "^1.2.3" - thread-loader "^2.1.2" - url-loader "^1.1.2" - vue-loader "^15.7.0" - webpack "^4.0.0" - webpack-bundle-analyzer "^3.3.0" - webpack-chain "^4.11.0" - webpack-dev-server "^3.4.1" - webpack-merge "^4.2.1" - -"@vue/cli-shared-utils@^3.12.1": - version "3.12.1" - resolved "https://registry.yarnpkg.com/@vue/cli-shared-utils/-/cli-shared-utils-3.12.1.tgz#bcf076287ddadeebbb97c6a748dfe9ff50ec8df0" - integrity sha512-jFblzRFjutGwu5utOKdVlPlsbA1lBUNNQlAThzNqej+JtTKJjnvjlhjKX0Gq0oOny5FjKWhoyfQ74p9h1qE6JQ== - dependencies: - "@hapi/joi" "^15.0.1" - chalk "^2.4.1" - execa "^1.0.0" - launch-editor "^2.2.1" - lru-cache "^5.1.1" - node-ipc "^9.1.1" - open "^6.3.0" - ora "^3.4.0" - request "^2.87.0" - request-promise-native "^1.0.7" - semver "^6.0.0" - string.prototype.padstart "^3.0.0" - -"@vue/cli-shared-utils@^4.5.15": - version "4.5.15" - resolved "https://registry.yarnpkg.com/@vue/cli-shared-utils/-/cli-shared-utils-4.5.15.tgz#dba3858165dbe3465755f256a4890e69084532d6" - integrity sha512-SKaej9hHzzjKSOw1NlFmc6BSE0vcqUQMQiv1cxQ2DhVyy4QxZXBmzmiLBUBe+hYZZs1neXW7n//udeN9bCAY+Q== - dependencies: - "@hapi/joi" "^15.0.1" - chalk "^2.4.2" - execa "^1.0.0" - launch-editor "^2.2.1" - lru-cache "^5.1.1" - node-ipc "^9.1.1" - open "^6.3.0" - ora "^3.4.0" - read-pkg "^5.1.1" - request "^2.88.2" - semver "^6.1.0" - strip-ansi "^6.0.0" - -"@vue/component-compiler-utils@^3.0.0", "@vue/component-compiler-utils@^3.1.0": - version "3.3.0" - resolved "https://registry.yarnpkg.com/@vue/component-compiler-utils/-/component-compiler-utils-3.3.0.tgz#f9f5fb53464b0c37b2c8d2f3fbfe44df60f61dc9" - integrity sha512-97sfH2mYNU+2PzGrmK2haqffDpVASuib9/w2/noxiFi31Z54hW+q3izKQXXQZSNhtiUpAI36uSuYepeBe4wpHQ== - dependencies: - consolidate "^0.15.1" - hash-sum "^1.0.2" - lru-cache "^4.1.2" - merge-source-map "^1.1.0" - postcss "^7.0.36" - postcss-selector-parser "^6.0.2" - source-map "~0.6.1" - vue-template-es2015-compiler "^1.9.0" - optionalDependencies: - prettier "^1.18.2 || ^2.0.0" - -"@vue/eslint-config-typescript@^4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@vue/eslint-config-typescript/-/eslint-config-typescript-4.0.0.tgz#a202983598a4a826460cbb8ee43826875b0f6673" - integrity sha512-uSMAMgw4xDgVdZQhpbtJRo8nMV4oOy3Ht8olfOo7xvYFYLMF2JZ1tDRKd9/NSusxA72O2Vma+HzmyzDHg9evcQ== - dependencies: - "@typescript-eslint/eslint-plugin" "^1.1.0" - "@typescript-eslint/parser" "^1.1.0" - -"@vue/preload-webpack-plugin@^1.1.0": - version "1.1.2" - resolved "https://registry.yarnpkg.com/@vue/preload-webpack-plugin/-/preload-webpack-plugin-1.1.2.tgz#ceb924b4ecb3b9c43871c7a429a02f8423e621ab" - integrity sha512-LIZMuJk38pk9U9Ur4YzHjlIyMuxPlACdBIHH9/nGYVTsaGKOSnSuELiE8vS9wa+dJpIYspYUOqk+L1Q4pgHQHQ== - -"@vue/web-component-wrapper@^1.2.0": - version "1.3.0" - resolved "https://registry.yarnpkg.com/@vue/web-component-wrapper/-/web-component-wrapper-1.3.0.tgz#b6b40a7625429d2bd7c2281ddba601ed05dc7f1a" - integrity sha512-Iu8Tbg3f+emIIMmI2ycSI8QcEuAUgPTgHwesDU1eKMLE4YC/c/sFbGc70QgMq31ijRftV0R7vCm9co6rldCeOA== - -"@webassemblyjs/ast@1.9.0": - version "1.9.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.9.0.tgz#bd850604b4042459a5a41cd7d338cbed695ed964" - integrity sha512-C6wW5L+b7ogSDVqymbkkvuW9kruN//YisMED04xzeBBqjHa2FYnmvOlS6Xj68xWQRgWvI9cIglsjFowH/RJyEA== - dependencies: - "@webassemblyjs/helper-module-context" "1.9.0" - "@webassemblyjs/helper-wasm-bytecode" "1.9.0" - "@webassemblyjs/wast-parser" "1.9.0" - -"@webassemblyjs/floating-point-hex-parser@1.9.0": - version "1.9.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.9.0.tgz#3c3d3b271bddfc84deb00f71344438311d52ffb4" - integrity sha512-TG5qcFsS8QB4g4MhrxK5TqfdNe7Ey/7YL/xN+36rRjl/BlGE/NcBvJcqsRgCP6Z92mRE+7N50pRIi8SmKUbcQA== - -"@webassemblyjs/helper-api-error@1.9.0": - version "1.9.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-api-error/-/helper-api-error-1.9.0.tgz#203f676e333b96c9da2eeab3ccef33c45928b6a2" - integrity sha512-NcMLjoFMXpsASZFxJ5h2HZRcEhDkvnNFOAKneP5RbKRzaWJN36NC4jqQHKwStIhGXu5mUWlUUk7ygdtrO8lbmw== - -"@webassemblyjs/helper-buffer@1.9.0": - version "1.9.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-buffer/-/helper-buffer-1.9.0.tgz#a1442d269c5feb23fcbc9ef759dac3547f29de00" - integrity sha512-qZol43oqhq6yBPx7YM3m9Bv7WMV9Eevj6kMi6InKOuZxhw+q9hOkvq5e/PpKSiLfyetpaBnogSbNCfBwyB00CA== - -"@webassemblyjs/helper-code-frame@1.9.0": - version "1.9.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-code-frame/-/helper-code-frame-1.9.0.tgz#647f8892cd2043a82ac0c8c5e75c36f1d9159f27" - integrity sha512-ERCYdJBkD9Vu4vtjUYe8LZruWuNIToYq/ME22igL+2vj2dQ2OOujIZr3MEFvfEaqKoVqpsFKAGsRdBSBjrIvZA== - dependencies: - "@webassemblyjs/wast-printer" "1.9.0" - -"@webassemblyjs/helper-fsm@1.9.0": - version "1.9.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-fsm/-/helper-fsm-1.9.0.tgz#c05256b71244214671f4b08ec108ad63b70eddb8" - integrity sha512-OPRowhGbshCb5PxJ8LocpdX9Kl0uB4XsAjl6jH/dWKlk/mzsANvhwbiULsaiqT5GZGT9qinTICdj6PLuM5gslw== - -"@webassemblyjs/helper-module-context@1.9.0": - version "1.9.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-module-context/-/helper-module-context-1.9.0.tgz#25d8884b76839871a08a6c6f806c3979ef712f07" - integrity sha512-MJCW8iGC08tMk2enck1aPW+BE5Cw8/7ph/VGZxwyvGbJwjktKkDK7vy7gAmMDx88D7mhDTCNKAW5tED+gZ0W8g== - dependencies: - "@webassemblyjs/ast" "1.9.0" - -"@webassemblyjs/helper-wasm-bytecode@1.9.0": - version "1.9.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.9.0.tgz#4fed8beac9b8c14f8c58b70d124d549dd1fe5790" - integrity sha512-R7FStIzyNcd7xKxCZH5lE0Bqy+hGTwS3LJjuv1ZVxd9O7eHCedSdrId/hMOd20I+v8wDXEn+bjfKDLzTepoaUw== - -"@webassemblyjs/helper-wasm-section@1.9.0": - version "1.9.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.9.0.tgz#5a4138d5a6292ba18b04c5ae49717e4167965346" - integrity sha512-XnMB8l3ek4tvrKUUku+IVaXNHz2YsJyOOmz+MMkZvh8h1uSJpSen6vYnw3IoQ7WwEuAhL8Efjms1ZWjqh2agvw== - dependencies: - "@webassemblyjs/ast" "1.9.0" - "@webassemblyjs/helper-buffer" "1.9.0" - "@webassemblyjs/helper-wasm-bytecode" "1.9.0" - "@webassemblyjs/wasm-gen" "1.9.0" - -"@webassemblyjs/ieee754@1.9.0": - version "1.9.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/ieee754/-/ieee754-1.9.0.tgz#15c7a0fbaae83fb26143bbacf6d6df1702ad39e4" - integrity sha512-dcX8JuYU/gvymzIHc9DgxTzUUTLexWwt8uCTWP3otys596io0L5aW02Gb1RjYpx2+0Jus1h4ZFqjla7umFniTg== - dependencies: - "@xtuc/ieee754" "^1.2.0" - -"@webassemblyjs/leb128@1.9.0": - version "1.9.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/leb128/-/leb128-1.9.0.tgz#f19ca0b76a6dc55623a09cffa769e838fa1e1c95" - integrity sha512-ENVzM5VwV1ojs9jam6vPys97B/S65YQtv/aanqnU7D8aSoHFX8GyhGg0CMfyKNIHBuAVjy3tlzd5QMMINa7wpw== - dependencies: - "@xtuc/long" "4.2.2" - -"@webassemblyjs/utf8@1.9.0": - version "1.9.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/utf8/-/utf8-1.9.0.tgz#04d33b636f78e6a6813227e82402f7637b6229ab" - integrity sha512-GZbQlWtopBTP0u7cHrEx+73yZKrQoBMpwkGEIqlacljhXCkVM1kMQge/Mf+csMJAjEdSwhOyLAS0AoR3AG5P8w== - -"@webassemblyjs/wasm-edit@1.9.0": - version "1.9.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-edit/-/wasm-edit-1.9.0.tgz#3fe6d79d3f0f922183aa86002c42dd256cfee9cf" - integrity sha512-FgHzBm80uwz5M8WKnMTn6j/sVbqilPdQXTWraSjBwFXSYGirpkSWE2R9Qvz9tNiTKQvoKILpCuTjBKzOIm0nxw== - dependencies: - "@webassemblyjs/ast" "1.9.0" - "@webassemblyjs/helper-buffer" "1.9.0" - "@webassemblyjs/helper-wasm-bytecode" "1.9.0" - "@webassemblyjs/helper-wasm-section" "1.9.0" - "@webassemblyjs/wasm-gen" "1.9.0" - "@webassemblyjs/wasm-opt" "1.9.0" - "@webassemblyjs/wasm-parser" "1.9.0" - "@webassemblyjs/wast-printer" "1.9.0" - -"@webassemblyjs/wasm-gen@1.9.0": - version "1.9.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-gen/-/wasm-gen-1.9.0.tgz#50bc70ec68ded8e2763b01a1418bf43491a7a49c" - integrity sha512-cPE3o44YzOOHvlsb4+E9qSqjc9Qf9Na1OO/BHFy4OI91XDE14MjFN4lTMezzaIWdPqHnsTodGGNP+iRSYfGkjA== - dependencies: - "@webassemblyjs/ast" "1.9.0" - "@webassemblyjs/helper-wasm-bytecode" "1.9.0" - "@webassemblyjs/ieee754" "1.9.0" - "@webassemblyjs/leb128" "1.9.0" - "@webassemblyjs/utf8" "1.9.0" - -"@webassemblyjs/wasm-opt@1.9.0": - version "1.9.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-opt/-/wasm-opt-1.9.0.tgz#2211181e5b31326443cc8112eb9f0b9028721a61" - integrity sha512-Qkjgm6Anhm+OMbIL0iokO7meajkzQD71ioelnfPEj6r4eOFuqm4YC3VBPqXjFyyNwowzbMD+hizmprP/Fwkl2A== - dependencies: - "@webassemblyjs/ast" "1.9.0" - "@webassemblyjs/helper-buffer" "1.9.0" - "@webassemblyjs/wasm-gen" "1.9.0" - "@webassemblyjs/wasm-parser" "1.9.0" - -"@webassemblyjs/wasm-parser@1.9.0": - version "1.9.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-parser/-/wasm-parser-1.9.0.tgz#9d48e44826df4a6598294aa6c87469d642fff65e" - integrity sha512-9+wkMowR2AmdSWQzsPEjFU7njh8HTO5MqO8vjwEHuM+AMHioNqSBONRdr0NQQ3dVQrzp0s8lTcYqzUdb7YgELA== - dependencies: - "@webassemblyjs/ast" "1.9.0" - "@webassemblyjs/helper-api-error" "1.9.0" - "@webassemblyjs/helper-wasm-bytecode" "1.9.0" - "@webassemblyjs/ieee754" "1.9.0" - "@webassemblyjs/leb128" "1.9.0" - "@webassemblyjs/utf8" "1.9.0" - -"@webassemblyjs/wast-parser@1.9.0": - version "1.9.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-parser/-/wast-parser-1.9.0.tgz#3031115d79ac5bd261556cecc3fa90a3ef451914" - integrity sha512-qsqSAP3QQ3LyZjNC/0jBJ/ToSxfYJ8kYyuiGvtn/8MK89VrNEfwj7BPQzJVHi0jGTRK2dGdJ5PRqhtjzoww+bw== - dependencies: - "@webassemblyjs/ast" "1.9.0" - "@webassemblyjs/floating-point-hex-parser" "1.9.0" - "@webassemblyjs/helper-api-error" "1.9.0" - "@webassemblyjs/helper-code-frame" "1.9.0" - "@webassemblyjs/helper-fsm" "1.9.0" - "@xtuc/long" "4.2.2" - -"@webassemblyjs/wast-printer@1.9.0": - version "1.9.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-printer/-/wast-printer-1.9.0.tgz#4935d54c85fef637b00ce9f52377451d00d47899" - integrity sha512-2J0nE95rHXHyQ24cWjMKJ1tqB/ds8z/cyeOZxJhcb+rW+SQASVjuznUSmdz5GpVJTzU8JkhYut0D3siFDD6wsA== - dependencies: - "@webassemblyjs/ast" "1.9.0" - "@webassemblyjs/wast-parser" "1.9.0" - "@xtuc/long" "4.2.2" - -"@xtuc/ieee754@^1.2.0": - version "1.2.0" - resolved "https://registry.yarnpkg.com/@xtuc/ieee754/-/ieee754-1.2.0.tgz#eef014a3145ae477a1cbc00cd1e552336dceb790" - integrity sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA== - -"@xtuc/long@4.2.2": - version "4.2.2" - resolved "https://registry.yarnpkg.com/@xtuc/long/-/long-4.2.2.tgz#d291c6a4e97989b5c61d9acf396ae4fe133a718d" - integrity sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ== - -accepts@~1.3.4, accepts@~1.3.5, accepts@~1.3.7: - version "1.3.7" - resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.7.tgz#531bc726517a3b2b41f850021c6cc15eaab507cd" - integrity sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA== - dependencies: - mime-types "~2.1.24" - negotiator "0.6.2" - -acorn-jsx@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-3.0.1.tgz#afdf9488fb1ecefc8348f6fb22f464e32a58b36b" - integrity sha1-r9+UiPsezvyDSPb7IvRk4ypYs2s= - dependencies: - acorn "^3.0.4" - -acorn-jsx@^5.0.0: - version "5.3.2" - resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" - integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== - -acorn-walk@^6.1.1: - version "6.2.0" - resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-6.2.0.tgz#123cb8f3b84c2171f1f7fb252615b1c78a6b1a8c" - integrity sha512-7evsyfH1cLOCdAzZAd43Cic04yKydNx0cF+7tiA19p1XnLLPU4dpCQOqpjqwokFe//vS0QqfqqjCS2JkiIs0cA== - -acorn-walk@^7.1.1: - version "7.2.0" - resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-7.2.0.tgz#0de889a601203909b0fbe07b8938dc21d2e967bc" - integrity sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA== - -acorn@^3.0.4: - version "3.3.0" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-3.3.0.tgz#45e37fb39e8da3f25baee3ff5369e2bb5f22017a" - integrity sha1-ReN/s56No/JbruP/U2niu18iAXo= - -acorn@^5.5.0: - version "5.7.4" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.7.4.tgz#3e8d8a9947d0599a1796d10225d7432f4a4acf5e" - integrity sha512-1D++VG7BhrtvQpNbBzovKNc1FLGGEE/oGe7b9xJm/RFHMBeUaUGpluV9RLjZa47YFdPcDAenEYuq9pQPcMdLJg== - -acorn@^6.0.2, acorn@^6.0.7, acorn@^6.1.1, acorn@^6.4.1: - version "6.4.2" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.4.2.tgz#35866fd710528e92de10cf06016498e47e39e1e6" - integrity sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ== - -acorn@^7.1.1: - version "7.4.1" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa" - integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A== - -address@^1.0.3: - version "1.1.2" - resolved "https://registry.yarnpkg.com/address/-/address-1.1.2.tgz#bf1116c9c758c51b7a933d296b72c221ed9428b6" - integrity sha512-aT6camzM4xEA54YVJYSqxz1kv4IHnQZRtThJJHhUMRExaU5spC7jX5ugSwTaTgJliIgs4VhZOk7htClvQ/LmRA== - -ajv-errors@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/ajv-errors/-/ajv-errors-1.0.1.tgz#f35986aceb91afadec4102fbd85014950cefa64d" - integrity sha512-DCRfO/4nQ+89p/RK43i8Ezd41EqdGIU4ld7nGF8OQ14oc/we5rEntLCUa7+jrn3nn83BosfwZA0wb4pon2o8iQ== - -ajv-keywords@^2.1.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-2.1.1.tgz#617997fc5f60576894c435f940d819e135b80762" - integrity sha1-YXmX/F9gV2iUxDX5QNgZ4TW4B2I= - -ajv-keywords@^3.1.0, ajv-keywords@^3.4.1, ajv-keywords@^3.5.2: - version "3.5.2" - resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.5.2.tgz#31f29da5ab6e00d1c2d329acf7b5929614d5014d" - integrity sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ== - -ajv@^5.2.3, ajv@^5.3.0: - version "5.5.2" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-5.5.2.tgz#73b5eeca3fab653e3d3f9422b341ad42205dc965" - integrity sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU= - dependencies: - co "^4.6.0" - fast-deep-equal "^1.0.0" - fast-json-stable-stringify "^2.0.0" - json-schema-traverse "^0.3.0" - -ajv@^6.1.0, ajv@^6.10.2, ajv@^6.12.2, ajv@^6.12.3, ajv@^6.12.4, ajv@^6.9.1: - version "6.12.6" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" - integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== - dependencies: - fast-deep-equal "^3.1.1" - fast-json-stable-stringify "^2.0.0" - json-schema-traverse "^0.4.1" - uri-js "^4.2.2" - -alphanum-sort@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/alphanum-sort/-/alphanum-sort-1.0.2.tgz#97a1119649b211ad33691d9f9f486a8ec9fbe0a3" - integrity sha1-l6ERlkmyEa0zaR2fn0hqjsn74KM= - -ansi-colors@^3.0.0: - version "3.2.4" - resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-3.2.4.tgz#e3a3da4bfbae6c86a9c285625de124a234026fbf" - integrity sha512-hHUXGagefjN2iRrID63xckIvotOXOojhQKWIPUZ4mNUZ9nLZW+7FMNoE1lOkEhNWYsx/7ysGIuJYCiMAA9FnrA== - -ansi-escapes@^3.0.0, ansi-escapes@^3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-3.2.0.tgz#8780b98ff9dbf5638152d1f1fe5c1d7b4442976b" - integrity sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ== - -ansi-html-community@0.0.8: - version "0.0.8" - resolved "https://registry.yarnpkg.com/ansi-html-community/-/ansi-html-community-0.0.8.tgz#69fbc4d6ccbe383f9736934ae34c3f8290f1bf41" - integrity sha512-1APHAyr3+PCamwNw3bXCPp4HFLONZt/yIH0sZp0/469KWNTEy+qN5jQ3GVX6DMZ1UXAi34yVwtTeaG/HpBuuzw== - -ansi-regex@^2.0.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" - integrity sha1-w7M6te42DYbg5ijwRorn7yfWVN8= - -ansi-regex@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" - integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg= - -ansi-regex@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997" - integrity sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg== - -ansi-regex@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" - integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== - -ansi-styles@^2.2.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" - integrity sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4= - -ansi-styles@^3.2.0, ansi-styles@^3.2.1: - version "3.2.1" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" - integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== - dependencies: - color-convert "^1.9.0" - -ansi-styles@^4.0.0, ansi-styles@^4.1.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" - integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== - dependencies: - color-convert "^2.0.1" - -any-promise@^1.0.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/any-promise/-/any-promise-1.3.0.tgz#abc6afeedcea52e809cdc0376aed3ce39635d17f" - integrity sha1-q8av7tzqUugJzcA3au0845Y10X8= - -anymatch@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-2.0.0.tgz#bcb24b4f37934d9aa7ac17b4adaf89e7c76ef2eb" - integrity sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw== - dependencies: - micromatch "^3.1.4" - normalize-path "^2.1.1" - -anymatch@~3.1.2: - version "3.1.2" - resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.2.tgz#c0557c096af32f106198f4f4e2a383537e378716" - integrity sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg== - dependencies: - normalize-path "^3.0.0" - picomatch "^2.0.4" - -aproba@^1.1.1: - version "1.2.0" - resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" - integrity sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw== - -arch@^2.1.1: - version "2.2.0" - resolved "https://registry.yarnpkg.com/arch/-/arch-2.2.0.tgz#1bc47818f305764f23ab3306b0bfc086c5a29d11" - integrity sha512-Of/R0wqp83cgHozfIYLbBMnej79U/SVGOOyuB3VVFv1NRM/PSFMK12x9KVtiYzJqmnU5WR2qp0Z5rHb7sWGnFQ== - -argparse@^1.0.7: - version "1.0.10" - resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" - integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== - dependencies: - sprintf-js "~1.0.2" - -arr-diff@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520" - integrity sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA= - -arr-flatten@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1" - integrity sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg== - -arr-union@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4" - integrity sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ= - -array-flatten@1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" - integrity sha1-ml9pkFGx5wczKPKgCJaLZOopVdI= - -array-flatten@^2.1.0: - version "2.1.2" - resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-2.1.2.tgz#24ef80a28c1a893617e2149b0c6d0d788293b099" - integrity sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ== - -array-union@^1.0.1, array-union@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39" - integrity sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk= - dependencies: - array-uniq "^1.0.1" - -array-union@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" - integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== - -array-uniq@^1.0.1: - version "1.0.3" - resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6" - integrity sha1-r2rId6Jcx/dOBYiUdThY39sk/bY= - -array-unique@^0.3.2: - version "0.3.2" - resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428" - integrity sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg= - -asn1.js@^5.2.0: - version "5.4.1" - resolved "https://registry.yarnpkg.com/asn1.js/-/asn1.js-5.4.1.tgz#11a980b84ebb91781ce35b0fdc2ee294e3783f07" - integrity sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA== - dependencies: - bn.js "^4.0.0" - inherits "^2.0.1" - minimalistic-assert "^1.0.0" - safer-buffer "^2.1.0" - -asn1@~0.2.3: - version "0.2.6" - resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.6.tgz#0d3a7bb6e64e02a90c0303b31f292868ea09a08d" - integrity sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ== - dependencies: - safer-buffer "~2.1.0" - -assert-plus@1.0.0, assert-plus@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" - integrity sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU= - -assert@^1.1.1: - version "1.5.0" - resolved "https://registry.yarnpkg.com/assert/-/assert-1.5.0.tgz#55c109aaf6e0aefdb3dc4b71240c70bf574b18eb" - integrity sha512-EDsgawzwoun2CZkCgtxJbv392v4nbk9XDD06zI+kQYoBM/3RBWLlEyJARDOmhAAosBjWACEkKL6S+lIZtcAubA== - dependencies: - object-assign "^4.1.1" - util "0.10.3" - -assign-symbols@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367" - integrity sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c= - -astral-regex@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-1.0.0.tgz#6c8c3fb827dd43ee3918f27b82782ab7658a6fd9" - integrity sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg== - -async-each@^1.0.1: - version "1.0.3" - resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.3.tgz#b727dbf87d7651602f06f4d4ac387f47d91b0cbf" - integrity sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ== - -async-limiter@~1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.1.tgz#dd379e94f0db8310b08291f9d64c3209766617fd" - integrity sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ== - -async@^2.6.2: - version "2.6.3" - resolved "https://registry.yarnpkg.com/async/-/async-2.6.3.tgz#d72625e2344a3656e3a3ad4fa749fa83299d82ff" - integrity sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg== - dependencies: - lodash "^4.17.14" - -asynckit@^0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" - integrity sha1-x57Zf380y48robyXkLzDZkdLS3k= - -at-least-node@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/at-least-node/-/at-least-node-1.0.0.tgz#602cd4b46e844ad4effc92a8011a3c46e0238dc2" - integrity sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg== - -atob@^2.1.2: - version "2.1.2" - resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9" - integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg== - -autoprefixer@^9.5.1: - version "9.8.8" - resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-9.8.8.tgz#fd4bd4595385fa6f06599de749a4d5f7a474957a" - integrity sha512-eM9d/swFopRt5gdJ7jrpCwgvEMIayITpojhkkSMRsFHYuH5bkSQ4p/9qTEHtmNudUZh22Tehu7I6CxAW0IXTKA== - dependencies: - browserslist "^4.12.0" - caniuse-lite "^1.0.30001109" - normalize-range "^0.1.2" - num2fraction "^1.2.2" - picocolors "^0.2.1" - postcss "^7.0.32" - postcss-value-parser "^4.1.0" - -aws-sign2@~0.7.0: - version "0.7.0" - resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8" - integrity sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg= - -aws4@^1.8.0: - version "1.11.0" - resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.11.0.tgz#d61f46d83b2519250e2784daf5b09479a8b41c59" - integrity sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA== - -axios@^0.18.0: - version "0.18.1" - resolved "https://registry.yarnpkg.com/axios/-/axios-0.18.1.tgz#ff3f0de2e7b5d180e757ad98000f1081b87bcea3" - integrity sha512-0BfJq4NSfQXd+SkFdrvFbG7addhYSBA2mQwISr46pD6E5iqkWg02RAs8vyTT/j0RTnoYmeXauBuSv1qKwR179g== - dependencies: - follow-redirects "1.5.10" - is-buffer "^2.0.2" - -babel-code-frame@^6.22.0, babel-code-frame@^6.26.0: - version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b" - integrity sha1-Y/1D99weO7fONZR9uP42mj9Yx0s= - dependencies: - chalk "^1.1.3" - esutils "^2.0.2" - js-tokens "^3.0.2" - -babel-eslint@^10.0.1: - version "10.1.0" - resolved "https://registry.yarnpkg.com/babel-eslint/-/babel-eslint-10.1.0.tgz#6968e568a910b78fb3779cdd8b6ac2f479943232" - integrity sha512-ifWaTHQ0ce+448CYop8AdrQiBsGrnC+bMgfyKFdi6EsPLTAWG+QfyDeM6OH+FmWnKvEq5NnBMLvlBUPKQZoDSg== - dependencies: - "@babel/code-frame" "^7.0.0" - "@babel/parser" "^7.7.0" - "@babel/traverse" "^7.7.0" - "@babel/types" "^7.7.0" - eslint-visitor-keys "^1.0.0" - resolve "^1.12.0" - -balanced-match@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" - integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== - -base64-js@^1.0.2: - version "1.5.1" - resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" - integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== - -base@^0.11.1: - version "0.11.2" - resolved "https://registry.yarnpkg.com/base/-/base-0.11.2.tgz#7bde5ced145b6d551a90db87f83c558b4eb48a8f" - integrity sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg== - dependencies: - cache-base "^1.0.1" - class-utils "^0.3.5" - component-emitter "^1.2.1" - define-property "^1.0.0" - isobject "^3.0.1" - mixin-deep "^1.2.0" - pascalcase "^0.1.1" - -batch@0.6.1: - version "0.6.1" - resolved "https://registry.yarnpkg.com/batch/-/batch-0.6.1.tgz#dc34314f4e679318093fc760272525f94bf25c16" - integrity sha1-3DQxT05nkxgJP8dgJyUl+UvyXBY= - -bcrypt-pbkdf@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz#a4301d389b6a43f9b67ff3ca11a3f6637e360e9e" - integrity sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4= - dependencies: - tweetnacl "^0.14.3" - -bfj@^6.1.1: - version "6.1.2" - resolved "https://registry.yarnpkg.com/bfj/-/bfj-6.1.2.tgz#325c861a822bcb358a41c78a33b8e6e2086dde7f" - integrity sha512-BmBJa4Lip6BPRINSZ0BPEIfB1wUY/9rwbwvIHQA1KjX9om29B6id0wnWXq7m3bn5JrUVjeOTnVuhPT1FiHwPGw== - dependencies: - bluebird "^3.5.5" - check-types "^8.0.3" - hoopy "^0.1.4" - tryer "^1.0.1" - -big.js@^3.1.3: - version "3.2.0" - resolved "https://registry.yarnpkg.com/big.js/-/big.js-3.2.0.tgz#a5fc298b81b9e0dca2e458824784b65c52ba588e" - integrity sha512-+hN/Zh2D08Mx65pZ/4g5bsmNiZUuChDiQfTUQ7qJr4/kuopCr88xZsAXv6mBoZEsUI4OuGHlX59qE94K2mMW8Q== - -big.js@^5.2.2: - version "5.2.2" - resolved "https://registry.yarnpkg.com/big.js/-/big.js-5.2.2.tgz#65f0af382f578bcdc742bd9c281e9cb2d7768328" - integrity sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ== - -binary-extensions@^1.0.0: - version "1.13.1" - resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.13.1.tgz#598afe54755b2868a5330d2aff9d4ebb53209b65" - integrity sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw== - -binary-extensions@^2.0.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d" - integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA== - -bindings@^1.5.0: - version "1.5.0" - resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.5.0.tgz#10353c9e945334bc0511a6d90b38fbc7c9c504df" - integrity sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ== - dependencies: - file-uri-to-path "1.0.0" - -bluebird@^3.1.1, bluebird@^3.5.1, bluebird@^3.5.5: - version "3.7.2" - resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f" - integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg== - -bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.11.9: - version "4.12.0" - resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.12.0.tgz#775b3f278efbb9718eec7361f483fb36fbbfea88" - integrity sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA== - -bn.js@^5.0.0, bn.js@^5.1.1: - version "5.2.0" - resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.2.0.tgz#358860674396c6997771a9d051fcc1b57d4ae002" - integrity sha512-D7iWRBvnZE8ecXiLj/9wbxH7Tk79fAh8IHaTNq1RWRixsS02W+5qS+iE9yq6RYl0asXx5tw0bLhmT5pIfbSquw== - -body-parser@1.19.0: - version "1.19.0" - resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.19.0.tgz#96b2709e57c9c4e09a6fd66a8fd979844f69f08a" - integrity sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw== - dependencies: - bytes "3.1.0" - content-type "~1.0.4" - debug "2.6.9" - depd "~1.1.2" - http-errors "1.7.2" - iconv-lite "0.4.24" - on-finished "~2.3.0" - qs "6.7.0" - raw-body "2.4.0" - type-is "~1.6.17" - -bonjour@^3.5.0: - version "3.5.0" - resolved "https://registry.yarnpkg.com/bonjour/-/bonjour-3.5.0.tgz#8e890a183d8ee9a2393b3844c691a42bcf7bc9f5" - integrity sha1-jokKGD2O6aI5OzhExpGkK897yfU= - dependencies: - array-flatten "^2.1.0" - deep-equal "^1.0.1" - dns-equal "^1.0.0" - dns-txt "^2.0.2" - multicast-dns "^6.0.1" - multicast-dns-service-types "^1.1.0" - -boolbase@^1.0.0, boolbase@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e" - integrity sha1-aN/1++YMUes3cl6p4+0xDcwed24= - -brace-expansion@^1.1.7: - version "1.1.11" - resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" - integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== - dependencies: - balanced-match "^1.0.0" - concat-map "0.0.1" - -braces@^2.3.1, braces@^2.3.2: - version "2.3.2" - resolved "https://registry.yarnpkg.com/braces/-/braces-2.3.2.tgz#5979fd3f14cd531565e5fa2df1abfff1dfaee729" - integrity sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w== - dependencies: - arr-flatten "^1.1.0" - array-unique "^0.3.2" - extend-shallow "^2.0.1" - fill-range "^4.0.0" - isobject "^3.0.1" - repeat-element "^1.1.2" - snapdragon "^0.8.1" - snapdragon-node "^2.0.1" - split-string "^3.0.2" - to-regex "^3.0.1" - -braces@^3.0.1, braces@~3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" - integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== - dependencies: - fill-range "^7.0.1" - -brorand@^1.0.1, brorand@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f" - integrity sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8= - -browserify-aes@^1.0.0, browserify-aes@^1.0.4: - version "1.2.0" - resolved "https://registry.yarnpkg.com/browserify-aes/-/browserify-aes-1.2.0.tgz#326734642f403dabc3003209853bb70ad428ef48" - integrity sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA== - dependencies: - buffer-xor "^1.0.3" - cipher-base "^1.0.0" - create-hash "^1.1.0" - evp_bytestokey "^1.0.3" - inherits "^2.0.1" - safe-buffer "^5.0.1" - -browserify-cipher@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/browserify-cipher/-/browserify-cipher-1.0.1.tgz#8d6474c1b870bfdabcd3bcfcc1934a10e94f15f0" - integrity sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w== - dependencies: - browserify-aes "^1.0.4" - browserify-des "^1.0.0" - evp_bytestokey "^1.0.0" - -browserify-des@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/browserify-des/-/browserify-des-1.0.2.tgz#3af4f1f59839403572f1c66204375f7a7f703e9c" - integrity sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A== - dependencies: - cipher-base "^1.0.1" - des.js "^1.0.0" - inherits "^2.0.1" - safe-buffer "^5.1.2" - -browserify-rsa@^4.0.0, browserify-rsa@^4.0.1: - version "4.1.0" - resolved "https://registry.yarnpkg.com/browserify-rsa/-/browserify-rsa-4.1.0.tgz#b2fd06b5b75ae297f7ce2dc651f918f5be158c8d" - integrity sha512-AdEER0Hkspgno2aR97SAf6vi0y0k8NuOpGnVH3O99rcA5Q6sh8QxcngtHuJ6uXwnfAXNM4Gn1Gb7/MV1+Ymbog== - dependencies: - bn.js "^5.0.0" - randombytes "^2.0.1" - -browserify-sign@^4.0.0: - version "4.2.1" - resolved "https://registry.yarnpkg.com/browserify-sign/-/browserify-sign-4.2.1.tgz#eaf4add46dd54be3bb3b36c0cf15abbeba7956c3" - integrity sha512-/vrA5fguVAKKAVTNJjgSm1tRQDHUU6DbwO9IROu/0WAzC8PKhucDSh18J0RMvVeHAn5puMd+QHC2erPRNf8lmg== - dependencies: - bn.js "^5.1.1" - browserify-rsa "^4.0.1" - create-hash "^1.2.0" - create-hmac "^1.1.7" - elliptic "^6.5.3" - inherits "^2.0.4" - parse-asn1 "^5.1.5" - readable-stream "^3.6.0" - safe-buffer "^5.2.0" - -browserify-zlib@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/browserify-zlib/-/browserify-zlib-0.2.0.tgz#2869459d9aa3be245fe8fe2ca1f46e2e7f54d73f" - integrity sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA== - dependencies: - pako "~1.0.5" - -browserslist@^4.0.0, browserslist@^4.12.0, browserslist@^4.5.4: - version "4.17.6" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.17.6.tgz#c76be33e7786b497f66cad25a73756c8b938985d" - integrity sha512-uPgz3vyRTlEiCv4ee9KlsKgo2V6qPk7Jsn0KAn2OBqbqKo3iNcPEC1Ti6J4dwnz+aIRfEEEuOzC9IBk8tXUomw== - dependencies: - caniuse-lite "^1.0.30001274" - electron-to-chromium "^1.3.886" - escalade "^3.1.1" - node-releases "^2.0.1" - picocolors "^1.0.0" - -buffer-from@^1.0.0: - version "1.1.2" - resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" - integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== - -buffer-indexof@^1.0.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/buffer-indexof/-/buffer-indexof-1.1.1.tgz#52fabcc6a606d1a00302802648ef68f639da268c" - integrity sha512-4/rOEg86jivtPTeOUUT61jJO1Ya1TrR/OkqCSZDyq84WJh3LuuiphBYJN+fm5xufIk4XAFcEwte/8WzC8If/1g== - -buffer-json@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/buffer-json/-/buffer-json-2.0.0.tgz#f73e13b1e42f196fe2fd67d001c7d7107edd7c23" - integrity sha512-+jjPFVqyfF1esi9fvfUs3NqM0pH1ziZ36VP4hmA/y/Ssfo/5w5xHKfTw9BwQjoJ1w/oVtpLomqwUHKdefGyuHw== - -buffer-xor@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/buffer-xor/-/buffer-xor-1.0.3.tgz#26e61ed1422fb70dd42e6e36729ed51d855fe8d9" - integrity sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk= - -buffer@^4.3.0: - version "4.9.2" - resolved "https://registry.yarnpkg.com/buffer/-/buffer-4.9.2.tgz#230ead344002988644841ab0244af8c44bbe3ef8" - integrity sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg== - dependencies: - base64-js "^1.0.2" - ieee754 "^1.1.4" - isarray "^1.0.0" - -builtin-modules@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f" - integrity sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8= - -builtin-status-codes@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz#85982878e21b98e1c66425e03d0174788f569ee8" - integrity sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug= - -bytes@3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048" - integrity sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg= - -bytes@3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.0.tgz#f6cf7933a360e0588fa9fde85651cdc7f805d1f6" - integrity sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg== - -cacache@^10.0.4: - version "10.0.4" - resolved "https://registry.yarnpkg.com/cacache/-/cacache-10.0.4.tgz#6452367999eff9d4188aefd9a14e9d7c6a263460" - integrity sha512-Dph0MzuH+rTQzGPNT9fAnrPmMmjKfST6trxJeK7NQuHRaVw24VzPRWTmg9MpcwOVQZO0E1FBICUlFeNaKPIfHA== - dependencies: - bluebird "^3.5.1" - chownr "^1.0.1" - glob "^7.1.2" - graceful-fs "^4.1.11" - lru-cache "^4.1.1" - mississippi "^2.0.0" - mkdirp "^0.5.1" - move-concurrently "^1.0.1" - promise-inflight "^1.0.1" - rimraf "^2.6.2" - ssri "^5.2.4" - unique-filename "^1.1.0" - y18n "^4.0.0" - -cacache@^12.0.2: - version "12.0.4" - resolved "https://registry.yarnpkg.com/cacache/-/cacache-12.0.4.tgz#668bcbd105aeb5f1d92fe25570ec9525c8faa40c" - integrity sha512-a0tMB40oefvuInr4Cwb3GerbL9xTj1D5yg0T5xrjGCGyfvbxseIXX7BAO/u/hIXdafzOI5JC3wDwHyf24buOAQ== - dependencies: - bluebird "^3.5.5" - chownr "^1.1.1" - figgy-pudding "^3.5.1" - glob "^7.1.4" - graceful-fs "^4.1.15" - infer-owner "^1.0.3" - lru-cache "^5.1.1" - mississippi "^3.0.0" - mkdirp "^0.5.1" - move-concurrently "^1.0.1" - promise-inflight "^1.0.1" - rimraf "^2.6.3" - ssri "^6.0.1" - unique-filename "^1.1.1" - y18n "^4.0.0" - -cache-base@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/cache-base/-/cache-base-1.0.1.tgz#0a7f46416831c8b662ee36fe4e7c59d76f666ab2" - integrity sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ== - dependencies: - collection-visit "^1.0.0" - component-emitter "^1.2.1" - get-value "^2.0.6" - has-value "^1.0.0" - isobject "^3.0.1" - set-value "^2.0.0" - to-object-path "^0.3.0" - union-value "^1.0.0" - unset-value "^1.0.0" - -cache-loader@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/cache-loader/-/cache-loader-2.0.1.tgz#5758f41a62d7c23941e3c3c7016e6faeb03acb07" - integrity sha512-V99T3FOynmGx26Zom+JrVBytLBsmUCzVG2/4NnUKgvXN4bEV42R1ERl1IyiH/cvFIDA1Ytq2lPZ9tXDSahcQpQ== - dependencies: - loader-utils "^1.1.0" - mkdirp "^0.5.1" - neo-async "^2.6.0" - normalize-path "^3.0.0" - schema-utils "^1.0.0" - -cache-loader@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/cache-loader/-/cache-loader-4.1.0.tgz#9948cae353aec0a1fcb1eafda2300816ec85387e" - integrity sha512-ftOayxve0PwKzBF/GLsZNC9fJBXl8lkZE3TOsjkboHfVHVkL39iUEs1FO07A33mizmci5Dudt38UZrrYXDtbhw== - dependencies: - buffer-json "^2.0.0" - find-cache-dir "^3.0.0" - loader-utils "^1.2.3" - mkdirp "^0.5.1" - neo-async "^2.6.1" - schema-utils "^2.0.0" - -call-bind@^1.0.0, call-bind@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.2.tgz#b1d4e89e688119c3c9a903ad30abb2f6a919be3c" - integrity sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA== - dependencies: - function-bind "^1.1.1" - get-intrinsic "^1.0.2" - -call-me-maybe@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/call-me-maybe/-/call-me-maybe-1.0.1.tgz#26d208ea89e37b5cbde60250a15f031c16a4d66b" - integrity sha1-JtII6onje1y95gJQoV8DHBak1ms= - -caller-callsite@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/caller-callsite/-/caller-callsite-2.0.0.tgz#847e0fce0a223750a9a027c54b33731ad3154134" - integrity sha1-hH4PzgoiN1CpoCfFSzNzGtMVQTQ= - dependencies: - callsites "^2.0.0" - -caller-path@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/caller-path/-/caller-path-0.1.0.tgz#94085ef63581ecd3daa92444a8fe94e82577751f" - integrity sha1-lAhe9jWB7NPaqSREqP6U6CV3dR8= - dependencies: - callsites "^0.2.0" - -caller-path@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/caller-path/-/caller-path-2.0.0.tgz#468f83044e369ab2010fac5f06ceee15bb2cb1f4" - integrity sha1-Ro+DBE42mrIBD6xfBs7uFbsssfQ= - dependencies: - caller-callsite "^2.0.0" - -callsites@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/callsites/-/callsites-0.2.0.tgz#afab96262910a7f33c19a5775825c69f34e350ca" - integrity sha1-r6uWJikQp/M8GaV3WCXGnzTjUMo= - -callsites@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/callsites/-/callsites-2.0.0.tgz#06eb84f00eea413da86affefacbffb36093b3c50" - integrity sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA= - -callsites@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" - integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== - -camel-case@3.0.x: - version "3.0.0" - resolved "https://registry.yarnpkg.com/camel-case/-/camel-case-3.0.0.tgz#ca3c3688a4e9cf3a4cda777dc4dcbc713249cf73" - integrity sha1-yjw2iKTpzzpM2nd9xNy8cTJJz3M= - dependencies: - no-case "^2.2.0" - upper-case "^1.1.1" - -camelcase@^5.0.0: - version "5.3.1" - resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" - integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== - -caniuse-api@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/caniuse-api/-/caniuse-api-3.0.0.tgz#5e4d90e2274961d46291997df599e3ed008ee4c0" - integrity sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw== - dependencies: - browserslist "^4.0.0" - caniuse-lite "^1.0.0" - lodash.memoize "^4.1.2" - lodash.uniq "^4.5.0" - -caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001109, caniuse-lite@^1.0.30001274: - version "1.0.30001279" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001279.tgz#eb06818da481ef5096a3b3760f43e5382ed6b0ce" - integrity sha512-VfEHpzHEXj6/CxggTwSFoZBBYGQfQv9Cf42KPlO79sWXCD1QNKWKsKzFeWL7QpZHJQYAvocqV6Rty1yJMkqWLQ== - -case-sensitive-paths-webpack-plugin@^2.2.0: - version "2.4.0" - resolved "https://registry.yarnpkg.com/case-sensitive-paths-webpack-plugin/-/case-sensitive-paths-webpack-plugin-2.4.0.tgz#db64066c6422eed2e08cc14b986ca43796dbc6d4" - integrity sha512-roIFONhcxog0JSSWbvVAh3OocukmSgpqOH6YpMkCvav/ySIV3JKg4Dc8vYtQjYi/UxpNE36r/9v+VqTQqgkYmw== - -caseless@~0.12.0: - version "0.12.0" - resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" - integrity sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw= - -chalk@^1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" - integrity sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg= - dependencies: - ansi-styles "^2.2.1" - escape-string-regexp "^1.0.2" - has-ansi "^2.0.0" - strip-ansi "^3.0.0" - supports-color "^2.0.0" - -chalk@^2.0.0, chalk@^2.0.1, chalk@^2.1.0, chalk@^2.3.0, chalk@^2.4.1, chalk@^2.4.2: - version "2.4.2" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" - integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== - dependencies: - ansi-styles "^3.2.1" - escape-string-regexp "^1.0.5" - supports-color "^5.3.0" - -chalk@^4.0.0, chalk@^4.1.0: - version "4.1.2" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" - integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== - dependencies: - ansi-styles "^4.1.0" - supports-color "^7.1.0" - -chardet@^0.4.0: - version "0.4.2" - resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.4.2.tgz#b5473b33dc97c424e5d98dc87d55d4d8a29c8bf2" - integrity sha1-tUc7M9yXxCTl2Y3IfVXU2KKci/I= - -chardet@^0.7.0: - version "0.7.0" - resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e" - integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA== - -check-types@^8.0.3: - version "8.0.3" - resolved "https://registry.yarnpkg.com/check-types/-/check-types-8.0.3.tgz#3356cca19c889544f2d7a95ed49ce508a0ecf552" - integrity sha512-YpeKZngUmG65rLudJ4taU7VLkOCTMhNl/u4ctNC56LQS/zJTyNH0Lrtwm1tfTsbLlwvlfsA2d1c8vCf/Kh2KwQ== - -chokidar@^2.1.8: - version "2.1.8" - resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.1.8.tgz#804b3a7b6a99358c3c5c61e71d8728f041cff917" - integrity sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg== - dependencies: - anymatch "^2.0.0" - async-each "^1.0.1" - braces "^2.3.2" - glob-parent "^3.1.0" - inherits "^2.0.3" - is-binary-path "^1.0.0" - is-glob "^4.0.0" - normalize-path "^3.0.0" - path-is-absolute "^1.0.0" - readdirp "^2.2.1" - upath "^1.1.1" - optionalDependencies: - fsevents "^1.2.7" - -chokidar@^3.3.0, chokidar@^3.4.1: - version "3.5.2" - resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.2.tgz#dba3976fcadb016f66fd365021d91600d01c1e75" - integrity sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ== - dependencies: - anymatch "~3.1.2" - braces "~3.0.2" - glob-parent "~5.1.2" - is-binary-path "~2.1.0" - is-glob "~4.0.1" - normalize-path "~3.0.0" - readdirp "~3.6.0" - optionalDependencies: - fsevents "~2.3.2" - -chownr@^1.0.1, chownr@^1.1.1: - version "1.1.4" - resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.4.tgz#6fc9d7b42d32a583596337666e7d08084da2cc6b" - integrity sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg== - -chrome-trace-event@^1.0.2: - version "1.0.3" - resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz#1015eced4741e15d06664a957dbbf50d041e26ac" - integrity sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg== - -ci-info@^1.5.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-1.6.0.tgz#2ca20dbb9ceb32d4524a683303313f0304b1e497" - integrity sha512-vsGdkwSCDpWmP80ncATX7iea5DWQemg1UgCW5J8tqjU3lYw4FBYuj89J0CTVomA7BEfvSZd84GmHko+MxFQU2A== - -cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: - version "1.0.4" - resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.4.tgz#8760e4ecc272f4c363532f926d874aae2c1397de" - integrity sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q== - dependencies: - inherits "^2.0.1" - safe-buffer "^5.0.1" - -circular-json@^0.3.1: - version "0.3.3" - resolved "https://registry.yarnpkg.com/circular-json/-/circular-json-0.3.3.tgz#815c99ea84f6809529d2f45791bdf82711352d66" - integrity sha512-UZK3NBx2Mca+b5LsG7bY183pHWt5Y1xts4P3Pz7ENTwGVnJOUWbRb3ocjvX7hx9tq/yTAdclXm9sZ38gNuem4A== - -class-utils@^0.3.5: - version "0.3.6" - resolved "https://registry.yarnpkg.com/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463" - integrity sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg== - dependencies: - arr-union "^3.1.0" - define-property "^0.2.5" - isobject "^3.0.0" - static-extend "^0.1.1" - -clean-css@4.2.x: - version "4.2.4" - resolved "https://registry.yarnpkg.com/clean-css/-/clean-css-4.2.4.tgz#733bf46eba4e607c6891ea57c24a989356831178" - integrity sha512-EJUDT7nDVFDvaQgAo2G/PJvxmp1o/c6iXLbswsBbUFXi1Nr+AjA2cKmfbKDMjMvzEe75g3P6JkaDDAKk96A85A== - dependencies: - source-map "~0.6.0" - -cli-cursor@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-2.1.0.tgz#b35dac376479facc3e94747d41d0d0f5238ffcb5" - integrity sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU= - dependencies: - restore-cursor "^2.0.0" - -cli-highlight@^2.1.0: - version "2.1.11" - resolved "https://registry.yarnpkg.com/cli-highlight/-/cli-highlight-2.1.11.tgz#49736fa452f0aaf4fae580e30acb26828d2dc1bf" - integrity sha512-9KDcoEVwyUXrjcJNvHD0NFc/hiwe/WPVYIleQh2O1N2Zro5gWJZ/K+3DGn8w8P/F6FxOgzyC5bxDyHIgCSPhGg== - dependencies: - chalk "^4.0.0" - highlight.js "^10.7.1" - mz "^2.4.0" - parse5 "^5.1.1" - parse5-htmlparser2-tree-adapter "^6.0.0" - yargs "^16.0.0" - -cli-spinners@^2.0.0: - version "2.6.1" - resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-2.6.1.tgz#adc954ebe281c37a6319bfa401e6dd2488ffb70d" - integrity sha512-x/5fWmGMnbKQAaNwN+UZlV79qBLM9JFnJuJ03gIi5whrob0xV0ofNVHy9DhwGdsMJQc2OKv0oGmLzvaqvAVv+g== - -cli-width@^2.0.0: - version "2.2.1" - resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.2.1.tgz#b0433d0b4e9c847ef18868a4ef16fd5fc8271c48" - integrity sha512-GRMWDxpOB6Dgk2E5Uo+3eEBvtOOlimMmpbFiKuLFnQzYDavtLFY3K5ona41jgN/WdRZtG7utuVSVTL4HbZHGkw== - -clipboardy@^2.0.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/clipboardy/-/clipboardy-2.3.0.tgz#3c2903650c68e46a91b388985bc2774287dba290" - integrity sha512-mKhiIL2DrQIsuXMgBgnfEHOZOryC7kY7YO//TN6c63wlEm3NG5tz+YgY5rVi29KCmq/QQjKYvM7a19+MDOTHOQ== - dependencies: - arch "^2.1.1" - execa "^1.0.0" - is-wsl "^2.1.1" - -cliui@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/cliui/-/cliui-5.0.0.tgz#deefcfdb2e800784aa34f46fa08e06851c7bbbc5" - integrity sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA== - dependencies: - string-width "^3.1.0" - strip-ansi "^5.2.0" - wrap-ansi "^5.1.0" - -cliui@^7.0.2: - version "7.0.4" - resolved "https://registry.yarnpkg.com/cliui/-/cliui-7.0.4.tgz#a0265ee655476fc807aea9df3df8df7783808b4f" - integrity sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ== - dependencies: - string-width "^4.2.0" - strip-ansi "^6.0.0" - wrap-ansi "^7.0.0" - -clone@^1.0.2: - version "1.0.4" - resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.4.tgz#da309cc263df15994c688ca902179ca3c7cd7c7e" - integrity sha1-2jCcwmPfFZlMaIypAheco8fNfH4= - -co@^4.6.0: - version "4.6.0" - resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" - integrity sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ= - -coa@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/coa/-/coa-2.0.2.tgz#43f6c21151b4ef2bf57187db0d73de229e3e7ec3" - integrity sha512-q5/jG+YQnSy4nRTV4F7lPepBJZ8qBNJJDBuJdoejDyLXgmL7IEo+Le2JDZudFTFt7mrCqIRaSjws4ygRCTCAXA== - dependencies: - "@types/q" "^1.5.1" - chalk "^2.4.1" - q "^1.1.2" - -collection-visit@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/collection-visit/-/collection-visit-1.0.0.tgz#4bc0373c164bc3291b4d368c829cf1a80a59dca0" - integrity sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA= - dependencies: - map-visit "^1.0.0" - object-visit "^1.0.0" - -color-convert@^1.9.0, color-convert@^1.9.3: - version "1.9.3" - resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" - integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== - dependencies: - color-name "1.1.3" - -color-convert@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" - integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== - dependencies: - color-name "~1.1.4" - -color-name@1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" - integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= - -color-name@^1.0.0, color-name@~1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" - integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== - -color-string@^1.6.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/color-string/-/color-string-1.6.0.tgz#c3915f61fe267672cb7e1e064c9d692219f6c312" - integrity sha512-c/hGS+kRWJutUBEngKKmk4iH3sD59MBkoxVapS/0wgpCz2u7XsNloxknyvBhzwEs1IbV36D9PwqLPJ2DTu3vMA== - dependencies: - color-name "^1.0.0" - simple-swizzle "^0.2.2" - -color@^3.0.0: - version "3.2.1" - resolved "https://registry.yarnpkg.com/color/-/color-3.2.1.tgz#3544dc198caf4490c3ecc9a790b54fe9ff45e164" - integrity sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA== - dependencies: - color-convert "^1.9.3" - color-string "^1.6.0" - -combined-stream@^1.0.6, combined-stream@~1.0.6: - version "1.0.8" - resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" - integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== - dependencies: - delayed-stream "~1.0.0" - -commander@2.17.x: - version "2.17.1" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.17.1.tgz#bd77ab7de6de94205ceacc72f1716d29f20a77bf" - integrity sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg== - -commander@^2.12.1, commander@^2.18.0, commander@^2.20.0: - version "2.20.3" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" - integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== - -commander@~2.19.0: - version "2.19.0" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.19.0.tgz#f6198aa84e5b83c46054b94ddedbfed5ee9ff12a" - integrity sha512-6tvAOO+D6OENvRAh524Dh9jcfKTYDQAqvqezbCW82xj5X0pSrcpxtvRKHLG0yBY6SD7PSDrJaj+0AiOcKVd1Xg== - -commondir@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b" - integrity sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs= - -component-emitter@^1.2.1: - version "1.3.0" - resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0" - integrity sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg== - -compressible@~2.0.16: - version "2.0.18" - resolved "https://registry.yarnpkg.com/compressible/-/compressible-2.0.18.tgz#af53cca6b070d4c3c0750fbd77286a6d7cc46fba" - integrity sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg== - dependencies: - mime-db ">= 1.43.0 < 2" - -compression@^1.7.4: - version "1.7.4" - resolved "https://registry.yarnpkg.com/compression/-/compression-1.7.4.tgz#95523eff170ca57c29a0ca41e6fe131f41e5bb8f" - integrity sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ== - dependencies: - accepts "~1.3.5" - bytes "3.0.0" - compressible "~2.0.16" - debug "2.6.9" - on-headers "~1.0.2" - safe-buffer "5.1.2" - vary "~1.1.2" - -concat-map@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" - integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= - -concat-stream@^1.5.0, concat-stream@^1.6.0: - version "1.6.2" - resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34" - integrity sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw== - dependencies: - buffer-from "^1.0.0" - inherits "^2.0.3" - readable-stream "^2.2.2" - typedarray "^0.0.6" - -connect-history-api-fallback@^1.6.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/connect-history-api-fallback/-/connect-history-api-fallback-1.6.0.tgz#8b32089359308d111115d81cad3fceab888f97bc" - integrity sha512-e54B99q/OUoH64zYYRf3HBP5z24G38h5D3qXu23JGRoigpX5Ss4r9ZnDk3g0Z8uQC2x2lPaJ+UlWBc1ZWBWdLg== - -console-browserify@^1.1.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/console-browserify/-/console-browserify-1.2.0.tgz#67063cef57ceb6cf4993a2ab3a55840ae8c49336" - integrity sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA== - -consolidate@^0.15.1: - version "0.15.1" - resolved "https://registry.yarnpkg.com/consolidate/-/consolidate-0.15.1.tgz#21ab043235c71a07d45d9aad98593b0dba56bab7" - integrity sha512-DW46nrsMJgy9kqAbPt5rKaCr7uFtpo4mSUvLHIUbJEjm0vo+aY5QLwBUq3FK4tRnJr/X0Psc0C4jf/h+HtXSMw== - dependencies: - bluebird "^3.1.1" - -constants-browserify@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/constants-browserify/-/constants-browserify-1.0.0.tgz#c20b96d8c617748aaf1c16021760cd27fcb8cb75" - integrity sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U= - -content-disposition@0.5.3: - version "0.5.3" - resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.3.tgz#e130caf7e7279087c5616c2007d0485698984fbd" - integrity sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g== - dependencies: - safe-buffer "5.1.2" - -content-type@~1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" - integrity sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA== - -cookie-signature@1.0.6: - version "1.0.6" - resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" - integrity sha1-4wOogrNCzD7oylE6eZmXNNqzriw= - -cookie@0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.0.tgz#beb437e7022b3b6d49019d088665303ebe9c14ba" - integrity sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg== - -copy-concurrently@^1.0.0: - version "1.0.5" - resolved "https://registry.yarnpkg.com/copy-concurrently/-/copy-concurrently-1.0.5.tgz#92297398cae34937fcafd6ec8139c18051f0b5e0" - integrity sha512-f2domd9fsVDFtaFcbaRZuYXwtdmnzqbADSwhSWYxYB/Q8zsdUUFMXVRwXGDMWmbEzAn1kdRrtI1T/KTFOL4X2A== - dependencies: - aproba "^1.1.1" - fs-write-stream-atomic "^1.0.8" - iferr "^0.1.5" - mkdirp "^0.5.1" - rimraf "^2.5.4" - run-queue "^1.0.0" - -copy-descriptor@^0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" - integrity sha1-Z29us8OZl8LuGsOpJP1hJHSPV40= - -copy-webpack-plugin@^4.6.0: - version "4.6.0" - resolved "https://registry.yarnpkg.com/copy-webpack-plugin/-/copy-webpack-plugin-4.6.0.tgz#e7f40dd8a68477d405dd1b7a854aae324b158bae" - integrity sha512-Y+SQCF+0NoWQryez2zXn5J5knmr9z/9qSQt7fbL78u83rxmigOy8X5+BFn8CFSuX+nKT8gpYwJX68ekqtQt6ZA== - dependencies: - cacache "^10.0.4" - find-cache-dir "^1.0.0" - globby "^7.1.1" - is-glob "^4.0.0" - loader-utils "^1.1.0" - minimatch "^3.0.4" - p-limit "^1.0.0" - serialize-javascript "^1.4.0" - -core-util-is@1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" - integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac= - -core-util-is@~1.0.0: - version "1.0.3" - resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85" - integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ== - -cosmiconfig@^5.0.0: - version "5.2.1" - resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-5.2.1.tgz#040f726809c591e77a17c0a3626ca45b4f168b1a" - integrity sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA== - dependencies: - import-fresh "^2.0.0" - is-directory "^0.3.1" - js-yaml "^3.13.1" - parse-json "^4.0.0" - -cosmiconfig@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-6.0.0.tgz#da4fee853c52f6b1e6935f41c1a2fc50bd4a9982" - integrity sha512-xb3ZL6+L8b9JLLCx3ZdoZy4+2ECphCMo2PwqgP1tlfVq6M6YReyzBJtvWWtbDSpNr9hn96pkCiZqUcFEc+54Qg== - dependencies: - "@types/parse-json" "^4.0.0" - import-fresh "^3.1.0" - parse-json "^5.0.0" - path-type "^4.0.0" - yaml "^1.7.2" - -create-ecdh@^4.0.0: - version "4.0.4" - resolved "https://registry.yarnpkg.com/create-ecdh/-/create-ecdh-4.0.4.tgz#d6e7f4bffa66736085a0762fd3a632684dabcc4e" - integrity sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A== - dependencies: - bn.js "^4.1.0" - elliptic "^6.5.3" - -create-hash@^1.1.0, create-hash@^1.1.2, create-hash@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/create-hash/-/create-hash-1.2.0.tgz#889078af11a63756bcfb59bd221996be3a9ef196" - integrity sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg== - dependencies: - cipher-base "^1.0.1" - inherits "^2.0.1" - md5.js "^1.3.4" - ripemd160 "^2.0.1" - sha.js "^2.4.0" - -create-hmac@^1.1.0, create-hmac@^1.1.4, create-hmac@^1.1.7: - version "1.1.7" - resolved "https://registry.yarnpkg.com/create-hmac/-/create-hmac-1.1.7.tgz#69170c78b3ab957147b2b8b04572e47ead2243ff" - integrity sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg== - dependencies: - cipher-base "^1.0.3" - create-hash "^1.1.0" - inherits "^2.0.1" - ripemd160 "^2.0.0" - safe-buffer "^5.0.1" - sha.js "^2.4.8" - -cross-spawn@^5.0.1, cross-spawn@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449" - integrity sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk= - dependencies: - lru-cache "^4.0.1" - shebang-command "^1.2.0" - which "^1.2.9" - -cross-spawn@^6.0.0, cross-spawn@^6.0.5: - version "6.0.5" - resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" - integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ== - dependencies: - nice-try "^1.0.4" - path-key "^2.0.1" - semver "^5.5.0" - shebang-command "^1.2.0" - which "^1.2.9" - -cross-spawn@^7.0.0: - version "7.0.3" - resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" - integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== - dependencies: - path-key "^3.1.0" - shebang-command "^2.0.0" - which "^2.0.1" - -crypto-browserify@^3.11.0: - version "3.12.0" - resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.12.0.tgz#396cf9f3137f03e4b8e532c58f698254e00f80ec" - integrity sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg== - dependencies: - browserify-cipher "^1.0.0" - browserify-sign "^4.0.0" - create-ecdh "^4.0.0" - create-hash "^1.1.0" - create-hmac "^1.1.0" - diffie-hellman "^5.0.0" - inherits "^2.0.1" - pbkdf2 "^3.0.3" - public-encrypt "^4.0.0" - randombytes "^2.0.0" - randomfill "^1.0.3" - -css-color-names@0.0.4, css-color-names@^0.0.4: - version "0.0.4" - resolved "https://registry.yarnpkg.com/css-color-names/-/css-color-names-0.0.4.tgz#808adc2e79cf84738069b646cb20ec27beb629e0" - integrity sha1-gIrcLnnPhHOAabZGyyDsJ762KeA= - -css-declaration-sorter@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/css-declaration-sorter/-/css-declaration-sorter-4.0.1.tgz#c198940f63a76d7e36c1e71018b001721054cb22" - integrity sha512-BcxQSKTSEEQUftYpBVnsH4SF05NTuBokb19/sBt6asXGKZ/6VP7PLG1CBCkFDYOnhXhPh0jMhO6xZ71oYHXHBA== - dependencies: - postcss "^7.0.1" - timsort "^0.3.0" - -css-loader@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-1.0.1.tgz#6885bb5233b35ec47b006057da01cc640b6b79fe" - integrity sha512-+ZHAZm/yqvJ2kDtPne3uX0C+Vr3Zn5jFn2N4HywtS5ujwvsVkyg0VArEXpl3BgczDA8anieki1FIzhchX4yrDw== - dependencies: - babel-code-frame "^6.26.0" - css-selector-tokenizer "^0.7.0" - icss-utils "^2.1.0" - loader-utils "^1.0.2" - lodash "^4.17.11" - postcss "^6.0.23" - postcss-modules-extract-imports "^1.2.0" - postcss-modules-local-by-default "^1.2.0" - postcss-modules-scope "^1.1.0" - postcss-modules-values "^1.3.0" - postcss-value-parser "^3.3.0" - source-list-map "^2.0.0" - -css-select-base-adapter@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/css-select-base-adapter/-/css-select-base-adapter-0.1.1.tgz#3b2ff4972cc362ab88561507a95408a1432135d7" - integrity sha512-jQVeeRG70QI08vSTwf1jHxp74JoZsr2XSgETae8/xC8ovSnL2WF87GTLO86Sbwdt2lK4Umg4HnnwMO4YF3Ce7w== - -css-select@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/css-select/-/css-select-2.1.0.tgz#6a34653356635934a81baca68d0255432105dbef" - integrity sha512-Dqk7LQKpwLoH3VovzZnkzegqNSuAziQyNZUcrdDM401iY+R5NkGBXGmtO05/yaXQziALuPogeG0b7UAgjnTJTQ== - dependencies: - boolbase "^1.0.0" - css-what "^3.2.1" - domutils "^1.7.0" - nth-check "^1.0.2" - -css-select@^4.1.3: - version "4.1.3" - resolved "https://registry.yarnpkg.com/css-select/-/css-select-4.1.3.tgz#a70440f70317f2669118ad74ff105e65849c7067" - integrity sha512-gT3wBNd9Nj49rAbmtFHj1cljIAOLYSX1nZ8CB7TBO3INYckygm5B7LISU/szY//YmdiSLbJvDLOx9VnMVpMBxA== - dependencies: - boolbase "^1.0.0" - css-what "^5.0.0" - domhandler "^4.2.0" - domutils "^2.6.0" - nth-check "^2.0.0" - -css-selector-tokenizer@^0.7.0: - version "0.7.3" - resolved "https://registry.yarnpkg.com/css-selector-tokenizer/-/css-selector-tokenizer-0.7.3.tgz#735f26186e67c749aaf275783405cf0661fae8f1" - integrity sha512-jWQv3oCEL5kMErj4wRnK/OPoBi0D+P1FR2cDCKYPaMeD2eW3/mttav8HT4hT1CKopiJI/psEULjkClhvJo4Lvg== - dependencies: - cssesc "^3.0.0" - fastparse "^1.1.2" - -css-tree@1.0.0-alpha.37: - version "1.0.0-alpha.37" - resolved "https://registry.yarnpkg.com/css-tree/-/css-tree-1.0.0-alpha.37.tgz#98bebd62c4c1d9f960ec340cf9f7522e30709a22" - integrity sha512-DMxWJg0rnz7UgxKT0Q1HU/L9BeJI0M6ksor0OgqOnF+aRCDWg/N2641HmVyU9KVIu0OVVWOb2IpC9A+BJRnejg== - dependencies: - mdn-data "2.0.4" - source-map "^0.6.1" - -css-tree@^1.1.2: - version "1.1.3" - resolved "https://registry.yarnpkg.com/css-tree/-/css-tree-1.1.3.tgz#eb4870fb6fd7707327ec95c2ff2ab09b5e8db91d" - integrity sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q== - dependencies: - mdn-data "2.0.14" - source-map "^0.6.1" - -css-what@^3.2.1: - version "3.4.2" - resolved "https://registry.yarnpkg.com/css-what/-/css-what-3.4.2.tgz#ea7026fcb01777edbde52124e21f327e7ae950e4" - integrity sha512-ACUm3L0/jiZTqfzRM3Hi9Q8eZqd6IK37mMWPLz9PJxkLWllYeRf+EHUSHYEtFop2Eqytaq1FizFVh7XfBnXCDQ== - -css-what@^5.0.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/css-what/-/css-what-5.1.0.tgz#3f7b707aadf633baf62c2ceb8579b545bb40f7fe" - integrity sha512-arSMRWIIFY0hV8pIxZMEfmMI47Wj3R/aWpZDDxWYCPEiOMv6tfOrnpDtgxBYPEQD4V0Y/958+1TdC3iWTFcUPw== - -cssesc@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee" - integrity sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg== - -cssnano-preset-default@^4.0.0, cssnano-preset-default@^4.0.8: - version "4.0.8" - resolved "https://registry.yarnpkg.com/cssnano-preset-default/-/cssnano-preset-default-4.0.8.tgz#920622b1fc1e95a34e8838203f1397a504f2d3ff" - integrity sha512-LdAyHuq+VRyeVREFmuxUZR1TXjQm8QQU/ktoo/x7bz+SdOge1YKc5eMN6pRW7YWBmyq59CqYba1dJ5cUukEjLQ== - dependencies: - css-declaration-sorter "^4.0.1" - cssnano-util-raw-cache "^4.0.1" - postcss "^7.0.0" - postcss-calc "^7.0.1" - postcss-colormin "^4.0.3" - postcss-convert-values "^4.0.1" - postcss-discard-comments "^4.0.2" - postcss-discard-duplicates "^4.0.2" - postcss-discard-empty "^4.0.1" - postcss-discard-overridden "^4.0.1" - postcss-merge-longhand "^4.0.11" - postcss-merge-rules "^4.0.3" - postcss-minify-font-values "^4.0.2" - postcss-minify-gradients "^4.0.2" - postcss-minify-params "^4.0.2" - postcss-minify-selectors "^4.0.2" - postcss-normalize-charset "^4.0.1" - postcss-normalize-display-values "^4.0.2" - postcss-normalize-positions "^4.0.2" - postcss-normalize-repeat-style "^4.0.2" - postcss-normalize-string "^4.0.2" - postcss-normalize-timing-functions "^4.0.2" - postcss-normalize-unicode "^4.0.1" - postcss-normalize-url "^4.0.1" - postcss-normalize-whitespace "^4.0.2" - postcss-ordered-values "^4.1.2" - postcss-reduce-initial "^4.0.3" - postcss-reduce-transforms "^4.0.2" - postcss-svgo "^4.0.3" - postcss-unique-selectors "^4.0.1" - -cssnano-util-get-arguments@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/cssnano-util-get-arguments/-/cssnano-util-get-arguments-4.0.0.tgz#ed3a08299f21d75741b20f3b81f194ed49cc150f" - integrity sha1-7ToIKZ8h11dBsg87gfGU7UnMFQ8= - -cssnano-util-get-match@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/cssnano-util-get-match/-/cssnano-util-get-match-4.0.0.tgz#c0e4ca07f5386bb17ec5e52250b4f5961365156d" - integrity sha1-wOTKB/U4a7F+xeUiULT1lhNlFW0= - -cssnano-util-raw-cache@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/cssnano-util-raw-cache/-/cssnano-util-raw-cache-4.0.1.tgz#b26d5fd5f72a11dfe7a7846fb4c67260f96bf282" - integrity sha512-qLuYtWK2b2Dy55I8ZX3ky1Z16WYsx544Q0UWViebptpwn/xDBmog2TLg4f+DBMg1rJ6JDWtn96WHbOKDWt1WQA== - dependencies: - postcss "^7.0.0" - -cssnano-util-same-parent@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/cssnano-util-same-parent/-/cssnano-util-same-parent-4.0.1.tgz#574082fb2859d2db433855835d9a8456ea18bbf3" - integrity sha512-WcKx5OY+KoSIAxBW6UBBRay1U6vkYheCdjyVNDm85zt5K9mHoGOfsOsqIszfAqrQQFIIKgjh2+FDgIj/zsl21Q== - -cssnano@^4.0.0, cssnano@^4.1.10: - version "4.1.11" - resolved "https://registry.yarnpkg.com/cssnano/-/cssnano-4.1.11.tgz#c7b5f5b81da269cb1fd982cb960c1200910c9a99" - integrity sha512-6gZm2htn7xIPJOHY824ERgj8cNPgPxyCSnkXc4v7YvNW+TdVfzgngHcEhy/8D11kUWRUMbke+tC+AUcUsnMz2g== - dependencies: - cosmiconfig "^5.0.0" - cssnano-preset-default "^4.0.8" - is-resolvable "^1.0.0" - postcss "^7.0.0" - -csso@^4.0.2: - version "4.2.0" - resolved "https://registry.yarnpkg.com/csso/-/csso-4.2.0.tgz#ea3a561346e8dc9f546d6febedd50187cf389529" - integrity sha512-wvlcdIbf6pwKEk7vHj8/Bkc0B4ylXZruLvOgs9doS5eOsOpuodOV2zJChSpkp+pRpYQLQMeF04nr3Z68Sta9jA== - dependencies: - css-tree "^1.1.2" - -current-script-polyfill@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/current-script-polyfill/-/current-script-polyfill-1.0.0.tgz#f31cf7e4f3e218b0726e738ca92a02d3488ef615" - integrity sha1-8xz35PPiGLBybnOMqSoC00iO9hU= - -cyclist@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/cyclist/-/cyclist-1.0.1.tgz#596e9698fd0c80e12038c2b82d6eb1b35b6224d9" - integrity sha1-WW6WmP0MgOEgOMK4LW6xs1tiJNk= - -dashdash@^1.12.0: - version "1.14.1" - resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" - integrity sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA= - dependencies: - assert-plus "^1.0.0" - -de-indent@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/de-indent/-/de-indent-1.0.2.tgz#b2038e846dc33baa5796128d0804b455b8c1e21d" - integrity sha1-sgOOhG3DO6pXlhKNCAS0VbjB4h0= - -debug@2.6.9, debug@^2.2.0, debug@^2.3.3: - version "2.6.9" - resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" - integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== - dependencies: - ms "2.0.0" - -debug@=3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" - integrity sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g== - dependencies: - ms "2.0.0" - -debug@^3.1.0, debug@^3.1.1, debug@^3.2.6: - version "3.2.7" - resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a" - integrity sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ== - dependencies: - ms "^2.1.1" - -debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1: - version "4.3.2" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.2.tgz#f0a49c18ac8779e31d4a0c6029dfb76873c7428b" - integrity sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw== - dependencies: - ms "2.1.2" - -decamelize@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" - integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA= - -decode-uri-component@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545" - integrity sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU= - -deep-equal@^1.0.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-1.1.1.tgz#b5c98c942ceffaf7cb051e24e1434a25a2e6076a" - integrity sha512-yd9c5AdiqVcR+JjcwUQb9DkhJc8ngNr0MahEBGvDiJw8puWab2yZlh+nkasOnZP+EGTAP6rRp2JzJhJZzvNF8g== - dependencies: - is-arguments "^1.0.4" - is-date-object "^1.0.1" - is-regex "^1.0.4" - object-is "^1.0.1" - object-keys "^1.1.1" - regexp.prototype.flags "^1.2.0" - -deep-is@~0.1.3: - version "0.1.4" - resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831" - integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== - -deepmerge@^1.5.2: - version "1.5.2" - resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-1.5.2.tgz#10499d868844cdad4fee0842df8c7f6f0c95a753" - integrity sha512-95k0GDqvBjZavkuvzx/YqVLv/6YYa17fz6ILMSf7neqQITCPbnfEnQvEgMPNjH4kgobe7+WIL0yJEHku+H3qtQ== - -deepmerge@^2.1.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-2.2.1.tgz#5d3ff22a01c00f645405a2fbc17d0778a1801170" - integrity sha512-R9hc1Xa/NOBi9WRVUWg19rl1UB7Tt4kuPd+thNJgFZoxXsTz7ncaPaeIm+40oSGuP33DfMb4sZt1QIGiJzC4EA== - -deepmerge@^4.2.2: - version "4.2.2" - resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.2.2.tgz#44d2ea3679b8f4d4ffba33f03d865fc1e7bf4955" - integrity sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg== - -default-gateway@^4.2.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/default-gateway/-/default-gateway-4.2.0.tgz#167104c7500c2115f6dd69b0a536bb8ed720552b" - integrity sha512-h6sMrVB1VMWVrW13mSc6ia/DwYYw5MN6+exNu1OaJeFac5aSAvwM7lZ0NVfTABuSkQelr4h5oebg3KB1XPdjgA== - dependencies: - execa "^1.0.0" - ip-regex "^2.1.0" - -default-gateway@^5.0.2: - version "5.0.5" - resolved "https://registry.yarnpkg.com/default-gateway/-/default-gateway-5.0.5.tgz#4fd6bd5d2855d39b34cc5a59505486e9aafc9b10" - integrity sha512-z2RnruVmj8hVMmAnEJMTIJNijhKCDiGjbLP+BHJFOT7ld3Bo5qcIBpVYDniqhbMIIf+jZDlkP2MkPXiQy/DBLA== - dependencies: - execa "^3.3.0" - -defaults@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/defaults/-/defaults-1.0.3.tgz#c656051e9817d9ff08ed881477f3fe4019f3ef7d" - integrity sha1-xlYFHpgX2f8I7YgUd/P+QBnz730= - dependencies: - clone "^1.0.2" - -define-properties@^1.1.2, define-properties@^1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1" - integrity sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ== - dependencies: - object-keys "^1.0.12" - -define-property@^0.2.5: - version "0.2.5" - resolved "https://registry.yarnpkg.com/define-property/-/define-property-0.2.5.tgz#c35b1ef918ec3c990f9a5bc57be04aacec5c8116" - integrity sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY= - dependencies: - is-descriptor "^0.1.0" - -define-property@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/define-property/-/define-property-1.0.0.tgz#769ebaaf3f4a63aad3af9e8d304c9bbe79bfb0e6" - integrity sha1-dp66rz9KY6rTr56NMEybvnm/sOY= - dependencies: - is-descriptor "^1.0.0" - -define-property@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/define-property/-/define-property-2.0.2.tgz#d459689e8d654ba77e02a817f8710d702cb16e9d" - integrity sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ== - dependencies: - is-descriptor "^1.0.2" - isobject "^3.0.1" - -del@^4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/del/-/del-4.1.1.tgz#9e8f117222ea44a31ff3a156c049b99052a9f0b4" - integrity sha512-QwGuEUouP2kVwQenAsOof5Fv8K9t3D8Ca8NxcXKrIpEHjTXK5J2nXLdP+ALI1cgv8wj7KuwBhTwBkOZSJKM5XQ== - dependencies: - "@types/glob" "^7.1.1" - globby "^6.1.0" - is-path-cwd "^2.0.0" - is-path-in-cwd "^2.0.0" - p-map "^2.0.0" - pify "^4.0.1" - rimraf "^2.6.3" - -delayed-stream@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" - integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk= - -depd@~1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" - integrity sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak= - -des.js@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/des.js/-/des.js-1.0.1.tgz#5382142e1bdc53f85d86d53e5f4aa7deb91e0843" - integrity sha512-Q0I4pfFrv2VPd34/vfLrFOoRmlYj3OV50i7fskps1jZWK1kApMWWT9G6RRUeYedLcBDIhnSDaUvJMb3AhUlaEA== - dependencies: - inherits "^2.0.1" - minimalistic-assert "^1.0.0" - -destroy@~1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" - integrity sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA= - -detect-node@^2.0.4: - version "2.1.0" - resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.1.0.tgz#c9c70775a49c3d03bc2c06d9a73be550f978f8b1" - integrity sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g== - -diff@^4.0.1: - version "4.0.2" - resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d" - integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A== - -diffie-hellman@^5.0.0: - version "5.0.3" - resolved "https://registry.yarnpkg.com/diffie-hellman/-/diffie-hellman-5.0.3.tgz#40e8ee98f55a2149607146921c63e1ae5f3d2875" - integrity sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg== - dependencies: - bn.js "^4.1.0" - miller-rabin "^4.0.0" - randombytes "^2.0.0" - -dir-glob@^2.0.0, dir-glob@^2.2.2: - version "2.2.2" - resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-2.2.2.tgz#fa09f0694153c8918b18ba0deafae94769fc50c4" - integrity sha512-f9LBi5QWzIW3I6e//uxZoLBlUt9kcp66qo0sSCxL6YZKc75R1c4MFCoe/LaZiBGmgujvQdxc5Bn3QhfyvK5Hsw== - dependencies: - path-type "^3.0.0" - -dir-glob@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f" - integrity sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA== - dependencies: - path-type "^4.0.0" - -dns-equal@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/dns-equal/-/dns-equal-1.0.0.tgz#b39e7f1da6eb0a75ba9c17324b34753c47e0654d" - integrity sha1-s55/HabrCnW6nBcySzR1PEfgZU0= - -dns-packet@^1.3.1: - version "1.3.4" - resolved "https://registry.yarnpkg.com/dns-packet/-/dns-packet-1.3.4.tgz#e3455065824a2507ba886c55a89963bb107dec6f" - integrity sha512-BQ6F4vycLXBvdrJZ6S3gZewt6rcrks9KBgM9vrhW+knGRqc8uEdT7fuCwloc7nny5xNoMJ17HGH0R/6fpo8ECA== - dependencies: - ip "^1.1.0" - safe-buffer "^5.0.1" - -dns-txt@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/dns-txt/-/dns-txt-2.0.2.tgz#b91d806f5d27188e4ab3e7d107d881a1cc4642b6" - integrity sha1-uR2Ab10nGI5Ks+fRB9iBocxGQrY= - dependencies: - buffer-indexof "^1.0.0" - -doctrine@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.1.0.tgz#5cd01fc101621b42c4cd7f5d1a66243716d3f39d" - integrity sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw== - dependencies: - esutils "^2.0.2" - -doctrine@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961" - integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w== - dependencies: - esutils "^2.0.2" - -dom-converter@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/dom-converter/-/dom-converter-0.2.0.tgz#6721a9daee2e293682955b6afe416771627bb768" - integrity sha512-gd3ypIPfOMr9h5jIKq8E3sHOTCjeirnl0WK5ZdS1AW0Odt0b1PaWaHdJ4Qk4klv+YB9aJBS7mESXjFoDQPu6DA== - dependencies: - utila "~0.4" - -dom-serializer@0: - version "0.2.2" - resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-0.2.2.tgz#1afb81f533717175d478655debc5e332d9f9bb51" - integrity sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g== - dependencies: - domelementtype "^2.0.1" - entities "^2.0.0" - -dom-serializer@^1.0.1: - version "1.3.2" - resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-1.3.2.tgz#6206437d32ceefaec7161803230c7a20bc1b4d91" - integrity sha512-5c54Bk5Dw4qAxNOI1pFEizPSjVsx5+bpJKmL2kPn8JhBUq2q09tTCa3mjijun2NfK78NMouDYNMBkOrPZiS+ig== - dependencies: - domelementtype "^2.0.1" - domhandler "^4.2.0" - entities "^2.0.0" - -domain-browser@^1.1.1: - version "1.2.0" - resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-1.2.0.tgz#3d31f50191a6749dd1375a7f522e823d42e54eda" - integrity sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA== - -domelementtype@1, domelementtype@^1.3.1: - version "1.3.1" - resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-1.3.1.tgz#d048c44b37b0d10a7f2a3d5fee3f4333d790481f" - integrity sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w== - -domelementtype@^2.0.1, domelementtype@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-2.2.0.tgz#9a0b6c2782ed6a1c7323d42267183df9bd8b1d57" - integrity sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A== - -domhandler@^4.0.0, domhandler@^4.2.0: - version "4.2.2" - resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-4.2.2.tgz#e825d721d19a86b8c201a35264e226c678ee755f" - integrity sha512-PzE9aBMsdZO8TK4BnuJwH0QT41wgMbRzuZrHUcpYncEjmQazq8QEaBWgLG7ZyC/DAZKEgglpIA6j4Qn/HmxS3w== - dependencies: - domelementtype "^2.2.0" - -domutils@^1.7.0: - version "1.7.0" - resolved "https://registry.yarnpkg.com/domutils/-/domutils-1.7.0.tgz#56ea341e834e06e6748af7a1cb25da67ea9f8c2a" - integrity sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg== - dependencies: - dom-serializer "0" - domelementtype "1" - -domutils@^2.5.2, domutils@^2.6.0: - version "2.8.0" - resolved "https://registry.yarnpkg.com/domutils/-/domutils-2.8.0.tgz#4437def5db6e2d1f5d6ee859bd95ca7d02048135" - integrity sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A== - dependencies: - dom-serializer "^1.0.1" - domelementtype "^2.2.0" - domhandler "^4.2.0" - -dot-prop@^5.2.0: - version "5.3.0" - resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-5.3.0.tgz#90ccce708cd9cd82cc4dc8c3ddd9abdd55b20e88" - integrity sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q== - dependencies: - is-obj "^2.0.0" - -dotenv-expand@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/dotenv-expand/-/dotenv-expand-5.1.0.tgz#3fbaf020bfd794884072ea26b1e9791d45a629f0" - integrity sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA== - -dotenv@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-7.0.0.tgz#a2be3cd52736673206e8a85fb5210eea29628e7c" - integrity sha512-M3NhsLbV1i6HuGzBUH8vXrtxOk+tWmzWKDMbAVSUp3Zsjm7ywFeuwrUXhmhQyRK1q5B5GGy7hcXPbj3bnfZg2g== - -duplexer@^0.1.1: - version "0.1.2" - resolved "https://registry.yarnpkg.com/duplexer/-/duplexer-0.1.2.tgz#3abe43aef3835f8ae077d136ddce0f276b0400e6" - integrity sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg== - -duplexify@^3.4.2, duplexify@^3.6.0: - version "3.7.1" - resolved "https://registry.yarnpkg.com/duplexify/-/duplexify-3.7.1.tgz#2a4df5317f6ccfd91f86d6fd25d8d8a103b88309" - integrity sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g== - dependencies: - end-of-stream "^1.0.0" - inherits "^2.0.1" - readable-stream "^2.0.0" - stream-shift "^1.0.0" - -easy-stack@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/easy-stack/-/easy-stack-1.0.1.tgz#8afe4264626988cabb11f3c704ccd0c835411066" - integrity sha512-wK2sCs4feiiJeFXn3zvY0p41mdU5VUgbgs1rNsc/y5ngFUijdWd+iIN8eoyuZHKB8xN6BL4PdWmzqFmxNg6V2w== - -ecc-jsbn@~0.1.1: - version "0.1.2" - resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9" - integrity sha1-OoOpBOVDUyh4dMVkt1SThoSamMk= - dependencies: - jsbn "~0.1.0" - safer-buffer "^2.1.0" - -ee-first@1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" - integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0= - -ejs@^2.6.1: - version "2.7.4" - resolved "https://registry.yarnpkg.com/ejs/-/ejs-2.7.4.tgz#48661287573dcc53e366c7a1ae52c3a120eec9ba" - integrity sha512-7vmuyh5+kuUyJKePhQfRQBhXV5Ce+RnaeeQArKu1EAMpL3WbgMt5WG6uQZpEVvYSSsxMXRKOewtDk9RaTKXRlA== - -electron-to-chromium@^1.3.886: - version "1.3.892" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.892.tgz#0e3f5bb1de577e2e5a6dffd5a4b278c4a735cd39" - integrity sha512-YDW4yIjdfMnbRoBjRZ/aNQYmT6JgQFLwmTSDRJMQdrY4MByEzppdXp3rnJ0g4LBWcsYTUvwKKClYN1ofZ0COOQ== - -elliptic@^6.5.3: - version "6.5.4" - resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.4.tgz#da37cebd31e79a1367e941b592ed1fbebd58abbb" - integrity sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ== - dependencies: - bn.js "^4.11.9" - brorand "^1.1.0" - hash.js "^1.0.0" - hmac-drbg "^1.0.1" - inherits "^2.0.4" - minimalistic-assert "^1.0.1" - minimalistic-crypto-utils "^1.0.1" - -emoji-regex@^7.0.1: - version "7.0.3" - resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156" - integrity sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA== - -emoji-regex@^8.0.0: - version "8.0.0" - resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" - integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== - -emojis-list@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-2.1.0.tgz#4daa4d9db00f9819880c79fa457ae5b09a1fd389" - integrity sha1-TapNnbAPmBmIDHn6RXrlsJof04k= - -emojis-list@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-3.0.0.tgz#5570662046ad29e2e916e71aae260abdff4f6a78" - integrity sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q== - -encodeurl@~1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" - integrity sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k= - -end-of-stream@^1.0.0, end-of-stream@^1.1.0: - version "1.4.4" - resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0" - integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q== - dependencies: - once "^1.4.0" - -enhanced-resolve@^4.0.0, enhanced-resolve@^4.5.0: - version "4.5.0" - resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-4.5.0.tgz#2f3cfd84dbe3b487f18f2db2ef1e064a571ca5ec" - integrity sha512-Nv9m36S/vxpsI+Hc4/ZGRs0n9mXqSWGGq49zxb/cJfPAQMbUtttJAlNPS4AQzaBdw/pKskw5bMbekT/Y7W/Wlg== - dependencies: - graceful-fs "^4.1.2" - memory-fs "^0.5.0" - tapable "^1.0.0" - -entities@^2.0.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/entities/-/entities-2.2.0.tgz#098dc90ebb83d8dffa089d55256b351d34c4da55" - integrity sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A== - -entities@^2.0.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/entities/-/entities-2.2.0.tgz#098dc90ebb83d8dffa089d55256b351d34c4da55" - integrity sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A== - -entities@^2.0.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/entities/-/entities-2.2.0.tgz#098dc90ebb83d8dffa089d55256b351d34c4da55" - integrity sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A== - -entities@^2.0.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/entities/-/entities-2.2.0.tgz#098dc90ebb83d8dffa089d55256b351d34c4da55" - integrity sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A== - -entities@^2.0.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/entities/-/entities-2.2.0.tgz#098dc90ebb83d8dffa089d55256b351d34c4da55" - integrity sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A== - -errno@^0.1.3, errno@~0.1.7: - version "0.1.8" - resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.8.tgz#8bb3e9c7d463be4976ff888f76b4809ebc2e811f" - integrity sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A== - dependencies: - prr "~1.0.1" - -error-ex@^1.3.1: - version "1.3.2" - resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" - integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g== - dependencies: - is-arrayish "^0.2.1" - -error-stack-parser@^2.0.2: - version "2.0.6" - resolved "https://registry.yarnpkg.com/error-stack-parser/-/error-stack-parser-2.0.6.tgz#5a99a707bd7a4c58a797902d48d82803ede6aad8" - integrity sha512-d51brTeqC+BHlwF0BhPtcYgF5nlzf9ZZ0ZIUQNZpc9ZB9qw5IJ2diTrBY9jlCJkTLITYPjmiX6OWCwH+fuyNgQ== - dependencies: - stackframe "^1.1.1" - -es-abstract@^1.17.2, es-abstract@^1.19.1: - version "1.19.1" - resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.19.1.tgz#d4885796876916959de78edaa0df456627115ec3" - integrity sha512-2vJ6tjA/UfqLm2MPs7jxVybLoB8i1t1Jd9R3kISld20sIxPcTbLuggQOUxeWeAvIUkduv/CfMjuh4WmiXr2v9w== - dependencies: - call-bind "^1.0.2" - es-to-primitive "^1.2.1" - function-bind "^1.1.1" - get-intrinsic "^1.1.1" - get-symbol-description "^1.0.0" - has "^1.0.3" - has-symbols "^1.0.2" - internal-slot "^1.0.3" - is-callable "^1.2.4" - is-negative-zero "^2.0.1" - is-regex "^1.1.4" - is-shared-array-buffer "^1.0.1" - is-string "^1.0.7" - is-weakref "^1.0.1" - object-inspect "^1.11.0" - object-keys "^1.1.1" - object.assign "^4.1.2" - string.prototype.trimend "^1.0.4" - string.prototype.trimstart "^1.0.4" - unbox-primitive "^1.0.1" - -es-to-primitive@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.1.tgz#e55cd4c9cdc188bcefb03b366c736323fc5c898a" - integrity sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA== - dependencies: - is-callable "^1.1.4" - is-date-object "^1.0.1" - is-symbol "^1.0.2" - -escalade@^3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" - integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== - -escape-html@~1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" - integrity sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg= - -escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" - integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= - -eslint-loader@^2.1.2: - version "2.2.1" - resolved "https://registry.yarnpkg.com/eslint-loader/-/eslint-loader-2.2.1.tgz#28b9c12da54057af0845e2a6112701a2f6bf8337" - integrity sha512-RLgV9hoCVsMLvOxCuNjdqOrUqIj9oJg8hF44vzJaYqsAHuY9G2YAeN3joQ9nxP0p5Th9iFSIpKo+SD8KISxXRg== - dependencies: - loader-fs-cache "^1.0.0" - loader-utils "^1.0.2" - object-assign "^4.0.1" - object-hash "^1.1.4" - rimraf "^2.6.1" - -eslint-plugin-vue@^4.7.1: - version "4.7.1" - resolved "https://registry.yarnpkg.com/eslint-plugin-vue/-/eslint-plugin-vue-4.7.1.tgz#c829b9fc62582c1897b5a0b94afd44ecca511e63" - integrity sha512-esETKhVMI7Vdli70Wt4bvAwnZBJeM0pxVX9Yb0wWKxdCJc2EADalVYK/q2FzMw8oKN0wPMdqVCKS8kmR89recA== - dependencies: - vue-eslint-parser "^2.0.3" - -eslint-plugin-vue@^5.0.0: - version "5.2.3" - resolved "https://registry.yarnpkg.com/eslint-plugin-vue/-/eslint-plugin-vue-5.2.3.tgz#3ee7597d823b5478804b2feba9863b1b74273961" - integrity sha512-mGwMqbbJf0+VvpGR5Lllq0PMxvTdrZ/ZPjmhkacrCHbubJeJOt+T6E3HUzAifa2Mxi7RSdJfC9HFpOeSYVMMIw== - dependencies: - vue-eslint-parser "^5.0.0" - -eslint-scope@^3.7.1: - version "3.7.3" - resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-3.7.3.tgz#bb507200d3d17f60247636160b4826284b108535" - integrity sha512-W+B0SvF4gamyCTmUc+uITPY0989iXVfKvhwtmJocTaYoc/3khEHmEmvfY/Gn9HA9VV75jrQECsHizkNw1b68FA== - dependencies: - esrecurse "^4.1.0" - estraverse "^4.1.1" - -eslint-scope@^4.0.0, eslint-scope@^4.0.3: - version "4.0.3" - resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-4.0.3.tgz#ca03833310f6889a3264781aa82e63eb9cfe7848" - integrity sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg== - dependencies: - esrecurse "^4.1.0" - estraverse "^4.1.1" - -eslint-scope@^5.1.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c" - integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw== - dependencies: - esrecurse "^4.3.0" - estraverse "^4.1.1" - -eslint-utils@^1.3.1: - version "1.4.3" - resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-1.4.3.tgz#74fec7c54d0776b6f67e0251040b5806564e981f" - integrity sha512-fbBN5W2xdY45KulGXmLHZ3c3FHfVYmKg0IrAKGOkT/464PQsx2UeIzfz1RmEci+KLm1bBaAzZAh8+/E+XAeZ8Q== - dependencies: - eslint-visitor-keys "^1.1.0" - -eslint-utils@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-3.0.0.tgz#8aebaface7345bb33559db0a1f13a1d2d48c3672" - integrity sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA== - dependencies: - eslint-visitor-keys "^2.0.0" - -eslint-visitor-keys@^1.0.0, eslint-visitor-keys@^1.1.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz#30ebd1ef7c2fdff01c3a4f151044af25fab0523e" - integrity sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ== - -eslint-visitor-keys@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz#f65328259305927392c938ed44eb0a5c9b2bd303" - integrity sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw== - -eslint@^4.19.1: - version "4.19.1" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-4.19.1.tgz#32d1d653e1d90408854bfb296f076ec7e186a300" - integrity sha512-bT3/1x1EbZB7phzYu7vCr1v3ONuzDtX8WjuM9c0iYxe+cq+pwcKEoQjl7zd3RpC6YOLgnSy3cTN58M2jcoPDIQ== - dependencies: - ajv "^5.3.0" - babel-code-frame "^6.22.0" - chalk "^2.1.0" - concat-stream "^1.6.0" - cross-spawn "^5.1.0" - debug "^3.1.0" - doctrine "^2.1.0" - eslint-scope "^3.7.1" - eslint-visitor-keys "^1.0.0" - espree "^3.5.4" - esquery "^1.0.0" - esutils "^2.0.2" - file-entry-cache "^2.0.0" - functional-red-black-tree "^1.0.1" - glob "^7.1.2" - globals "^11.0.1" - ignore "^3.3.3" - imurmurhash "^0.1.4" - inquirer "^3.0.6" - is-resolvable "^1.0.0" - js-yaml "^3.9.1" - json-stable-stringify-without-jsonify "^1.0.1" - levn "^0.3.0" - lodash "^4.17.4" - minimatch "^3.0.2" - mkdirp "^0.5.1" - natural-compare "^1.4.0" - optionator "^0.8.2" - path-is-inside "^1.0.2" - pluralize "^7.0.0" - progress "^2.0.0" - regexpp "^1.0.1" - require-uncached "^1.0.3" - semver "^5.3.0" - strip-ansi "^4.0.0" - strip-json-comments "~2.0.1" - table "4.0.2" - text-table "~0.2.0" - -eslint@^5.16.0: - version "5.16.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-5.16.0.tgz#a1e3ac1aae4a3fbd8296fcf8f7ab7314cbb6abea" - integrity sha512-S3Rz11i7c8AA5JPv7xAH+dOyq/Cu/VXHiHXBPOU1k/JAM5dXqQPt3qcrhpHSorXmrpu2g0gkIBVXAqCpzfoZIg== - dependencies: - "@babel/code-frame" "^7.0.0" - ajv "^6.9.1" - chalk "^2.1.0" - cross-spawn "^6.0.5" - debug "^4.0.1" - doctrine "^3.0.0" - eslint-scope "^4.0.3" - eslint-utils "^1.3.1" - eslint-visitor-keys "^1.0.0" - espree "^5.0.1" - esquery "^1.0.1" - esutils "^2.0.2" - file-entry-cache "^5.0.1" - functional-red-black-tree "^1.0.1" - glob "^7.1.2" - globals "^11.7.0" - ignore "^4.0.6" - import-fresh "^3.0.0" - imurmurhash "^0.1.4" - inquirer "^6.2.2" - js-yaml "^3.13.0" - json-stable-stringify-without-jsonify "^1.0.1" - levn "^0.3.0" - lodash "^4.17.11" - minimatch "^3.0.4" - mkdirp "^0.5.1" - natural-compare "^1.4.0" - optionator "^0.8.2" - path-is-inside "^1.0.2" - progress "^2.0.0" - regexpp "^2.0.1" - semver "^5.5.1" - strip-ansi "^4.0.0" - strip-json-comments "^2.0.1" - table "^5.2.3" - text-table "^0.2.0" - -espree@^3.5.2, espree@^3.5.4: - version "3.5.4" - resolved "https://registry.yarnpkg.com/espree/-/espree-3.5.4.tgz#b0f447187c8a8bed944b815a660bddf5deb5d1a7" - integrity sha512-yAcIQxtmMiB/jL32dzEp2enBeidsB7xWPLNiw3IIkpVds1P+h7qF9YwJq1yUNzp2OKXgAprs4F61ih66UsoD1A== - dependencies: - acorn "^5.5.0" - acorn-jsx "^3.0.0" - -espree@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/espree/-/espree-4.1.0.tgz#728d5451e0fd156c04384a7ad89ed51ff54eb25f" - integrity sha512-I5BycZW6FCVIub93TeVY1s7vjhP9CY6cXCznIRfiig7nRviKZYdRnj/sHEWC6A7WE9RDWOFq9+7OsWSYz8qv2w== - dependencies: - acorn "^6.0.2" - acorn-jsx "^5.0.0" - eslint-visitor-keys "^1.0.0" - -espree@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/espree/-/espree-5.0.1.tgz#5d6526fa4fc7f0788a5cf75b15f30323e2f81f7a" - integrity sha512-qWAZcWh4XE/RwzLJejfcofscgMc9CamR6Tn1+XRXNzrvUSSbiAjGOI/fggztjIi7y9VLPqnICMIPiGyr8JaZ0A== - dependencies: - acorn "^6.0.7" - acorn-jsx "^5.0.0" - eslint-visitor-keys "^1.0.0" - -esprima@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" - integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== - -esquery@^1.0.0, esquery@^1.0.1: - version "1.4.0" - resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.4.0.tgz#2148ffc38b82e8c7057dfed48425b3e61f0f24a5" - integrity sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w== - dependencies: - estraverse "^5.1.0" - -esrecurse@^4.1.0, esrecurse@^4.3.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921" - integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== - dependencies: - estraverse "^5.2.0" - -estraverse@^4.1.1: - version "4.3.0" - resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" - integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== - -estraverse@^5.1.0, estraverse@^5.2.0: - version "5.3.0" - resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" - integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== - -esutils@^2.0.2: - version "2.0.3" - resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" - integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== - -etag@~1.8.1: - version "1.8.1" - resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" - integrity sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc= - -event-pubsub@4.3.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/event-pubsub/-/event-pubsub-4.3.0.tgz#f68d816bc29f1ec02c539dc58c8dd40ce72cb36e" - integrity sha512-z7IyloorXvKbFx9Bpie2+vMJKKx1fH1EN5yiTfp8CiLOTptSYy1g8H4yDpGlEdshL1PBiFtBHepF2cNsqeEeFQ== - -eventemitter3@^4.0.0: - version "4.0.7" - resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f" - integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw== - -events@^3.0.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400" - integrity sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q== - -eventsource@^1.0.7: - version "1.1.0" - resolved "https://registry.yarnpkg.com/eventsource/-/eventsource-1.1.0.tgz#00e8ca7c92109e94b0ddf32dac677d841028cfaf" - integrity sha512-VSJjT5oCNrFvCS6igjzPAt5hBzQ2qPBFIbJ03zLI9SE0mxwZpMw6BfJrbFHm1a141AavMEB8JHmBhWAd66PfCg== - dependencies: - original "^1.0.0" - -evp_bytestokey@^1.0.0, evp_bytestokey@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz#7fcbdb198dc71959432efe13842684e0525acb02" - integrity sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA== - dependencies: - md5.js "^1.3.4" - safe-buffer "^5.1.1" - -execa@^0.8.0: - version "0.8.0" - resolved "https://registry.yarnpkg.com/execa/-/execa-0.8.0.tgz#d8d76bbc1b55217ed190fd6dd49d3c774ecfc8da" - integrity sha1-2NdrvBtVIX7RkP1t1J08d07PyNo= - dependencies: - 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" - -execa@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/execa/-/execa-1.0.0.tgz#c6236a5bb4df6d6f15e88e7f017798216749ddd8" - integrity sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA== - dependencies: - cross-spawn "^6.0.0" - get-stream "^4.0.0" - is-stream "^1.1.0" - npm-run-path "^2.0.0" - p-finally "^1.0.0" - signal-exit "^3.0.0" - strip-eof "^1.0.0" - -execa@^3.3.0: - version "3.4.0" - resolved "https://registry.yarnpkg.com/execa/-/execa-3.4.0.tgz#c08ed4550ef65d858fac269ffc8572446f37eb89" - integrity sha512-r9vdGQk4bmCuK1yKQu1KTwcT2zwfWdbdaXfCtAh+5nU/4fSX+JAb7vZGvI5naJrQlvONrEB20jeruESI69530g== - dependencies: - cross-spawn "^7.0.0" - get-stream "^5.0.0" - human-signals "^1.1.1" - is-stream "^2.0.0" - merge-stream "^2.0.0" - npm-run-path "^4.0.0" - onetime "^5.1.0" - p-finally "^2.0.0" - signal-exit "^3.0.2" - strip-final-newline "^2.0.0" - -expand-brackets@^2.1.4: - version "2.1.4" - resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-2.1.4.tgz#b77735e315ce30f6b6eff0f83b04151a22449622" - integrity sha1-t3c14xXOMPa27/D4OwQVGiJEliI= - dependencies: - debug "^2.3.3" - define-property "^0.2.5" - extend-shallow "^2.0.1" - posix-character-classes "^0.1.0" - regex-not "^1.0.0" - snapdragon "^0.8.1" - to-regex "^3.0.1" - -express@^4.16.3, express@^4.17.1: - version "4.17.1" - resolved "https://registry.yarnpkg.com/express/-/express-4.17.1.tgz#4491fc38605cf51f8629d39c2b5d026f98a4c134" - integrity sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g== - dependencies: - accepts "~1.3.7" - array-flatten "1.1.1" - body-parser "1.19.0" - content-disposition "0.5.3" - content-type "~1.0.4" - cookie "0.4.0" - cookie-signature "1.0.6" - debug "2.6.9" - depd "~1.1.2" - encodeurl "~1.0.2" - escape-html "~1.0.3" - etag "~1.8.1" - finalhandler "~1.1.2" - fresh "0.5.2" - merge-descriptors "1.0.1" - methods "~1.1.2" - on-finished "~2.3.0" - parseurl "~1.3.3" - path-to-regexp "0.1.7" - proxy-addr "~2.0.5" - qs "6.7.0" - range-parser "~1.2.1" - safe-buffer "5.1.2" - send "0.17.1" - serve-static "1.14.1" - setprototypeof "1.1.1" - statuses "~1.5.0" - type-is "~1.6.18" - utils-merge "1.0.1" - vary "~1.1.2" - -extend-shallow@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f" - integrity sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8= - dependencies: - is-extendable "^0.1.0" - -extend-shallow@^3.0.0, extend-shallow@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-3.0.2.tgz#26a71aaf073b39fb2127172746131c2704028db8" - integrity sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg= - dependencies: - assign-symbols "^1.0.0" - is-extendable "^1.0.1" - -extend@~3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" - integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== - -external-editor@^2.0.4: - version "2.2.0" - resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-2.2.0.tgz#045511cfd8d133f3846673d1047c154e214ad3d5" - integrity sha512-bSn6gvGxKt+b7+6TKEv1ZycHleA7aHhRHyAqJyp5pbUFuYYNIzpZnQDk7AsYckyWdEnTeAnay0aCy2aV6iTk9A== - dependencies: - chardet "^0.4.0" - iconv-lite "^0.4.17" - tmp "^0.0.33" - -external-editor@^3.0.3: - version "3.1.0" - resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-3.1.0.tgz#cb03f740befae03ea4d283caed2741a83f335495" - integrity sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew== - dependencies: - chardet "^0.7.0" - iconv-lite "^0.4.24" - tmp "^0.0.33" - -extglob@^2.0.4: - version "2.0.4" - resolved "https://registry.yarnpkg.com/extglob/-/extglob-2.0.4.tgz#ad00fe4dc612a9232e8718711dc5cb5ab0285543" - integrity sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw== - dependencies: - array-unique "^0.3.2" - define-property "^1.0.0" - expand-brackets "^2.1.4" - extend-shallow "^2.0.1" - fragment-cache "^0.2.1" - regex-not "^1.0.0" - snapdragon "^0.8.1" - to-regex "^3.0.1" - -extsprintf@1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05" - integrity sha1-lpGEQOMEGnpBT4xS48V06zw+HgU= - -extsprintf@^1.2.0: - version "1.4.1" - resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.1.tgz#8d172c064867f235c0c84a596806d279bf4bcc07" - integrity sha512-Wrk35e8ydCKDj/ArClo1VrPVmN8zph5V4AtHwIuHhvMXsKf73UT3BOD+azBIW+3wOJ4FhEH7zyaJCFvChjYvMA== - -fast-deep-equal@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz#c053477817c86b51daa853c81e059b733d023614" - integrity sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ= - -fast-deep-equal@^3.1.1: - version "3.1.3" - resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" - integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== - -fast-glob@^2.2.6: - version "2.2.7" - resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-2.2.7.tgz#6953857c3afa475fff92ee6015d52da70a4cd39d" - integrity sha512-g1KuQwHOZAmOZMuBtHdxDtju+T2RT8jgCC9aANsbpdiDDTSnjgfuVsIBNKbUeJI3oKMRExcfNDtJl4OhbffMsw== - dependencies: - "@mrmlnc/readdir-enhanced" "^2.2.1" - "@nodelib/fs.stat" "^1.1.2" - glob-parent "^3.1.0" - is-glob "^4.0.0" - merge2 "^1.2.3" - micromatch "^3.1.10" - -fast-glob@^3.1.1: - version "3.2.7" - resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.7.tgz#fd6cb7a2d7e9aa7a7846111e85a196d6b2f766a1" - integrity sha512-rYGMRwip6lUMvYD3BTScMwT1HtAs2d71SMv66Vrxs0IekGZEjhM0pcMfjQPnknBt2zeCwQMEupiN02ZP4DiT1Q== - dependencies: - "@nodelib/fs.stat" "^2.0.2" - "@nodelib/fs.walk" "^1.2.3" - glob-parent "^5.1.2" - merge2 "^1.3.0" - micromatch "^4.0.4" - -fast-json-stable-stringify@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" - integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== - -fast-levenshtein@~2.0.6: - version "2.0.6" - resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" - integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc= - -fastparse@^1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/fastparse/-/fastparse-1.1.2.tgz#91728c5a5942eced8531283c79441ee4122c35a9" - integrity sha512-483XLLxTVIwWK3QTrMGRqUfUpoOs/0hbQrl2oz4J0pAcm3A3bu84wxTFqGqkJzewCLdME38xJLJAxBABfQT8sQ== - -fastq@^1.6.0: - version "1.13.0" - resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.13.0.tgz#616760f88a7526bdfc596b7cab8c18938c36b98c" - integrity sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw== - dependencies: - reusify "^1.0.4" - -faye-websocket@^0.11.3: - version "0.11.4" - resolved "https://registry.yarnpkg.com/faye-websocket/-/faye-websocket-0.11.4.tgz#7f0d9275cfdd86a1c963dc8b65fcc451edcbb1da" - integrity sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g== - dependencies: - websocket-driver ">=0.5.1" - -figgy-pudding@^3.5.1: - version "3.5.2" - resolved "https://registry.yarnpkg.com/figgy-pudding/-/figgy-pudding-3.5.2.tgz#b4eee8148abb01dcf1d1ac34367d59e12fa61d6e" - integrity sha512-0btnI/H8f2pavGMN8w40mlSKOfTK2SVJmBfBeVIj3kNw0swwgzyRq0d5TJVOwodFmtvpPeWPN/MCcfuWF0Ezbw== - -figures@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/figures/-/figures-2.0.0.tgz#3ab1a2d2a62c8bfb431a0c94cb797a2fce27c962" - integrity sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI= - dependencies: - escape-string-regexp "^1.0.5" - -file-entry-cache@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-2.0.0.tgz#c392990c3e684783d838b8c84a45d8a048458361" - integrity sha1-w5KZDD5oR4PYOLjISkXYoEhFg2E= - dependencies: - flat-cache "^1.2.1" - object-assign "^4.0.1" - -file-entry-cache@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-5.0.1.tgz#ca0f6efa6dd3d561333fb14515065c2fafdf439c" - integrity sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g== - dependencies: - flat-cache "^2.0.1" - -file-loader@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/file-loader/-/file-loader-3.0.1.tgz#f8e0ba0b599918b51adfe45d66d1e771ad560faa" - integrity sha512-4sNIOXgtH/9WZq4NvlfU3Opn5ynUsqBwSLyM+I7UOwdGigTBYfVVQEwe/msZNX/j4pCJTIM14Fsw66Svo1oVrw== - dependencies: - loader-utils "^1.0.2" - schema-utils "^1.0.0" - -file-saver@^2.0.2: - version "2.0.5" - resolved "https://registry.yarnpkg.com/file-saver/-/file-saver-2.0.5.tgz#d61cfe2ce059f414d899e9dd6d4107ee25670c38" - integrity sha512-P9bmyZ3h/PRG+Nzga+rbdI4OEpNDzAVyy74uVO9ATgzLK6VtAsYybF/+TOCvrc0MO793d6+42lLyZTw7/ArVzA== - -file-uri-to-path@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz#553a7b8446ff6f684359c445f1e37a05dacc33dd" - integrity sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw== - -filesize@^3.6.1: - version "3.6.1" - resolved "https://registry.yarnpkg.com/filesize/-/filesize-3.6.1.tgz#090bb3ee01b6f801a8a8be99d31710b3422bb317" - integrity sha512-7KjR1vv6qnicaPMi1iiTcI85CyYwRO/PSFCu6SvqL8jN2Wjt/NIYQTFtFs7fSDCYOstUkEWIQGFUg5YZQfjlcg== - -fill-range@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-4.0.0.tgz#d544811d428f98eb06a63dc402d2403c328c38f7" - integrity sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc= - dependencies: - extend-shallow "^2.0.1" - is-number "^3.0.0" - repeat-string "^1.6.1" - to-regex-range "^2.1.0" - -fill-range@^7.0.1: - version "7.0.1" - resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" - integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== - dependencies: - to-regex-range "^5.0.1" - -finalhandler@~1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.2.tgz#b7e7d000ffd11938d0fdb053506f6ebabe9f587d" - integrity sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA== - dependencies: - debug "2.6.9" - encodeurl "~1.0.2" - escape-html "~1.0.3" - on-finished "~2.3.0" - parseurl "~1.3.3" - statuses "~1.5.0" - unpipe "~1.0.0" - -find-cache-dir@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-0.1.1.tgz#c8defae57c8a52a8a784f9e31c57c742e993a0b9" - integrity sha1-yN765XyKUqinhPnjHFfHQumToLk= - dependencies: - commondir "^1.0.1" - mkdirp "^0.5.1" - pkg-dir "^1.0.0" - -find-cache-dir@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-1.0.0.tgz#9288e3e9e3cc3748717d39eade17cf71fc30ee6f" - integrity sha1-kojj6ePMN0hxfTnq3hfPcfww7m8= - dependencies: - commondir "^1.0.1" - make-dir "^1.0.0" - pkg-dir "^2.0.0" - -find-cache-dir@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-2.1.0.tgz#8d0f94cd13fe43c6c7c261a0d86115ca918c05f7" - integrity sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ== - dependencies: - commondir "^1.0.1" - make-dir "^2.0.0" - pkg-dir "^3.0.0" - -find-cache-dir@^3.0.0: - version "3.3.2" - resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-3.3.2.tgz#b30c5b6eff0730731aea9bbd9dbecbd80256d64b" - integrity sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig== - dependencies: - commondir "^1.0.1" - make-dir "^3.0.2" - pkg-dir "^4.1.0" - -find-up@^1.0.0: - version "1.1.2" - resolved "https://registry.yarnpkg.com/find-up/-/find-up-1.1.2.tgz#6b2e9822b1a2ce0a60ab64d610eccad53cb24d0f" - integrity sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8= - dependencies: - path-exists "^2.0.0" - pinkie-promise "^2.0.0" - -find-up@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7" - integrity sha1-RdG35QbHF93UgndaK3eSCjwMV6c= - dependencies: - locate-path "^2.0.0" - -find-up@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/find-up/-/find-up-3.0.0.tgz#49169f1d7993430646da61ecc5ae355c21c97b73" - integrity sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg== - dependencies: - locate-path "^3.0.0" - -find-up@^4.0.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19" - integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw== - dependencies: - locate-path "^5.0.0" - path-exists "^4.0.0" - -flat-cache@^1.2.1: - version "1.3.4" - resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-1.3.4.tgz#2c2ef77525cc2929007dfffa1dd314aa9c9dee6f" - integrity sha512-VwyB3Lkgacfik2vhqR4uv2rvebqmDvFu4jlN/C1RzWoJEo8I7z4Q404oiqYCkq41mni8EzQnm95emU9seckwtg== - dependencies: - circular-json "^0.3.1" - graceful-fs "^4.1.2" - rimraf "~2.6.2" - write "^0.2.1" - -flat-cache@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-2.0.1.tgz#5d296d6f04bda44a4630a301413bdbc2ec085ec0" - integrity sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA== - dependencies: - flatted "^2.0.0" - rimraf "2.6.3" - write "1.0.3" - -flatted@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/flatted/-/flatted-2.0.2.tgz#4575b21e2bcee7434aa9be662f4b7b5f9c2b5138" - integrity sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA== - -flush-write-stream@^1.0.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/flush-write-stream/-/flush-write-stream-1.1.1.tgz#8dd7d873a1babc207d94ead0c2e0e44276ebf2e8" - integrity sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w== - dependencies: - inherits "^2.0.3" - readable-stream "^2.3.6" - -follow-redirects@1.5.10: - version "1.5.10" - resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.5.10.tgz#7b7a9f9aea2fdff36786a94ff643ed07f4ff5e2a" - integrity sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ== - dependencies: - debug "=3.1.0" - -follow-redirects@^1.0.0: - version "1.14.5" - resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.14.5.tgz#f09a5848981d3c772b5392309778523f8d85c381" - integrity sha512-wtphSXy7d4/OR+MvIFbCVBDzZ5520qV8XfPklSN5QtxuMUJZ+b0Wnst1e1lCDocfzuCkHqj8k0FpZqO+UIaKNA== - -for-in@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" - integrity sha1-gQaNKVqBQuwKxybG4iAMMPttXoA= - -forever-agent@~0.6.1: - version "0.6.1" - resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" - integrity sha1-+8cfDEGt6zf5bFd60e1C2P2sypE= - -"fork-ts-checker-webpack-plugin-v5@npm:fork-ts-checker-webpack-plugin@^5.0.11": - version "5.2.1" - resolved "https://registry.yarnpkg.com/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-5.2.1.tgz#79326d869797906fa8b24e2abcf9421fc805450d" - integrity sha512-SVi+ZAQOGbtAsUWrZvGzz38ga2YqjWvca1pXQFUArIVXqli0lLoDQ8uS0wg0kSpcwpZmaW5jVCZXQebkyUQSsw== - dependencies: - "@babel/code-frame" "^7.8.3" - "@types/json-schema" "^7.0.5" - chalk "^4.1.0" - cosmiconfig "^6.0.0" - deepmerge "^4.2.2" - fs-extra "^9.0.0" - memfs "^3.1.2" - minimatch "^3.0.4" - schema-utils "2.7.0" - semver "^7.3.2" - tapable "^1.0.0" - -fork-ts-checker-webpack-plugin@^3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-3.1.1.tgz#a1642c0d3e65f50c2cc1742e9c0a80f441f86b19" - integrity sha512-DuVkPNrM12jR41KM2e+N+styka0EgLkTnXmNcXdgOM37vtGeY+oCBK/Jx0hzSeEU6memFCtWb4htrHPMDfwwUQ== - dependencies: - babel-code-frame "^6.22.0" - chalk "^2.4.1" - chokidar "^3.3.0" - micromatch "^3.1.10" - minimatch "^3.0.4" - semver "^5.6.0" - tapable "^1.0.0" - worker-rpc "^0.1.0" - -form-data@~2.3.2: - version "2.3.3" - resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6" - integrity sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ== - dependencies: - asynckit "^0.4.0" - combined-stream "^1.0.6" - mime-types "^2.1.12" - -forwarded@0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811" - integrity sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow== - -fragment-cache@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/fragment-cache/-/fragment-cache-0.2.1.tgz#4290fad27f13e89be7f33799c6bc5a0abfff0d19" - integrity sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk= - dependencies: - map-cache "^0.2.2" - -fresh@0.5.2: - version "0.5.2" - resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" - integrity sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac= - -from2@^2.1.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/from2/-/from2-2.3.0.tgz#8bfb5502bde4a4d36cfdeea007fcca21d7e382af" - integrity sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8= - dependencies: - inherits "^2.0.1" - readable-stream "^2.0.0" - -fs-extra@^7.0.1: - version "7.0.1" - resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-7.0.1.tgz#4f189c44aa123b895f722804f55ea23eadc348e9" - integrity sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw== - dependencies: - graceful-fs "^4.1.2" - jsonfile "^4.0.0" - universalify "^0.1.0" - -fs-extra@^9.0.0: - version "9.1.0" - resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-9.1.0.tgz#5954460c764a8da2094ba3554bf839e6b9a7c86d" - integrity sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ== - dependencies: - at-least-node "^1.0.0" - graceful-fs "^4.2.0" - jsonfile "^6.0.1" - universalify "^2.0.0" - -fs-monkey@1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/fs-monkey/-/fs-monkey-1.0.3.tgz#ae3ac92d53bb328efe0e9a1d9541f6ad8d48e2d3" - integrity sha512-cybjIfiiE+pTWicSCLFHSrXZ6EilF30oh91FDP9S2B051prEa7QWfrVTQm10/dDpswBDXZugPa1Ogu8Yh+HV0Q== - -fs-write-stream-atomic@^1.0.8: - version "1.0.10" - resolved "https://registry.yarnpkg.com/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz#b47df53493ef911df75731e70a9ded0189db40c9" - integrity sha1-tH31NJPvkR33VzHnCp3tAYnbQMk= - dependencies: - graceful-fs "^4.1.2" - iferr "^0.1.5" - imurmurhash "^0.1.4" - readable-stream "1 || 2" - -fs.realpath@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" - integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= - -fsevents@^1.2.7: - version "1.2.13" - resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.2.13.tgz#f325cb0455592428bcf11b383370ef70e3bfcc38" - integrity sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw== - dependencies: - bindings "^1.5.0" - nan "^2.12.1" - -fsevents@~2.3.2: - version "2.3.2" - resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" - integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== - -function-bind@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" - integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== - -functional-red-black-tree@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" - integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc= - -get-caller-file@^2.0.1, get-caller-file@^2.0.5: - version "2.0.5" - resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" - integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== - -get-intrinsic@^1.0.2, get-intrinsic@^1.1.0, get-intrinsic@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.1.1.tgz#15f59f376f855c446963948f0d24cd3637b4abc6" - integrity sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q== - dependencies: - function-bind "^1.1.1" - has "^1.0.3" - has-symbols "^1.0.1" - -get-stream@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14" - integrity sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ= - -get-stream@^4.0.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5" - integrity sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w== - dependencies: - pump "^3.0.0" - -get-stream@^5.0.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-5.2.0.tgz#4966a1795ee5ace65e706c4b7beb71257d6e22d3" - integrity sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA== - dependencies: - pump "^3.0.0" - -get-symbol-description@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/get-symbol-description/-/get-symbol-description-1.0.0.tgz#7fdb81c900101fbd564dd5f1a30af5aadc1e58d6" - integrity sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw== - dependencies: - call-bind "^1.0.2" - get-intrinsic "^1.1.1" - -get-value@^2.0.3, get-value@^2.0.6: - version "2.0.6" - resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28" - integrity sha1-3BXKHGcjh8p2vTesCjlbogQqLCg= - -getpass@^0.1.1: - version "0.1.7" - resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa" - integrity sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo= - dependencies: - assert-plus "^1.0.0" - -glob-parent@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-3.1.0.tgz#9e6af6299d8d3bd2bd40430832bd113df906c5ae" - integrity sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4= - dependencies: - is-glob "^3.1.0" - path-dirname "^1.0.0" - -glob-parent@^5.1.2, glob-parent@~5.1.2: - version "5.1.2" - resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" - integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== - dependencies: - is-glob "^4.0.1" - -glob-to-regexp@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.3.0.tgz#8c5a1494d2066c570cc3bfe4496175acc4d502ab" - integrity sha1-jFoUlNIGbFcMw7/kSWF1rMTVAqs= - -glob@^7.0.3, glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4: - version "7.2.0" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.0.tgz#d15535af7732e02e948f4c41628bd910293f6023" - integrity sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q== - dependencies: - fs.realpath "^1.0.0" - inflight "^1.0.4" - inherits "2" - minimatch "^3.0.4" - once "^1.3.0" - path-is-absolute "^1.0.0" - -globals@^11.0.1, globals@^11.1.0, globals@^11.7.0: - version "11.12.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" - integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== - -globby@^11.0.3: - version "11.0.4" - resolved "https://registry.yarnpkg.com/globby/-/globby-11.0.4.tgz#2cbaff77c2f2a62e71e9b2813a67b97a3a3001a5" - integrity sha512-9O4MVG9ioZJ08ffbcyVYyLOJLk5JQ688pJ4eMGLpdWLHq/Wr1D9BlriLQyL0E+jbkuePVZXYFj47QM/v093wHg== - dependencies: - array-union "^2.1.0" - dir-glob "^3.0.1" - fast-glob "^3.1.1" - ignore "^5.1.4" - merge2 "^1.3.0" - slash "^3.0.0" - -globby@^6.1.0: - version "6.1.0" - resolved "https://registry.yarnpkg.com/globby/-/globby-6.1.0.tgz#f5a6d70e8395e21c858fb0489d64df02424d506c" - integrity sha1-9abXDoOV4hyFj7BInWTfAkJNUGw= - dependencies: - array-union "^1.0.1" - glob "^7.0.3" - object-assign "^4.0.1" - pify "^2.0.0" - pinkie-promise "^2.0.0" - -globby@^7.1.1: - version "7.1.1" - resolved "https://registry.yarnpkg.com/globby/-/globby-7.1.1.tgz#fb2ccff9401f8600945dfada97440cca972b8680" - integrity sha1-+yzP+UAfhgCUXfral0QMypcrhoA= - dependencies: - 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" - -globby@^9.2.0: - version "9.2.0" - resolved "https://registry.yarnpkg.com/globby/-/globby-9.2.0.tgz#fd029a706c703d29bdd170f4b6db3a3f7a7cb63d" - integrity sha512-ollPHROa5mcxDEkwg6bPt3QbEf4pDQSNtd6JPL1YvOvAo/7/0VAm9TccUeoTmarjPw4pfUthSCqcyfNB1I3ZSg== - dependencies: - "@types/glob" "^7.1.1" - array-union "^1.0.2" - dir-glob "^2.2.2" - fast-glob "^2.2.6" - glob "^7.1.3" - ignore "^4.0.3" - pify "^4.0.1" - slash "^2.0.0" - -graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0: - version "4.2.8" - resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.8.tgz#e412b8d33f5e006593cbd3cee6df9f2cebbe802a" - integrity sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg== - -gzip-size@^5.0.0: - version "5.1.1" - resolved "https://registry.yarnpkg.com/gzip-size/-/gzip-size-5.1.1.tgz#cb9bee692f87c0612b232840a873904e4c135274" - integrity sha512-FNHi6mmoHvs1mxZAds4PpdCS6QG8B4C1krxJsMutgxl5t3+GlRTzzI3NEkifXx2pVsOvJdOGSmIgDhQ55FwdPA== - dependencies: - duplexer "^0.1.1" - pify "^4.0.1" - -handle-thing@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/handle-thing/-/handle-thing-2.0.1.tgz#857f79ce359580c340d43081cc648970d0bb234e" - integrity sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg== - -har-schema@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92" - integrity sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI= - -har-validator@~5.1.3: - version "5.1.5" - resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.1.5.tgz#1f0803b9f8cb20c0fa13822df1ecddb36bde1efd" - integrity sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w== - dependencies: - ajv "^6.12.3" - har-schema "^2.0.0" - -has-ansi@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" - integrity sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE= - dependencies: - ansi-regex "^2.0.0" - -has-bigints@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/has-bigints/-/has-bigints-1.0.1.tgz#64fe6acb020673e3b78db035a5af69aa9d07b113" - integrity sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA== - -has-flag@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" - integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= - -has-flag@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" - integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== - -has-symbols@^1.0.1, has-symbols@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.2.tgz#165d3070c00309752a1236a479331e3ac56f1423" - integrity sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw== - -has-tostringtag@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.0.tgz#7e133818a7d394734f941e73c3d3f9291e658b25" - integrity sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ== - dependencies: - has-symbols "^1.0.2" - -has-value@^0.3.1: - version "0.3.1" - resolved "https://registry.yarnpkg.com/has-value/-/has-value-0.3.1.tgz#7b1f58bada62ca827ec0a2078025654845995e1f" - integrity sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8= - dependencies: - get-value "^2.0.3" - has-values "^0.1.4" - isobject "^2.0.0" - -has-value@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/has-value/-/has-value-1.0.0.tgz#18b281da585b1c5c51def24c930ed29a0be6b177" - integrity sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc= - dependencies: - get-value "^2.0.6" - has-values "^1.0.0" - isobject "^3.0.0" - -has-values@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/has-values/-/has-values-0.1.4.tgz#6d61de95d91dfca9b9a02089ad384bff8f62b771" - integrity sha1-bWHeldkd/Km5oCCJrThL/49it3E= - -has-values@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/has-values/-/has-values-1.0.0.tgz#95b0b63fec2146619a6fe57fe75628d5a39efe4f" - integrity sha1-lbC2P+whRmGab+V/51Yo1aOe/k8= - dependencies: - is-number "^3.0.0" - kind-of "^4.0.0" - -has@^1.0.0, has@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" - integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== - dependencies: - function-bind "^1.1.1" - -hash-base@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/hash-base/-/hash-base-3.1.0.tgz#55c381d9e06e1d2997a883b4a3fddfe7f0d3af33" - integrity sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA== - dependencies: - inherits "^2.0.4" - readable-stream "^3.6.0" - safe-buffer "^5.2.0" - -hash-sum@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/hash-sum/-/hash-sum-1.0.2.tgz#33b40777754c6432573c120cc3808bbd10d47f04" - integrity sha1-M7QHd3VMZDJXPBIMw4CLvRDUfwQ= - -hash.js@^1.0.0, hash.js@^1.0.3: - version "1.1.7" - resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.1.7.tgz#0babca538e8d4ee4a0f8988d68866537a003cf42" - integrity sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA== - dependencies: - inherits "^2.0.3" - minimalistic-assert "^1.0.1" - -he@1.2.x, he@^1.1.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" - integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== - -hex-color-regex@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/hex-color-regex/-/hex-color-regex-1.1.0.tgz#4c06fccb4602fe2602b3c93df82d7e7dbf1a8a8e" - integrity sha512-l9sfDFsuqtOqKDsQdqrMRk0U85RZc0RtOR9yPI7mRVOa4FsR/BVnZ0shmQRM96Ji99kYZP/7hn1cedc1+ApsTQ== - -highlight.js@^10.7.1: - version "10.7.3" - resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-10.7.3.tgz#697272e3991356e40c3cac566a74eef681756531" - integrity sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A== - -highlight.js@^9.12.0: - version "9.18.5" - resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-9.18.5.tgz#d18a359867f378c138d6819edfc2a8acd5f29825" - integrity sha512-a5bFyofd/BHCX52/8i8uJkjr9DYwXIPnM/plwI6W7ezItLGqzt7X2G2nXuYSfsIJdkwwj/g9DG1LkcGJI/dDoA== - -hmac-drbg@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1" - integrity sha1-0nRXAQJabHdabFRXk+1QL8DGSaE= - dependencies: - hash.js "^1.0.3" - minimalistic-assert "^1.0.0" - minimalistic-crypto-utils "^1.0.1" - -hoopy@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/hoopy/-/hoopy-0.1.4.tgz#609207d661100033a9a9402ad3dea677381c1b1d" - integrity sha512-HRcs+2mr52W0K+x8RzcLzuPPmVIKMSv97RGHy0Ea9y/mpcaK+xTrjICA04KAHi4GRzxliNqNJEFYWHghy3rSfQ== - -hosted-git-info@^2.1.4: - version "2.8.9" - resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.9.tgz#dffc0bf9a21c02209090f2aa69429e1414daf3f9" - integrity sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw== - -hpack.js@^2.1.6: - version "2.1.6" - resolved "https://registry.yarnpkg.com/hpack.js/-/hpack.js-2.1.6.tgz#87774c0949e513f42e84575b3c45681fade2a0b2" - integrity sha1-h3dMCUnlE/QuhFdbPEVoH63ioLI= - dependencies: - inherits "^2.0.1" - obuf "^1.0.0" - readable-stream "^2.0.1" - wbuf "^1.1.0" - -hsl-regex@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/hsl-regex/-/hsl-regex-1.0.0.tgz#d49330c789ed819e276a4c0d272dffa30b18fe6e" - integrity sha1-1JMwx4ntgZ4nakwNJy3/owsY/m4= - -hsla-regex@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/hsla-regex/-/hsla-regex-1.0.0.tgz#c1ce7a3168c8c6614033a4b5f7877f3b225f9c38" - integrity sha1-wc56MWjIxmFAM6S194d/OyJfnDg= - -html-entities@^1.3.1: - version "1.4.0" - resolved "https://registry.yarnpkg.com/html-entities/-/html-entities-1.4.0.tgz#cfbd1b01d2afaf9adca1b10ae7dffab98c71d2dc" - integrity sha512-8nxjcBcd8wovbeKx7h3wTji4e6+rhaVuPNpMqwWgnHh+N9ToqsCs6XztWRBPQ+UtzsoMAdKZtUENoVzU/EMtZA== - -html-minifier@^3.2.3: - version "3.5.21" - resolved "https://registry.yarnpkg.com/html-minifier/-/html-minifier-3.5.21.tgz#d0040e054730e354db008463593194015212d20c" - integrity sha512-LKUKwuJDhxNa3uf/LPR/KVjm/l3rBqtYeCOAekvG8F1vItxMUpueGd94i/asDDr8/1u7InxzFA5EeGjhhG5mMA== - dependencies: - camel-case "3.0.x" - clean-css "4.2.x" - commander "2.17.x" - he "1.2.x" - param-case "2.1.x" - relateurl "0.2.x" - uglify-js "3.4.x" - -html-webpack-plugin@^3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/html-webpack-plugin/-/html-webpack-plugin-3.2.0.tgz#b01abbd723acaaa7b37b6af4492ebda03d9dd37b" - integrity sha1-sBq71yOsqqeze2r0SS69oD2d03s= - dependencies: - html-minifier "^3.2.3" - loader-utils "^0.2.16" - lodash "^4.17.3" - pretty-error "^2.0.2" - tapable "^1.0.0" - toposort "^1.0.0" - util.promisify "1.0.0" - -htmlparser2@^6.1.0: - version "6.1.0" - resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-6.1.0.tgz#c4d762b6c3371a05dbe65e94ae43a9f845fb8fb7" - integrity sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A== - dependencies: - domelementtype "^2.0.1" - domhandler "^4.0.0" - domutils "^2.5.2" - entities "^2.0.0" - -http-deceiver@^1.2.7: - version "1.2.7" - resolved "https://registry.yarnpkg.com/http-deceiver/-/http-deceiver-1.2.7.tgz#fa7168944ab9a519d337cb0bec7284dc3e723d87" - integrity sha1-+nFolEq5pRnTN8sL7HKE3D5yPYc= - -http-errors@1.7.2: - version "1.7.2" - resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.2.tgz#4f5029cf13239f31036e5b2e55292bcfbcc85c8f" - integrity sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg== - dependencies: - depd "~1.1.2" - inherits "2.0.3" - setprototypeof "1.1.1" - statuses ">= 1.5.0 < 2" - toidentifier "1.0.0" - -http-errors@~1.6.2: - version "1.6.3" - resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.3.tgz#8b55680bb4be283a0b5bf4ea2e38580be1d9320d" - integrity sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0= - dependencies: - depd "~1.1.2" - inherits "2.0.3" - setprototypeof "1.1.0" - statuses ">= 1.4.0 < 2" - -http-errors@~1.7.2: - version "1.7.3" - resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.3.tgz#6c619e4f9c60308c38519498c14fbb10aacebb06" - integrity sha512-ZTTX0MWrsQ2ZAhA1cejAwDLycFsd7I7nVtnkT3Ol0aqodaKW+0CTZDQ1uBv5whptCnc8e8HeRRJxRs0kmm/Qfw== - dependencies: - depd "~1.1.2" - inherits "2.0.4" - setprototypeof "1.1.1" - statuses ">= 1.5.0 < 2" - toidentifier "1.0.0" - -http-parser-js@>=0.5.1: - version "0.5.3" - resolved "https://registry.yarnpkg.com/http-parser-js/-/http-parser-js-0.5.3.tgz#01d2709c79d41698bb01d4decc5e9da4e4a033d9" - integrity sha512-t7hjvef/5HEK7RWTdUzVUhl8zkEu+LlaE0IYzdMuvbSDipxBRpOn4Uhw8ZyECEa808iVT8XCjzo6xmYt4CiLZg== - -http-proxy-middleware@0.19.1: - version "0.19.1" - resolved "https://registry.yarnpkg.com/http-proxy-middleware/-/http-proxy-middleware-0.19.1.tgz#183c7dc4aa1479150306498c210cdaf96080a43a" - integrity sha512-yHYTgWMQO8VvwNS22eLLloAkvungsKdKTLO8AJlftYIKNfJr3GK3zK0ZCfzDDGUBttdGc8xFy1mCitvNKQtC3Q== - dependencies: - http-proxy "^1.17.0" - is-glob "^4.0.0" - lodash "^4.17.11" - micromatch "^3.1.10" - -http-proxy@^1.17.0: - version "1.18.1" - resolved "https://registry.yarnpkg.com/http-proxy/-/http-proxy-1.18.1.tgz#401541f0534884bbf95260334e72f88ee3976549" - integrity sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ== - dependencies: - eventemitter3 "^4.0.0" - follow-redirects "^1.0.0" - requires-port "^1.0.0" - -http-signature@~1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1" - integrity sha1-muzZJRFHcvPZW2WmCruPfBj7rOE= - dependencies: - assert-plus "^1.0.0" - jsprim "^1.2.2" - sshpk "^1.7.0" - -https-browserify@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-1.0.0.tgz#ec06c10e0a34c0f2faf199f7fd7fc78fffd03c73" - integrity sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM= - -human-signals@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-1.1.1.tgz#c5b1cd14f50aeae09ab6c59fe63ba3395fe4dfa3" - integrity sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw== - -iconv-lite@0.4.24, iconv-lite@^0.4.17, iconv-lite@^0.4.24: - version "0.4.24" - resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" - integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== - dependencies: - safer-buffer ">= 2.1.2 < 3" - -icss-replace-symbols@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/icss-replace-symbols/-/icss-replace-symbols-1.1.0.tgz#06ea6f83679a7749e386cfe1fe812ae5db223ded" - integrity sha1-Bupvg2ead0njhs/h/oEq5dsiPe0= - -icss-utils@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/icss-utils/-/icss-utils-2.1.0.tgz#83f0a0ec378bf3246178b6c2ad9136f135b1c962" - integrity sha1-g/Cg7DeL8yRheLbCrZE28TWxyWI= - dependencies: - postcss "^6.0.1" - -ieee754@^1.1.4: - version "1.2.1" - resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" - integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== - -iferr@^0.1.5: - version "0.1.5" - resolved "https://registry.yarnpkg.com/iferr/-/iferr-0.1.5.tgz#c60eed69e6d8fdb6b3104a1fcbca1c192dc5b501" - integrity sha1-xg7taebY/bazEEofy8ocGS3FtQE= - -ignore@^3.3.3, ignore@^3.3.5: - version "3.3.10" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.3.10.tgz#0a97fb876986e8081c631160f8f9f389157f0043" - integrity sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug== - -ignore@^4.0.3, ignore@^4.0.6: - version "4.0.6" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" - integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg== - -ignore@^5.1.4, ignore@^5.1.8: - version "5.1.9" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.1.9.tgz#9ec1a5cbe8e1446ec60d4420060d43aa6e7382fb" - integrity sha512-2zeMQpbKz5dhZ9IwL0gbxSW5w0NK/MSAMtNuhgIHEPmaU3vPdKPL0UdvUCXs5SS4JAwsBxysK5sFMW8ocFiVjQ== - -import-cwd@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/import-cwd/-/import-cwd-2.1.0.tgz#aa6cf36e722761285cb371ec6519f53e2435b0a9" - integrity sha1-qmzzbnInYShcs3HsZRn1PiQ1sKk= - dependencies: - import-from "^2.1.0" - -import-fresh@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-2.0.0.tgz#d81355c15612d386c61f9ddd3922d4304822a546" - integrity sha1-2BNVwVYS04bGH53dOSLUMEgipUY= - dependencies: - caller-path "^2.0.0" - resolve-from "^3.0.0" - -import-fresh@^3.0.0, import-fresh@^3.1.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" - integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw== - dependencies: - parent-module "^1.0.0" - resolve-from "^4.0.0" - -import-from@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/import-from/-/import-from-2.1.0.tgz#335db7f2a7affd53aaa471d4b8021dee36b7f3b1" - integrity sha1-M1238qev/VOqpHHUuAId7ja387E= - dependencies: - resolve-from "^3.0.0" - -import-local@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/import-local/-/import-local-2.0.0.tgz#55070be38a5993cf18ef6db7e961f5bee5c5a09d" - integrity sha512-b6s04m3O+s3CGSbqDIyP4R6aAwAeYlVq9+WUWep6iHa8ETRf9yei1U48C5MmfJmV9AiLYYBKPMq/W+/WRpQmCQ== - dependencies: - pkg-dir "^3.0.0" - resolve-cwd "^2.0.0" - -imurmurhash@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" - integrity sha1-khi5srkoojixPcT7a21XbyMUU+o= - -indexes-of@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/indexes-of/-/indexes-of-1.0.1.tgz#f30f716c8e2bd346c7b67d3df3915566a7c05607" - integrity sha1-8w9xbI4r00bHtn0985FVZqfAVgc= - -infer-owner@^1.0.3: - version "1.0.4" - resolved "https://registry.yarnpkg.com/infer-owner/-/infer-owner-1.0.4.tgz#c4cefcaa8e51051c2a40ba2ce8a3d27295af9467" - integrity sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A== - -inflight@^1.0.4: - version "1.0.6" - resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" - integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= - dependencies: - once "^1.3.0" - wrappy "1" - -inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.1, inherits@~2.0.3: - version "2.0.4" - resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" - integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== - -inherits@2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.1.tgz#b17d08d326b4423e568eff719f91b0b1cbdf69f1" - integrity sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE= - -inherits@2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" - integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= - -inquirer@^3.0.6: - version "3.3.0" - resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-3.3.0.tgz#9dd2f2ad765dcab1ff0443b491442a20ba227dc9" - integrity sha512-h+xtnyk4EwKvFWHrUYsWErEVR+igKtLdchu+o0Z1RL7VU/jVMFbYir2bp6bAj8efFNxWqHX0dIss6fJQ+/+qeQ== - dependencies: - ansi-escapes "^3.0.0" - chalk "^2.0.0" - cli-cursor "^2.1.0" - cli-width "^2.0.0" - external-editor "^2.0.4" - figures "^2.0.0" - lodash "^4.3.0" - mute-stream "0.0.7" - run-async "^2.2.0" - rx-lite "^4.0.8" - rx-lite-aggregates "^4.0.8" - string-width "^2.1.0" - strip-ansi "^4.0.0" - through "^2.3.6" - -inquirer@^6.2.2: - version "6.5.2" - resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-6.5.2.tgz#ad50942375d036d327ff528c08bd5fab089928ca" - integrity sha512-cntlB5ghuB0iuO65Ovoi8ogLHiWGs/5yNrtUcKjFhSSiVeAIVpD7koaSU9RM8mpXw5YDi9RdYXGQMaOURB7ycQ== - dependencies: - 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" - -internal-ip@^4.3.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/internal-ip/-/internal-ip-4.3.0.tgz#845452baad9d2ca3b69c635a137acb9a0dad0907" - integrity sha512-S1zBo1D6zcsyuC6PMmY5+55YMILQ9av8lotMx447Bq6SAgo/sDK6y6uUKmuYhW7eacnIhFfsPmCNYdDzsnnDCg== - dependencies: - default-gateway "^4.2.0" - ipaddr.js "^1.9.0" - -internal-slot@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.3.tgz#7347e307deeea2faac2ac6205d4bc7d34967f59c" - integrity sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA== - dependencies: - get-intrinsic "^1.1.0" - has "^1.0.3" - side-channel "^1.0.4" - -ip-regex@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/ip-regex/-/ip-regex-2.1.0.tgz#fa78bf5d2e6913c911ce9f819ee5146bb6d844e9" - integrity sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk= - -ip@^1.1.0, ip@^1.1.5: - version "1.1.5" - resolved "https://registry.yarnpkg.com/ip/-/ip-1.1.5.tgz#bdded70114290828c0a039e72ef25f5aaec4354a" - integrity sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo= - -ipaddr.js@1.9.1, ipaddr.js@^1.9.0: - version "1.9.1" - resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3" - integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g== - -is-absolute-url@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/is-absolute-url/-/is-absolute-url-2.1.0.tgz#50530dfb84fcc9aa7dbe7852e83a37b93b9f2aa6" - integrity sha1-UFMN+4T8yap9vnhS6Do3uTufKqY= - -is-absolute-url@^3.0.3: - version "3.0.3" - resolved "https://registry.yarnpkg.com/is-absolute-url/-/is-absolute-url-3.0.3.tgz#96c6a22b6a23929b11ea0afb1836c36ad4a5d698" - integrity sha512-opmNIX7uFnS96NtPmhWQgQx6/NYFgsUXYMllcfzwWKUMwfo8kku1TvE6hkNcH+Q1ts5cMVrsY7j0bxXQDciu9Q== - -is-accessor-descriptor@^0.1.6: - version "0.1.6" - resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz#a9e12cb3ae8d876727eeef3843f8a0897b5c98d6" - integrity sha1-qeEss66Nh2cn7u84Q/igiXtcmNY= - dependencies: - kind-of "^3.0.2" - -is-accessor-descriptor@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz#169c2f6d3df1f992618072365c9b0ea1f6878656" - integrity sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ== - dependencies: - kind-of "^6.0.0" - -is-arguments@^1.0.4: - version "1.1.1" - resolved "https://registry.yarnpkg.com/is-arguments/-/is-arguments-1.1.1.tgz#15b3f88fda01f2a97fec84ca761a560f123efa9b" - integrity sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA== - dependencies: - call-bind "^1.0.2" - has-tostringtag "^1.0.0" - -is-arrayish@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" - integrity sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0= - -is-arrayish@^0.3.1: - version "0.3.2" - resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.3.2.tgz#4574a2ae56f7ab206896fb431eaeed066fdf8f03" - integrity sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ== - -is-bigint@^1.0.1: - version "1.0.4" - resolved "https://registry.yarnpkg.com/is-bigint/-/is-bigint-1.0.4.tgz#08147a1875bc2b32005d41ccd8291dffc6691df3" - integrity sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg== - dependencies: - has-bigints "^1.0.1" - -is-binary-path@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-1.0.1.tgz#75f16642b480f187a711c814161fd3a4a7655898" - integrity sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg= - dependencies: - binary-extensions "^1.0.0" - -is-binary-path@~2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" - integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw== - dependencies: - binary-extensions "^2.0.0" - -is-boolean-object@^1.1.0: - version "1.1.2" - resolved "https://registry.yarnpkg.com/is-boolean-object/-/is-boolean-object-1.1.2.tgz#5c6dc200246dd9321ae4b885a114bb1f75f63719" - integrity sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA== - dependencies: - call-bind "^1.0.2" - has-tostringtag "^1.0.0" - -is-buffer@^1.1.5: - version "1.1.6" - resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" - integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== - -is-buffer@^2.0.2: - version "2.0.5" - resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-2.0.5.tgz#ebc252e400d22ff8d77fa09888821a24a658c191" - integrity sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ== - -is-callable@^1.1.4, is-callable@^1.2.4: - version "1.2.4" - resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.4.tgz#47301d58dd0259407865547853df6d61fe471945" - integrity sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w== - -is-ci@^1.0.10: - version "1.2.1" - resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-1.2.1.tgz#e3779c8ee17fccf428488f6e281187f2e632841c" - integrity sha512-s6tfsaQaQi3JNciBH6shVqEDvhGut0SUXr31ag8Pd8BBbVVlcGfWhpPmEOoM6RJ5TFhbypvf5yyRw/VXW1IiWg== - dependencies: - ci-info "^1.5.0" - -is-color-stop@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-color-stop/-/is-color-stop-1.1.0.tgz#cfff471aee4dd5c9e158598fbe12967b5cdad345" - integrity sha1-z/9HGu5N1cnhWFmPvhKWe1za00U= - dependencies: - css-color-names "^0.0.4" - hex-color-regex "^1.1.0" - hsl-regex "^1.0.0" - hsla-regex "^1.0.0" - rgb-regex "^1.0.1" - rgba-regex "^1.0.0" - -is-core-module@^2.2.0: - version "2.8.0" - resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.8.0.tgz#0321336c3d0925e497fd97f5d95cb114a5ccd548" - integrity sha512-vd15qHsaqrRL7dtH6QNuy0ndJmRDrS9HAM1CAiSifNUFv4x1a0CCVsj18hJ1mShxIG6T2i1sO78MkP56r0nYRw== - dependencies: - has "^1.0.3" - -is-data-descriptor@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56" - integrity sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y= - dependencies: - kind-of "^3.0.2" - -is-data-descriptor@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz#d84876321d0e7add03990406abbbbd36ba9268c7" - integrity sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ== - dependencies: - kind-of "^6.0.0" - -is-date-object@^1.0.1: - version "1.0.5" - resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.5.tgz#0841d5536e724c25597bf6ea62e1bd38298df31f" - integrity sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ== - dependencies: - has-tostringtag "^1.0.0" - -is-descriptor@^0.1.0: - version "0.1.6" - resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-0.1.6.tgz#366d8240dde487ca51823b1ab9f07a10a78251ca" - integrity sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg== - dependencies: - is-accessor-descriptor "^0.1.6" - is-data-descriptor "^0.1.4" - kind-of "^5.0.0" - -is-descriptor@^1.0.0, is-descriptor@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-1.0.2.tgz#3b159746a66604b04f8c81524ba365c5f14d86ec" - integrity sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg== - dependencies: - is-accessor-descriptor "^1.0.0" - is-data-descriptor "^1.0.0" - kind-of "^6.0.2" - -is-directory@^0.3.1: - version "0.3.1" - resolved "https://registry.yarnpkg.com/is-directory/-/is-directory-0.3.1.tgz#61339b6f2475fc772fd9c9d83f5c8575dc154ae1" - integrity sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE= - -is-docker@^2.0.0: - version "2.2.1" - resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-2.2.1.tgz#33eeabe23cfe86f14bde4408a02c0cfb853acdaa" - integrity sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ== - -is-extendable@^0.1.0, is-extendable@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" - integrity sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik= - -is-extendable@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-1.0.1.tgz#a7470f9e426733d81bd81e1155264e3a3507cab4" - integrity sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA== - dependencies: - is-plain-object "^2.0.4" - -is-extglob@^2.1.0, is-extglob@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" - integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= - -is-fullwidth-code-point@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" - integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8= - -is-fullwidth-code-point@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" - integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== - -is-glob@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-3.1.0.tgz#7ba5ae24217804ac70707b96922567486cc3e84a" - integrity sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo= - dependencies: - is-extglob "^2.1.0" - -is-glob@^4.0.0, is-glob@^4.0.1, is-glob@~4.0.1: - version "4.0.3" - resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" - integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== - dependencies: - is-extglob "^2.1.1" - -is-negative-zero@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.1.tgz#3de746c18dda2319241a53675908d8f766f11c24" - integrity sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w== - -is-number-object@^1.0.4: - version "1.0.6" - resolved "https://registry.yarnpkg.com/is-number-object/-/is-number-object-1.0.6.tgz#6a7aaf838c7f0686a50b4553f7e54a96494e89f0" - integrity sha512-bEVOqiRcvo3zO1+G2lVMy+gkkEm9Yh7cDMRusKKu5ZJKPUYSJwICTKZrNKHA2EbSP0Tu0+6B/emsYNHZyn6K8g== - dependencies: - has-tostringtag "^1.0.0" - -is-negative-zero@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.1.tgz#3de746c18dda2319241a53675908d8f766f11c24" - integrity sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w== - -is-number-object@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/is-number-object/-/is-number-object-1.0.4.tgz#36ac95e741cf18b283fc1ddf5e83da798e3ec197" - integrity sha512-zohwelOAur+5uXtk8O3GPQ1eAcu4ZX3UwxQhUlfFFMNpUd83gXgjbhJh6HmB6LUNV/ieOLQuDwJO3dWJosUeMw== - -is-negative-zero@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.1.tgz#3de746c18dda2319241a53675908d8f766f11c24" - integrity sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w== - -is-number-object@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/is-number-object/-/is-number-object-1.0.4.tgz#36ac95e741cf18b283fc1ddf5e83da798e3ec197" - integrity sha512-zohwelOAur+5uXtk8O3GPQ1eAcu4ZX3UwxQhUlfFFMNpUd83gXgjbhJh6HmB6LUNV/ieOLQuDwJO3dWJosUeMw== - -is-negative-zero@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.1.tgz#3de746c18dda2319241a53675908d8f766f11c24" - integrity sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w== - -is-number-object@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/is-number-object/-/is-number-object-1.0.4.tgz#36ac95e741cf18b283fc1ddf5e83da798e3ec197" - integrity sha512-zohwelOAur+5uXtk8O3GPQ1eAcu4ZX3UwxQhUlfFFMNpUd83gXgjbhJh6HmB6LUNV/ieOLQuDwJO3dWJosUeMw== - -is-negative-zero@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.1.tgz#3de746c18dda2319241a53675908d8f766f11c24" - integrity sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w== - -is-number-object@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/is-number-object/-/is-number-object-1.0.4.tgz#36ac95e741cf18b283fc1ddf5e83da798e3ec197" - integrity sha512-zohwelOAur+5uXtk8O3GPQ1eAcu4ZX3UwxQhUlfFFMNpUd83gXgjbhJh6HmB6LUNV/ieOLQuDwJO3dWJosUeMw== - -is-number@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195" - integrity sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU= - dependencies: - kind-of "^3.0.2" - -is-number@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" - integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== - -is-obj@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-2.0.0.tgz#473fb05d973705e3fd9620545018ca8e22ef4982" - integrity sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w== - -is-path-cwd@^2.0.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/is-path-cwd/-/is-path-cwd-2.2.0.tgz#67d43b82664a7b5191fd9119127eb300048a9fdb" - integrity sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ== - -is-path-in-cwd@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/is-path-in-cwd/-/is-path-in-cwd-2.1.0.tgz#bfe2dca26c69f397265a4009963602935a053acb" - integrity sha512-rNocXHgipO+rvnP6dk3zI20RpOtrAM/kzbB258Uw5BWr3TpXi861yzjo16Dn4hUox07iw5AyeMLHWsujkjzvRQ== - dependencies: - is-path-inside "^2.1.0" - -is-path-inside@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-2.1.0.tgz#7c9810587d659a40d27bcdb4d5616eab059494b2" - integrity sha512-wiyhTzfDWsvwAW53OBWF5zuvaOGlZ6PwYxAbPVDhpm+gM09xKQGjBq/8uYN12aDvMxnAnq3dxTyoSoRNmg5YFg== - dependencies: - path-is-inside "^1.0.2" - -is-plain-obj@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e" - integrity sha1-caUMhCnfync8kqOQpKA7OfzVHT4= - -is-plain-object@^2.0.3, is-plain-object@^2.0.4: - version "2.0.4" - resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677" - integrity sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og== - dependencies: - isobject "^3.0.1" - -is-regex@^1.0.4, is-regex@^1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.4.tgz#eef5663cd59fa4c0ae339505323df6854bb15958" - integrity sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg== - dependencies: - call-bind "^1.0.2" - has-tostringtag "^1.0.0" - -is-resolvable@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-resolvable/-/is-resolvable-1.1.0.tgz#fb18f87ce1feb925169c9a407c19318a3206ed88" - integrity sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg== - -is-shared-array-buffer@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.1.tgz#97b0c85fbdacb59c9c446fe653b82cf2b5b7cfe6" - integrity sha512-IU0NmyknYZN0rChcKhRO1X8LYz5Isj/Fsqh8NJOSf+N/hCOTwy29F32Ik7a+QszE63IdvmwdTPDd6cZ5pg4cwA== - -is-stream@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" - integrity sha1-EtSj3U5o4Lec6428hBc66A2RykQ= - -is-stream@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077" - integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg== - -is-string@^1.0.5, is-string@^1.0.7: - version "1.0.7" - resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.7.tgz#0dd12bf2006f255bb58f695110eff7491eebc0fd" - integrity sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg== - dependencies: - has-tostringtag "^1.0.0" - -is-symbol@^1.0.2, is-symbol@^1.0.3: - version "1.0.4" - resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.4.tgz#a6dac93b635b063ca6872236de88910a57af139c" - integrity sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg== - dependencies: - has-symbols "^1.0.2" - -is-typedarray@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" - integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo= - -is-weakref@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-weakref/-/is-weakref-1.0.1.tgz#842dba4ec17fa9ac9850df2d6efbc1737274f2a2" - integrity sha512-b2jKc2pQZjaeFYWEf7ScFj+Be1I+PXmlu572Q8coTXZ+LD/QQZ7ShPMst8h16riVgyXTQwUsFEl74mDvc/3MHQ== - dependencies: - call-bind "^1.0.0" - -is-windows@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" - integrity sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA== - -is-wsl@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-1.1.0.tgz#1f16e4aa22b04d1336b66188a66af3c600c3a66d" - integrity sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0= - -is-wsl@^2.1.1: - version "2.2.0" - resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-2.2.0.tgz#74a4c76e77ca9fd3f932f290c17ea326cd157271" - integrity sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww== - dependencies: - is-docker "^2.0.0" - -isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" - integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= - -isexe@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" - integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= - -isobject@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" - integrity sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk= - dependencies: - isarray "1.0.0" - -isobject@^3.0.0, isobject@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" - integrity sha1-TkMekrEalzFjaqH5yNHMvP2reN8= - -isstream@~0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" - integrity sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo= - -javascript-stringify@^1.6.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/javascript-stringify/-/javascript-stringify-1.6.0.tgz#142d111f3a6e3dae8f4a9afd77d45855b5a9cce3" - integrity sha1-FC0RHzpuPa6PSpr9d9RYVbWpzOM= - -js-message@1.0.7: - version "1.0.7" - resolved "https://registry.yarnpkg.com/js-message/-/js-message-1.0.7.tgz#fbddd053c7a47021871bb8b2c95397cc17c20e47" - integrity sha512-efJLHhLjIyKRewNS9EGZ4UpI8NguuL6fKkhRxVuMmrGV2xN/0APGdQYwLFky5w9naebSZ0OwAGp0G6/2Cg90rA== - -js-queue@2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/js-queue/-/js-queue-2.0.2.tgz#0be590338f903b36c73d33c31883a821412cd482" - integrity sha512-pbKLsbCfi7kriM3s1J4DDCo7jQkI58zPLHi0heXPzPlj0hjUsm+FesPUbE0DSbIVIK503A36aUBoCN7eMFedkA== - dependencies: - easy-stack "^1.0.1" - -js-tokens@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b" - integrity sha1-mGbfOVECEw449/mWvOtlRDIJwls= - -js-tokens@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" - integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== - -js-yaml@^3.13.0, js-yaml@^3.13.1, js-yaml@^3.9.1: - version "3.14.1" - resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.1.tgz#dae812fdb3825fa306609a8717383c50c36a0537" - integrity sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g== - dependencies: - argparse "^1.0.7" - esprima "^4.0.0" - -jsbn@~0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" - integrity sha1-peZUwuWi3rXyAdls77yoDA7y9RM= - -jsesc@^2.5.1: - version "2.5.2" - resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" - integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== - -json-parse-better-errors@^1.0.1, json-parse-better-errors@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9" - integrity sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw== - -json-parse-even-better-errors@^2.3.0: - version "2.3.1" - resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d" - integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w== - -json-schema-traverse@^0.3.0: - version "0.3.1" - resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz#349a6d44c53a51de89b40805c5d5e59b417d3340" - integrity sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A= - -json-schema-traverse@^0.4.1: - version "0.4.1" - resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" - integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== - -json-schema@0.2.3: - version "0.2.3" - resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" - integrity sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM= - -json-stable-stringify-without-jsonify@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" - integrity sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE= - -json-stringify-safe@~5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" - integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus= - -json3@^3.3.3: - version "3.3.3" - resolved "https://registry.yarnpkg.com/json3/-/json3-3.3.3.tgz#7fc10e375fc5ae42c4705a5cc0aa6f62be305b81" - integrity sha512-c7/8mbUsKigAbLkD5B010BK4D9LZm7A1pNItkEwiUZRpIN66exu/e7YQWysGun+TRKaJp8MhemM+VkfWv42aCA== - -json5@^0.5.0: - version "0.5.1" - resolved "https://registry.yarnpkg.com/json5/-/json5-0.5.1.tgz#1eade7acc012034ad84e2396767ead9fa5495821" - integrity sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE= - -json5@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.1.tgz#779fb0018604fa854eacbf6252180d83543e3dbe" - integrity sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow== - dependencies: - minimist "^1.2.0" - -jsonfile@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb" - integrity sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss= - optionalDependencies: - graceful-fs "^4.1.6" - -jsonfile@^6.0.1: - version "6.1.0" - resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-6.1.0.tgz#bc55b2634793c679ec6403094eb13698a6ec0aae" - integrity sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ== - dependencies: - universalify "^2.0.0" - optionalDependencies: - graceful-fs "^4.1.6" - -jsprim@^1.2.2: - version "1.4.1" - resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2" - integrity sha1-MT5mvB5cwG5Di8G3SZwuXFastqI= - dependencies: - assert-plus "1.0.0" - extsprintf "1.3.0" - json-schema "0.2.3" - verror "1.10.0" - -killable@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/killable/-/killable-1.0.1.tgz#4c8ce441187a061c7474fb87ca08e2a638194892" - integrity sha512-LzqtLKlUwirEUyl/nicirVmNiPvYs7l5n8wOPP7fyJVpUPkvCnW/vuiXGpylGUlnPDnB7311rARzAt3Mhswpjg== - -kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0: - version "3.2.2" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" - integrity sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ= - dependencies: - is-buffer "^1.1.5" - -kind-of@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-4.0.0.tgz#20813df3d712928b207378691a45066fae72dd57" - integrity sha1-IIE989cSkosgc3hpGkUGb65y3Vc= - dependencies: - is-buffer "^1.1.5" - -kind-of@^5.0.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-5.1.0.tgz#729c91e2d857b7a419a1f9aa65685c4c33f5845d" - integrity sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw== - -kind-of@^6.0.0, kind-of@^6.0.2: - version "6.0.3" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd" - integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw== - -launch-editor-middleware@^2.2.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/launch-editor-middleware/-/launch-editor-middleware-2.2.1.tgz#e14b07e6c7154b0a4b86a0fd345784e45804c157" - integrity sha512-s0UO2/gEGiCgei3/2UN3SMuUj1phjQN8lcpnvgLSz26fAzNWPQ6Nf/kF5IFClnfU2ehp6LrmKdMU/beveO+2jg== - dependencies: - launch-editor "^2.2.1" - -launch-editor@^2.2.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/launch-editor/-/launch-editor-2.2.1.tgz#871b5a3ee39d6680fcc26d37930b6eeda89db0ca" - integrity sha512-On+V7K2uZK6wK7x691ycSUbLD/FyKKelArkbaAMSSJU8JmqmhwN2+mnJDNINuJWSrh2L0kDk+ZQtbC/gOWUwLw== - dependencies: - chalk "^2.3.0" - shell-quote "^1.6.1" - -levn@^0.3.0, levn@~0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" - integrity sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4= - dependencies: - prelude-ls "~1.1.2" - type-check "~0.3.2" - -lines-and-columns@^1.1.6: - version "1.1.6" - resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.1.6.tgz#1c00c743b433cd0a4e80758f7b64a57440d9ff00" - integrity sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA= - -loader-fs-cache@^1.0.0: - version "1.0.3" - resolved "https://registry.yarnpkg.com/loader-fs-cache/-/loader-fs-cache-1.0.3.tgz#f08657646d607078be2f0a032f8bd69dd6f277d9" - integrity sha512-ldcgZpjNJj71n+2Mf6yetz+c9bM4xpKtNds4LbqXzU/PTdeAX0g3ytnU1AJMEcTk2Lex4Smpe3Q/eCTsvUBxbA== - dependencies: - find-cache-dir "^0.1.1" - mkdirp "^0.5.1" - -loader-runner@^2.3.1, loader-runner@^2.4.0: - version "2.4.0" - resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-2.4.0.tgz#ed47066bfe534d7e84c4c7b9998c2a75607d9357" - integrity sha512-Jsmr89RcXGIwivFY21FcRrisYZfvLMTWx5kOLc+JTxtpBOG6xML0vzbc6SEQG2FO9/4Fc3wW4LVcB5DmGflaRw== - -loader-utils@^0.2.16: - version "0.2.17" - resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-0.2.17.tgz#f86e6374d43205a6e6c60e9196f17c0299bfb348" - integrity sha1-+G5jdNQyBabmxg6RlvF8Apm/s0g= - dependencies: - big.js "^3.1.3" - emojis-list "^2.0.0" - json5 "^0.5.0" - object-assign "^4.0.1" - -loader-utils@^1.0.2, loader-utils@^1.1.0, loader-utils@^1.2.3: - version "1.4.0" - resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-1.4.0.tgz#c579b5e34cb34b1a74edc6c1fb36bfa371d5a613" - integrity sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA== - dependencies: - big.js "^5.2.2" - emojis-list "^3.0.0" - json5 "^1.0.1" - -locate-path@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e" - integrity sha1-K1aLJl7slExtnA3pw9u7ygNUzY4= - dependencies: - p-locate "^2.0.0" - path-exists "^3.0.0" - -locate-path@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e" - integrity sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A== - dependencies: - p-locate "^3.0.0" - path-exists "^3.0.0" - -locate-path@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0" - integrity sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g== - dependencies: - p-locate "^4.1.0" - -lodash.defaultsdeep@^4.6.1: - version "4.6.1" - resolved "https://registry.yarnpkg.com/lodash.defaultsdeep/-/lodash.defaultsdeep-4.6.1.tgz#512e9bd721d272d94e3d3a63653fa17516741ca6" - integrity sha512-3j8wdDzYuWO3lM3Reg03MuQR957t287Rpcxp1njpEa8oDrikb+FwGdW3n+FELh/A6qib6yPit0j/pv9G/yeAqA== - -lodash.mapvalues@^4.6.0: - version "4.6.0" - resolved "https://registry.yarnpkg.com/lodash.mapvalues/-/lodash.mapvalues-4.6.0.tgz#1bafa5005de9dd6f4f26668c30ca37230cc9689c" - integrity sha1-G6+lAF3p3W9PJmaMMMo3IwzJaJw= - -lodash.memoize@^4.1.2: - version "4.1.2" - resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe" - integrity sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4= - -lodash.transform@^4.6.0: - version "4.6.0" - resolved "https://registry.yarnpkg.com/lodash.transform/-/lodash.transform-4.6.0.tgz#12306422f63324aed8483d3f38332b5f670547a0" - integrity sha1-EjBkIvYzJK7YSD0/ODMrX2cFR6A= - -lodash.unescape@4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/lodash.unescape/-/lodash.unescape-4.0.1.tgz#bf2249886ce514cda112fae9218cdc065211fc9c" - integrity sha1-vyJJiGzlFM2hEvrpIYzcBlIR/Jw= - -lodash.uniq@^4.5.0: - version "4.5.0" - resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" - integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M= - -lodash@^4.17.11, lodash@^4.17.12, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.20, lodash@^4.17.21, lodash@^4.17.3, lodash@^4.17.4, lodash@^4.3.0: - version "4.17.21" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" - integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== - -log-symbols@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-2.2.0.tgz#5740e1c5d6f0dfda4ad9323b5332107ef6b4c40a" - integrity sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg== - dependencies: - chalk "^2.0.1" - -loglevel@^1.6.8: - version "1.7.1" - resolved "https://registry.yarnpkg.com/loglevel/-/loglevel-1.7.1.tgz#005fde2f5e6e47068f935ff28573e125ef72f197" - integrity sha512-Hesni4s5UkWkwCGJMQGAh71PaLUmKFM60dHvq0zi/vDhhrzuk+4GgNbTXJ12YYQJn6ZKBDNIjYcuQGKudvqrIw== - -lower-case@^1.1.1: - version "1.1.4" - resolved "https://registry.yarnpkg.com/lower-case/-/lower-case-1.1.4.tgz#9a2cabd1b9e8e0ae993a4bf7d5875c39c42e8eac" - integrity sha1-miyr0bno4K6ZOkv31YdcOcQujqw= - -lru-cache@^4.0.1, lru-cache@^4.1.1, lru-cache@^4.1.2: - version "4.1.5" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.5.tgz#8bbe50ea85bed59bc9e33dcab8235ee9bcf443cd" - integrity sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g== - dependencies: - pseudomap "^1.0.2" - yallist "^2.1.2" - -lru-cache@^5.1.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" - integrity sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w== - dependencies: - yallist "^3.0.2" - -lru-cache@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" - integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA== - dependencies: - yallist "^4.0.0" - -make-dir@^1.0.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-1.3.0.tgz#79c1033b80515bd6d24ec9933e860ca75ee27f0c" - integrity sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ== - dependencies: - pify "^3.0.0" - -make-dir@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-2.1.0.tgz#5f0310e18b8be898cc07009295a30ae41e91e6f5" - integrity sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA== - dependencies: - pify "^4.0.1" - semver "^5.6.0" - -make-dir@^3.0.2: - version "3.1.0" - resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-3.1.0.tgz#415e967046b3a7f1d185277d84aa58203726a13f" - integrity sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw== - dependencies: - semver "^6.0.0" - -map-cache@^0.2.2: - version "0.2.2" - resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf" - integrity sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8= - -map-visit@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/map-visit/-/map-visit-1.0.0.tgz#ecdca8f13144e660f1b5bd41f12f3479d98dfb8f" - integrity sha1-7Nyo8TFE5mDxtb1B8S80edmN+48= - dependencies: - object-visit "^1.0.0" - -md5.js@^1.3.4: - version "1.3.5" - resolved "https://registry.yarnpkg.com/md5.js/-/md5.js-1.3.5.tgz#b5d07b8e3216e3e27cd728d72f70d1e6a342005f" - integrity sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg== - dependencies: - hash-base "^3.0.0" - inherits "^2.0.1" - safe-buffer "^5.1.2" - -mdn-data@2.0.14: - version "2.0.14" - resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.0.14.tgz#7113fc4281917d63ce29b43446f701e68c25ba50" - integrity sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow== - -mdn-data@2.0.4: - version "2.0.4" - resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.0.4.tgz#699b3c38ac6f1d728091a64650b65d388502fd5b" - integrity sha512-iV3XNKw06j5Q7mi6h+9vbx23Tv7JkjEVgKHW4pimwyDGWm0OIQntJJ+u1C6mg6mK1EaTv42XQ7w76yuzH7M2cA== - -media-typer@0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" - integrity sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g= - -memfs@^3.1.2: - version "3.3.0" - resolved "https://registry.yarnpkg.com/memfs/-/memfs-3.3.0.tgz#4da2d1fc40a04b170a56622c7164c6be2c4cbef2" - integrity sha512-BEE62uMfKOavX3iG7GYX43QJ+hAeeWnwIAuJ/R6q96jaMtiLzhsxHJC8B1L7fK7Pt/vXDRwb3SG/yBpNGDPqzg== - dependencies: - fs-monkey "1.0.3" - -memory-fs@^0.4.1: - version "0.4.1" - resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.4.1.tgz#3a9a20b8462523e447cfbc7e8bb80ed667bfc552" - integrity sha1-OpoguEYlI+RHz7x+i7gO1me/xVI= - dependencies: - errno "^0.1.3" - readable-stream "^2.0.1" - -memory-fs@^0.5.0: - version "0.5.0" - resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.5.0.tgz#324c01288b88652966d161db77838720845a8e3c" - integrity sha512-jA0rdU5KoQMC0e6ppoNRtpp6vjFq6+NY7r8hywnC7V+1Xj/MtHwGIbB1QaK/dunyjWteJzmkpd7ooeWg10T7GA== - dependencies: - errno "^0.1.3" - readable-stream "^2.0.1" - -merge-descriptors@1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" - integrity sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E= - -merge-source-map@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/merge-source-map/-/merge-source-map-1.1.0.tgz#2fdde7e6020939f70906a68f2d7ae685e4c8c646" - integrity sha512-Qkcp7P2ygktpMPh2mCQZaf3jhN6D3Z/qVZHSdWvQ+2Ef5HgRAPBO57A77+ENm0CPx2+1Ce/MYKi3ymqdfuqibw== - dependencies: - source-map "^0.6.1" - -merge-stream@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" - integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== - -merge2@^1.2.3, merge2@^1.3.0: - version "1.4.1" - resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" - integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== - -methods@~1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" - integrity sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4= - -microevent.ts@~0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/microevent.ts/-/microevent.ts-0.1.1.tgz#70b09b83f43df5172d0205a63025bce0f7357fa0" - integrity sha512-jo1OfR4TaEwd5HOrt5+tAZ9mqT4jmpNAusXtyfNzqVm9uiSYFZlKM1wYL4oU7azZW/PxQW53wM0S6OR1JHNa2g== - -micromatch@^3.1.10, micromatch@^3.1.4: - version "3.1.10" - resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23" - integrity sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg== - dependencies: - arr-diff "^4.0.0" - array-unique "^0.3.2" - braces "^2.3.1" - define-property "^2.0.2" - extend-shallow "^3.0.2" - extglob "^2.0.4" - fragment-cache "^0.2.1" - kind-of "^6.0.2" - nanomatch "^1.2.9" - object.pick "^1.3.0" - regex-not "^1.0.0" - snapdragon "^0.8.1" - to-regex "^3.0.2" - -micromatch@^4.0.0, micromatch@^4.0.4: - version "4.0.4" - resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.4.tgz#896d519dfe9db25fce94ceb7a500919bf881ebf9" - integrity sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg== - dependencies: - braces "^3.0.1" - picomatch "^2.2.3" - -miller-rabin@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/miller-rabin/-/miller-rabin-4.0.1.tgz#f080351c865b0dc562a8462966daa53543c78a4d" - integrity sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA== - dependencies: - bn.js "^4.0.0" - brorand "^1.0.1" - -mime-db@1.51.0, "mime-db@>= 1.43.0 < 2": - version "1.51.0" - resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.51.0.tgz#d9ff62451859b18342d960850dc3cfb77e63fb0c" - integrity sha512-5y8A56jg7XVQx2mbv1lu49NR4dokRnhZYTtL+KGfaa27uq4pSTXkwQkFJl4pkRMyNFz/EtYDSkiiEHx3F7UN6g== - -mime-types@^2.1.12, mime-types@~2.1.17, mime-types@~2.1.19, mime-types@~2.1.24: - version "2.1.34" - resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.34.tgz#5a712f9ec1503511a945803640fafe09d3793c24" - integrity sha512-6cP692WwGIs9XXdOO4++N+7qjqv0rqxxVvJ3VHPh/Sc9mVZcQP+ZGhkKiTvWMQRr2tbHkJP/Yn7Y0npb3ZBs4A== - dependencies: - mime-db "1.51.0" - -mime@1.6.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" - integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== - -mime@^2.0.3, mime@^2.4.4: - version "2.6.0" - resolved "https://registry.yarnpkg.com/mime/-/mime-2.6.0.tgz#a2a682a95cd4d0cb1d6257e28f83da7e35800367" - integrity sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg== - -mimic-fn@^1.0.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.2.0.tgz#820c86a39334640e99516928bd03fca88057d022" - integrity sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ== - -mimic-fn@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" - integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== - -mini-css-extract-plugin@^0.8.0: - version "0.8.2" - resolved "https://registry.yarnpkg.com/mini-css-extract-plugin/-/mini-css-extract-plugin-0.8.2.tgz#a875e169beb27c88af77dd962771c9eedc3da161" - integrity sha512-a3Y4of27Wz+mqK3qrcd3VhYz6cU0iW5x3Sgvqzbj+XmlrSizmvu8QQMl5oMYJjgHOC4iyt+w7l4umP+dQeW3bw== - dependencies: - loader-utils "^1.1.0" - normalize-url "1.9.1" - schema-utils "^1.0.0" - webpack-sources "^1.1.0" - -minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7" - integrity sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A== - -minimalistic-crypto-utils@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a" - integrity sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo= - -minimatch@^3.0.2, minimatch@^3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" - integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== - dependencies: - brace-expansion "^1.1.7" - -minimist@^1.2.0, minimist@^1.2.5: - version "1.2.5" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" - integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== - -mississippi@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/mississippi/-/mississippi-2.0.0.tgz#3442a508fafc28500486feea99409676e4ee5a6f" - integrity sha512-zHo8v+otD1J10j/tC+VNoGK9keCuByhKovAvdn74dmxJl9+mWHnx6EMsDN4lgRoMI/eYo2nchAxniIbUPb5onw== - dependencies: - concat-stream "^1.5.0" - duplexify "^3.4.2" - end-of-stream "^1.1.0" - flush-write-stream "^1.0.0" - from2 "^2.1.0" - parallel-transform "^1.1.0" - pump "^2.0.1" - pumpify "^1.3.3" - stream-each "^1.1.0" - through2 "^2.0.0" - -mississippi@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/mississippi/-/mississippi-3.0.0.tgz#ea0a3291f97e0b5e8776b363d5f0a12d94c67022" - integrity sha512-x471SsVjUtBRtcvd4BzKE9kFC+/2TeWgKCgw0bZcw1b9l2X3QX5vCWgF+KaZaYm87Ss//rHnWryupDrgLvmSkA== - dependencies: - concat-stream "^1.5.0" - duplexify "^3.4.2" - end-of-stream "^1.1.0" - flush-write-stream "^1.0.0" - from2 "^2.1.0" - parallel-transform "^1.1.0" - pump "^3.0.0" - pumpify "^1.3.3" - stream-each "^1.1.0" - through2 "^2.0.0" - -mixin-deep@^1.2.0: - version "1.3.2" - resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.2.tgz#1120b43dc359a785dce65b55b82e257ccf479566" - integrity sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA== - dependencies: - for-in "^1.0.2" - is-extendable "^1.0.1" - -mkdirp@^0.5.1, mkdirp@^0.5.3, mkdirp@^0.5.5, mkdirp@~0.5.1: - version "0.5.5" - resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.5.tgz#d91cefd62d1436ca0f41620e251288d420099def" - integrity sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ== - dependencies: - minimist "^1.2.5" - -move-concurrently@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/move-concurrently/-/move-concurrently-1.0.1.tgz#be2c005fda32e0b29af1f05d7c4b33214c701f92" - integrity sha1-viwAX9oy4LKa8fBdfEszIUxwH5I= - dependencies: - aproba "^1.1.1" - copy-concurrently "^1.0.0" - fs-write-stream-atomic "^1.0.8" - mkdirp "^0.5.1" - rimraf "^2.5.4" - run-queue "^1.0.3" - -ms@2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" - integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= - -ms@2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a" - integrity sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg== - -ms@2.1.2: - version "2.1.2" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" - integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== - -ms@^2.1.1: - version "2.1.3" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" - integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== - -multicast-dns-service-types@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/multicast-dns-service-types/-/multicast-dns-service-types-1.1.0.tgz#899f11d9686e5e05cb91b35d5f0e63b773cfc901" - integrity sha1-iZ8R2WhuXgXLkbNdXw5jt3PPyQE= - -multicast-dns@^6.0.1: - version "6.2.3" - resolved "https://registry.yarnpkg.com/multicast-dns/-/multicast-dns-6.2.3.tgz#a0ec7bd9055c4282f790c3c82f4e28db3b31b229" - integrity sha512-ji6J5enbMyGRHIAkAOu3WdV8nggqviKCEKtXcOqfphZZtQrmHKycfynJ2V7eVPUA4NhJ6V7Wf4TmGbTwKE9B6g== - dependencies: - dns-packet "^1.3.1" - thunky "^1.0.2" - -mute-stream@0.0.7: - version "0.0.7" - resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab" - integrity sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s= - -mz@^2.4.0: - version "2.7.0" - resolved "https://registry.yarnpkg.com/mz/-/mz-2.7.0.tgz#95008057a56cafadc2bc63dde7f9ff6955948e32" - integrity sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q== - dependencies: - any-promise "^1.0.0" - object-assign "^4.0.1" - thenify-all "^1.0.0" - -nan@^2.12.1: - version "2.15.0" - resolved "https://registry.yarnpkg.com/nan/-/nan-2.15.0.tgz#3f34a473ff18e15c1b5626b62903b5ad6e665fee" - integrity sha512-8ZtvEnA2c5aYCZYd1cvgdnU6cqwixRoYg70xPLWUws5ORTa/lnw+u4amixRS/Ac5U5mQVgp9pnlSUnbNWFaWZQ== - -nanomatch@^1.2.9: - version "1.2.13" - resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119" - integrity sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA== - dependencies: - arr-diff "^4.0.0" - array-unique "^0.3.2" - define-property "^2.0.2" - extend-shallow "^3.0.2" - fragment-cache "^0.2.1" - is-windows "^1.0.2" - kind-of "^6.0.2" - object.pick "^1.3.0" - regex-not "^1.0.0" - snapdragon "^0.8.1" - to-regex "^3.0.1" - -natural-compare@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" - integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc= - -negotiator@0.6.2: - version "0.6.2" - resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.2.tgz#feacf7ccf525a77ae9634436a64883ffeca346fb" - integrity sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw== - -neo-async@^2.5.0, neo-async@^2.6.0, neo-async@^2.6.1: - version "2.6.2" - resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f" - integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw== - -nice-try@^1.0.4: - version "1.0.5" - resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" - integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ== - -no-case@^2.2.0: - version "2.3.2" - resolved "https://registry.yarnpkg.com/no-case/-/no-case-2.3.2.tgz#60b813396be39b3f1288a4c1ed5d1e7d28b464ac" - integrity sha512-rmTZ9kz+f3rCvK2TD1Ue/oZlns7OGoIWP4fc3llxxRXlOkHKoWPPWJOfFYpITabSow43QJbRIoHQXtt10VldyQ== - dependencies: - lower-case "^1.1.1" - -node-forge@^0.10.0: - version "0.10.0" - resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-0.10.0.tgz#32dea2afb3e9926f02ee5ce8794902691a676bf3" - integrity sha512-PPmu8eEeG9saEUvI97fm4OYxXVB6bFvyNTyiUOBichBpFG8A1Ljw3bY62+5oOjDEMHRnd0Y7HQ+x7uzxOzC6JA== - -node-ipc@^9.1.1: - version "9.2.1" - resolved "https://registry.yarnpkg.com/node-ipc/-/node-ipc-9.2.1.tgz#b32f66115f9d6ce841dc4ec2009d6a733f98bb6b" - integrity sha512-mJzaM6O3xHf9VT8BULvJSbdVbmHUKRNOH7zDDkCrA1/T+CVjq2WVIDfLt0azZRXpgArJtl3rtmEozrbXPZ9GaQ== - dependencies: - event-pubsub "4.3.0" - js-message "1.0.7" - js-queue "2.0.2" - -node-libs-browser@^2.2.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/node-libs-browser/-/node-libs-browser-2.2.1.tgz#b64f513d18338625f90346d27b0d235e631f6425" - integrity sha512-h/zcD8H9kaDZ9ALUWwlBUDo6TKF8a7qBSCSEGfjTVIYeqsioSKaAX+BN7NgiMGp6iSIXZ3PxgCu8KS3b71YK5Q== - dependencies: - assert "^1.1.1" - browserify-zlib "^0.2.0" - buffer "^4.3.0" - console-browserify "^1.1.0" - constants-browserify "^1.0.0" - crypto-browserify "^3.11.0" - domain-browser "^1.1.1" - events "^3.0.0" - https-browserify "^1.0.0" - os-browserify "^0.3.0" - path-browserify "0.0.1" - process "^0.11.10" - punycode "^1.2.4" - querystring-es3 "^0.2.0" - readable-stream "^2.3.3" - stream-browserify "^2.0.1" - stream-http "^2.7.2" - string_decoder "^1.0.0" - timers-browserify "^2.0.4" - tty-browserify "0.0.0" - url "^0.11.0" - util "^0.11.0" - vm-browserify "^1.0.1" - -node-releases@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.1.tgz#3d1d395f204f1f2f29a54358b9fb678765ad2fc5" - integrity sha512-CqyzN6z7Q6aMeF/ktcMVTzhAHCEpf8SOarwpzpf8pNBY2k5/oM34UHldUwp8VKI7uxct2HxSRdJjBaZeESzcxA== - -normalize-package-data@^2.5.0: - version "2.5.0" - resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8" - integrity sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA== - dependencies: - hosted-git-info "^2.1.4" - resolve "^1.10.0" - semver "2 || 3 || 4 || 5" - validate-npm-package-license "^3.0.1" - -normalize-path@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-1.0.0.tgz#32d0e472f91ff345701c15a8311018d3b0a90379" - integrity sha1-MtDkcvkf80VwHBWoMRAY07CpA3k= - -normalize-path@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9" - integrity sha1-GrKLVW4Zg2Oowab35vogE3/mrtk= - dependencies: - remove-trailing-separator "^1.0.1" - -normalize-path@^3.0.0, normalize-path@~3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" - integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== - -normalize-range@^0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/normalize-range/-/normalize-range-0.1.2.tgz#2d10c06bdfd312ea9777695a4d28439456b75942" - integrity sha1-LRDAa9/TEuqXd2laTShDlFa3WUI= - -normalize-url@1.9.1: - version "1.9.1" - resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-1.9.1.tgz#2cc0d66b31ea23036458436e3620d85954c66c3c" - integrity sha1-LMDWazHqIwNkWENuNiDYWVTGbDw= - dependencies: - object-assign "^4.0.1" - prepend-http "^1.0.0" - query-string "^4.1.0" - sort-keys "^1.0.0" - -normalize-url@^3.0.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-3.3.0.tgz#b2e1c4dc4f7c6d57743df733a4f5978d18650559" - integrity sha512-U+JJi7duF1o+u2pynbp2zXDW2/PADgC30f0GsHZtRh+HOcXHnw137TrNlyxxRvWW5fjKd3bcLHPxofWuCjaeZg== - -npm-run-path@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f" - integrity sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8= - dependencies: - path-key "^2.0.0" - -npm-run-path@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea" - integrity sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw== - dependencies: - path-key "^3.0.0" - -nth-check@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/nth-check/-/nth-check-1.0.2.tgz#b2bd295c37e3dd58a3bf0700376663ba4d9cf05c" - integrity sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg== - dependencies: - boolbase "~1.0.0" - -nth-check@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/nth-check/-/nth-check-2.0.1.tgz#2efe162f5c3da06a28959fbd3db75dbeea9f0fc2" - integrity sha512-it1vE95zF6dTT9lBsYbxvqh0Soy4SPowchj0UBGj/V6cTPnXXtQOPUbhZ6CmGzAD/rW22LQK6E96pcdJXk4A4w== - dependencies: - boolbase "^1.0.0" - -num2fraction@^1.2.2: - version "1.2.2" - resolved "https://registry.yarnpkg.com/num2fraction/-/num2fraction-1.2.2.tgz#6f682b6a027a4e9ddfa4564cd2589d1d4e669ede" - integrity sha1-b2gragJ6Tp3fpFZM0lidHU5mnt4= - -oauth-sign@~0.9.0: - version "0.9.0" - resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455" - integrity sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ== - -object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" - integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= - -object-copy@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/object-copy/-/object-copy-0.1.0.tgz#7e7d858b781bd7c991a41ba975ed3812754e998c" - integrity sha1-fn2Fi3gb18mRpBupde04EnVOmYw= - dependencies: - copy-descriptor "^0.1.0" - define-property "^0.2.5" - kind-of "^3.0.3" - -object-hash@^1.1.4: - version "1.3.1" - resolved "https://registry.yarnpkg.com/object-hash/-/object-hash-1.3.1.tgz#fde452098a951cb145f039bb7d455449ddc126df" - integrity sha512-OSuu/pU4ENM9kmREg0BdNrUDIl1heYa4mBZacJc+vVWz4GtAwu7jO8s4AIt2aGRUTqxykpWzI3Oqnsm13tTMDA== - -object-inspect@^1.11.0, object-inspect@^1.9.0: - version "1.11.0" - resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.11.0.tgz#9dceb146cedd4148a0d9e51ab88d34cf509922b1" - integrity sha512-jp7ikS6Sd3GxQfZJPyH3cjcbJF6GZPClgdV+EFygjFLQ5FmW/dRUnTd9PQ9k0JhoNDabWFbpF1yCdSWCC6gexg== - -object-is@^1.0.1: - version "1.1.5" - resolved "https://registry.yarnpkg.com/object-is/-/object-is-1.1.5.tgz#b9deeaa5fc7f1846a0faecdceec138e5778f53ac" - integrity sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.3" - -object-keys@^1.0.12, object-keys@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" - integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== - -object-visit@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/object-visit/-/object-visit-1.0.1.tgz#f79c4493af0c5377b59fe39d395e41042dd045bb" - integrity sha1-95xEk68MU3e1n+OdOV5BBC3QRbs= - dependencies: - isobject "^3.0.0" - -object.assign@^4.1.2: - version "4.1.2" - resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.2.tgz#0ed54a342eceb37b38ff76eb831a0e788cb63940" - integrity sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ== - dependencies: - call-bind "^1.0.0" - define-properties "^1.1.3" - has-symbols "^1.0.1" - object-keys "^1.1.1" - -object.getownpropertydescriptors@^2.0.3, object.getownpropertydescriptors@^2.1.0: - version "2.1.3" - resolved "https://registry.yarnpkg.com/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.3.tgz#b223cf38e17fefb97a63c10c91df72ccb386df9e" - integrity sha512-VdDoCwvJI4QdC6ndjpqFmoL3/+HxffFBbcJzKi5hwLLqqx3mdbedRpfZDdK0SrOSauj8X4GzBvnDZl4vTN7dOw== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.3" - es-abstract "^1.19.1" - -object.pick@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/object.pick/-/object.pick-1.3.0.tgz#87a10ac4c1694bd2e1cbf53591a66141fb5dd747" - integrity sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c= - dependencies: - isobject "^3.0.1" - -object.values@^1.1.0: - version "1.1.5" - resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.1.5.tgz#959f63e3ce9ef108720333082131e4a459b716ac" - integrity sha512-QUZRW0ilQ3PnPpbNtgdNV1PDbEqLIiSFB3l+EnGtBQ/8SUTLj1PZwtQHABZtLgwpJZTSZhuGLOGk57Drx2IvYg== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.3" - es-abstract "^1.19.1" - -obuf@^1.0.0, obuf@^1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/obuf/-/obuf-1.1.2.tgz#09bea3343d41859ebd446292d11c9d4db619084e" - integrity sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg== - -on-finished@~2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" - integrity sha1-IPEzZIGwg811M3mSoWlxqi2QaUc= - dependencies: - ee-first "1.1.1" - -on-headers@~1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/on-headers/-/on-headers-1.0.2.tgz#772b0ae6aaa525c399e489adfad90c403eb3c28f" - integrity sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA== - -once@^1.3.0, once@^1.3.1, once@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" - integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= - dependencies: - wrappy "1" - -onetime@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/onetime/-/onetime-2.0.1.tgz#067428230fd67443b2794b22bba528b6867962d4" - integrity sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ= - dependencies: - mimic-fn "^1.0.0" - -onetime@^5.1.0: - version "5.1.2" - resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e" - integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg== - dependencies: - mimic-fn "^2.1.0" - -open@^6.3.0: - version "6.4.0" - resolved "https://registry.yarnpkg.com/open/-/open-6.4.0.tgz#5c13e96d0dc894686164f18965ecfe889ecfc8a9" - integrity sha512-IFenVPgF70fSm1keSd2iDBIDIBZkroLeuffXq+wKTzTJlBpesFWojV9lb8mzOfaAzM1sr7HQHuO0vtV0zYekGg== - dependencies: - is-wsl "^1.1.0" - -opener@^1.5.1: - version "1.5.2" - resolved "https://registry.yarnpkg.com/opener/-/opener-1.5.2.tgz#5d37e1f35077b9dcac4301372271afdeb2a13598" - integrity sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A== - -opn@^5.5.0: - version "5.5.0" - resolved "https://registry.yarnpkg.com/opn/-/opn-5.5.0.tgz#fc7164fab56d235904c51c3b27da6758ca3b9bfc" - integrity sha512-PqHpggC9bLV0VeWcdKhkpxY+3JTzetLSqTCWL/z/tFIbI6G8JCjondXklT1JinczLz2Xib62sSp0T/gKT4KksA== - dependencies: - is-wsl "^1.1.0" - -optionator@^0.8.2: - version "0.8.3" - resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.3.tgz#84fa1d036fe9d3c7e21d99884b601167ec8fb495" - integrity sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA== - dependencies: - deep-is "~0.1.3" - fast-levenshtein "~2.0.6" - levn "~0.3.0" - prelude-ls "~1.1.2" - type-check "~0.3.2" - word-wrap "~1.2.3" - -ora@^3.4.0: - version "3.4.0" - resolved "https://registry.yarnpkg.com/ora/-/ora-3.4.0.tgz#bf0752491059a3ef3ed4c85097531de9fdbcd318" - integrity sha512-eNwHudNbO1folBP3JsZ19v9azXWtQZjICdr3Q0TDPIaeBQ3mXLrh54wM+er0+hSp+dWKf+Z8KM58CYzEyIYxYg== - dependencies: - chalk "^2.4.2" - cli-cursor "^2.1.0" - cli-spinners "^2.0.0" - log-symbols "^2.2.0" - strip-ansi "^5.2.0" - wcwidth "^1.0.1" - -original@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/original/-/original-1.0.2.tgz#e442a61cffe1c5fd20a65f3261c26663b303f25f" - integrity sha512-hyBVl6iqqUOJ8FqRe+l/gS8H+kKYjrEndd5Pm1MfBtsEKA038HkkdbAl/72EAXGyonD/PFsvmVG+EvcIpliMBg== - dependencies: - url-parse "^1.4.3" - -os-browserify@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/os-browserify/-/os-browserify-0.3.0.tgz#854373c7f5c2315914fc9bfc6bd8238fdda1ec27" - integrity sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc= - -os-tmpdir@~1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" - integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ= - -p-finally@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" - integrity sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4= - -p-finally@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-2.0.1.tgz#bd6fcaa9c559a096b680806f4d657b3f0f240561" - integrity sha512-vpm09aKwq6H9phqRQzecoDpD8TmVyGw70qmWlyq5onxY7tqyTTFVvxMykxQSQKILBSFlbXpypIw2T1Ml7+DDtw== - -p-limit@^1.0.0, p-limit@^1.1.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.3.0.tgz#b86bd5f0c25690911c7590fcbfc2010d54b3ccb8" - integrity sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q== - dependencies: - p-try "^1.0.0" - -p-limit@^2.0.0, p-limit@^2.2.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" - integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w== - dependencies: - p-try "^2.0.0" - -p-locate@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43" - integrity sha1-IKAQOyIqcMj9OcwuWAaA893l7EM= - dependencies: - p-limit "^1.1.0" - -p-locate@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-3.0.0.tgz#322d69a05c0264b25997d9f40cd8a891ab0064a4" - integrity sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ== - dependencies: - p-limit "^2.0.0" - -p-locate@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07" - integrity sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A== - dependencies: - p-limit "^2.2.0" - -p-map@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/p-map/-/p-map-2.1.0.tgz#310928feef9c9ecc65b68b17693018a665cea175" - integrity sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw== - -p-retry@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/p-retry/-/p-retry-3.0.1.tgz#316b4c8893e2c8dc1cfa891f406c4b422bebf328" - integrity sha512-XE6G4+YTTkT2a0UWb2kjZe8xNwf8bIbnqpc/IS/idOBVhyves0mK5OJgeocjx7q5pvX/6m23xuzVPYT1uGM73w== - dependencies: - retry "^0.12.0" - -p-try@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3" - integrity sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M= - -p-try@^2.0.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" - integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== - -pako@~1.0.5: - version "1.0.11" - resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.11.tgz#6c9599d340d54dfd3946380252a35705a6b992bf" - integrity sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw== - -parallel-transform@^1.1.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/parallel-transform/-/parallel-transform-1.2.0.tgz#9049ca37d6cb2182c3b1d2c720be94d14a5814fc" - integrity sha512-P2vSmIu38uIlvdcU7fDkyrxj33gTUy/ABO5ZUbGowxNCopBq/OoD42bP4UmMrJoPyk4Uqf0mu3mtWBhHCZD8yg== - dependencies: - cyclist "^1.0.1" - inherits "^2.0.3" - readable-stream "^2.1.5" - -param-case@2.1.x: - version "2.1.1" - resolved "https://registry.yarnpkg.com/param-case/-/param-case-2.1.1.tgz#df94fd8cf6531ecf75e6bef9a0858fbc72be2247" - integrity sha1-35T9jPZTHs915r75oIWPvHK+Ikc= - dependencies: - no-case "^2.2.0" - -parent-module@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" - integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== - dependencies: - callsites "^3.0.0" - -parse-asn1@^5.0.0, parse-asn1@^5.1.5: - version "5.1.6" - resolved "https://registry.yarnpkg.com/parse-asn1/-/parse-asn1-5.1.6.tgz#385080a3ec13cb62a62d39409cb3e88844cdaed4" - integrity sha512-RnZRo1EPU6JBnra2vGHj0yhp6ebyjBZpmUCLHWiFhxlzvBCCpAuZ7elsBp1PVAbQN0/04VD/19rfzlBSwLstMw== - dependencies: - asn1.js "^5.2.0" - browserify-aes "^1.0.0" - evp_bytestokey "^1.0.0" - pbkdf2 "^3.0.3" - safe-buffer "^5.1.1" - -parse-json@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-4.0.0.tgz#be35f5425be1f7f6c747184f98a788cb99477ee0" - integrity sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA= - dependencies: - error-ex "^1.3.1" - json-parse-better-errors "^1.0.1" - -parse-json@^5.0.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.2.0.tgz#c76fc66dee54231c962b22bcc8a72cf2f99753cd" - integrity sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg== - dependencies: - "@babel/code-frame" "^7.0.0" - error-ex "^1.3.1" - json-parse-even-better-errors "^2.3.0" - lines-and-columns "^1.1.6" - -parse5-htmlparser2-tree-adapter@^6.0.0: - version "6.0.1" - resolved "https://registry.yarnpkg.com/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-6.0.1.tgz#2cdf9ad823321140370d4dbf5d3e92c7c8ddc6e6" - integrity sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA== - dependencies: - parse5 "^6.0.1" - -parse5@^5.1.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/parse5/-/parse5-5.1.1.tgz#f68e4e5ba1852ac2cadc00f4555fff6c2abb6178" - integrity sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug== - -parse5@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/parse5/-/parse5-6.0.1.tgz#e1a1c085c569b3dc08321184f19a39cc27f7c30b" - integrity sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw== - -parseurl@~1.3.2, parseurl@~1.3.3: - version "1.3.3" - resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" - integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== - -pascalcase@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14" - integrity sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ= - -path-browserify@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-0.0.1.tgz#e6c4ddd7ed3aa27c68a20cc4e50e1a4ee83bbc4a" - integrity sha512-BapA40NHICOS+USX9SN4tyhq+A2RrN/Ws5F0Z5aMHDp98Fl86lX8Oti8B7uN93L4Ifv4fHOEA+pQw87gmMO/lQ== - -path-dirname@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/path-dirname/-/path-dirname-1.0.2.tgz#cc33d24d525e099a5388c0336c6e32b9160609e0" - integrity sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA= - -path-exists@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-2.1.0.tgz#0feb6c64f0fc518d9a754dd5efb62c7022761f4b" - integrity sha1-D+tsZPD8UY2adU3V77YscCJ2H0s= - dependencies: - pinkie-promise "^2.0.0" - -path-exists@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" - integrity sha1-zg6+ql94yxiSXqfYENe1mwEP1RU= - -path-exists@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" - integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== - -path-is-absolute@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" - integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= - -path-is-inside@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53" - integrity sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM= - -path-key@^2.0.0, path-key@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" - integrity sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A= - -path-key@^3.0.0, path-key@^3.1.0: - version "3.1.1" - resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" - integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== - -path-parse@^1.0.6: - version "1.0.7" - resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" - integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== - -path-to-regexp@0.1.7: - version "0.1.7" - resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" - integrity sha1-32BBeABfUi8V60SQ5yR6G/qmf4w= - -path-type@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/path-type/-/path-type-3.0.0.tgz#cef31dc8e0a1a3bb0d105c0cd97cf3bf47f4e36f" - integrity sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg== - dependencies: - pify "^3.0.0" - -path-type@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" - integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== - -pbkdf2@^3.0.3: - version "3.1.2" - resolved "https://registry.yarnpkg.com/pbkdf2/-/pbkdf2-3.1.2.tgz#dd822aa0887580e52f1a039dc3eda108efae3075" - integrity sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA== - dependencies: - create-hash "^1.1.2" - create-hmac "^1.1.4" - ripemd160 "^2.0.1" - safe-buffer "^5.0.1" - sha.js "^2.4.8" - -performance-now@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" - integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns= - -picocolors@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-0.2.1.tgz#570670f793646851d1ba135996962abad587859f" - integrity sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA== - -picocolors@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" - integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== - -picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.3: - version "2.3.0" - resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.0.tgz#f1f061de8f6a4bf022892e2d128234fb98302972" - integrity sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw== - -pify@^2.0.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" - integrity sha1-7RQaasBDqEnqWISY59yosVMw6Qw= - -pify@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176" - integrity sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY= - -pify@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/pify/-/pify-4.0.1.tgz#4b2cd25c50d598735c50292224fd8c6df41e3231" - integrity sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g== - -pinkie-promise@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa" - integrity sha1-ITXW36ejWMBprJsXh3YogihFD/o= - dependencies: - pinkie "^2.0.0" - -pinkie@^2.0.0: - version "2.0.4" - resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" - integrity sha1-clVrgM+g1IqXToDnckjoDtT3+HA= - -pkg-dir@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-1.0.0.tgz#7a4b508a8d5bb2d629d447056ff4e9c9314cf3d4" - integrity sha1-ektQio1bstYp1EcFb/TpyTFM89Q= - dependencies: - find-up "^1.0.0" - -pkg-dir@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-2.0.0.tgz#f6d5d1109e19d63edf428e0bd57e12777615334b" - integrity sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s= - dependencies: - find-up "^2.1.0" - -pkg-dir@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-3.0.0.tgz#2749020f239ed990881b1f71210d51eb6523bea3" - integrity sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw== - dependencies: - find-up "^3.0.0" - -pkg-dir@^4.1.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3" - integrity sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ== - dependencies: - find-up "^4.0.0" - -pluralize@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-7.0.0.tgz#298b89df8b93b0221dbf421ad2b1b1ea23fc6777" - integrity sha512-ARhBOdzS3e41FbkW/XWrTEtukqqLoK5+Z/4UeDaLuSW+39JPeFgs4gCGqsrJHVZX0fUrx//4OF0K1CUGwlIFow== - -portfinder@^1.0.20, portfinder@^1.0.26: - version "1.0.28" - resolved "https://registry.yarnpkg.com/portfinder/-/portfinder-1.0.28.tgz#67c4622852bd5374dd1dd900f779f53462fac778" - integrity sha512-Se+2isanIcEqf2XMHjyUKskczxbPH7dQnlMjXX6+dybayyHvAf/TCgyMRlzf/B6QDhAEFOGes0pzRo3by4AbMA== - dependencies: - async "^2.6.2" - debug "^3.1.1" - mkdirp "^0.5.5" - -posix-character-classes@^0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" - integrity sha1-AerA/jta9xoqbAL+q7jB/vfgDqs= - -postcss-calc@^7.0.1: - version "7.0.5" - resolved "https://registry.yarnpkg.com/postcss-calc/-/postcss-calc-7.0.5.tgz#f8a6e99f12e619c2ebc23cf6c486fdc15860933e" - integrity sha512-1tKHutbGtLtEZF6PT4JSihCHfIVldU72mZ8SdZHIYriIZ9fh9k9aWSppaT8rHsyI3dX+KSR+W+Ix9BMY3AODrg== - dependencies: - postcss "^7.0.27" - postcss-selector-parser "^6.0.2" - postcss-value-parser "^4.0.2" - -postcss-colormin@^4.0.3: - version "4.0.3" - resolved "https://registry.yarnpkg.com/postcss-colormin/-/postcss-colormin-4.0.3.tgz#ae060bce93ed794ac71264f08132d550956bd381" - integrity sha512-WyQFAdDZpExQh32j0U0feWisZ0dmOtPl44qYmJKkq9xFWY3p+4qnRzCHeNrkeRhwPHz9bQ3mo0/yVkaply0MNw== - dependencies: - browserslist "^4.0.0" - color "^3.0.0" - has "^1.0.0" - postcss "^7.0.0" - postcss-value-parser "^3.0.0" - -postcss-convert-values@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/postcss-convert-values/-/postcss-convert-values-4.0.1.tgz#ca3813ed4da0f812f9d43703584e449ebe189a7f" - integrity sha512-Kisdo1y77KUC0Jmn0OXU/COOJbzM8cImvw1ZFsBgBgMgb1iL23Zs/LXRe3r+EZqM3vGYKdQ2YJVQ5VkJI+zEJQ== - dependencies: - postcss "^7.0.0" - postcss-value-parser "^3.0.0" - -postcss-discard-comments@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/postcss-discard-comments/-/postcss-discard-comments-4.0.2.tgz#1fbabd2c246bff6aaad7997b2b0918f4d7af4033" - integrity sha512-RJutN259iuRf3IW7GZyLM5Sw4GLTOH8FmsXBnv8Ab/Tc2k4SR4qbV4DNbyyY4+Sjo362SyDmW2DQ7lBSChrpkg== - dependencies: - postcss "^7.0.0" - -postcss-discard-duplicates@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/postcss-discard-duplicates/-/postcss-discard-duplicates-4.0.2.tgz#3fe133cd3c82282e550fc9b239176a9207b784eb" - integrity sha512-ZNQfR1gPNAiXZhgENFfEglF93pciw0WxMkJeVmw8eF+JZBbMD7jp6C67GqJAXVZP2BWbOztKfbsdmMp/k8c6oQ== - dependencies: - postcss "^7.0.0" - -postcss-discard-empty@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/postcss-discard-empty/-/postcss-discard-empty-4.0.1.tgz#c8c951e9f73ed9428019458444a02ad90bb9f765" - integrity sha512-B9miTzbznhDjTfjvipfHoqbWKwd0Mj+/fL5s1QOz06wufguil+Xheo4XpOnc4NqKYBCNqqEzgPv2aPBIJLox0w== - dependencies: - postcss "^7.0.0" - -postcss-discard-overridden@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/postcss-discard-overridden/-/postcss-discard-overridden-4.0.1.tgz#652aef8a96726f029f5e3e00146ee7a4e755ff57" - integrity sha512-IYY2bEDD7g1XM1IDEsUT4//iEYCxAmP5oDSFMVU/JVvT7gh+l4fmjciLqGgwjdWpQIdb0Che2VX00QObS5+cTg== - dependencies: - postcss "^7.0.0" - -postcss-load-config@^2.0.0: - version "2.1.2" - resolved "https://registry.yarnpkg.com/postcss-load-config/-/postcss-load-config-2.1.2.tgz#c5ea504f2c4aef33c7359a34de3573772ad7502a" - integrity sha512-/rDeGV6vMUo3mwJZmeHfEDvwnTKKqQ0S7OHUi/kJvvtx3aWtyWG2/0ZWnzCt2keEclwN6Tf0DST2v9kITdOKYw== - dependencies: - cosmiconfig "^5.0.0" - import-cwd "^2.0.0" - -postcss-loader@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/postcss-loader/-/postcss-loader-3.0.0.tgz#6b97943e47c72d845fa9e03f273773d4e8dd6c2d" - integrity sha512-cLWoDEY5OwHcAjDnkyRQzAXfs2jrKjXpO/HQFcc5b5u/r7aa471wdmChmwfnv7x2u840iat/wi0lQ5nbRgSkUA== - dependencies: - loader-utils "^1.1.0" - postcss "^7.0.0" - postcss-load-config "^2.0.0" - schema-utils "^1.0.0" - -postcss-merge-longhand@^4.0.11: - version "4.0.11" - resolved "https://registry.yarnpkg.com/postcss-merge-longhand/-/postcss-merge-longhand-4.0.11.tgz#62f49a13e4a0ee04e7b98f42bb16062ca2549e24" - integrity sha512-alx/zmoeXvJjp7L4mxEMjh8lxVlDFX1gqWHzaaQewwMZiVhLo42TEClKaeHbRf6J7j82ZOdTJ808RtN0ZOZwvw== - dependencies: - css-color-names "0.0.4" - postcss "^7.0.0" - postcss-value-parser "^3.0.0" - stylehacks "^4.0.0" - -postcss-merge-rules@^4.0.3: - version "4.0.3" - resolved "https://registry.yarnpkg.com/postcss-merge-rules/-/postcss-merge-rules-4.0.3.tgz#362bea4ff5a1f98e4075a713c6cb25aefef9a650" - integrity sha512-U7e3r1SbvYzO0Jr3UT/zKBVgYYyhAz0aitvGIYOYK5CPmkNih+WDSsS5tvPrJ8YMQYlEMvsZIiqmn7HdFUaeEQ== - dependencies: - browserslist "^4.0.0" - caniuse-api "^3.0.0" - cssnano-util-same-parent "^4.0.0" - postcss "^7.0.0" - postcss-selector-parser "^3.0.0" - vendors "^1.0.0" - -postcss-minify-font-values@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/postcss-minify-font-values/-/postcss-minify-font-values-4.0.2.tgz#cd4c344cce474343fac5d82206ab2cbcb8afd5a6" - integrity sha512-j85oO6OnRU9zPf04+PZv1LYIYOprWm6IA6zkXkrJXyRveDEuQggG6tvoy8ir8ZwjLxLuGfNkCZEQG7zan+Hbtg== - dependencies: - postcss "^7.0.0" - postcss-value-parser "^3.0.0" - -postcss-minify-gradients@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/postcss-minify-gradients/-/postcss-minify-gradients-4.0.2.tgz#93b29c2ff5099c535eecda56c4aa6e665a663471" - integrity sha512-qKPfwlONdcf/AndP1U8SJ/uzIJtowHlMaSioKzebAXSG4iJthlWC9iSWznQcX4f66gIWX44RSA841HTHj3wK+Q== - dependencies: - cssnano-util-get-arguments "^4.0.0" - is-color-stop "^1.0.0" - postcss "^7.0.0" - postcss-value-parser "^3.0.0" - -postcss-minify-params@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/postcss-minify-params/-/postcss-minify-params-4.0.2.tgz#6b9cef030c11e35261f95f618c90036d680db874" - integrity sha512-G7eWyzEx0xL4/wiBBJxJOz48zAKV2WG3iZOqVhPet/9geefm/Px5uo1fzlHu+DOjT+m0Mmiz3jkQzVHe6wxAWg== - dependencies: - alphanum-sort "^1.0.0" - browserslist "^4.0.0" - cssnano-util-get-arguments "^4.0.0" - postcss "^7.0.0" - postcss-value-parser "^3.0.0" - uniqs "^2.0.0" - -postcss-minify-selectors@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/postcss-minify-selectors/-/postcss-minify-selectors-4.0.2.tgz#e2e5eb40bfee500d0cd9243500f5f8ea4262fbd8" - integrity sha512-D5S1iViljXBj9kflQo4YutWnJmwm8VvIsU1GeXJGiG9j8CIg9zs4voPMdQDUmIxetUOh60VilsNzCiAFTOqu3g== - dependencies: - alphanum-sort "^1.0.0" - has "^1.0.0" - postcss "^7.0.0" - postcss-selector-parser "^3.0.0" - -postcss-modules-extract-imports@^1.2.0: - version "1.2.1" - resolved "https://registry.yarnpkg.com/postcss-modules-extract-imports/-/postcss-modules-extract-imports-1.2.1.tgz#dc87e34148ec7eab5f791f7cd5849833375b741a" - integrity sha512-6jt9XZwUhwmRUhb/CkyJY020PYaPJsCyt3UjbaWo6XEbH/94Hmv6MP7fG2C5NDU/BcHzyGYxNtHvM+LTf9HrYw== - dependencies: - postcss "^6.0.1" - -postcss-modules-local-by-default@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/postcss-modules-local-by-default/-/postcss-modules-local-by-default-1.2.0.tgz#f7d80c398c5a393fa7964466bd19500a7d61c069" - integrity sha1-99gMOYxaOT+nlkRmvRlQCn1hwGk= - dependencies: - css-selector-tokenizer "^0.7.0" - postcss "^6.0.1" - -postcss-modules-scope@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/postcss-modules-scope/-/postcss-modules-scope-1.1.0.tgz#d6ea64994c79f97b62a72b426fbe6056a194bb90" - integrity sha1-1upkmUx5+XtipytCb75gVqGUu5A= - dependencies: - css-selector-tokenizer "^0.7.0" - postcss "^6.0.1" - -postcss-modules-values@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/postcss-modules-values/-/postcss-modules-values-1.3.0.tgz#ecffa9d7e192518389f42ad0e83f72aec456ea20" - integrity sha1-7P+p1+GSUYOJ9CrQ6D9yrsRW6iA= - dependencies: - icss-replace-symbols "^1.1.0" - postcss "^6.0.1" - -postcss-normalize-charset@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/postcss-normalize-charset/-/postcss-normalize-charset-4.0.1.tgz#8b35add3aee83a136b0471e0d59be58a50285dd4" - integrity sha512-gMXCrrlWh6G27U0hF3vNvR3w8I1s2wOBILvA87iNXaPvSNo5uZAMYsZG7XjCUf1eVxuPfyL4TJ7++SGZLc9A3g== - dependencies: - postcss "^7.0.0" - -postcss-normalize-display-values@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/postcss-normalize-display-values/-/postcss-normalize-display-values-4.0.2.tgz#0dbe04a4ce9063d4667ed2be476bb830c825935a" - integrity sha512-3F2jcsaMW7+VtRMAqf/3m4cPFhPD3EFRgNs18u+k3lTJJlVe7d0YPO+bnwqo2xg8YiRpDXJI2u8A0wqJxMsQuQ== - dependencies: - cssnano-util-get-match "^4.0.0" - postcss "^7.0.0" - postcss-value-parser "^3.0.0" - -postcss-normalize-positions@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/postcss-normalize-positions/-/postcss-normalize-positions-4.0.2.tgz#05f757f84f260437378368a91f8932d4b102917f" - integrity sha512-Dlf3/9AxpxE+NF1fJxYDeggi5WwV35MXGFnnoccP/9qDtFrTArZ0D0R+iKcg5WsUd8nUYMIl8yXDCtcrT8JrdA== - dependencies: - cssnano-util-get-arguments "^4.0.0" - has "^1.0.0" - postcss "^7.0.0" - postcss-value-parser "^3.0.0" - -postcss-normalize-repeat-style@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-4.0.2.tgz#c4ebbc289f3991a028d44751cbdd11918b17910c" - integrity sha512-qvigdYYMpSuoFs3Is/f5nHdRLJN/ITA7huIoCyqqENJe9PvPmLhNLMu7QTjPdtnVf6OcYYO5SHonx4+fbJE1+Q== - dependencies: - cssnano-util-get-arguments "^4.0.0" - cssnano-util-get-match "^4.0.0" - postcss "^7.0.0" - postcss-value-parser "^3.0.0" - -postcss-normalize-string@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/postcss-normalize-string/-/postcss-normalize-string-4.0.2.tgz#cd44c40ab07a0c7a36dc5e99aace1eca4ec2690c" - integrity sha512-RrERod97Dnwqq49WNz8qo66ps0swYZDSb6rM57kN2J+aoyEAJfZ6bMx0sx/F9TIEX0xthPGCmeyiam/jXif0eA== - dependencies: - has "^1.0.0" - postcss "^7.0.0" - postcss-value-parser "^3.0.0" - -postcss-normalize-timing-functions@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-4.0.2.tgz#8e009ca2a3949cdaf8ad23e6b6ab99cb5e7d28d9" - integrity sha512-acwJY95edP762e++00Ehq9L4sZCEcOPyaHwoaFOhIwWCDfik6YvqsYNxckee65JHLKzuNSSmAdxwD2Cud1Z54A== - dependencies: - cssnano-util-get-match "^4.0.0" - postcss "^7.0.0" - postcss-value-parser "^3.0.0" - -postcss-normalize-unicode@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/postcss-normalize-unicode/-/postcss-normalize-unicode-4.0.1.tgz#841bd48fdcf3019ad4baa7493a3d363b52ae1cfb" - integrity sha512-od18Uq2wCYn+vZ/qCOeutvHjB5jm57ToxRaMeNuf0nWVHaP9Hua56QyMF6fs/4FSUnVIw0CBPsU0K4LnBPwYwg== - dependencies: - browserslist "^4.0.0" - postcss "^7.0.0" - postcss-value-parser "^3.0.0" - -postcss-normalize-url@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/postcss-normalize-url/-/postcss-normalize-url-4.0.1.tgz#10e437f86bc7c7e58f7b9652ed878daaa95faae1" - integrity sha512-p5oVaF4+IHwu7VpMan/SSpmpYxcJMtkGppYf0VbdH5B6hN8YNmVyJLuY9FmLQTzY3fag5ESUUHDqM+heid0UVA== - dependencies: - is-absolute-url "^2.0.0" - normalize-url "^3.0.0" - postcss "^7.0.0" - postcss-value-parser "^3.0.0" - -postcss-normalize-whitespace@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/postcss-normalize-whitespace/-/postcss-normalize-whitespace-4.0.2.tgz#bf1d4070fe4fcea87d1348e825d8cc0c5faa7d82" - integrity sha512-tO8QIgrsI3p95r8fyqKV+ufKlSHh9hMJqACqbv2XknufqEDhDvbguXGBBqxw9nsQoXWf0qOqppziKJKHMD4GtA== - dependencies: - postcss "^7.0.0" - postcss-value-parser "^3.0.0" - -postcss-ordered-values@^4.1.2: - version "4.1.2" - resolved "https://registry.yarnpkg.com/postcss-ordered-values/-/postcss-ordered-values-4.1.2.tgz#0cf75c820ec7d5c4d280189559e0b571ebac0eee" - integrity sha512-2fCObh5UanxvSxeXrtLtlwVThBvHn6MQcu4ksNT2tsaV2Fg76R2CV98W7wNSlX+5/pFwEyaDwKLLoEV7uRybAw== - dependencies: - cssnano-util-get-arguments "^4.0.0" - postcss "^7.0.0" - postcss-value-parser "^3.0.0" - -postcss-reduce-initial@^4.0.3: - version "4.0.3" - resolved "https://registry.yarnpkg.com/postcss-reduce-initial/-/postcss-reduce-initial-4.0.3.tgz#7fd42ebea5e9c814609639e2c2e84ae270ba48df" - integrity sha512-gKWmR5aUulSjbzOfD9AlJiHCGH6AEVLaM0AV+aSioxUDd16qXP1PCh8d1/BGVvpdWn8k/HiK7n6TjeoXN1F7DA== - dependencies: - browserslist "^4.0.0" - caniuse-api "^3.0.0" - has "^1.0.0" - postcss "^7.0.0" - -postcss-reduce-transforms@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/postcss-reduce-transforms/-/postcss-reduce-transforms-4.0.2.tgz#17efa405eacc6e07be3414a5ca2d1074681d4e29" - integrity sha512-EEVig1Q2QJ4ELpJXMZR8Vt5DQx8/mo+dGWSR7vWXqcob2gQLyQGsionYcGKATXvQzMPn6DSN1vTN7yFximdIAg== - dependencies: - cssnano-util-get-match "^4.0.0" - has "^1.0.0" - postcss "^7.0.0" - postcss-value-parser "^3.0.0" - -postcss-selector-parser@^3.0.0: - version "3.1.2" - resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-3.1.2.tgz#b310f5c4c0fdaf76f94902bbaa30db6aa84f5270" - integrity sha512-h7fJ/5uWuRVyOtkO45pnt1Ih40CEleeyCHzipqAZO2e5H20g25Y48uYnFUiShvY4rZWNJ/Bib/KVPmanaCtOhA== - dependencies: - dot-prop "^5.2.0" - indexes-of "^1.0.1" - uniq "^1.0.1" - -postcss-selector-parser@^6.0.2: - version "6.0.6" - resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.0.6.tgz#2c5bba8174ac2f6981ab631a42ab0ee54af332ea" - integrity sha512-9LXrvaaX3+mcv5xkg5kFwqSzSH1JIObIx51PrndZwlmznwXRfxMddDvo9gve3gVR8ZTKgoFDdWkbRFmEhT4PMg== - dependencies: - cssesc "^3.0.0" - util-deprecate "^1.0.2" - -postcss-svgo@^4.0.3: - version "4.0.3" - resolved "https://registry.yarnpkg.com/postcss-svgo/-/postcss-svgo-4.0.3.tgz#343a2cdbac9505d416243d496f724f38894c941e" - integrity sha512-NoRbrcMWTtUghzuKSoIm6XV+sJdvZ7GZSc3wdBN0W19FTtp2ko8NqLsgoh/m9CzNhU3KLPvQmjIwtaNFkaFTvw== - dependencies: - postcss "^7.0.0" - postcss-value-parser "^3.0.0" - svgo "^1.0.0" - -postcss-unique-selectors@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/postcss-unique-selectors/-/postcss-unique-selectors-4.0.1.tgz#9446911f3289bfd64c6d680f073c03b1f9ee4bac" - integrity sha512-+JanVaryLo9QwZjKrmJgkI4Fn8SBgRO6WXQBJi7KiAVPlmxikB5Jzc4EvXMT2H0/m0RjrVVm9rGNhZddm/8Spg== - dependencies: - alphanum-sort "^1.0.0" - postcss "^7.0.0" - uniqs "^2.0.0" - -postcss-value-parser@^3.0.0, postcss-value-parser@^3.3.0: - version "3.3.1" - resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz#9ff822547e2893213cf1c30efa51ac5fd1ba8281" - integrity sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ== - -postcss-value-parser@^4.0.2, postcss-value-parser@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.1.0.tgz#443f6a20ced6481a2bda4fa8532a6e55d789a2cb" - integrity sha512-97DXOFbQJhk71ne5/Mt6cOu6yxsSfM0QGQyl0L25Gca4yGWEGJaig7l7gbCX623VqTBNGLRLaVUCnNkcedlRSQ== - -postcss@^6.0.1, postcss@^6.0.23: - version "6.0.23" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-6.0.23.tgz#61c82cc328ac60e677645f979054eb98bc0e3324" - integrity sha512-soOk1h6J3VMTZtVeVpv15/Hpdl2cBLX3CAw4TAbkpTJiNPk9YP/zWcD1ND+xEtvyuuvKzbxliTOIyvkSeSJ6ag== - dependencies: - chalk "^2.4.1" - source-map "^0.6.1" - supports-color "^5.4.0" - -postcss@^7.0.0, postcss@^7.0.1, postcss@^7.0.27, postcss@^7.0.32, postcss@^7.0.36: - version "7.0.39" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.39.tgz#9624375d965630e2e1f2c02a935c82a59cb48309" - integrity sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA== - dependencies: - picocolors "^0.2.1" - source-map "^0.6.1" - -prelude-ls@~1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" - integrity sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ= - -prepend-http@^1.0.0: - version "1.0.4" - resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-1.0.4.tgz#d4f4562b0ce3696e41ac52d0e002e57a635dc6dc" - integrity sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw= - -"prettier@^1.18.2 || ^2.0.0": - version "2.4.1" - resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.4.1.tgz#671e11c89c14a4cfc876ce564106c4a6726c9f5c" - integrity sha512-9fbDAXSBcc6Bs1mZrDYb3XKzDLm4EXXL9sC1LqKP5rZkT6KRr/rf9amVUcODVXgguK/isJz0d0hP72WeaKWsvA== - -pretty-error@^2.0.2: - version "2.1.2" - resolved "https://registry.yarnpkg.com/pretty-error/-/pretty-error-2.1.2.tgz#be89f82d81b1c86ec8fdfbc385045882727f93b6" - integrity sha512-EY5oDzmsX5wvuynAByrmY0P0hcp+QpnAKbJng2A2MPjVKXCxrDSUkzghVJ4ZGPIv+JC4gX8fPUWscC0RtjsWGw== - dependencies: - lodash "^4.17.20" - renderkid "^2.0.4" - -process-nextick-args@~2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" - integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== - -process@^0.11.10: - version "0.11.10" - resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" - integrity sha1-czIwDoQBYb2j5podHZGn1LwW8YI= - -progress@^2.0.0: - version "2.0.3" - resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" - integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== - -promise-inflight@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/promise-inflight/-/promise-inflight-1.0.1.tgz#98472870bf228132fcbdd868129bad12c3c029e3" - integrity sha1-mEcocL8igTL8vdhoEputEsPAKeM= - -proxy-addr@~2.0.5: - version "2.0.7" - resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.7.tgz#f19fe69ceab311eeb94b42e70e8c2070f9ba1025" - integrity sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg== - dependencies: - forwarded "0.2.0" - ipaddr.js "1.9.1" - -prr@~1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/prr/-/prr-1.0.1.tgz#d3fc114ba06995a45ec6893f484ceb1d78f5f476" - integrity sha1-0/wRS6BplaRexok/SEzrHXj19HY= - -pseudomap@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3" - integrity sha1-8FKijacOYYkX7wqKw0wa5aaChrM= - -psl@^1.1.28: - version "1.8.0" - resolved "https://registry.yarnpkg.com/psl/-/psl-1.8.0.tgz#9326f8bcfb013adcc005fdff056acce020e51c24" - integrity sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ== - -public-encrypt@^4.0.0: - version "4.0.3" - resolved "https://registry.yarnpkg.com/public-encrypt/-/public-encrypt-4.0.3.tgz#4fcc9d77a07e48ba7527e7cbe0de33d0701331e0" - integrity sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q== - dependencies: - bn.js "^4.1.0" - browserify-rsa "^4.0.0" - create-hash "^1.1.0" - parse-asn1 "^5.0.0" - randombytes "^2.0.1" - safe-buffer "^5.1.2" - -pump@^2.0.0, pump@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/pump/-/pump-2.0.1.tgz#12399add6e4cf7526d973cbc8b5ce2e2908b3909" - integrity sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA== - dependencies: - end-of-stream "^1.1.0" - once "^1.3.1" - -pump@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64" - integrity sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww== - dependencies: - end-of-stream "^1.1.0" - once "^1.3.1" - -pumpify@^1.3.3: - version "1.5.1" - resolved "https://registry.yarnpkg.com/pumpify/-/pumpify-1.5.1.tgz#36513be246ab27570b1a374a5ce278bfd74370ce" - integrity sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ== - dependencies: - duplexify "^3.6.0" - inherits "^2.0.3" - pump "^2.0.0" - -punycode@1.3.2: - version "1.3.2" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d" - integrity sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0= - -punycode@^1.2.4: - version "1.4.1" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" - integrity sha1-wNWmOycYgArY4esPpSachN1BhF4= - -punycode@^2.1.0, punycode@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" - integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== - -q@^1.1.2: - version "1.5.1" - resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7" - integrity sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc= - -qs@6.7.0: - version "6.7.0" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.7.0.tgz#41dc1a015e3d581f1621776be31afb2876a9b1bc" - integrity sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ== - -qs@~6.5.2: - version "6.5.2" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36" - integrity sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA== - -query-string@^4.1.0: - version "4.3.4" - resolved "https://registry.yarnpkg.com/query-string/-/query-string-4.3.4.tgz#bbb693b9ca915c232515b228b1a02b609043dbeb" - integrity sha1-u7aTucqRXCMlFbIosaArYJBD2+s= - dependencies: - object-assign "^4.1.0" - strict-uri-encode "^1.0.0" - -querystring-es3@^0.2.0: - version "0.2.1" - resolved "https://registry.yarnpkg.com/querystring-es3/-/querystring-es3-0.2.1.tgz#9ec61f79049875707d69414596fd907a4d711e73" - integrity sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM= - -querystring@0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620" - integrity sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA= - -querystringify@^2.1.1: - version "2.2.0" - resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-2.2.0.tgz#3345941b4153cb9d082d8eee4cda2016a9aef7f6" - integrity sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ== - -queue-microtask@^1.2.2: - version "1.2.3" - resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" - integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== - -randombytes@^2.0.0, randombytes@^2.0.1, randombytes@^2.0.5, randombytes@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" - integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ== - dependencies: - safe-buffer "^5.1.0" - -randomfill@^1.0.3: - version "1.0.4" - resolved "https://registry.yarnpkg.com/randomfill/-/randomfill-1.0.4.tgz#c92196fc86ab42be983f1bf31778224931d61458" - integrity sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw== - dependencies: - randombytes "^2.0.5" - safe-buffer "^5.1.0" - -range-parser@^1.2.1, range-parser@~1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" - integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg== - -raw-body@2.4.0: - version "2.4.0" - resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.4.0.tgz#a1ce6fb9c9bc356ca52e89256ab59059e13d0332" - integrity sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q== - dependencies: - bytes "3.1.0" - http-errors "1.7.2" - iconv-lite "0.4.24" - unpipe "1.0.0" - -read-pkg@^5.0.0, read-pkg@^5.1.1: - version "5.2.0" - resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-5.2.0.tgz#7bf295438ca5a33e56cd30e053b34ee7250c93cc" - integrity sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg== - dependencies: - "@types/normalize-package-data" "^2.4.0" - normalize-package-data "^2.5.0" - parse-json "^5.0.0" - type-fest "^0.6.0" - -"readable-stream@1 || 2", readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.3.3, readable-stream@^2.3.6, readable-stream@~2.3.6: - version "2.3.7" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57" - integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw== - dependencies: - core-util-is "~1.0.0" - inherits "~2.0.3" - isarray "~1.0.0" - process-nextick-args "~2.0.0" - safe-buffer "~5.1.1" - string_decoder "~1.1.1" - util-deprecate "~1.0.1" - -readable-stream@^3.0.6, readable-stream@^3.6.0: - version "3.6.0" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198" - integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA== - dependencies: - inherits "^2.0.3" - string_decoder "^1.1.1" - util-deprecate "^1.0.1" - -readdirp@^2.2.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.2.1.tgz#0e87622a3325aa33e892285caf8b4e846529a525" - integrity sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ== - dependencies: - graceful-fs "^4.1.11" - micromatch "^3.1.10" - readable-stream "^2.0.2" - -readdirp@~3.6.0: - version "3.6.0" - resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7" - integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA== - dependencies: - picomatch "^2.2.1" - -regex-not@^1.0.0, regex-not@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/regex-not/-/regex-not-1.0.2.tgz#1f4ece27e00b0b65e0247a6810e6a85d83a5752c" - integrity sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A== - dependencies: - extend-shallow "^3.0.2" - safe-regex "^1.1.0" - -regexp.prototype.flags@^1.2.0: - version "1.3.1" - resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.3.1.tgz#7ef352ae8d159e758c0eadca6f8fcb4eef07be26" - integrity sha512-JiBdRBq91WlY7uRJ0ds7R+dU02i6LKi8r3BuQhNXn+kmeLN+EfHhfjqMRis1zJxnlu88hq/4dx0P2OP3APRTOA== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.3" - -regexpp@^1.0.1: - version "1.1.0" - resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-1.1.0.tgz#0e3516dd0b7904f413d2d4193dce4618c3a689ab" - integrity sha512-LOPw8FpgdQF9etWMaAfG/WRthIdXJGYp4mJ2Jgn/2lpkbod9jPn0t9UqN7AxBOKNfzRbYyVfgc7Vk4t/MpnXgw== - -regexpp@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-2.0.1.tgz#8d19d31cf632482b589049f8281f93dbcba4d07f" - integrity sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw== - -regexpp@^3.1.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.2.0.tgz#0425a2768d8f23bad70ca4b90461fa2f1213e1b2" - integrity sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg== - -relateurl@0.2.x: - version "0.2.7" - resolved "https://registry.yarnpkg.com/relateurl/-/relateurl-0.2.7.tgz#54dbf377e51440aca90a4cd274600d3ff2d888a9" - integrity sha1-VNvzd+UUQKypCkzSdGANP/LYiKk= - -remove-trailing-separator@^1.0.1: - version "1.1.0" - resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef" - integrity sha1-wkvOKig62tW8P1jg1IJJuSN52O8= - -renderkid@^2.0.4: - version "2.0.7" - resolved "https://registry.yarnpkg.com/renderkid/-/renderkid-2.0.7.tgz#464f276a6bdcee606f4a15993f9b29fc74ca8609" - integrity sha512-oCcFyxaMrKsKcTY59qnCAtmDVSLfPbrv6A3tVbPdFMMrv5jaK10V6m40cKsoPNhAqN6rmHW9sswW4o3ruSrwUQ== - dependencies: - css-select "^4.1.3" - dom-converter "^0.2.0" - htmlparser2 "^6.1.0" - lodash "^4.17.21" - strip-ansi "^3.0.1" - -repeat-element@^1.1.2: - version "1.1.4" - resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.4.tgz#be681520847ab58c7568ac75fbfad28ed42d39e9" - integrity sha512-LFiNfRcSu7KK3evMyYOuCzv3L10TW7yC1G2/+StMjK8Y6Vqd2MG7r/Qjw4ghtuCOjFvlnms/iMmLqpvW/ES/WQ== - -repeat-string@^1.6.1: - version "1.6.1" - resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" - integrity sha1-jcrkcOHIirwtYA//Sndihtp15jc= - -request-promise-core@1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/request-promise-core/-/request-promise-core-1.1.4.tgz#3eedd4223208d419867b78ce815167d10593a22f" - integrity sha512-TTbAfBBRdWD7aNNOoVOBH4pN/KigV6LyapYNNlAPA8JwbovRti1E88m3sYAwsLi5ryhPKsE9APwnjFTgdUjTpw== - dependencies: - lodash "^4.17.19" - -request-promise-native@^1.0.7: - version "1.0.9" - resolved "https://registry.yarnpkg.com/request-promise-native/-/request-promise-native-1.0.9.tgz#e407120526a5efdc9a39b28a5679bf47b9d9dc28" - integrity sha512-wcW+sIUiWnKgNY0dqCpOZkUbF/I+YPi+f09JZIDa39Ec+q82CpSYniDp+ISgTTbKmnpJWASeJBPZmoxH84wt3g== - dependencies: - request-promise-core "1.1.4" - stealthy-require "^1.1.1" - tough-cookie "^2.3.3" - -request@^2.87.0, request@^2.88.2: - version "2.88.2" - resolved "https://registry.yarnpkg.com/request/-/request-2.88.2.tgz#d73c918731cb5a87da047e207234146f664d12b3" - integrity sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw== - dependencies: - aws-sign2 "~0.7.0" - aws4 "^1.8.0" - caseless "~0.12.0" - combined-stream "~1.0.6" - extend "~3.0.2" - forever-agent "~0.6.1" - form-data "~2.3.2" - har-validator "~5.1.3" - http-signature "~1.2.0" - is-typedarray "~1.0.0" - isstream "~0.1.2" - json-stringify-safe "~5.0.1" - mime-types "~2.1.19" - oauth-sign "~0.9.0" - performance-now "^2.1.0" - qs "~6.5.2" - safe-buffer "^5.1.2" - tough-cookie "~2.5.0" - tunnel-agent "^0.6.0" - uuid "^3.3.2" - -require-directory@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" - integrity sha1-jGStX9MNqxyXbiNE/+f3kqam30I= - -require-main-filename@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b" - integrity sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg== - -require-uncached@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/require-uncached/-/require-uncached-1.0.3.tgz#4e0d56d6c9662fd31e43011c4b95aa49955421d3" - integrity sha1-Tg1W1slmL9MeQwEcS5WqSZVUIdM= - dependencies: - caller-path "^0.1.0" - resolve-from "^1.0.0" - -requires-port@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" - integrity sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8= - -resolve-cwd@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-2.0.0.tgz#00a9f7387556e27038eae232caa372a6a59b665a" - integrity sha1-AKn3OHVW4nA46uIyyqNypqWbZlo= - dependencies: - resolve-from "^3.0.0" - -resolve-from@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-1.0.1.tgz#26cbfe935d1aeeeabb29bc3fe5aeb01e93d44226" - integrity sha1-Jsv+k10a7uq7Kbw/5a6wHpPUQiY= - -resolve-from@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-3.0.0.tgz#b22c7af7d9d6881bc8b6e653335eebcb0a188748" - integrity sha1-six699nWiBvItuZTM17rywoYh0g= - -resolve-from@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" - integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== - -resolve-url@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" - integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo= - -resolve@^1.10.0, resolve@^1.12.0, resolve@^1.3.2: - version "1.20.0" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.20.0.tgz#629a013fb3f70755d6f0b7935cc1c2c5378b1975" - integrity sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A== - dependencies: - is-core-module "^2.2.0" - path-parse "^1.0.6" - -restore-cursor@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-2.0.0.tgz#9f7ee287f82fd326d4fd162923d62129eee0dfaf" - integrity sha1-n37ih/gv0ybU/RYpI9YhKe7g368= - dependencies: - onetime "^2.0.0" - signal-exit "^3.0.2" - -ret@~0.1.10: - version "0.1.15" - resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc" - integrity sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg== - -retry@^0.12.0: - version "0.12.0" - resolved "https://registry.yarnpkg.com/retry/-/retry-0.12.0.tgz#1b42a6266a21f07421d1b0b54b7dc167b01c013b" - integrity sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs= - -reusify@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" - integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== - -rgb-regex@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/rgb-regex/-/rgb-regex-1.0.1.tgz#c0e0d6882df0e23be254a475e8edd41915feaeb1" - integrity sha1-wODWiC3w4jviVKR16O3UGRX+rrE= - -rgba-regex@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/rgba-regex/-/rgba-regex-1.0.0.tgz#43374e2e2ca0968b0ef1523460b7d730ff22eeb3" - integrity sha1-QzdOLiyglosO8VI0YLfXMP8i7rM= - -rimraf@2.6.3, rimraf@~2.6.2: - version "2.6.3" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab" - integrity sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA== - dependencies: - glob "^7.1.3" - -rimraf@^2.5.4, rimraf@^2.6.1, rimraf@^2.6.2, rimraf@^2.6.3: - version "2.7.1" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec" - integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w== - dependencies: - glob "^7.1.3" - -ripemd160@^2.0.0, ripemd160@^2.0.1: - version "2.0.2" - resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-2.0.2.tgz#a1c1a6f624751577ba5d07914cbc92850585890c" - integrity sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA== - dependencies: - hash-base "^3.0.0" - inherits "^2.0.1" - -run-async@^2.2.0: - version "2.4.1" - resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.4.1.tgz#8440eccf99ea3e70bd409d49aab88e10c189a455" - integrity sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ== - -run-parallel@^1.1.9: - version "1.2.0" - resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" - integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA== - dependencies: - queue-microtask "^1.2.2" - -run-queue@^1.0.0, run-queue@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/run-queue/-/run-queue-1.0.3.tgz#e848396f057d223f24386924618e25694161ec47" - integrity sha1-6Eg5bwV9Ij8kOGkkYY4laUFh7Ec= - dependencies: - aproba "^1.1.1" - -rx-lite-aggregates@^4.0.8: - version "4.0.8" - resolved "https://registry.yarnpkg.com/rx-lite-aggregates/-/rx-lite-aggregates-4.0.8.tgz#753b87a89a11c95467c4ac1626c4efc4e05c67be" - integrity sha1-dTuHqJoRyVRnxKwWJsTvxOBcZ74= - dependencies: - rx-lite "*" - -rx-lite@*, rx-lite@^4.0.8: - version "4.0.8" - resolved "https://registry.yarnpkg.com/rx-lite/-/rx-lite-4.0.8.tgz#0b1e11af8bc44836f04a6407e92da42467b79444" - integrity sha1-Cx4Rr4vESDbwSmQH6S2kJGe3lEQ= - -rxjs@^6.4.0: - version "6.6.7" - resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.6.7.tgz#90ac018acabf491bf65044235d5863c4dab804c9" - integrity sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ== - dependencies: - tslib "^1.9.0" - -safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: - version "5.1.2" - resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" - integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== - -safe-buffer@>=5.1.0, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@^5.2.0, safe-buffer@~5.2.0: - version "5.2.1" - resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" - integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== - -safe-regex@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/safe-regex/-/safe-regex-1.1.0.tgz#40a3669f3b077d1e943d44629e157dd48023bf2e" - integrity sha1-QKNmnzsHfR6UPURinhV91IAjvy4= - dependencies: - ret "~0.1.10" - -"safer-buffer@>= 2.1.2 < 3", safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0: - version "2.1.2" - resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" - integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== - -sax@~1.2.4: - version "1.2.4" - resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" - integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== - -schema-utils@2.7.0: - version "2.7.0" - resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-2.7.0.tgz#17151f76d8eae67fbbf77960c33c676ad9f4efc7" - integrity sha512-0ilKFI6QQF5nxDZLFn2dMjvc4hjg/Wkg7rHd3jK6/A4a1Hl9VFdQWvgB1UMGoU94pad1P/8N7fMcEnLnSiju8A== - dependencies: - "@types/json-schema" "^7.0.4" - ajv "^6.12.2" - ajv-keywords "^3.4.1" - -schema-utils@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-1.0.0.tgz#0b79a93204d7b600d4b2850d1f66c2a34951c770" - integrity sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g== - dependencies: - ajv "^6.1.0" - ajv-errors "^1.0.0" - ajv-keywords "^3.1.0" - -schema-utils@^2.0.0: - version "2.7.1" - resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-2.7.1.tgz#1ca4f32d1b24c590c203b8e7a50bf0ea4cd394d7" - integrity sha512-SHiNtMOUGWBQJwzISiVYKu82GiV4QYGePp3odlY1tuKO7gPtphAT5R/py0fA6xtbgLL/RvtJZnU9b8s0F1q0Xg== - dependencies: - "@types/json-schema" "^7.0.5" - ajv "^6.12.4" - ajv-keywords "^3.5.2" - -select-hose@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/select-hose/-/select-hose-2.0.0.tgz#625d8658f865af43ec962bfc376a37359a4994ca" - integrity sha1-Yl2GWPhlr0Psliv8N2o3NZpJlMo= - -selfsigned@^1.10.8: - version "1.10.11" - resolved "https://registry.yarnpkg.com/selfsigned/-/selfsigned-1.10.11.tgz#24929cd906fe0f44b6d01fb23999a739537acbe9" - integrity sha512-aVmbPOfViZqOZPgRBT0+3u4yZFHpmnIghLMlAcb5/xhp5ZtB/RVnKhz5vl2M32CLXAqR4kha9zfhNg0Lf/sxKA== - dependencies: - node-forge "^0.10.0" - -"semver@2 || 3 || 4 || 5", semver@^5.3.0, semver@^5.5.0, semver@^5.5.1, semver@^5.6.0: - version "5.7.1" - resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" - integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== - -semver@5.5.0: - version "5.5.0" - resolved "https://registry.yarnpkg.com/semver/-/semver-5.5.0.tgz#dc4bbc7a6ca9d916dee5d43516f0092b58f7b8ab" - integrity sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA== - -semver@^6.0.0, semver@^6.1.0, semver@^6.3.0: - version "6.3.0" - resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" - integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== - -semver@^7.3.2, semver@^7.3.5: - version "7.3.5" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.5.tgz#0b621c879348d8998e4b0e4be94b3f12e6018ef7" - integrity sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ== - dependencies: - lru-cache "^6.0.0" - -send@0.17.1: - version "0.17.1" - resolved "https://registry.yarnpkg.com/send/-/send-0.17.1.tgz#c1d8b059f7900f7466dd4938bdc44e11ddb376c8" - integrity sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg== - dependencies: - debug "2.6.9" - depd "~1.1.2" - destroy "~1.0.4" - encodeurl "~1.0.2" - escape-html "~1.0.3" - etag "~1.8.1" - fresh "0.5.2" - http-errors "~1.7.2" - mime "1.6.0" - ms "2.1.1" - on-finished "~2.3.0" - range-parser "~1.2.1" - statuses "~1.5.0" - -serialize-javascript@^1.4.0: - version "1.9.1" - resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-1.9.1.tgz#cfc200aef77b600c47da9bb8149c943e798c2fdb" - integrity sha512-0Vb/54WJ6k5v8sSWN09S0ora+Hnr+cX40r9F170nT+mSkaxltoE/7R3OrIdBSUv1OoiobH1QoWQbCnAO+e8J1A== - -serialize-javascript@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-4.0.0.tgz#b525e1238489a5ecfc42afacc3fe99e666f4b1aa" - integrity sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw== - dependencies: - randombytes "^2.1.0" - -serve-index@^1.9.1: - version "1.9.1" - resolved "https://registry.yarnpkg.com/serve-index/-/serve-index-1.9.1.tgz#d3768d69b1e7d82e5ce050fff5b453bea12a9239" - integrity sha1-03aNabHn2C5c4FD/9bRTvqEqkjk= - dependencies: - accepts "~1.3.4" - batch "0.6.1" - debug "2.6.9" - escape-html "~1.0.3" - http-errors "~1.6.2" - mime-types "~2.1.17" - parseurl "~1.3.2" - -serve-static@1.14.1: - version "1.14.1" - resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.14.1.tgz#666e636dc4f010f7ef29970a88a674320898b2f9" - integrity sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg== - dependencies: - encodeurl "~1.0.2" - escape-html "~1.0.3" - parseurl "~1.3.3" - send "0.17.1" - -set-blocking@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" - integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc= - -set-value@^2.0.0, set-value@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/set-value/-/set-value-2.0.1.tgz#a18d40530e6f07de4228c7defe4227af8cad005b" - integrity sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw== - dependencies: - extend-shallow "^2.0.1" - is-extendable "^0.1.1" - is-plain-object "^2.0.3" - split-string "^3.0.1" - -setimmediate@^1.0.4: - version "1.0.5" - resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" - integrity sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU= - -setprototypeof@1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.0.tgz#d0bd85536887b6fe7c0d818cb962d9d91c54e656" - integrity sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ== - -setprototypeof@1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.1.tgz#7e95acb24aa92f5885e0abef5ba131330d4ae683" - integrity sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw== - -sha.js@^2.4.0, sha.js@^2.4.8: - version "2.4.11" - resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.4.11.tgz#37a5cf0b81ecbc6943de109ba2960d1b26584ae7" - integrity sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ== - dependencies: - inherits "^2.0.1" - safe-buffer "^5.0.1" - -shebang-command@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" - integrity sha1-RKrGW2lbAzmJaMOfNj/uXer98eo= - dependencies: - shebang-regex "^1.0.0" - -shebang-command@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" - integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== - dependencies: - shebang-regex "^3.0.0" - -shebang-regex@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" - integrity sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM= - -shebang-regex@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" - integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== - -shell-quote@^1.6.1: - version "1.7.3" - resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.7.3.tgz#aa40edac170445b9a431e17bb62c0b881b9c4123" - integrity sha512-Vpfqwm4EnqGdlsBFNmHhxhElJYrdfcxPThu+ryKS5J8L/fhAwLazFZtq+S+TWZ9ANj2piSQLGj6NQg+lKPmxrw== - -side-channel@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf" - integrity sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw== - dependencies: - call-bind "^1.0.0" - get-intrinsic "^1.0.2" - object-inspect "^1.9.0" - -signal-exit@^3.0.0, signal-exit@^3.0.2: - version "3.0.5" - resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.5.tgz#9e3e8cc0c75a99472b44321033a7702e7738252f" - integrity sha512-KWcOiKeQj6ZyXx7zq4YxSMgHRlod4czeBQZrPb8OKcohcqAXShm7E20kEMle9WBt26hFcAf0qLOcp5zmY7kOqQ== - -simple-swizzle@^0.2.2: - version "0.2.2" - resolved "https://registry.yarnpkg.com/simple-swizzle/-/simple-swizzle-0.2.2.tgz#a4da6b635ffcccca33f70d17cb92592de95e557a" - integrity sha1-pNprY1/8zMoz9w0Xy5JZLeleVXo= - dependencies: - is-arrayish "^0.3.1" - -slash@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55" - integrity sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU= - -slash@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/slash/-/slash-2.0.0.tgz#de552851a1759df3a8f206535442f5ec4ddeab44" - integrity sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A== - -slash@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" - integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== - -slice-ansi@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-1.0.0.tgz#044f1a49d8842ff307aad6b505ed178bd950134d" - integrity sha512-POqxBK6Lb3q6s047D/XsDVNPnF9Dl8JSaqe9h9lURl0OdNqy/ujDrOiIHtsqXMGbWWTIomRzAMaTyawAU//Reg== - dependencies: - is-fullwidth-code-point "^2.0.0" - -slice-ansi@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-2.1.0.tgz#cacd7693461a637a5788d92a7dd4fba068e81636" - integrity sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ== - dependencies: - ansi-styles "^3.2.0" - astral-regex "^1.0.0" - is-fullwidth-code-point "^2.0.0" - -snapdragon-node@^2.0.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b" - integrity sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw== - dependencies: - define-property "^1.0.0" - isobject "^3.0.0" - snapdragon-util "^3.0.1" - -snapdragon-util@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/snapdragon-util/-/snapdragon-util-3.0.1.tgz#f956479486f2acd79700693f6f7b805e45ab56e2" - integrity sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ== - dependencies: - kind-of "^3.2.0" - -snapdragon@^0.8.1: - version "0.8.2" - resolved "https://registry.yarnpkg.com/snapdragon/-/snapdragon-0.8.2.tgz#64922e7c565b0e14204ba1aa7d6964278d25182d" - integrity sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg== - dependencies: - base "^0.11.1" - debug "^2.2.0" - define-property "^0.2.5" - extend-shallow "^2.0.1" - map-cache "^0.2.2" - source-map "^0.5.6" - source-map-resolve "^0.5.0" - use "^3.1.0" - -sockjs-client@^1.5.0: - version "1.5.2" - resolved "https://registry.yarnpkg.com/sockjs-client/-/sockjs-client-1.5.2.tgz#4bc48c2da9ce4769f19dc723396b50f5c12330a3" - integrity sha512-ZzRxPBISQE7RpzlH4tKJMQbHM9pabHluk0WBaxAQ+wm/UieeBVBou0p4wVnSQGN9QmpAZygQ0cDIypWuqOFmFQ== - dependencies: - debug "^3.2.6" - eventsource "^1.0.7" - faye-websocket "^0.11.3" - inherits "^2.0.4" - json3 "^3.3.3" - url-parse "^1.5.3" - -sockjs@^0.3.21: - version "0.3.21" - resolved "https://registry.yarnpkg.com/sockjs/-/sockjs-0.3.21.tgz#b34ffb98e796930b60a0cfa11904d6a339a7d417" - integrity sha512-DhbPFGpxjc6Z3I+uX07Id5ZO2XwYsWOrYjaSeieES78cq+JaJvVe5q/m1uvjIQhXinhIeCFRH6JgXe+mvVMyXw== - dependencies: - faye-websocket "^0.11.3" - uuid "^3.4.0" - websocket-driver "^0.7.4" - -sort-keys@^1.0.0: - version "1.1.2" - resolved "https://registry.yarnpkg.com/sort-keys/-/sort-keys-1.1.2.tgz#441b6d4d346798f1b4e49e8920adfba0e543f9ad" - integrity sha1-RBttTTRnmPG05J6JIK37oOVD+a0= - dependencies: - is-plain-obj "^1.0.0" - -source-list-map@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-2.0.1.tgz#3993bd873bfc48479cca9ea3a547835c7c154b34" - integrity sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw== - -source-map-resolve@^0.5.0: - version "0.5.3" - resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.3.tgz#190866bece7553e1f8f267a2ee82c606b5509a1a" - integrity sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw== - dependencies: - atob "^2.1.2" - decode-uri-component "^0.2.0" - resolve-url "^0.2.1" - source-map-url "^0.4.0" - urix "^0.1.0" - -source-map-support@~0.5.12: - version "0.5.20" - resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.20.tgz#12166089f8f5e5e8c56926b377633392dd2cb6c9" - integrity sha512-n1lZZ8Ve4ksRqizaBQgxXDgKwttHDhyfQjA6YZZn8+AroHbsIz+JjwxQDxbp+7y5OYCI8t1Yk7etjD9CRd2hIw== - dependencies: - buffer-from "^1.0.0" - source-map "^0.6.0" - -source-map-url@^0.4.0: - version "0.4.1" - resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.1.tgz#0af66605a745a5a2f91cf1bbf8a7afbc283dec56" - integrity sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw== - -source-map@^0.5.0, source-map@^0.5.6: - version "0.5.7" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" - integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= - -source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.0, source-map@~0.6.1: - version "0.6.1" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" - integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== - -spdx-correct@^3.0.0: - version "3.1.1" - resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.1.1.tgz#dece81ac9c1e6713e5f7d1b6f17d468fa53d89a9" - integrity sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w== - dependencies: - spdx-expression-parse "^3.0.0" - spdx-license-ids "^3.0.0" - -spdx-exceptions@^2.1.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz#3f28ce1a77a00372683eade4a433183527a2163d" - integrity sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A== - -spdx-expression-parse@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz#cf70f50482eefdc98e3ce0a6833e4a53ceeba679" - integrity sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q== - dependencies: - spdx-exceptions "^2.1.0" - spdx-license-ids "^3.0.0" - -spdx-license-ids@^3.0.0: - version "3.0.10" - resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.10.tgz#0d9becccde7003d6c658d487dd48a32f0bf3014b" - integrity sha512-oie3/+gKf7QtpitB0LYLETe+k8SifzsX4KixvpOsbI6S0kRiRQ5MKOio8eMSAKQ17N06+wdEOXRiId+zOxo0hA== - -spdy-transport@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/spdy-transport/-/spdy-transport-3.0.0.tgz#00d4863a6400ad75df93361a1608605e5dcdcf31" - integrity sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw== - dependencies: - debug "^4.1.0" - detect-node "^2.0.4" - hpack.js "^2.1.6" - obuf "^1.1.2" - readable-stream "^3.0.6" - wbuf "^1.7.3" - -spdy@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/spdy/-/spdy-4.0.2.tgz#b74f466203a3eda452c02492b91fb9e84a27677b" - integrity sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA== - dependencies: - debug "^4.1.0" - handle-thing "^2.0.0" - http-deceiver "^1.2.7" - select-hose "^2.0.0" - spdy-transport "^3.0.0" - -split-string@^3.0.1, split-string@^3.0.2: - version "3.1.0" - resolved "https://registry.yarnpkg.com/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2" - integrity sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw== - dependencies: - extend-shallow "^3.0.0" - -sprintf-js@~1.0.2: - version "1.0.3" - resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" - integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= - -sshpk@^1.7.0: - version "1.16.1" - resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.16.1.tgz#fb661c0bef29b39db40769ee39fa70093d6f6877" - integrity sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg== - dependencies: - asn1 "~0.2.3" - assert-plus "^1.0.0" - bcrypt-pbkdf "^1.0.0" - dashdash "^1.12.0" - ecc-jsbn "~0.1.1" - getpass "^0.1.1" - jsbn "~0.1.0" - safer-buffer "^2.0.2" - tweetnacl "~0.14.0" - -ssri@^5.2.4: - version "5.3.0" - resolved "https://registry.yarnpkg.com/ssri/-/ssri-5.3.0.tgz#ba3872c9c6d33a0704a7d71ff045e5ec48999d06" - integrity sha512-XRSIPqLij52MtgoQavH/x/dU1qVKtWUAAZeOHsR9c2Ddi4XerFy3mc1alf+dLJKl9EUIm/Ht+EowFkTUOA6GAQ== - dependencies: - safe-buffer "^5.1.1" - -ssri@^6.0.1: - version "6.0.2" - resolved "https://registry.yarnpkg.com/ssri/-/ssri-6.0.2.tgz#157939134f20464e7301ddba3e90ffa8f7728ac5" - integrity sha512-cepbSq/neFK7xB6A50KHN0xHDotYzq58wWCa5LeWqnPrHG8GzfEjO/4O8kpmcGW+oaxkvhEJCWgbgNk4/ZV93Q== - dependencies: - figgy-pudding "^3.5.1" - -stable@^0.1.8: - version "0.1.8" - resolved "https://registry.yarnpkg.com/stable/-/stable-0.1.8.tgz#836eb3c8382fe2936feaf544631017ce7d47a3cf" - integrity sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w== - -stackframe@^1.1.1: - version "1.2.0" - resolved "https://registry.yarnpkg.com/stackframe/-/stackframe-1.2.0.tgz#52429492d63c62eb989804c11552e3d22e779303" - integrity sha512-GrdeshiRmS1YLMYgzF16olf2jJ/IzxXY9lhKOskuVziubpTYcYqyOwYeJKzQkwy7uN0fYSsbsC4RQaXf9LCrYA== - -static-extend@^0.1.1: - version "0.1.2" - resolved "https://registry.yarnpkg.com/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6" - integrity sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY= - dependencies: - define-property "^0.2.5" - object-copy "^0.1.0" - -"statuses@>= 1.4.0 < 2", "statuses@>= 1.5.0 < 2", statuses@~1.5.0: - version "1.5.0" - resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" - integrity sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow= - -stealthy-require@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/stealthy-require/-/stealthy-require-1.1.1.tgz#35b09875b4ff49f26a777e509b3090a3226bf24b" - integrity sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks= - -stream-browserify@^2.0.1: - version "2.0.2" - resolved "https://registry.yarnpkg.com/stream-browserify/-/stream-browserify-2.0.2.tgz#87521d38a44aa7ee91ce1cd2a47df0cb49dd660b" - integrity sha512-nX6hmklHs/gr2FuxYDltq8fJA1GDlxKQCz8O/IM4atRqBH8OORmBNgfvW5gG10GT/qQ9u0CzIvr2X5Pkt6ntqg== - dependencies: - inherits "~2.0.1" - readable-stream "^2.0.2" - -stream-each@^1.1.0: - version "1.2.3" - resolved "https://registry.yarnpkg.com/stream-each/-/stream-each-1.2.3.tgz#ebe27a0c389b04fbcc233642952e10731afa9bae" - integrity sha512-vlMC2f8I2u/bZGqkdfLQW/13Zihpej/7PmSiMQsbYddxuTsJp8vRe2x2FvVExZg7FaOds43ROAuFJwPR4MTZLw== - dependencies: - end-of-stream "^1.1.0" - stream-shift "^1.0.0" - -stream-http@^2.7.2: - version "2.8.3" - resolved "https://registry.yarnpkg.com/stream-http/-/stream-http-2.8.3.tgz#b2d242469288a5a27ec4fe8933acf623de6514fc" - integrity sha512-+TSkfINHDo4J+ZobQLWiMouQYB+UVYFttRA94FpEzzJ7ZdqcL4uUUQ7WkdkI4DSozGmgBUE/a47L+38PenXhUw== - dependencies: - builtin-status-codes "^3.0.0" - inherits "^2.0.1" - readable-stream "^2.3.6" - to-arraybuffer "^1.0.0" - xtend "^4.0.0" - -stream-shift@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/stream-shift/-/stream-shift-1.0.1.tgz#d7088281559ab2778424279b0877da3c392d5a3d" - integrity sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ== - -strict-uri-encode@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz#279b225df1d582b1f54e65addd4352e18faa0713" - integrity sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM= - -string-width@^2.0.0, string-width@^2.1.0, string-width@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" - integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw== - dependencies: - is-fullwidth-code-point "^2.0.0" - strip-ansi "^4.0.0" - -string-width@^3.0.0, string-width@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-3.1.0.tgz#22767be21b62af1081574306f69ac51b62203961" - integrity sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w== - dependencies: - emoji-regex "^7.0.1" - is-fullwidth-code-point "^2.0.0" - strip-ansi "^5.1.0" - -string-width@^4.1.0, string-width@^4.2.0: - version "4.2.3" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" - integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== - dependencies: - emoji-regex "^8.0.0" - is-fullwidth-code-point "^3.0.0" - strip-ansi "^6.0.1" - -string.prototype.padend@^3.0.0: - version "3.1.3" - resolved "https://registry.yarnpkg.com/string.prototype.padend/-/string.prototype.padend-3.1.3.tgz#997a6de12c92c7cb34dc8a201a6c53d9bd88a5f1" - integrity sha512-jNIIeokznm8SD/TZISQsZKYu7RJyheFNt84DUPrh482GC8RVp2MKqm2O5oBRdGxbDQoXrhhWtPIWQOiy20svUg== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.3" - es-abstract "^1.19.1" - -string.prototype.padstart@^3.0.0: - version "3.1.3" - resolved "https://registry.yarnpkg.com/string.prototype.padstart/-/string.prototype.padstart-3.1.3.tgz#4551d0117d9501692ec6000b15056ac3f816cfa5" - integrity sha512-NZydyOMtYxpTjGqp0VN5PYUF/tsU15yDMZnUdj16qRUIUiMJkHHSDElYyQFrMu+/WloTpA7MQSiADhBicDfaoA== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.3" - es-abstract "^1.19.1" - -string.prototype.trimend@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz#e75ae90c2942c63504686c18b287b4a0b1a45f80" - integrity sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.3" - -string.prototype.trimstart@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz#b36399af4ab2999b4c9c648bd7a3fb2bb26feeed" - integrity sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.3" - -string_decoder@^1.0.0, string_decoder@^1.1.1: - version "1.3.0" - resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" - integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== - dependencies: - safe-buffer "~5.2.0" - -string_decoder@~1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" - integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== - dependencies: - safe-buffer "~5.1.0" - -strip-ansi@^3.0.0, strip-ansi@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" - integrity sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8= - dependencies: - ansi-regex "^2.0.0" - -strip-ansi@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" - integrity sha1-qEeQIusaw2iocTibY1JixQXuNo8= - dependencies: - ansi-regex "^3.0.0" - -strip-ansi@^5, strip-ansi@^5.0.0, strip-ansi@^5.1.0, strip-ansi@^5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae" - integrity sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA== - dependencies: - ansi-regex "^4.1.0" - -strip-ansi@^6.0.0, strip-ansi@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" - integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== - dependencies: - ansi-regex "^5.0.1" - -strip-eof@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" - integrity sha1-u0P/VZim6wXYm1n80SnJgzE2Br8= - -strip-final-newline@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad" - integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA== - -strip-indent@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-2.0.0.tgz#5ef8db295d01e6ed6cbf7aab96998d7822527b68" - integrity sha1-XvjbKV0B5u1sv3qrlpmNeCJSe2g= - -strip-json-comments@^2.0.1, strip-json-comments@~2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" - integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo= - -stylehacks@^4.0.0: - version "4.0.3" - resolved "https://registry.yarnpkg.com/stylehacks/-/stylehacks-4.0.3.tgz#6718fcaf4d1e07d8a1318690881e8d96726a71d5" - integrity sha512-7GlLk9JwlElY4Y6a/rmbH2MhVlTyVmiJd1PfTCqFaIBEGMYNsrO/v3SeGTdhBThLg4Z+NbOk/qFMwCa+J+3p/g== - dependencies: - browserslist "^4.0.0" - postcss "^7.0.0" - postcss-selector-parser "^3.0.0" - -supports-color@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" - integrity sha1-U10EXOa2Nj+kARcIRimZXp3zJMc= - -supports-color@^5.3.0, supports-color@^5.4.0: - version "5.5.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" - integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== - dependencies: - has-flag "^3.0.0" - -supports-color@^6.1.0: - version "6.1.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-6.1.0.tgz#0764abc69c63d5ac842dd4867e8d025e880df8f3" - integrity sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ== - dependencies: - has-flag "^3.0.0" - -supports-color@^7.1.0: - version "7.2.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" - integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== - dependencies: - has-flag "^4.0.0" - -svgo@^1.0.0: - version "1.3.2" - resolved "https://registry.yarnpkg.com/svgo/-/svgo-1.3.2.tgz#b6dc511c063346c9e415b81e43401145b96d4167" - integrity sha512-yhy/sQYxR5BkC98CY7o31VGsg014AKLEPxdfhora76l36hD9Rdy5NZA/Ocn6yayNPgSamYdtX2rFJdcv07AYVw== - dependencies: - chalk "^2.4.1" - coa "^2.0.2" - css-select "^2.0.0" - css-select-base-adapter "^0.1.1" - css-tree "1.0.0-alpha.37" - csso "^4.0.2" - js-yaml "^3.13.1" - mkdirp "~0.5.1" - object.values "^1.1.0" - sax "~1.2.4" - stable "^0.1.8" - unquote "~1.1.1" - util.promisify "~1.0.0" - -table@4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/table/-/table-4.0.2.tgz#a33447375391e766ad34d3486e6e2aedc84d2e36" - integrity sha512-UUkEAPdSGxtRpiV9ozJ5cMTtYiqz7Ni1OGqLXRCynrvzdtR1p+cfOWe2RJLwvUG8hNanaSRjecIqwOjqeatDsA== - dependencies: - ajv "^5.2.3" - ajv-keywords "^2.1.0" - chalk "^2.1.0" - lodash "^4.17.4" - slice-ansi "1.0.0" - string-width "^2.1.1" - -table@^5.2.3: - version "5.4.6" - resolved "https://registry.yarnpkg.com/table/-/table-5.4.6.tgz#1292d19500ce3f86053b05f0e8e7e4a3bb21079e" - integrity sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug== - dependencies: - ajv "^6.10.2" - lodash "^4.17.14" - slice-ansi "^2.1.0" - string-width "^3.0.0" - -tapable@^1.0.0, tapable@^1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/tapable/-/tapable-1.1.3.tgz#a1fccc06b58db61fd7a45da2da44f5f3a3e67ba2" - integrity sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA== - -terser-webpack-plugin@^1.2.3, terser-webpack-plugin@^1.4.3: - version "1.4.5" - resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-1.4.5.tgz#a217aefaea330e734ffacb6120ec1fa312d6040b" - integrity sha512-04Rfe496lN8EYruwi6oPQkG0vo8C+HT49X687FZnpPF0qMAIHONI6HEXYPKDOE8e5HjXTyKfqRd/agHtH0kOtw== - dependencies: - cacache "^12.0.2" - find-cache-dir "^2.1.0" - is-wsl "^1.1.0" - schema-utils "^1.0.0" - serialize-javascript "^4.0.0" - source-map "^0.6.1" - terser "^4.1.2" - webpack-sources "^1.4.0" - worker-farm "^1.7.0" - -terser@^4.1.2: - version "4.8.0" - resolved "https://registry.yarnpkg.com/terser/-/terser-4.8.0.tgz#63056343d7c70bb29f3af665865a46fe03a0df17" - integrity sha512-EAPipTNeWsb/3wLPeup1tVPaXfIaU68xMnVdPafIL1TV05OhASArYyIfFvnvJCNrR2NIOvDVNNTFRa+Re2MWyw== - dependencies: - commander "^2.20.0" - source-map "~0.6.1" - source-map-support "~0.5.12" - -text-table@^0.2.0, text-table@~0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" - integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ= - -thenify-all@^1.0.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/thenify-all/-/thenify-all-1.6.0.tgz#1a1918d402d8fc3f98fbf234db0bcc8cc10e9726" - integrity sha1-GhkY1ALY/D+Y+/I02wvMjMEOlyY= - dependencies: - thenify ">= 3.1.0 < 4" - -"thenify@>= 3.1.0 < 4": - version "3.3.1" - resolved "https://registry.yarnpkg.com/thenify/-/thenify-3.3.1.tgz#8932e686a4066038a016dd9e2ca46add9838a95f" - integrity sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw== - dependencies: - any-promise "^1.0.0" - -thread-loader@^2.1.2, thread-loader@^2.1.3: - version "2.1.3" - resolved "https://registry.yarnpkg.com/thread-loader/-/thread-loader-2.1.3.tgz#cbd2c139fc2b2de6e9d28f62286ab770c1acbdda" - integrity sha512-wNrVKH2Lcf8ZrWxDF/khdlLlsTMczdcwPA9VEK4c2exlEPynYWxi9op3nPTo5lAnDIkE0rQEB3VBP+4Zncc9Hg== - dependencies: - loader-runner "^2.3.1" - loader-utils "^1.1.0" - neo-async "^2.6.0" - -through2@^2.0.0: - version "2.0.5" - resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.5.tgz#01c1e39eb31d07cb7d03a96a70823260b23132cd" - integrity sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ== - dependencies: - readable-stream "~2.3.6" - xtend "~4.0.1" - -through@^2.3.6: - version "2.3.8" - resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" - integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU= - -thunky@^1.0.2: - version "1.1.0" - resolved "https://registry.yarnpkg.com/thunky/-/thunky-1.1.0.tgz#5abaf714a9405db0504732bbccd2cedd9ef9537d" - integrity sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA== - -timers-browserify@^2.0.4: - version "2.0.12" - resolved "https://registry.yarnpkg.com/timers-browserify/-/timers-browserify-2.0.12.tgz#44a45c11fbf407f34f97bccd1577c652361b00ee" - integrity sha512-9phl76Cqm6FhSX9Xe1ZUAMLtm1BLkKj2Qd5ApyWkXzsMRaA7dgr81kf4wJmQf/hAvg8EEyJxDo3du/0KlhPiKQ== - dependencies: - setimmediate "^1.0.4" - -timsort@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/timsort/-/timsort-0.3.0.tgz#405411a8e7e6339fe64db9a234de11dc31e02bd4" - integrity sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q= - -tmp@^0.0.33: - version "0.0.33" - resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" - integrity sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw== - dependencies: - os-tmpdir "~1.0.2" - -to-arraybuffer@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz#7d229b1fcc637e466ca081180836a7aabff83f43" - integrity sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M= - -to-fast-properties@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" - integrity sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4= - -to-object-path@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/to-object-path/-/to-object-path-0.3.0.tgz#297588b7b0e7e0ac08e04e672f85c1f4999e17af" - integrity sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68= - dependencies: - kind-of "^3.0.2" - -to-regex-range@^2.1.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-2.1.1.tgz#7c80c17b9dfebe599e27367e0d4dd5590141db38" - integrity sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg= - dependencies: - is-number "^3.0.0" - repeat-string "^1.6.1" - -to-regex-range@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" - integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== - dependencies: - is-number "^7.0.0" - -to-regex@^3.0.1, to-regex@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/to-regex/-/to-regex-3.0.2.tgz#13cfdd9b336552f30b51f33a8ae1b42a7a7599ce" - integrity sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw== - dependencies: - define-property "^2.0.2" - extend-shallow "^3.0.2" - regex-not "^1.0.2" - safe-regex "^1.1.0" - -toidentifier@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.0.tgz#7e1be3470f1e77948bc43d94a3c8f4d7752ba553" - integrity sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw== - -toposort@^1.0.0: - version "1.0.7" - resolved "https://registry.yarnpkg.com/toposort/-/toposort-1.0.7.tgz#2e68442d9f64ec720b8cc89e6443ac6caa950029" - integrity sha1-LmhELZ9k7HILjMieZEOsbKqVACk= - -tough-cookie@^2.3.3, tough-cookie@~2.5.0: - version "2.5.0" - resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.5.0.tgz#cd9fb2a0aa1d5a12b473bd9fb96fa3dcff65ade2" - integrity sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g== - dependencies: - psl "^1.1.28" - punycode "^2.1.1" - -tryer@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/tryer/-/tryer-1.0.1.tgz#f2c85406800b9b0f74c9f7465b81eaad241252f8" - integrity sha512-c3zayb8/kWWpycWYg87P71E1S1ZL6b6IJxfb5fvsUgsf0S2MVGaDhDXXjDMpdCpfWXqptc+4mXwmiy1ypXqRAA== - -ts-loader@^6.2.2: - version "6.2.2" - resolved "https://registry.yarnpkg.com/ts-loader/-/ts-loader-6.2.2.tgz#dffa3879b01a1a1e0a4b85e2b8421dc0dfff1c58" - integrity sha512-HDo5kXZCBml3EUPcc7RlZOV/JGlLHwppTLEHb3SHnr5V7NXD4klMEkrhJe5wgRbaWsSXi+Y1SIBN/K9B6zWGWQ== - dependencies: - chalk "^2.3.0" - enhanced-resolve "^4.0.0" - loader-utils "^1.0.2" - micromatch "^4.0.0" - semver "^6.0.0" - -tslib@^1.8.0, tslib@^1.8.1, tslib@^1.9.0: - version "1.14.1" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" - integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== - -tslint@^5.20.1: - version "5.20.1" - resolved "https://registry.yarnpkg.com/tslint/-/tslint-5.20.1.tgz#e401e8aeda0152bc44dd07e614034f3f80c67b7d" - integrity sha512-EcMxhzCFt8k+/UP5r8waCf/lzmeSyVlqxqMEDQE7rWYiQky8KpIBz1JAoYXfROHrPZ1XXd43q8yQnULOLiBRQg== - dependencies: - "@babel/code-frame" "^7.0.0" - builtin-modules "^1.1.1" - chalk "^2.3.0" - commander "^2.12.1" - diff "^4.0.1" - glob "^7.1.1" - js-yaml "^3.13.1" - minimatch "^3.0.4" - mkdirp "^0.5.1" - resolve "^1.3.2" - semver "^5.3.0" - tslib "^1.8.0" - tsutils "^2.29.0" - -tsutils@^2.29.0: - version "2.29.0" - resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-2.29.0.tgz#32b488501467acbedd4b85498673a0812aca0b99" - integrity sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA== - dependencies: - tslib "^1.8.1" - -tsutils@^3.21.0, tsutils@^3.7.0: - version "3.21.0" - resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.21.0.tgz#b48717d394cea6c1e096983eed58e9d61715b623" - integrity sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA== - dependencies: - tslib "^1.8.1" - -tty-browserify@0.0.0: - version "0.0.0" - resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.0.tgz#a157ba402da24e9bf957f9aa69d524eed42901a6" - integrity sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY= - -tunnel-agent@^0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" - integrity sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0= - dependencies: - safe-buffer "^5.0.1" - -tweetnacl@^0.14.3, tweetnacl@~0.14.0: - version "0.14.5" - resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" - integrity sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q= - -type-check@~0.3.2: - version "0.3.2" - resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" - integrity sha1-WITKtRLPHTVeP7eE8wgEsrUg23I= - dependencies: - prelude-ls "~1.1.2" - -type-fest@^0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.6.0.tgz#8d2a2370d3df886eb5c90ada1c5bf6188acf838b" - integrity sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg== - -type-is@~1.6.17, type-is@~1.6.18: - version "1.6.18" - resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131" - integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g== - dependencies: - media-typer "0.3.0" - mime-types "~2.1.24" - -typedarray@^0.0.6: - version "0.0.6" - resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" - integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= - -typescript@^4.1.3: - version "4.4.4" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.4.4.tgz#2cd01a1a1f160704d3101fd5a58ff0f9fcb8030c" - integrity sha512-DqGhF5IKoBl8WNf8C1gu8q0xZSInh9j1kJJMqT3a94w1JzVaBU4EXOSMrz9yDqMT0xt3selp83fuFMQ0uzv6qA== - -uglify-js@3.4.x: - version "3.4.10" - resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.4.10.tgz#9ad9563d8eb3acdfb8d38597d2af1d815f6a755f" - integrity sha512-Y2VsbPVs0FIshJztycsO2SfPk7/KAF/T72qzv9u5EpQ4kB2hQoHlhNQTsNyy6ul7lQtqJN/AoWeS23OzEiEFxw== - dependencies: - commander "~2.19.0" - source-map "~0.6.1" - -unbox-primitive@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/unbox-primitive/-/unbox-primitive-1.0.1.tgz#085e215625ec3162574dc8859abee78a59b14471" - integrity sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw== - dependencies: - function-bind "^1.1.1" - has-bigints "^1.0.1" - has-symbols "^1.0.2" - which-boxed-primitive "^1.0.2" - -union-value@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.1.tgz#0b6fe7b835aecda61c6ea4d4f02c14221e109847" - integrity sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg== - dependencies: - arr-union "^3.1.0" - get-value "^2.0.6" - is-extendable "^0.1.1" - set-value "^2.0.1" - -uniq@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/uniq/-/uniq-1.0.1.tgz#b31c5ae8254844a3a8281541ce2b04b865a734ff" - integrity sha1-sxxa6CVIRKOoKBVBzisEuGWnNP8= - -uniqs@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/uniqs/-/uniqs-2.0.0.tgz#ffede4b36b25290696e6e165d4a59edb998e6b02" - integrity sha1-/+3ks2slKQaW5uFl1KWe25mOawI= - -unique-filename@^1.1.0, unique-filename@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/unique-filename/-/unique-filename-1.1.1.tgz#1d69769369ada0583103a1e6ae87681b56573230" - integrity sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ== - dependencies: - unique-slug "^2.0.0" - -unique-slug@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/unique-slug/-/unique-slug-2.0.2.tgz#baabce91083fc64e945b0f3ad613e264f7cd4e6c" - integrity sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w== - dependencies: - imurmurhash "^0.1.4" - -universalify@^0.1.0: - version "0.1.2" - resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" - integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg== - -universalify@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.0.tgz#75a4984efedc4b08975c5aeb73f530d02df25717" - integrity sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ== - -unpipe@1.0.0, unpipe@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" - integrity sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw= - -unquote@~1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/unquote/-/unquote-1.1.1.tgz#8fded7324ec6e88a0ff8b905e7c098cdc086d544" - integrity sha1-j97XMk7G6IoP+LkF58CYzcCG1UQ= - -unset-value@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/unset-value/-/unset-value-1.0.0.tgz#8376873f7d2335179ffb1e6fc3a8ed0dfc8ab559" - integrity sha1-g3aHP30jNRef+x5vw6jtDfyKtVk= - dependencies: - has-value "^0.3.1" - isobject "^3.0.0" - -upath@^1.1.1: - version "1.2.0" - resolved "https://registry.yarnpkg.com/upath/-/upath-1.2.0.tgz#8f66dbcd55a883acdae4408af8b035a5044c1894" - integrity sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg== - -upper-case@^1.1.1: - version "1.1.3" - resolved "https://registry.yarnpkg.com/upper-case/-/upper-case-1.1.3.tgz#f6b4501c2ec4cdd26ba78be7222961de77621598" - integrity sha1-9rRQHC7EzdJrp4vnIilh3ndiFZg= - -uri-js@^4.2.2: - version "4.4.1" - resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" - integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== - dependencies: - punycode "^2.1.0" - -urix@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72" - integrity sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI= - -url-loader@^1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/url-loader/-/url-loader-1.1.2.tgz#b971d191b83af693c5e3fea4064be9e1f2d7f8d8" - integrity sha512-dXHkKmw8FhPqu8asTc1puBfe3TehOCo2+RmOOev5suNCIYBcT626kxiWg1NBVkwc4rO8BGa7gP70W7VXuqHrjg== - dependencies: - loader-utils "^1.1.0" - mime "^2.0.3" - schema-utils "^1.0.0" - -url-parse@^1.4.3, url-parse@^1.5.3: - version "1.5.3" - resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.5.3.tgz#71c1303d38fb6639ade183c2992c8cc0686df862" - integrity sha512-IIORyIQD9rvj0A4CLWsHkBBJuNqWpFQe224b6j9t/ABmquIS0qDU2pY6kl6AuOrL5OkCXHMCFNe1jBcuAggjvQ== - dependencies: - querystringify "^2.1.1" - requires-port "^1.0.0" - -url@^0.11.0: - version "0.11.0" - resolved "https://registry.yarnpkg.com/url/-/url-0.11.0.tgz#3838e97cfc60521eb73c525a8e55bfdd9e2e28f1" - integrity sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE= - dependencies: - punycode "1.3.2" - querystring "0.2.0" - -use@^3.1.0: - version "3.1.1" - resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f" - integrity sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ== - -util-deprecate@^1.0.1, util-deprecate@^1.0.2, util-deprecate@~1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" - integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= - -util.promisify@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/util.promisify/-/util.promisify-1.0.0.tgz#440f7165a459c9a16dc145eb8e72f35687097030" - integrity sha512-i+6qA2MPhvoKLuxnJNpXAGhg7HphQOSUq2LKMZD0m15EiskXUkMvKdF4Uui0WYeCUGea+o2cw/ZuwehtfsrNkA== - dependencies: - define-properties "^1.1.2" - object.getownpropertydescriptors "^2.0.3" - -util.promisify@~1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/util.promisify/-/util.promisify-1.0.1.tgz#6baf7774b80eeb0f7520d8b81d07982a59abbaee" - integrity sha512-g9JpC/3He3bm38zsLupWryXHoEcS22YHthuPQSJdMy6KNrzIRzWqcsHzD/WUnqe45whVou4VIsPew37DoXWNrA== - dependencies: - define-properties "^1.1.3" - es-abstract "^1.17.2" - has-symbols "^1.0.1" - object.getownpropertydescriptors "^2.1.0" - -util@0.10.3: - version "0.10.3" - resolved "https://registry.yarnpkg.com/util/-/util-0.10.3.tgz#7afb1afe50805246489e3db7fe0ed379336ac0f9" - integrity sha1-evsa/lCAUkZInj23/g7TeTNqwPk= - dependencies: - inherits "2.0.1" - -util@^0.11.0: - version "0.11.1" - resolved "https://registry.yarnpkg.com/util/-/util-0.11.1.tgz#3236733720ec64bb27f6e26f421aaa2e1b588d61" - integrity sha512-HShAsny+zS2TZfaXxD9tYj4HQGlBezXZMZuM/S5PKLLoZkShZiGk9o5CzukI1LVHZvjdvZ2Sj1aW/Ndn2NB/HQ== - dependencies: - inherits "2.0.3" - -utila@~0.4: - version "0.4.0" - resolved "https://registry.yarnpkg.com/utila/-/utila-0.4.0.tgz#8a16a05d445657a3aea5eecc5b12a4fa5379772c" - integrity sha1-ihagXURWV6Oupe7MWxKk+lN5dyw= - -utils-merge@1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" - integrity sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM= - -uuid@^3.3.2, uuid@^3.4.0: - version "3.4.0" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee" - integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A== - -v-clipboard@^2.0.1: - version "2.2.3" - resolved "https://registry.yarnpkg.com/v-clipboard/-/v-clipboard-2.2.3.tgz#f5db3d7004145041b6d7d06ca48236de4cee3a41" - integrity sha512-Wg+ObZoYK6McHb5OOCFWvm0R7xHp0/p0G1ocx/8bO22jvA/yVY05rADbfiztwCokXBNfQuGv/XSd1ozcTFgekw== - -validate-npm-package-license@^3.0.1: - version "3.0.4" - resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a" - integrity sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew== - dependencies: - spdx-correct "^3.0.0" - spdx-expression-parse "^3.0.0" - -vary@~1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" - integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw= - -vendors@^1.0.0: - version "1.0.4" - resolved "https://registry.yarnpkg.com/vendors/-/vendors-1.0.4.tgz#e2b800a53e7a29b93506c3cf41100d16c4c4ad8e" - integrity sha512-/juG65kTL4Cy2su4P8HjtkTxk6VmJDiOPBufWniqQ6wknac6jNiXS9vU+hO3wgusiyqWlzTbVHi0dyJqRONg3w== - -verror@1.10.0: - version "1.10.0" - resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400" - integrity sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA= - dependencies: - assert-plus "^1.0.0" - core-util-is "1.0.2" - extsprintf "^1.2.0" - -vm-browserify@^1.0.1: - version "1.1.2" - resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-1.1.2.tgz#78641c488b8e6ca91a75f511e7a3b32a86e5dda0" - integrity sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ== - -vue-class-component@^6.0.0, vue-class-component@^6.2.0: - version "6.3.2" - resolved "https://registry.yarnpkg.com/vue-class-component/-/vue-class-component-6.3.2.tgz#e6037e84d1df2af3bde4f455e50ca1b9eec02be6" - integrity sha512-cH208IoM+jgZyEf/g7mnFyofwPDJTM/QvBNhYMjqGB8fCsRyTf68rH2ISw/G20tJv+5mIThQ3upKwoL4jLTr1A== - -vue-eslint-parser@^2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/vue-eslint-parser/-/vue-eslint-parser-2.0.3.tgz#c268c96c6d94cfe3d938a5f7593959b0ca3360d1" - integrity sha512-ZezcU71Owm84xVF6gfurBQUGg8WQ+WZGxgDEQu1IHFBZNx7BFZg3L1yHxrCBNNwbwFtE1GuvfJKMtb6Xuwc/Bw== - dependencies: - debug "^3.1.0" - eslint-scope "^3.7.1" - eslint-visitor-keys "^1.0.0" - espree "^3.5.2" - esquery "^1.0.0" - lodash "^4.17.4" - -vue-eslint-parser@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/vue-eslint-parser/-/vue-eslint-parser-5.0.0.tgz#00f4e4da94ec974b821a26ff0ed0f7a78402b8a1" - integrity sha512-JlHVZwBBTNVvzmifwjpZYn0oPWH2SgWv5dojlZBsrhablDu95VFD+hriB1rQGwbD+bms6g+rAFhQHk6+NyiS6g== - dependencies: - debug "^4.1.0" - eslint-scope "^4.0.0" - eslint-visitor-keys "^1.0.0" - espree "^4.1.0" - esquery "^1.0.1" - lodash "^4.17.11" - -vue-hot-reload-api@^2.3.0: - version "2.3.4" - resolved "https://registry.yarnpkg.com/vue-hot-reload-api/-/vue-hot-reload-api-2.3.4.tgz#532955cc1eb208a3d990b3a9f9a70574657e08f2" - integrity sha512-BXq3jwIagosjgNVae6tkHzzIk6a8MHFtzAdwhnV5VlvPTFxDCvIttgSiHWjdGoTJvXtmRu5HacExfdarRcFhog== - -vue-loader@^15.7.0: - version "15.9.8" - resolved "https://registry.yarnpkg.com/vue-loader/-/vue-loader-15.9.8.tgz#4b0f602afaf66a996be1e534fb9609dc4ab10e61" - integrity sha512-GwSkxPrihfLR69/dSV3+5CdMQ0D+jXg8Ma1S4nQXKJAznYFX14vHdc/NetQc34Dw+rBbIJyP7JOuVb9Fhprvog== - dependencies: - "@vue/component-compiler-utils" "^3.1.0" - hash-sum "^1.0.2" - loader-utils "^1.1.0" - vue-hot-reload-api "^2.3.0" - vue-style-loader "^4.1.0" - -vue-notification@^1.3.12: - version "1.3.20" - resolved "https://registry.yarnpkg.com/vue-notification/-/vue-notification-1.3.20.tgz#d85618127763b46f3e25b8962b857947d5a97cbe" - integrity sha512-vPj67Ah72p8xvtyVE8emfadqVWguOScAjt6OJDEUdcW5hW189NsqvfkOrctxHUUO9UYl9cTbIkzAEcPnHu+zBQ== - -vue-property-decorator@^7.3.0: - version "7.3.0" - resolved "https://registry.yarnpkg.com/vue-property-decorator/-/vue-property-decorator-7.3.0.tgz#d50d67f0b0f1c814f9f2fba36d6eeccbcc62dbb6" - integrity sha512-HarXfTQ/Nxm4s/APpAaGIGHq5ZzslApImQy8ZrtkfGamw8rUFAVgMS5C50/AQ80+wfw3Wpnf4bNzbmj75m/k2Q== - dependencies: - vue-class-component "^6.2.0" - -vue-router@^3.0.1: - version "3.5.3" - resolved "https://registry.yarnpkg.com/vue-router/-/vue-router-3.5.3.tgz#041048053e336829d05dafacf6a8fb669a2e7999" - integrity sha512-FUlILrW3DGitS2h+Xaw8aRNvGTwtuaxrRkNSHWTizOfLUie7wuYwezeZ50iflRn8YPV5kxmU2LQuu3nM/b3Zsg== - -vue-style-loader@^4.1.0: - version "4.1.3" - resolved "https://registry.yarnpkg.com/vue-style-loader/-/vue-style-loader-4.1.3.tgz#6d55863a51fa757ab24e89d9371465072aa7bc35" - integrity sha512-sFuh0xfbtpRlKfm39ss/ikqs9AbKCoXZBpHeVZ8Tx650o0k0q/YCM7FRvigtxpACezfq6af+a7JeqVTWvncqDg== - dependencies: - hash-sum "^1.0.2" - loader-utils "^1.0.2" - -vue-template-compiler@^2.6.12: - version "2.6.14" - resolved "https://registry.yarnpkg.com/vue-template-compiler/-/vue-template-compiler-2.6.14.tgz#a2f0e7d985670d42c9c9ee0d044fed7690f4f763" - integrity sha512-ODQS1SyMbjKoO1JBJZojSw6FE4qnh9rIpUZn2EUT86FKizx9uH5z6uXiIrm4/Nb/gwxTi/o17ZDEGWAXHvtC7g== - dependencies: - de-indent "^1.0.2" - he "^1.1.0" - -vue-template-es2015-compiler@^1.9.0: - version "1.9.1" - resolved "https://registry.yarnpkg.com/vue-template-es2015-compiler/-/vue-template-es2015-compiler-1.9.1.tgz#1ee3bc9a16ecbf5118be334bb15f9c46f82f5825" - integrity sha512-4gDntzrifFnCEvyoO8PqyJDmguXgVPxKiIxrBKjIowvL9l+N66196+72XVYR8BBf1Uv1Fgt3bGevJ+sEmxfZzw== - -vue@^2.6.12: - version "2.6.14" - resolved "https://registry.yarnpkg.com/vue/-/vue-2.6.14.tgz#e51aa5250250d569a3fbad3a8a5a687d6036e235" - integrity sha512-x2284lgYvjOMj3Za7kqzRcUSxBboHqtgRE2zlos1qWaOye5yUmHn42LB1250NJBLRwEcdrB0JRwyPTEPhfQjiQ== - -vuetify@^2.4.5: - version "2.5.14" - resolved "https://registry.yarnpkg.com/vuetify/-/vuetify-2.5.14.tgz#0545355fdea0ac2b37dbcb1dca405b62041f551c" - integrity sha512-3efk3WnOvh+r9muZ4Ie0FVfFVmPS/ag+l/20qGA45lXZAJuyLeYxJ5gXs5xnCpml1g8xmJfDQPvi8xC6DDuCdg== - -"vuex-typex@https://github.com/robinhundt/vuex-typex.git": - version "3.0.1" - resolved "https://github.com/robinhundt/vuex-typex.git#3e0da4d1e01eef6e0eed609ef97cb036ca8a692f" - dependencies: - deepmerge "^2.1.1" - vuex "^3.0.0" - -vuex@^3.0.0, vuex@^3.0.1: - version "3.6.2" - resolved "https://registry.yarnpkg.com/vuex/-/vuex-3.6.2.tgz#236bc086a870c3ae79946f107f16de59d5895e71" - integrity sha512-ETW44IqCgBpVomy520DT5jf8n0zoCac+sxWnn+hMe/CzaSejb/eVw2YToiXYX+Ex/AuHHia28vWTq4goAexFbw== - -watchpack-chokidar2@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/watchpack-chokidar2/-/watchpack-chokidar2-2.0.1.tgz#38500072ee6ece66f3769936950ea1771be1c957" - integrity sha512-nCFfBIPKr5Sh61s4LPpy1Wtfi0HE8isJ3d2Yb5/Ppw2P2B/3eVSEBjKfN0fmHJSK14+31KwMKmcrzs2GM4P0Ww== - dependencies: - chokidar "^2.1.8" - -watchpack@^1.7.4: - version "1.7.5" - resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-1.7.5.tgz#1267e6c55e0b9b5be44c2023aed5437a2c26c453" - integrity sha512-9P3MWk6SrKjHsGkLT2KHXdQ/9SNkyoJbabxnKOoJepsvJjJG8uYTR3yTPxPQvNDI3w4Nz1xnE0TLHK4RIVe/MQ== - dependencies: - graceful-fs "^4.1.2" - neo-async "^2.5.0" - optionalDependencies: - chokidar "^3.4.1" - watchpack-chokidar2 "^2.0.1" - -wbuf@^1.1.0, wbuf@^1.7.3: - version "1.7.3" - resolved "https://registry.yarnpkg.com/wbuf/-/wbuf-1.7.3.tgz#c1d8d149316d3ea852848895cb6a0bfe887b87df" - integrity sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA== - dependencies: - minimalistic-assert "^1.0.0" - -wcwidth@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/wcwidth/-/wcwidth-1.0.1.tgz#f0b0dcf915bc5ff1528afadb2c0e17b532da2fe8" - integrity sha1-8LDc+RW8X/FSivrbLA4XtTLaL+g= - dependencies: - defaults "^1.0.3" - -webpack-bundle-analyzer@^3.3.0: - version "3.9.0" - resolved "https://registry.yarnpkg.com/webpack-bundle-analyzer/-/webpack-bundle-analyzer-3.9.0.tgz#f6f94db108fb574e415ad313de41a2707d33ef3c" - integrity sha512-Ob8amZfCm3rMB1ScjQVlbYYUEJyEjdEtQ92jqiFUYt5VkEeO2v5UMbv49P/gnmCZm3A6yaFQzCBvpZqN4MUsdA== - dependencies: - acorn "^7.1.1" - acorn-walk "^7.1.1" - bfj "^6.1.1" - chalk "^2.4.1" - commander "^2.18.0" - ejs "^2.6.1" - express "^4.16.3" - filesize "^3.6.1" - gzip-size "^5.0.0" - lodash "^4.17.19" - mkdirp "^0.5.1" - opener "^1.5.1" - ws "^6.0.0" - -webpack-chain@^4.11.0: - version "4.12.1" - resolved "https://registry.yarnpkg.com/webpack-chain/-/webpack-chain-4.12.1.tgz#6c8439bbb2ab550952d60e1ea9319141906c02a6" - integrity sha512-BCfKo2YkDe2ByqkEWe1Rw+zko4LsyS75LVr29C6xIrxAg9JHJ4pl8kaIZ396SUSNp6b4815dRZPSTAS8LlURRQ== - dependencies: - deepmerge "^1.5.2" - javascript-stringify "^1.6.0" - -webpack-dev-middleware@^3.7.2: - version "3.7.3" - resolved "https://registry.yarnpkg.com/webpack-dev-middleware/-/webpack-dev-middleware-3.7.3.tgz#0639372b143262e2b84ab95d3b91a7597061c2c5" - integrity sha512-djelc/zGiz9nZj/U7PTBi2ViorGJXEWo/3ltkPbDyxCXhhEXkW0ce99falaok4TPj+AsxLiXJR0EBOb0zh9fKQ== - dependencies: - memory-fs "^0.4.1" - mime "^2.4.4" - mkdirp "^0.5.1" - range-parser "^1.2.1" - webpack-log "^2.0.0" - -webpack-dev-server@^3.4.1: - version "3.11.3" - resolved "https://registry.yarnpkg.com/webpack-dev-server/-/webpack-dev-server-3.11.3.tgz#8c86b9d2812bf135d3c9bce6f07b718e30f7c3d3" - integrity sha512-3x31rjbEQWKMNzacUZRE6wXvUFuGpH7vr0lIEbYpMAG9BOxi0928QU1BBswOAP3kg3H1O4hiS+sq4YyAn6ANnA== - dependencies: - ansi-html-community "0.0.8" - bonjour "^3.5.0" - chokidar "^2.1.8" - compression "^1.7.4" - connect-history-api-fallback "^1.6.0" - debug "^4.1.1" - del "^4.1.1" - express "^4.17.1" - html-entities "^1.3.1" - http-proxy-middleware "0.19.1" - import-local "^2.0.0" - internal-ip "^4.3.0" - ip "^1.1.5" - is-absolute-url "^3.0.3" - killable "^1.0.1" - loglevel "^1.6.8" - opn "^5.5.0" - p-retry "^3.0.1" - portfinder "^1.0.26" - schema-utils "^1.0.0" - selfsigned "^1.10.8" - semver "^6.3.0" - serve-index "^1.9.1" - sockjs "^0.3.21" - sockjs-client "^1.5.0" - spdy "^4.0.2" - strip-ansi "^3.0.1" - supports-color "^6.1.0" - url "^0.11.0" - webpack-dev-middleware "^3.7.2" - webpack-log "^2.0.0" - ws "^6.2.1" - yargs "^13.3.2" - -webpack-log@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/webpack-log/-/webpack-log-2.0.0.tgz#5b7928e0637593f119d32f6227c1e0ac31e1b47f" - integrity sha512-cX8G2vR/85UYG59FgkoMamwHUIkSSlV3bBMRsbxVXVUk2j6NleCKjQ/WE9eYg9WY4w25O9w8wKP4rzNZFmUcUg== - dependencies: - ansi-colors "^3.0.0" - uuid "^3.3.2" - -webpack-merge@^4.2.1: - version "4.2.2" - resolved "https://registry.yarnpkg.com/webpack-merge/-/webpack-merge-4.2.2.tgz#a27c52ea783d1398afd2087f547d7b9d2f43634d" - integrity sha512-TUE1UGoTX2Cd42j3krGYqObZbOD+xF7u28WB7tfUordytSjbWTIjK/8V0amkBfTYN4/pB/GIDlJZZ657BGG19g== - dependencies: - lodash "^4.17.15" - -webpack-sources@^1.1.0, webpack-sources@^1.4.0, webpack-sources@^1.4.1: - version "1.4.3" - resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-1.4.3.tgz#eedd8ec0b928fbf1cbfe994e22d2d890f330a933" - integrity sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ== - dependencies: - source-list-map "^2.0.0" - source-map "~0.6.1" - -webpack@^4.0.0, webpack@^4.41.0: - version "4.46.0" - resolved "https://registry.yarnpkg.com/webpack/-/webpack-4.46.0.tgz#bf9b4404ea20a073605e0a011d188d77cb6ad542" - integrity sha512-6jJuJjg8znb/xRItk7bkT0+Q7AHCYjjFnvKIWQPkNIOyRqoCGvkOs0ipeQzrqz4l5FtN5ZI/ukEHroeX/o1/5Q== - dependencies: - "@webassemblyjs/ast" "1.9.0" - "@webassemblyjs/helper-module-context" "1.9.0" - "@webassemblyjs/wasm-edit" "1.9.0" - "@webassemblyjs/wasm-parser" "1.9.0" - acorn "^6.4.1" - ajv "^6.10.2" - ajv-keywords "^3.4.1" - chrome-trace-event "^1.0.2" - enhanced-resolve "^4.5.0" - eslint-scope "^4.0.3" - json-parse-better-errors "^1.0.2" - loader-runner "^2.4.0" - loader-utils "^1.2.3" - memory-fs "^0.4.1" - micromatch "^3.1.10" - mkdirp "^0.5.3" - neo-async "^2.6.1" - node-libs-browser "^2.2.1" - schema-utils "^1.0.0" - tapable "^1.1.3" - terser-webpack-plugin "^1.4.3" - watchpack "^1.7.4" - webpack-sources "^1.4.1" - -websocket-driver@>=0.5.1, websocket-driver@^0.7.4: - version "0.7.4" - resolved "https://registry.yarnpkg.com/websocket-driver/-/websocket-driver-0.7.4.tgz#89ad5295bbf64b480abcba31e4953aca706f5760" - integrity sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg== - dependencies: - http-parser-js ">=0.5.1" - safe-buffer ">=5.1.0" - websocket-extensions ">=0.1.1" - -websocket-extensions@>=0.1.1: - version "0.1.4" - resolved "https://registry.yarnpkg.com/websocket-extensions/-/websocket-extensions-0.1.4.tgz#7f8473bc839dfd87608adb95d7eb075211578a42" - integrity sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg== - -which-boxed-primitive@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz#13757bc89b209b049fe5d86430e21cf40a89a8e6" - integrity sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg== - dependencies: - is-bigint "^1.0.1" - is-boolean-object "^1.1.0" - is-number-object "^1.0.4" - is-string "^1.0.5" - is-symbol "^1.0.3" - -which-module@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" - integrity sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho= - -which@^1.2.9: - version "1.3.1" - resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" - integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== - dependencies: - isexe "^2.0.0" - -which@^2.0.1: - version "2.0.2" - resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" - integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== - dependencies: - isexe "^2.0.0" - -word-wrap@~1.2.3: - version "1.2.3" - resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c" - integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ== - -worker-farm@^1.7.0: - version "1.7.0" - resolved "https://registry.yarnpkg.com/worker-farm/-/worker-farm-1.7.0.tgz#26a94c5391bbca926152002f69b84a4bf772e5a8" - integrity sha512-rvw3QTZc8lAxyVrqcSGVm5yP/IJ2UcB3U0graE3LCFoZ0Yn2x4EoVSqJKdB/T5M+FLcRPjz4TDacRf3OCfNUzw== - dependencies: - errno "~0.1.7" - -worker-rpc@^0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/worker-rpc/-/worker-rpc-0.1.1.tgz#cb565bd6d7071a8f16660686051e969ad32f54d5" - integrity sha512-P1WjMrUB3qgJNI9jfmpZ/htmBEjFh//6l/5y8SD9hg1Ef5zTTVVoRjTrTEzPrNBQvmhMxkoTsjOXN10GWU7aCg== - dependencies: - microevent.ts "~0.1.1" - -wrap-ansi@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-5.1.0.tgz#1fd1f67235d5b6d0fee781056001bfb694c03b09" - integrity sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q== - dependencies: - ansi-styles "^3.2.0" - string-width "^3.0.0" - strip-ansi "^5.0.0" - -wrap-ansi@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" - integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== - dependencies: - ansi-styles "^4.0.0" - string-width "^4.1.0" - strip-ansi "^6.0.0" - -wrappy@1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" - integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= - -write@1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/write/-/write-1.0.3.tgz#0800e14523b923a387e415123c865616aae0f5c3" - integrity sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig== - dependencies: - mkdirp "^0.5.1" - -write@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/write/-/write-0.2.1.tgz#5fc03828e264cea3fe91455476f7a3c566cb0757" - integrity sha1-X8A4KOJkzqP+kUVUdvejxWbLB1c= - dependencies: - mkdirp "^0.5.1" - -ws@^6.0.0, ws@^6.2.1: - version "6.2.2" - resolved "https://registry.yarnpkg.com/ws/-/ws-6.2.2.tgz#dd5cdbd57a9979916097652d78f1cc5faea0c32e" - integrity sha512-zmhltoSR8u1cnDsD43TX59mzoMZsLKqUweyYBAIvTngR3shc0W6aOZylZmq/7hqyVxPdi+5Ud2QInblgyE72fw== - dependencies: - async-limiter "~1.0.0" - -xtend@^4.0.0, xtend@~4.0.1: - version "4.0.2" - resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" - integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== - -y18n@^4.0.0: - version "4.0.3" - resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.3.tgz#b5f259c82cd6e336921efd7bfd8bf560de9eeedf" - integrity sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ== - -y18n@^5.0.5: - version "5.0.8" - resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" - integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== - -yallist@^2.1.2: - version "2.1.2" - resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52" - integrity sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI= - -yallist@^3.0.2: - version "3.1.1" - resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" - integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== - -yallist@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" - integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== - -yaml@^1.7.2: - version "1.10.2" - resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b" - integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg== - -yargs-parser@^13.1.2: - version "13.1.2" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-13.1.2.tgz#130f09702ebaeef2650d54ce6e3e5706f7a4fb38" - integrity sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg== - dependencies: - camelcase "^5.0.0" - decamelize "^1.2.0" - -yargs-parser@^20.2.2: - version "20.2.9" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee" - integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w== - -yargs@^13.3.2: - version "13.3.2" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-13.3.2.tgz#ad7ffefec1aa59565ac915f82dccb38a9c31a2dd" - integrity sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw== - dependencies: - cliui "^5.0.0" - find-up "^3.0.0" - get-caller-file "^2.0.1" - require-directory "^2.1.1" - require-main-filename "^2.0.0" - set-blocking "^2.0.0" - string-width "^3.0.0" - which-module "^2.0.0" - y18n "^4.0.0" - yargs-parser "^13.1.2" - -yargs@^16.0.0: - version "16.2.0" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-16.2.0.tgz#1c82bf0f6b6a66eafce7ef30e376f49a12477f66" - integrity sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw== - dependencies: - cliui "^7.0.2" - escalade "^3.1.1" - get-caller-file "^2.0.5" - require-directory "^2.1.1" - string-width "^4.2.0" - y18n "^5.0.5" - yargs-parser "^20.2.2" - -yorkie@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/yorkie/-/yorkie-2.0.0.tgz#92411912d435214e12c51c2ae1093e54b6bb83d9" - integrity sha512-jcKpkthap6x63MB4TxwCyuIGkV0oYP/YRyuQU5UO0Yz/E/ZAu+653/uov+phdmO54n6BcvFRyyt0RRrWdN2mpw== - dependencies: - execa "^0.8.0" - is-ci "^1.0.10" - normalize-path "^1.0.0" - strip-indent "^2.0.0" diff --git a/grady/functional_tests/.gitignore b/grady/functional_tests/.gitignore deleted file mode 100644 index 975c04dbfa8a288635c37f9f5e1ddc87f51fbd54..0000000000000000000000000000000000000000 --- a/grady/functional_tests/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -export.json -export.csv -screenshots diff --git a/grady/functional_tests/__init__.py b/grady/functional_tests/__init__.py deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/grady/functional_tests/data/hektor.json b/grady/functional_tests/data/hektor.json deleted file mode 100644 index 435d147f518046bf303eecd4caf9dad05b58094d..0000000000000000000000000000000000000000 --- a/grady/functional_tests/data/hektor.json +++ /dev/null @@ -1,36 +0,0 @@ -{ - "meta": { - "version": "6.0.0" - }, - "data": { - "module": { - "module_reference": "B.Inf.1801", - "total_score": 50, - "pass_score": 25, - "pass_only": false - }, - "submission_types": [ - { - "name": "Eine Bibliothek für Permutationen (I1-ID: l120mlc005h0)", - "full_score": 50, - "description": "A <b>description</b>!", - "solution": "Blub", - "programming_language": "java" - } - ], - "students": [ - { - "fullname": "Test, User", - "identifier": "20000000", - "username": "TU20000000", - "submissions": [ - { - "code": "234;", - "type": "Eine Bibliothek für Permutationen (I1-ID: l120mlc005h0)", - "tests": {} - } - ] - } - ] - } -} diff --git a/grady/functional_tests/test_auto_logout.py b/grady/functional_tests/test_auto_logout.py deleted file mode 100644 index ba936bbf3f53fe36d39b7d6de02d9052c1d9fcfb..0000000000000000000000000000000000000000 --- a/grady/functional_tests/test_auto_logout.py +++ /dev/null @@ -1,66 +0,0 @@ -import datetime -import logging -from selenium.webdriver.common.by import By -from selenium.webdriver.support.ui import WebDriverWait -from selenium.webdriver.support import expected_conditions as ec -from selenium.webdriver.common.action_chains import ActionChains - -from core.models import UserAccount -from functional_tests.util import (GradyTestCase, login, reset_browser_after_test) -from util import factory_boys as fact - -from rest_framework_jwt.settings import api_settings - -log = logging.getLogger(__name__) - - -class TestAutoLogout(GradyTestCase): - username = None - password = None - role = None - - def setUp(self): - self.username = 'reviewer' - self.password = 'p' - self.role = UserAccount.TUTOR - fact.UserAccountFactory( - username=self.username, - password=self.password, - role=self.role - ) - - def tearDown(self): - api_settings.reload() - self.saveScreenshots() - reset_browser_after_test(self.browser, self.live_server_url) - - def _login(self): - login(self.browser, self.live_server_url, self.username, self.password) - - def test_auto_logout_can_continue(self): - with self.settings(JWT_AUTH={ - 'JWT_EXPIRATION_DELTA': datetime.timedelta(seconds=15), - 'JWT_ALLOW_REFRESH': True, - } - ): - self._login() - initial_token = self.browser.execute_script( - 'return document.getElementById("app").__vue__.$store' - '._modules.root.state.Authentication.token' - ) - logout_dialog = self.browser.find_element_by_id('logout-dialog') - WebDriverWait(self.browser, 15, 0.2).until( - ec.visibility_of_element_located((By.ID, 'logout-dialog'))) - # the below line should work for clicking the button, but something - # obscures it, thus the workaround below the comment - # logout_dialog.find_element_by_id('continue-btn').click() - continue_btn = logout_dialog.find_element_by_id('continue-btn') - ActionChains(self.browser).move_to_element(continue_btn).click().perform() - WebDriverWait(self.browser, 15, 0.2).until( - ec.invisibility_of_element_located((By.ID, 'logout-dialog'))) - self.assertNotIn('login', self.browser.current_url) - new_token = self.browser.execute_script( - 'return document.getElementById("app").__vue__.$store.' - '_modules.root.state.Authentication.token' - ) - self.assertNotEqual(initial_token, new_token) diff --git a/grady/functional_tests/test_export_modal.py b/grady/functional_tests/test_export_modal.py deleted file mode 100644 index 61387780e8e6b4b8fe31f211f390ee222a1eeb21..0000000000000000000000000000000000000000 --- a/grady/functional_tests/test_export_modal.py +++ /dev/null @@ -1,143 +0,0 @@ -import json -import os -from pathlib import Path -from selenium.webdriver.support.ui import WebDriverWait -from selenium.webdriver.common.action_chains import ActionChains - - -from core.models import UserAccount -from functional_tests.util import GradyTestCase, login, reset_browser_after_test -from util import factory_boys as fact - - -def expect_file_to_be_downloaded(path): - """ - Checks if a file has finished downloading by checking if a file exists at the path and - no `.part` file is present in the directory containing path - :param path: path to check - :return: - """ - def condition(*args): - file_present = Path(path).is_file() - partial_file_present = any(dir_path.suffix == ".part" for - dir_path in Path(path).parent.iterdir()) - return file_present and not partial_file_present - return condition - - -JSON_EXPORT_FILE = os.path.join(os.path.dirname(__file__), 'export.json') - - -class ExportTestModal(GradyTestCase): - username = None - password = None - role = None - - def setUp(self): - self.username = 'reviewer' - self.password = 'p' - self.role = UserAccount.REVIEWER - fact.UserAccountFactory( - username=self.username, - password=self.password, - role=self.role - ) - - def tearDown(self): - self.saveScreenshots() - reset_browser_after_test(self.browser, self.live_server_url) - - def _login(self): - login(self.browser, self.live_server_url, self.username, self.password) - - def test_export_red_uncorrected_submissions(self): - def export_btn_is_not_green(*args): - exports_btn = self.browser.find_element_by_id('export-btn') - return 'success' not in exports_btn.get_attribute('class') - - fact.SubmissionFactory() - self._login() - WebDriverWait(self.browser, 10).until(export_btn_is_not_green) - - def test_export_warning_tooltip_uncorrected_submissions(self): - fact.SubmissionFactory() - self._login() - self.browser.execute_script( - "document.getElementById('export-btn').dispatchEvent(new Event('mouseenter'));" - ) - tooltip_uncorrected = self.browser.find_element_by_id('uncorrected-tooltip') - self.assertNotEqual(None, tooltip_uncorrected) - self.assertRaises(Exception, self.browser.find_element_by_id, 'corrected-tooltip') - - def test_export_green_all_corrected(self): - def export_btn_is_green(*args): - exports_btn = self.browser.find_element_by_id('export-btn') - return 'success' in exports_btn.get_attribute('class') - - fact.SubmissionTypeFactory() - self._login() - WebDriverWait(self.browser, 10).until(export_btn_is_green) - - def test_export_all_good_tooltip_all_corrected(self): - fact.SubmissionTypeFactory() - self._login() - self.browser.execute_script( - "document.getElementById('export-btn').dispatchEvent(new Event('mouseenter'));" - ) - tooltip_corrected = self.browser.find_element_by_id('corrected-tooltip') - self.assertNotEqual(None, tooltip_corrected) - self.assertRaises(Exception, self.browser.find_element_by_id, 'uncorrected-tooltip') - - def test_export_list_popup_contains_correct_items(self): - self._login() - export_btn = self.browser.find_element_by_id('export-btn') - export_btn.click() - export_menu = self.browser.find_element_by_class_name('menuable__content__active') - export_list = export_menu.find_element_by_class_name('v-list') - list_elements = export_list.find_elements_by_tag_name('div') - self.assertEqual(2, len(list_elements)) - self.assertEqual('Export student scores', list_elements[0].text) - self.assertEqual('Export whole instance data', list_elements[1].text) - - def test_export_student_scores_as_json(self): - fact.StudentInfoFactory() - fact.SubmissionFactory() - self._login() - export_btn = self.browser.find_element_by_id('export-btn') - export_btn.click() - export_scores = self.browser.find_element_by_id('export-list0') - export_scores.click() - data_export_modal = self.browser.find_element_by_id('data-export-modal') - data_export_btn = data_export_modal.find_element_by_id('export-data-download-btn') - ActionChains(self.browser).move_to_element(data_export_btn).click().perform() - WebDriverWait(self.browser, 10).until(expect_file_to_be_downloaded(JSON_EXPORT_FILE)) - try: - with open(JSON_EXPORT_FILE) as f: - data = json.load(f) - - self.assertEqual('B.Inf.4242 Test Module', - data[0]['Exams'][0]['exam']['moduleReference']) - except Exception as e: - print(data) - raise e - finally: - os.remove(JSON_EXPORT_FILE) - - def test_export_instance(self): - fact.SubmissionFactory() - self._login() - self.browser.find_element_by_id('export-btn').click() - self.browser.find_element_by_id('export-list1').click() - instance_export_modal = self.browser.find_element_by_id('instance-export-modal') - # instance_export_modal.find_element_by_id('instance-export-dl').click() - export_btn = instance_export_modal.find_element_by_id('instance-export-dl') - ActionChains(self.browser).move_to_element(export_btn).click().perform() - WebDriverWait(self.browser, 10).until(expect_file_to_be_downloaded(JSON_EXPORT_FILE)) - try: - with open(JSON_EXPORT_FILE) as f: - data = json.load(f) - self.assertEqual('B.Inf.4242 Test Module', data['examTypes'][0]['moduleReference']) - except Exception as e: - raise e - finally: - os.remove(JSON_EXPORT_FILE) diff --git a/grady/functional_tests/test_feedback_creation.py b/grady/functional_tests/test_feedback_creation.py deleted file mode 100644 index 4bfcfb9797223ccc2e27f098851d036f213a48df..0000000000000000000000000000000000000000 --- a/grady/functional_tests/test_feedback_creation.py +++ /dev/null @@ -1,357 +0,0 @@ -from selenium.webdriver import ActionChains -from selenium.webdriver.support.ui import WebDriverWait -from selenium.webdriver.support import expected_conditions as ec -from selenium.webdriver.common.by import By - -from core.models import UserAccount, Submission, FeedbackComment -from functional_tests.util import (GradyTestCase, login, reset_browser_after_test, - go_to_subscription, wait_until_code_changes, - correct_some_submission, assertion_is_true, - reconstruct_submission_code, wait_until_element_count_equals, - reconstruct_solution_code) -from util import factory_boys as fact - - -class UntestedParent: - class TestFeedbackCreationGeneric(GradyTestCase): - username = None - password = None - role = None - - def setUp(self): - self.sub_type = fact.SubmissionTypeFactory.create() - fact.SubmissionFactory.create_batch(2, type=self.sub_type) - - def tearDown(self): - self.saveScreenshots() - reset_browser_after_test(self.browser, self.live_server_url) - - def _login(self): - login(self.browser, self.live_server_url, self.username, self.password) - - def write_comments_on_lines(self, line_comment_tuples): - """ line_comment_tuples is an iterable containing tuples of - (line_no, comment) where the line number starts at 1 - """ - - sub_table = self.browser.find_element_by_class_name('submission-table') - lines = sub_table.find_elements_by_tag_name('tr') - - for (line_no, comment) in line_comment_tuples: - line = lines[line_no-1] - line.find_element_by_tag_name('button').click() - textarea = line.find_element_by_tag_name('textarea') - textarea.send_keys(comment) - line.find_element_by_id('submit-comment').click() - - def test_student_text_is_correctly_displayed(self): - self._login() - go_to_subscription(self) - code = reconstruct_submission_code(self) - # query db for Submission with seen code, throws if not present and test fails - Submission.objects.get(text=code) - - def test_submission_type_is_correctly_displayed(self): - self._login() - go_to_subscription(self) - sub_type_el = self.browser.find_element_by_id('submission-type') - title = sub_type_el.find_element_by_class_name('title') - self.assertEqual( - f'{self.sub_type.name} - Full score: {self.sub_type.full_score}', - title.text - ) - solution = reconstruct_solution_code(self) - self.assertEqual(self.sub_type.solution, solution) - description = sub_type_el.find_element_by_class_name('type-description') - html_el_in_desc = description.find_element_by_tag_name('h1') - self.assertEqual('This', html_el_in_desc.text) - - def test_test_output_is_displayed(self): - # create a test for every submission - test = None - for submission in Submission.objects.all(): - test = fact.TestFactory.create(submission=submission, annotation='This is a test') - self._login() - go_to_subscription(self) - tests = self.browser.find_element_by_id('submission-tests') - name_label = tests.find_element_by_name('test-name-label') - name_label.click() - self.assertIn(test.name, name_label.text) - self.assertIn(test.label, name_label.text) - test_output = tests.find_element_by_class_name('test-output') - WebDriverWait(self.browser, 10).until(ec.visibility_of(test_output)) - self.assertEqual(test.annotation, test_output.text) - - def test_can_give_max_score(self): - self._login() - go_to_subscription(self) - code = correct_some_submission(self) - submission_for_code = Submission.objects.get(text=code) - self.assertEqual(self.sub_type.full_score, submission_for_code.feedback.score) - - def test_zero_score_without_warning_gives_error(self): - self._login() - go_to_subscription(self) - self.browser.find_element_by_id('score-zero').click() - submit_btn = self.browser.find_element_by_id('submit-feedback') - assert submit_btn.get_attribute('disabled') - - def test_can_give_zero_score(self): - self._login() - go_to_subscription(self) - code = reconstruct_submission_code(self) - self.browser.find_element_by_id('score-zero').click() - self.write_comments_on_lines([(0, 'A comment')]) - self.browser.find_element_by_id('submit-feedback').click() - WebDriverWait(self.browser, 10).until(wait_until_code_changes(self, code)) - submission_for_code = Submission.objects.get(text=code) - self.assertEqual(0, submission_for_code.feedback.score) - - def test_can_give_comments_and_decreased_score(self): - self._login() - go_to_subscription(self) - code = reconstruct_submission_code(self) - - # give half full score - score_input = self.browser.find_element_by_id('score-input') - score_input.send_keys(self.sub_type.full_score // 2) - - # give feedback on first and last line of submission - comment_text = 'This is feedback' - self.write_comments_on_lines([ - (1, comment_text), (0, comment_text) # 0 corresponds to the last line - ]) - - submit_btn = self.browser.find_element_by_id('submit-feedback') - submit_btn.click() - WebDriverWait(self.browser, 10).until( - wait_until_code_changes(self, code) - ) - submission_for_code = Submission.objects.get(text=code) - self.assertEqual(self.sub_type.full_score // 2, submission_for_code.feedback.score) - self.assertEqual(2, submission_for_code.feedback.feedback_lines.count()) - fst_comment = FeedbackComment.objects.get( - of_feedback=submission_for_code.feedback, - of_line=1 - ) - self.assertEqual(comment_text, fst_comment.text) - last_line_of_sub = len(submission_for_code.text.split('\n')) - snd_comment = FeedbackComment.objects.get( - of_feedback=submission_for_code.feedback, - of_line=last_line_of_sub - ) - self.assertEqual(comment_text, snd_comment.text) - - def test_can_skip_submission(self): - self._login() - go_to_subscription(self) - code = reconstruct_submission_code(self) - self.browser.find_element_by_id('skip-submission').click() - WebDriverWait(self.browser, 10).until(wait_until_code_changes(self, code)) - - def test_can_validate_submission(self): - self._login() - go_to_subscription(self) - - def correct(): - code = reconstruct_submission_code(self) - self.write_comments_on_lines([(0, 'A comment by me')]) - self.browser.find_element_by_id('score-zero').click() - self.browser.find_element_by_id('submit-feedback').click() - return code - code = correct() - WebDriverWait(self.browser, 10).until(wait_until_code_changes(self, code)) - correct() - - sub_url = 'correction/ended' - WebDriverWait(self.browser, 10).until(ec.url_contains(sub_url)) - - reset_browser_after_test(self.browser, self.live_server_url) # logs out user - - user_snd = 'tutor_snd' - password = 'p' - fact.UserAccountFactory(username=user_snd, password=password) - - login(self.browser, self.live_server_url, user_snd, password) - go_to_subscription(self, stage='validate') - self.write_comments_on_lines([(0, 'I disagree'), (1, 'Full points!')]) - code_final = reconstruct_submission_code(self) - self.browser.find_element_by_id('score-full').click() - self.browser.find_element_by_id('submit-feedback').click() - - WebDriverWait(self.browser, 10).until(wait_until_code_changes(self, code_final)) - code_non_final = reconstruct_submission_code(self) - self.browser.find_element_by_class_name('final-checkbox').click() - self.browser.find_element_by_id('submit-feedback').click() - - sub_url = 'correction/ended' - WebDriverWait(self.browser, 10).until(ec.url_contains(sub_url)) - - reset_browser_after_test(self.browser, self.live_server_url) - - user_rev = 'rev' - password = 'p' - role = UserAccount.REVIEWER - fact.UserAccountFactory(username=user_rev, password=password, role=role) - login(self.browser, self.live_server_url, user_rev, password) - - go_to_subscription(self, 'review') - code = reconstruct_submission_code(self) - self.assertEqual(code, code_non_final) - - submission_for_code = Submission.objects.get(text=code_final) - self.assertEqual(self.sub_type.full_score, submission_for_code.feedback.score) - self.assertEqual(3, submission_for_code.feedback.feedback_lines.count()) - - submission_for_code = Submission.objects.get(text=code_non_final) - self.assertEqual(0, submission_for_code.feedback.score) - self.assertEqual(1, submission_for_code.feedback.feedback_lines.count()) - - def test_final_button_not_present_in_review_stage(self): - self._login() - go_to_subscription(self) - - def correct(): - code = reconstruct_submission_code(self) - self.write_comments_on_lines([(0, 'Some comment')]) - self.browser.find_element_by_id('score-zero').click() - self.browser.find_element_by_id('submit-feedback').click() - return code - - code = correct() - WebDriverWait(self.browser, 10).until(wait_until_code_changes(self, code)) - correct() - - sub_url = 'correction/ended' - WebDriverWait(self.browser, 10).until(ec.url_contains(sub_url)) - - reset_browser_after_test(self.browser, self.live_server_url) # logs out user - - user_snd = 'tutor_snd' - password = 'p' - fact.UserAccountFactory(username=user_snd, password=password) - - login(self.browser, self.live_server_url, user_snd, password) - go_to_subscription(self, stage='validate') - self.write_comments_on_lines([(0, 'I disagree'), (1, 'Full points!')]) - code_final = reconstruct_submission_code(self) - self.browser.find_element_by_id('score-full').click() - self.browser.find_element_by_id('submit-feedback').click() - - WebDriverWait(self.browser, 10).until(wait_until_code_changes(self, code_final)) - self.browser.find_element_by_class_name('final-checkbox').click() - self.browser.find_element_by_id('submit-feedback').click() - - sub_url = 'correction/ended' - WebDriverWait(self.browser, 10).until(ec.url_contains(sub_url)) - - reset_browser_after_test(self.browser, self.live_server_url) - - user_rev = 'rev' - password = 'p' - role = UserAccount.REVIEWER - fact.UserAccountFactory(username=user_rev, password=password, role=role) - login(self.browser, self.live_server_url, user_rev, password) - - go_to_subscription(self, 'review') - try: - WebDriverWait(self.browser, 10).until( - ec.presence_of_element_located((By.CLASS_NAME, "final-checkbox")) - ) - not_found = False - except Exception: - not_found = True - - assert not_found - - def test_comments_are_sorted_by_last_updated(self): - self._login() - go_to_subscription(self) - - code = reconstruct_submission_code(self) - self.browser.find_element_by_id('score-full').click() - - # give feedback on first line - self.write_comments_on_lines([(1, 'first ever comment')]) - - submit_btn = self.browser.find_element_by_id('submit-feedback') - submit_btn.click() - - WebDriverWait(self.browser, 10).until( - wait_until_code_changes(self, code) - ) - - reset_browser_after_test(self.browser, self.live_server_url) # logs out user - - user_snd = 'tutor_snd' - password = 'p' - fact.UserAccountFactory(username=user_snd, password=password) - - login(self.browser, self.live_server_url, user_snd, password) - go_to_subscription(self, stage='validate') - - self.write_comments_on_lines([(1, 'the second comment')]) - self.browser.find_element_by_id('score-full').click() - self.browser.find_element_by_class_name('final-checkbox').click() - self.browser.find_element_by_id('submit-feedback').click() - - sub_url = 'correction/ended' - WebDriverWait(self.browser, 10).until(ec.url_contains(sub_url)) - - reset_browser_after_test(self.browser, self.live_server_url) # logs out user - self._login() - - # goto history - self.browser.find_element_by_id('feedback').click() - feedback_entry = self.browser.find_element_by_class_name('feedback-row') - ActionChains(self.browser).move_to_element(feedback_entry).click().perform() - - # validate that second comment is under the first comment - comments = self.browser.find_elements_by_class_name('dialog-box') - first_text = comments[0].find_element_by_class_name('message') - second_text = comments[1].find_element_by_class_name('message') - - self.assertEqual(len(comments), 2) - self.assertEqual(first_text.text, 'first ever comment') - self.assertEqual(second_text.text, 'the second comment') - - # give feedback on first line - self.write_comments_on_lines([(1, 'first comment updated')]) - self.browser.find_element_by_id('score-full').click() - self.browser.find_element_by_id('submit-feedback').click() - - WebDriverWait(self.browser, 5).until( - wait_until_element_count_equals(self, By.CLASS_NAME, "dialog-box", 2) - ) - - # validate that the edited first comment is under the second comment - comments = self.browser.find_elements_by_class_name('dialog-box') - first_text = comments[0].find_element_by_class_name('message') - second_text = comments[1].find_element_by_class_name('message') - - def assertion_one(): - return self.assertEqual(first_text.text, 'the second comment') - - def assertion_two(): - return self.assertEqual(second_text.text, 'first comment updated') - - # comments are sorted after about 0.5s of delay - WebDriverWait(self.browser, 2).until( - assertion_is_true(assertion_one) - ) - WebDriverWait(self.browser, 2).until( - assertion_is_true(assertion_two) - ) - - -class TestFeedbackCreationTutor(UntestedParent.TestFeedbackCreationGeneric): - def setUp(self): - super().setUp() - self.username = 'tutor' - self.password = 'p' - self.role = UserAccount.TUTOR - fact.UserAccountFactory( - username=self.username, - password=self.password, - role=self.role - ) diff --git a/grady/functional_tests/test_feedback_label_system.py b/grady/functional_tests/test_feedback_label_system.py deleted file mode 100644 index b990a2d57003dbfa13b47e0aaefa1248c4765244..0000000000000000000000000000000000000000 --- a/grady/functional_tests/test_feedback_label_system.py +++ /dev/null @@ -1,386 +0,0 @@ -from selenium.common.exceptions import NoSuchElementException -from selenium.webdriver.common.by import By -from selenium.webdriver.support.ui import WebDriverWait -from selenium.webdriver.support import expected_conditions as ec - -from core.models import FeedbackLabel -from functional_tests.util import (GradyTestCase, login, reset_browser_after_test, - query_returns_object, go_to_subscription, - reconstruct_submission_code, wait_until_code_changes) -from util import factory_boys as fact - - -class FeedbackLabelSystemTest(GradyTestCase): - username = None - password = None - role = None - - def setUp(self): - super().setUp() - self.username = 'tut' - self.password = 'p' - fact.UserAccountFactory( - username=self.username, - password=self.password, - ) - self.sub_type = fact.SubmissionTypeFactory.create() - fact.SubmissionFactory.create_batch(2, type=self.sub_type) - - def tearDown(self): - self.saveScreenshots() - reset_browser_after_test(self.browser, self.live_server_url) - - def _login(self): - login(self.browser, self.live_server_url, self.username, self.password) - - # creates a new label where colour_num is - # the index of the colour to click on the colour picker - def create_label(self, name, description, colour_num): - self.browser.find_element_by_id('create-label-section').click() - WebDriverWait(self.browser, 2).until( - ec.element_to_be_clickable((By.ID, 'label-name')) - ) - self.browser.find_element_by_id('label-name').send_keys(name) - self.browser.find_element_by_id('label-description').send_keys(description) - self.browser.find_elements_by_class_name('v-color-picker__color')[colour_num].click() - self.browser.find_element_by_id('create-label-btn').click() - WebDriverWait(self.browser, 10).until(query_returns_object(FeedbackLabel, name=name)) - self.browser.find_element_by_class_name('notification-title').click() - - # updates an already existing label with the given arguments - def update_label(self, old_name, new_name, description, colour_num): - self.browser.find_element_by_id('update-label-section').click() - WebDriverWait(self.browser, 2).until( - ec.element_to_be_clickable((By.ID, 'label-update-autocomplete')) - ) - old_name_input = self.browser.find_element_by_id('label-update-autocomplete') - old_name_input.click() - old_name_input.send_keys(old_name) - self.browser.find_element_by_class_name('label-updater-item').click() - self.browser.find_element_by_xpath( - '//div[contains(@class, "v-window-item--active")]//input[@id="label-name"]' - ).send_keys(new_name) - - self.browser.find_element_by_xpath( - '//div[contains(@class, "v-window-item--active")]//textarea[@id="label-description"]' - ).send_keys(description) - - self.browser.find_elements_by_xpath( - '//div[contains(@class, "v-window-item--active")]' - '//div[contains(@class, "v-color-picker__color")]' - )[colour_num].click() - self.browser.find_element_by_id('update-label-btn').click() - WebDriverWait(self.browser, 10).until( - query_returns_object(FeedbackLabel, name=old_name + new_name) - ) - self.browser.find_element_by_class_name('notification-title').click() - - def assign_label_to_feedback(self, name): - label_input = self.browser.find_element_by_xpath( - '//div[@id="feedback-label-selector"]//input[@id="label-add-autocomplete"]' - ) - label_input.click() - label_input.send_keys(name) - self.browser.find_element_by_class_name('label-adder-item').click() - - def remove_label_from_feedback(self, name): - self.browser.find_element_by_xpath( - f'//div[@id="feedback-label-selector"]//span[contains(@class, "v-chip__content") ' - f'and contains(text(), "{name}")]//button[contains(@class, "v-chip__close")]' - ).click() - - def assign_label_to_comment_line(self, line, name): - self.browser.find_element_by_xpath( - f'//span[contains(@class, "v-btn__content") and contains(text(), "{line}")]' - ).click() - label_input = self.browser.find_element_by_xpath( - '//div[@id="comment-label-selector"]//input[@id="label-add-autocomplete"]' - ) - label_input.click() - label_input.send_keys(name) - self.browser.find_element_by_class_name('label-adder-item').click() - self.browser.find_element_by_id('submit-comment').click() - - def remove_label_from_comment_line(self, line, name): - self.browser.find_element_by_xpath( - f'//tr[@id="sub-line-{line}"]//span[contains(text(), "{name}")]' - '//button[contains(@class, "v-chip__close")]' - ).click() - - # Removes any notification that could obstruct buttons. - def check_for_notification(self): - try: - self.browser.find_element_by_class_name('notification').click() - except NoSuchElementException: - pass - - def test_can_create_label(self): - self._login() - label_name = 'test name' - label_desc = 'test description' - self.create_label(label_name, label_desc, 3) - created_label = FeedbackLabel.objects.get(name='test name') - - self.assertEqual(created_label.name, label_name) - self.assertEqual(created_label.description, label_desc) - - def test_can_not_create_duplicate_label(self): - self._login() - label_name = 'duplicate' - label_desc = 'duplicate test' - self.create_label(label_name, label_desc, 3) - self.create_label(label_name, label_desc, 3) - WebDriverWait(self.browser, 2).until( - ec.visibility_of_element_located((By.CLASS_NAME, 'notification-content')) - ) - notification = self.browser.find_element_by_class_name('notification-content') - - labels = FeedbackLabel.objects.all() - self.assertIn('already exists', notification.text) - self.assertEqual(len(labels), 1) - - def test_can_update_label(self): - self._login() - self.create_label('test', 'some desc', 1) - self.update_label('test', 'updated', 'updated desc', 3) - - label = FeedbackLabel.objects.get(name='testupdated') - - self.assertEqual(label.name, 'testupdated') - self.assertEqual(label.description, 'some descupdated desc') - - def test_can_assign_label_to_feedback_draft(self): - self._login() - self.create_label('test', 'some desc', 1) - go_to_subscription(self) - code = reconstruct_submission_code(self) - self.assign_label_to_feedback('test') - labels = self.browser.find_elements_by_xpath( - '//div[@id="feedback-label-selector"]//div[contains(text(), "WILL BE ADDED")]/..//*' - ) - self.assertGreater(len(labels), 1) - - self.browser.find_element_by_id('score-full').click() - self.browser.find_element_by_id('submit-feedback').click() - WebDriverWait(self.browser, 10).until( - wait_until_code_changes(self, code) - ) - - label = FeedbackLabel.objects.get(name='test') - self.assertEqual(len(label.feedback.all()), 1) - - def test_can_remove_label_from_feedback_draft(self): - self._login() - self.create_label('test', 'some desc', 1) - go_to_subscription(self) - self.assign_label_to_feedback('test') - self.remove_label_from_feedback('test') - labels = self.browser.find_elements_by_xpath( - '//div[@id="feedback-label-selector"]//div[contains(text(), "WILL BE ADDED")]/..//*' - ) - - self.assertEqual(len(labels), 1) - - def test_can_remove_label_from_submitted_feedback(self): - self._login() - self.create_label('test', 'some desc', 1) - go_to_subscription(self) - code = reconstruct_submission_code(self) - self.assign_label_to_feedback('test') - self.browser.find_element_by_id('score-full').click() - self.browser.find_element_by_id('submit-feedback').click() - WebDriverWait(self.browser, 10).until( - wait_until_code_changes(self, code) - ) - - # logs out user - reset_browser_after_test(self.browser, self.live_server_url) - - username = 'tut_snd' - password = 'p' - fact.UserAccountFactory(username=username, password=password) - login(self.browser, self.live_server_url, username, password) - - go_to_subscription(self, stage='validate') - self.remove_label_from_feedback('test') - added = self.browser.find_elements_by_xpath( - '//div[@id="feedback-label-selector"]//div[contains(text(), "WILL BE ADDED")]/..//*' - ) - removed = self.browser.find_elements_by_xpath( - '//div[@id="feedback-label-selector"]//div[contains(text(), "WILL BE REMOVED")]/..//*' - ) - current = self.browser.find_elements_by_xpath( - '//div[@id="feedback-label-selector"]//div[contains(text(), "CURRENT LABELS")]/..//*' - ) - - self.assertGreater(len(removed), 1) - self.assertEqual(len(current), 1) - self.assertEqual(len(added), 1) - - self.browser.find_element_by_id('submit-feedback').click() - sub_url = 'correction/ended' - WebDriverWait(self.browser, 10).until(ec.url_contains(sub_url)) - label = FeedbackLabel.objects.get(name='test') - - self.assertEqual(len(label.feedback.all()), 0) - - def test_can_add_label_to_submitted_feedback(self): - self._login() - self.create_label('test', 'some test dec', 1) - self.create_label('add', 'add test dec', 4) - go_to_subscription(self) - code = reconstruct_submission_code(self) - self.assign_label_to_feedback('test') - self.browser.find_element_by_id('score-full').click() - self.browser.find_element_by_id('submit-feedback').click() - WebDriverWait(self.browser, 10).until( - wait_until_code_changes(self, code) - ) - - # logs out user - reset_browser_after_test(self.browser, self.live_server_url) - - username = 'tut_snd' - password = 'p' - fact.UserAccountFactory(username=username, password=password) - login(self.browser, self.live_server_url, username, password) - go_to_subscription(self, stage='validate') - - self.assign_label_to_feedback('add') - added = self.browser.find_elements_by_xpath( - '//div[@id="feedback-label-selector"]//div[contains(text(), "WILL BE ADDED")]/..//*' - ) - removed = self.browser.find_elements_by_xpath( - '//div[@id="feedback-label-selector"]//div[contains(text(), "WILL BE REMOVED")]/..//*' - ) - current = self.browser.find_elements_by_xpath( - '//div[@id="feedback-label-selector"]//div[contains(text(), "CURRENT LABELS")]/..//*' - ) - - self.assertEqual(len(removed), 1) - self.assertGreater(len(added), 1) - self.assertGreater(len(current), 1) - - self.browser.find_element_by_id('submit-feedback').click() - sub_url = 'correction/ended' - WebDriverWait(self.browser, 10).until(ec.url_contains(sub_url)) - new_label = FeedbackLabel.objects.get(name='add') - old_label = FeedbackLabel.objects.get(name='test') - - self.assertEqual(len(old_label.feedback.all()), 1) - self.assertEqual(len(new_label.feedback.all()), 1) - - def test_can_assign_label_to_comment(self): - self._login() - self.create_label('test', 'some desc', 1) - go_to_subscription(self) - code = reconstruct_submission_code(self) - comment_line = 1 - self.assign_label_to_comment_line(comment_line, 'test') - added = self.browser.find_elements_by_xpath( - f'//tr[@id="sub-line-{comment_line}"]//div[contains(text(), "WILL BE ADDED")]/..//*' - ) - self.assertGreater(len(added), 1) - - self.browser.find_element_by_id('score-full').click() - self.browser.find_element_by_id('submit-feedback').click() - WebDriverWait(self.browser, 10).until( - wait_until_code_changes(self, code) - ) - - label = FeedbackLabel.objects.get(name='test') - self.assertEqual(len(label.feedback_comments.all()), 1) - - def test_can_remove_label_from_submitted_comment(self): - self._login() - self.create_label('test', 'some desc', 1) - go_to_subscription(self) - code = reconstruct_submission_code(self) - comment_line = 1 - self.assign_label_to_comment_line(comment_line, 'test') - self.browser.find_element_by_id('score-full').click() - self.browser.find_element_by_id('submit-feedback').click() - WebDriverWait(self.browser, 10).until( - wait_until_code_changes(self, code) - ) - - # logs out user - reset_browser_after_test(self.browser, self.live_server_url) - - username = 'tut_snd' - password = 'p' - fact.UserAccountFactory(username=username, password=password) - login(self.browser, self.live_server_url, username, password) - - go_to_subscription(self, stage='validate') - self.browser.find_element_by_id('feedback-visibility-toggle').click() - - self.remove_label_from_comment_line(comment_line, 'test') - added = self.browser.find_elements_by_xpath( - f'//tr[@id="sub-line-{comment_line}"]//div[contains(text(), "WILL BE ADDED")]/..//*' - ) - removed = self.browser.find_elements_by_xpath( - f'//tr[@id="sub-line-{comment_line}"]//div[contains(text(), "WILL BE REMOVED")]/..//*' - ) - current = self.browser.find_elements_by_xpath( - f'//tr[@id="sub-line-{comment_line}"]//div[contains(text(), "CURRENT LABELS")]/..//*' - ) - - self.assertGreater(len(removed), 1) - self.assertEqual(len(added), 1) - self.assertEqual(len(current), 1) - - self.browser.find_element_by_id('submit-feedback').click() - sub_url = 'correction/ended' - WebDriverWait(self.browser, 10).until(ec.url_contains(sub_url)) - label = FeedbackLabel.objects.get(name='test') - - # comment still exists but is now invisible - self.assertEqual(label.feedback_comments.all()[0].visible_to_student, False) - - def test_can_add_label_to_submitted_comment(self): - self._login() - self.create_label('test', 'some desc', 1) - self.create_label('add', 'add test desc', 4) - go_to_subscription(self) - code = reconstruct_submission_code(self) - comment_line = 1 - self.assign_label_to_comment_line(comment_line, 'test') - self.browser.find_element_by_id('score-full').click() - self.browser.find_element_by_id('submit-feedback').click() - WebDriverWait(self.browser, 10).until( - wait_until_code_changes(self, code) - ) - - # logs out user - reset_browser_after_test(self.browser, self.live_server_url) - - username = 'tut_snd' - password = 'p' - fact.UserAccountFactory(username=username, password=password) - login(self.browser, self.live_server_url, username, password) - - go_to_subscription(self, stage='validate') - self.browser.find_element_by_id('feedback-visibility-toggle').click() - self.assign_label_to_comment_line(comment_line, 'add') - added = self.browser.find_elements_by_xpath( - f'//tr[@id="sub-line-{comment_line}"]//div[contains(text(), "WILL BE ADDED")]/..//*' - ) - removed = self.browser.find_elements_by_xpath( - f'//tr[@id="sub-line-{comment_line}"]//div[contains(text(), "WILL BE REMOVED")]/..//*' - ) - current = self.browser.find_elements_by_xpath( - f'//tr[@id="sub-line-{comment_line}"]//div[contains(text(), "CURRENT LABELS")]/..//*' - ) - - self.assertEqual(len(removed), 1) - self.assertGreater(len(current), 1) - self.assertGreater(len(added), 1) - - self.browser.find_element_by_id('submit-feedback').click() - sub_url = 'correction/ended' - WebDriverWait(self.browser, 10).until(ec.url_contains(sub_url)) - label = FeedbackLabel.objects.get(name='add') - - # comment still exists but is now invisible - self.assertEqual(len(label.feedback_comments.all()), 1) diff --git a/grady/functional_tests/test_feedback_update.py b/grady/functional_tests/test_feedback_update.py deleted file mode 100644 index b25c8ad3f797f83a0f8450d9a125ed454fa8ff5a..0000000000000000000000000000000000000000 --- a/grady/functional_tests/test_feedback_update.py +++ /dev/null @@ -1,80 +0,0 @@ -from selenium.webdriver import ActionChains -from selenium.webdriver.support import expected_conditions as ec -from selenium.webdriver.common.by import By - -from selenium.webdriver.support.ui import WebDriverWait - -from core.models import UserAccount -from functional_tests.util import (GradyTestCase, login, go_to_subscription, - reconstruct_submission_code, correct_some_submission, - reset_browser_after_test) -from util import factory_boys as fact - - -class TestFeedbackUpdate(GradyTestCase): - username = None - password = None - - def setUp(self): - super().setUp() - self.username = 'tut' - self.password = 'p' - fact.UserAccountFactory( - username=self.username, - password=self.password, - role=UserAccount.TUTOR - ) - self.sub_type = fact.SubmissionTypeFactory.create() - fact.SubmissionFactory.create_batch(2, type=self.sub_type) - - def tearDown(self): - self.saveScreenshots() - reset_browser_after_test(self.browser, self.live_server_url) - - def _login(self): - login(self.browser, self.live_server_url, self.username, self.password) - - def test_updating_own_feedback_doesnt_invalidate_other_tutors_assignment(self): - # First correct some submission as the first tutor - self._login() - code = correct_some_submission(self) - first_tab = self.browser.current_window_handle - - # open a new tab and go to the validation page of the just corrected submission - self.browser.execute_script('window.open()') - self.browser.switch_to.window(self.browser.window_handles[-1]) - self.browser.get(self.live_server_url) - second_tab = self.browser.current_window_handle - username = 'other_tut' - password = 'p' - fact.UserAccountFactory( - username=username, - password=password, - role=UserAccount.TUTOR - ) - login(self.browser, self.live_server_url, username, password) - go_to_subscription(self, stage='validate') - other_code = reconstruct_submission_code(self) - - # The submission to be validated should be the same as the one that has been corrected - self.assertEqual( - code, other_code, - "Code for validation submissions is different than initial") - - # Go to first tab and update the submission as the first tutor via the Feedback History page - self.browser.switch_to.window(first_tab) - self.browser.find_element_by_partial_link_text('Feedback History').click() - WebDriverWait(self.browser, 15, 0.2).until( - ec.visibility_of_element_located((By.CLASS_NAME, 'feedback-row'))) - feedback_entry = self.browser.find_element_by_class_name('feedback-row') - ActionChains(self.browser).move_to_element(feedback_entry).click().perform() - - self.browser.find_element_by_id('submit-feedback').click() - - # as the second tutor, submit the validated feedback - self.browser.switch_to.window(second_tab) - self.browser.find_element_by_id('submit-feedback').click() - WebDriverWait(self.browser, 10).until( - ec.url_contains('ended'), - 'Browser is not on Subscription ended site, therefore Feedback could not be submitted' - ) diff --git a/grady/functional_tests/test_front_pages.py b/grady/functional_tests/test_front_pages.py deleted file mode 100644 index 35bef4e36988a33e639d150857147c3a2be39c72..0000000000000000000000000000000000000000 --- a/grady/functional_tests/test_front_pages.py +++ /dev/null @@ -1,100 +0,0 @@ -from selenium.webdriver.support.ui import WebDriverWait - -from core import models -from core.models import UserAccount -from functional_tests.util import (GradyTestCase, login, subscriptions_loaded_cond, - extract_hrefs_hashes, reset_browser_after_test) -from util import factory_boys as fact - - -# This is a little hack to have Super test class which implements common behaviour -# and tests but is not executed. In order to have the testrunner ignore the -# FrontPageTestsTutorReviewer class we need to define it within a class which does not inherit from -# unittest -class UntestedParent: - class FrontPageTestsTutorReviewer(GradyTestCase): - username = None - password = None - role = None - - def setUp(self): - fact.SubmissionFactory.create_batch(4) - - def tearDown(self): - self.saveScreenshots() - reset_browser_after_test(self.browser, self.live_server_url) - - def _login(self): - login(self.browser, self.live_server_url, self.username, self.password) - - def test_statistics_are_shown(self): - self._login() - statistics = self.browser.find_element_by_id('correction-statistics') - title = statistics.find_element_by_class_name('title') - self.assertEqual('Statistics', title.text) - - def test_available_tasks_are_shown(self): - self._login() - WebDriverWait(self.browser, 10).until(subscriptions_loaded_cond(self.browser)) - tasks = self.browser.find_element_by_name('subscription-list') - submission_type_links = extract_hrefs_hashes( - tasks.find_elements_by_tag_name('a') - ) - sub_types = models.SubmissionType.objects.all() - default_group = models.Group.objects.first() - for sub_type in sub_types: - self.assertIn(f'/correction/{sub_type.pk}/feedback-creation/{default_group.pk}', - submission_type_links) - - -class FrontPageTestsTutor(UntestedParent.FrontPageTestsTutorReviewer): - def setUp(self): - super().setUp() - self.username = 'tutor' - self.password = 'p' - self.role = UserAccount.TUTOR - fact.UserAccountFactory( - username=self.username, - password=self.password - ) - - def tearDown(self): - reset_browser_after_test(self.browser, self.live_server_url) - - def test_side_bar_contains_correct_items(self): - self._login() - drawer = self.browser.find_element_by_class_name('v-navigation-drawer') - links = extract_hrefs_hashes(drawer.find_elements_by_tag_name('a')) - print(links) - self.assertTrue(all(link in links for link in ['/home', '/feedback'])) - footer = drawer.find_element_by_class_name('sidebar-footer') - feedback_link = footer.find_element_by_css_selector('#feedback-btn') - self.assertEqual('https://gitlab.gwdg.de/j.michal/grady/issues', - feedback_link.get_attribute('href')) - - -class FrontPageTestsReviewer(UntestedParent.FrontPageTestsTutorReviewer): - def setUp(self): - super().setUp() - self.username = 'reviewer' - self.password = 'p' - self.role = UserAccount.REVIEWER - fact.UserAccountFactory( - username=self.username, - password=self.password, - role=self.role - ) - - def tearDown(self): - reset_browser_after_test(self.browser, self.live_server_url) - - def test_side_bar_contains_correct_items(self): - self._login() - drawer = self.browser.find_element_by_class_name('v-navigation-drawer') - links = extract_hrefs_hashes(drawer.find_elements_by_tag_name('a')) - self.assertTrue(all(link in links for link in - ['/home', '/feedback', '/participant-overview', '/tutor-overview'])) - footer = drawer.find_element_by_class_name('sidebar-footer') - feedback_link = footer.find_element_by_css_selector('#feedback-btn') - self.assertEqual('https://gitlab.gwdg.de/j.michal/grady/issues', - feedback_link.get_attribute('href')) diff --git a/grady/functional_tests/test_import.py b/grady/functional_tests/test_import.py deleted file mode 100644 index bd7cb10983adc0d964fbd6711d71d55af2d852c2..0000000000000000000000000000000000000000 --- a/grady/functional_tests/test_import.py +++ /dev/null @@ -1,45 +0,0 @@ -import os -from selenium.webdriver.support.ui import WebDriverWait -from selenium.webdriver.common.action_chains import ActionChains - - -from core import models -from functional_tests.util import (GradyTestCase, login, query_returns_object, - reset_browser_after_test) -from util import factory_boys as fact - - -JSON_EXPORT_FILE = os.path.join(os.path.dirname(__file__), 'data/hektor.json') - - -class TestImport(GradyTestCase): - username = None - password = None - role = None - - def setUp(self): - super().setUp() - self.username = 'rev' - self.password = 'p' - fact.UserAccountFactory( - username=self.username, - password=self.password, - role=models.UserAccount.REVIEWER - ) - - def tearDown(self): - self.saveScreenshots() - reset_browser_after_test(self.browser, self.live_server_url) - - def _login(self): - login(self.browser, self.live_server_url, self.username, self.password) - - def test_reviewer_can_import_data(self): - self._login() - self.browser.find_element_by_id("import-data-list-item").click() - file_input = self.browser.find_element_by_id("file-input") - file_input.send_keys(JSON_EXPORT_FILE) - # self.browser.find_element_by_id("submit-import").click() - import_btn = self.browser.find_element_by_id('submit-import') - ActionChains(self.browser).move_to_element(import_btn).click().perform() - WebDriverWait(self.browser, 20).until(query_returns_object(models.SubmissionType)) diff --git a/grady/functional_tests/test_login_page.py b/grady/functional_tests/test_login_page.py deleted file mode 100644 index f99d47c429dfd313c48e69fb08ada4c6f37c9516..0000000000000000000000000000000000000000 --- a/grady/functional_tests/test_login_page.py +++ /dev/null @@ -1,160 +0,0 @@ -from selenium.webdriver.common.keys import Keys -from selenium.webdriver.support import expected_conditions as ec -from selenium.webdriver.support.ui import WebDriverWait -from selenium.webdriver.common.action_chains import ActionChains - -from constance.test import override_config -from core.models import UserAccount -from util.factories import make_test_data, make_exams -from functional_tests.util import GradyTestCase, reset_browser_after_test - - -class LoginPageTest(GradyTestCase): - - def setUp(self): - exams = make_exams([{ - 'module_reference': 'Test Exam 01', - 'total_score': 100, - 'pass_score': 60, - }] - ) - self.test_data = make_test_data(data_dict={ - 'exams': [{ - 'module_reference': 'Test Exam 01', - 'total_score': 100, - 'pass_score': 60, - 'exam_type_id': exams[0].exam_type_id - }], - 'submission_types': [ - { - 'name': '01. Sort this or that', - 'full_score': 35, - 'description': 'Very complicated', - 'solution': 'Trivial!', - 'exam_type': exams[0] - }, - { - 'name': '02. Merge this or that or maybe even this', - 'full_score': 35, - 'description': 'Very complicated', - 'solution': 'Trivial!', - 'exam_type': exams[0] - } - ], - 'students': [ - { - 'username': 'student01', - 'password': 'p', - 'exam': 'Test Exam 01' - }, - { - 'username': 'student02', - 'password': 'p', - 'exam': 'Test Exam 01' - } - ], - 'tutors': [ - {'username': 'tutor01', 'password': 'p'}, - {'username': 'tutor02', 'password': 'p'} - ], - 'reviewers': [ - {'username': 'reviewer', 'password': 'p'} - ], - 'submissions': [ - { - 'text': 'function blabl\n' - ' on multi lines\n' - ' for blabla in bla:\n' - ' lorem ipsum und so\n', - 'type': '01. Sort this or that', - 'user': 'student01', - 'feedback': { - 'score': 5, - 'is_final': True, - 'feedback_lines': { - '1': [{ - 'text': 'This is very bad!', - 'of_tutor': 'tutor01' - }], - } - - } - }, - { - 'text': 'function blabl\n' - ' asasxasx\n' - ' lorem ipsum und so\n', - 'type': '02. Merge this or that or maybe even this', - 'user': 'student01' - }, - { - 'text': 'function blabl\n' - ' on multi lines\n' - ' asasxasx\n' - ' lorem ipsum und so\n', - 'type': '01. Sort this or that', - 'user': 'student02' - }, - { - 'text': 'function lorem ipsum etc\n', - 'type': '02. Merge this or that or maybe even this', - 'user': 'student02' - }, - ]} - ) - - def tearDown(self): - self.saveScreenshots() - reset_browser_after_test(self.browser, self.live_server_url) - - def _login(self, account): - self.browser.get(self.live_server_url) - username_input = self.browser.find_element_by_xpath('//input[@id="username"]') - username_input.send_keys(account.username) - password_input = self.browser.find_element_by_xpath('//input[@id="password"]') - password_input.send_keys('p') - self.browser.find_element_by_xpath('//button[@type="submit"]').send_keys(Keys.ENTER) - WebDriverWait(self.browser, 10).until(ec.url_contains('/home')) - - def test_tutor_can_login(self): - tutor = self.test_data['tutors'][0] - self._login(tutor) - self.assertTrue(self.browser.current_url.endswith('#/home')) - - def test_reviewer_can_login(self): - reviewer = self.test_data['reviewers'][0] - self._login(reviewer) - self.assertTrue(self.browser.current_url.endswith('#/home')) - - def test_student_can_login(self): - student = self.test_data['students'][0] - self._login(student) - self.assertTrue(self.browser.current_url.endswith('#/home')) - - @override_config(REGISTRATION_PASSWORD='pw') - def test_can_register_account(self): - username = 'danny' - password = 'redrum-is-murder-reversed' - instance_password = 'pw' - self.browser.get(self.live_server_url) - self.browser.find_element_by_id('register').click() - self.browser.find_element_by_id('gdpr-notice') - # self.browser.find_element_by_id('accept-gdpr-notice').click() - accept_btn = self.browser.find_element_by_id('accept-gdpr-notice') - ActionChains(self.browser).move_to_element(accept_btn).click().perform() - username_input = self.browser.find_element_by_id('input-register-username') - username_input.send_keys(username) - instance_password_input = self.browser.find_element_by_id( - 'input-register-instance-password' - ) - instance_password_input.send_keys(instance_password) - password_input = self.browser.find_element_by_id('input-register-password') - password_input.send_keys(password) - password_repeat_input = self.browser.find_element_by_id('input-register-password-repeat') - password_repeat_input.send_keys(password) - register_submit_el = self.browser.find_element_by_id('register-submit') - register_submit_el.click() - WebDriverWait(self.browser, 10).until_not(ec.visibility_of(register_submit_el)) - tutor = UserAccount.objects.get(username=username) - self.assertEqual(UserAccount.TUTOR, tutor.role) - self.assertFalse(tutor.is_active, "Tutors should be inactive after registered") diff --git a/grady/functional_tests/test_multiple_exams.py b/grady/functional_tests/test_multiple_exams.py deleted file mode 100644 index 5729a45e50c14c1f7bfd6122db78234705957cb2..0000000000000000000000000000000000000000 --- a/grady/functional_tests/test_multiple_exams.py +++ /dev/null @@ -1,161 +0,0 @@ -from selenium.webdriver.common.keys import Keys -from selenium.webdriver.support import expected_conditions as ec -from selenium.webdriver.support.ui import WebDriverWait - -from util.factories import make_test_data, make_exams -from functional_tests.util import GradyTestCase, reset_browser_after_test - - -class TestMultipleExams(GradyTestCase): - - def setUp(self): - exams = make_exams([{ - 'module_reference': 'Test Exam 01', - 'total_score': 100, - 'pass_score': 60, - }, { - 'module_reference': 'Test Exam 02', - 'total_score': 120, - 'pass_score': 75}] - ) - - self.test_data = make_test_data(data_dict={ - 'exams': [{ - 'module_reference': 'Test Exam 01', - 'total_score': 100, - 'pass_score': 60, - 'exam_type_id': exams[0].exam_type_id - }, { - 'module_reference': 'Test Exam 02', - 'total_score': 120, - 'pass_score': 75, - 'exam_type_id': exams[1].exam_type_id - }], - 'submission_types': [ - { - 'name': '01. Sort this or that', - 'full_score': 35, - 'description': 'Very complicated', - 'solution': 'Trivial!', - 'exam_type': exams[0] - }, - { - 'name': '02. Merge this or that or maybe even this', - 'full_score': 35, - 'description': 'Very complicated', - 'solution': 'Trivial!', - 'exam_type': exams[0] - }, - { - 'name': '05', - 'full_score': 35, - 'description': 'It is not a story the jedi would tell you', - 'solution': 'Trivial!', - 'exam_type': exams[1] - } - ], - 'students': [ - { - 'username': 'student01', - 'password': 'p', - 'exam': 'Test Exam 01' - }, - { - 'username': 'student02', - 'password': 'p', - 'exam': 'Test Exam 01' - }, - { - 'username': 'student03', - 'password': 'p', - 'exam': 'Test Exam 02' - - }, - { - 'username': 'student04', - 'password': 'p', - 'exam': 'Test Exam 02' - } - ], - 'tutors': [ - {'username': 'tutor01', 'password': 'p'}, - {'username': 'tutor02', 'password': 'p'} - ], - 'reviewers': [ - {'username': 'reviewer', 'password': 'p'} - ], - 'submissions': [ - { - 'text': 'function blabl\n' - ' on multi lines\n' - ' for blabla in bla:\n' - ' lorem ipsum und so\n', - 'type': '01. Sort this or that', - 'user': 'student01', - 'feedback': { - 'score': 5, - 'is_final': True, - 'feedback_lines': { - '1': [{ - 'text': 'This is very bad!', - 'of_tutor': 'tutor01' - }], - } - - } - }, - { - 'text': 'function blabl\n' - ' asasxasx\n' - ' lorem ipsum und so\n', - 'type': '02. Merge this or that or maybe even this', - 'user': 'student01' - }, - { - 'text': 'function blabl\n' - ' on multi lines\n' - ' asasxasx\n' - ' lorem ipsum und so\n', - 'type': '01. Sort this or that', - 'user': 'student02' - }, - { - 'text': 'function lorem ipsum etc\n', - 'type': '02. Merge this or that or maybe even this', - 'user': 'student02' - } - ]} - ) - - def tearDown(self): - self.saveScreenshots() - reset_browser_after_test(self.browser, self.live_server_url) - - def _login(self, account): - self.browser.get(self.live_server_url) - username_input = self.browser.find_element_by_xpath('//input[@id="username"]') - username_input.send_keys(account.username) - password_input = self.browser.find_element_by_xpath('//input[@id="password"]') - password_input.send_keys('p') - self.browser.find_element_by_xpath('//button[@type="submit"]').send_keys(Keys.ENTER) - WebDriverWait(self.browser, 10).until(ec.url_contains('/exam_selection')) - - def test_selection_page(self): - reviewer = self.test_data['reviewers'][0] - self._login(reviewer) - self.assertTrue(self.browser.current_url.endswith('#/exam_selection')) - - def test_selection_of_exams(self): - testBool = True - reviewer = self.test_data['reviewers'][0] - self._login(reviewer) - items = self.browser.find_elements_by_id("listItem") - for i in range(len(items)): - itemText = items[i].text - items[i].click() - testBool = itemText == self.browser.find_element_by_class_name("title").text - if(not testBool): - break - self.browser.find_element_by_id("examsButton").click() - items = self.browser.find_elements_by_id("listItem") - self.assertTrue(testBool) diff --git a/grady/functional_tests/test_solution_comments.py b/grady/functional_tests/test_solution_comments.py deleted file mode 100644 index 0fa7e54f35f9afe488fbab68839e8dd176618525..0000000000000000000000000000000000000000 --- a/grady/functional_tests/test_solution_comments.py +++ /dev/null @@ -1,141 +0,0 @@ -from selenium.webdriver.common.by import By -from selenium.webdriver.remote.webelement import WebElement -from selenium.webdriver.support import expected_conditions as ec -from selenium.webdriver.support.ui import WebDriverWait -from selenium.webdriver.common.action_chains import ActionChains - - -from core import models -from functional_tests.util import (GradyTestCase, login, query_returns_object, - reset_browser_after_test, assertion_is_true) -from util import factory_boys as fact - - -class TestSolutionComments(GradyTestCase): - username = None - password = None - role = None - - def setUp(self): - super().setUp() - self.username = 'tut' - self.password = 'p' - fact.UserAccountFactory( - username=self.username, - password=self.password, - ) - self.sub_type = fact.SubmissionTypeFactory.create() - - def tearDown(self): - self.saveScreenshots() - reset_browser_after_test(self.browser, self.live_server_url) - - def _login(self): - login(self.browser, self.live_server_url, self.username, self.password) - - def _write_comment(self, text="A comment", line_no=1): - sub_types = self.browser.find_element_by_id('submission-types-list') - sub_types.find_element_by_tag_name('div').click() - solution_table = self.browser.find_element_by_class_name('solution-table') - tr_of_line = solution_table.find_element_by_id(f'solution-line-{line_no}') - tr_of_line.find_element_by_class_name('line-number-btn').click() - comment_input = tr_of_line.find_element_by_name('solution-comment-input') - comment_input.send_keys(text) - solution_table.find_element_by_id('submit-comment').click() - - def _edit_comment(self, old_text, new_text) -> WebElement: - solution_table = self.browser.find_element_by_class_name('solution-table') - comment = solution_table.find_element_by_xpath( - f"//div[@class='dialog-box' and .//*[contains(text(), '{old_text}')]]" - ) - comment.find_element_by_class_name('edit-button').click() - comment_input = solution_table.find_element_by_name('solution-comment-edit') - comment_input.send_keys(new_text) - solution_table.find_element_by_id('submit-comment').click() - return comment - - def test_tutor_can_add_comment(self): - self._login() - comment_text = 'A comment!' - self._write_comment(comment_text, 1) - solution_table = self.browser.find_element_by_class_name('solution-table') - displayed_text = solution_table.find_element_by_class_name('message').text - self.assertEqual(comment_text, displayed_text) - comment_obj = models.SolutionComment.objects.first() - self.assertEqual(comment_text, comment_obj.text) - self.assertEqual(1, comment_obj.of_line) - - def test_tutor_can_delete_own_comment(self): - self._login() - self._write_comment() - solution_table = self.browser.find_element_by_class_name('solution-table') - solution_table.find_element_by_class_name('delete-button').click() - # self.browser.find_element_by_id('confirm-delete-comment').click() - delete_btn = self.browser.find_element_by_id('confirm-delete-comment') - ActionChains(self.browser).move_to_element(delete_btn).click().perform() - WebDriverWait(self.browser, 10).until_not( - query_returns_object(models.SolutionComment), - "Solution comment not deleted." - ) - - def test_tutor_can_edit_own_comment(self): - self._login() - old_text = 'A comment' - new_text = 'A new text' - self._write_comment(old_text) - WebDriverWait(self.browser, 10).until(query_returns_object(models.SolutionComment)) - comment_obj = models.SolutionComment.objects.first() - self.assertEqual(old_text, comment_obj.text) - comment_el = self._edit_comment(old_text, new_text) - - def text_is_updated(): - displayed_text = comment_el.find_element_by_class_name('message').text - return self.assertEqual(new_text, displayed_text) - - WebDriverWait(self.browser, 3).until(assertion_is_true(text_is_updated)) - comment_obj.refresh_from_db() - self.assertEqual(new_text, comment_obj.text) - - def test_tutor_can_not_delete_edit_other_comment(self): - self._login() - self._write_comment() - username = 'tut2' - password = 'p' - fact.UserAccountFactory(username=username, password=password) - reset_browser_after_test(self.browser, self.live_server_url) - login(self.browser, self.live_server_url, username, password) - sub_types = self.browser.find_element_by_id('submission-types-list') - sub_types.find_element_by_tag_name('div').click() - solution_table = self.browser.find_element_by_class_name('solution-table') - # Set the implicit wait for those to shorter, to reduce test run time - self.browser.implicitly_wait(2) - edit_buttons = solution_table.find_elements_by_class_name('edit-button') - delete_buttons = solution_table.find_elements_by_class_name('delete-button') - self.browser.implicitly_wait(10) - self.assertEqual(0, len(edit_buttons)) - self.assertEqual(0, len(delete_buttons)) - - def test_reviewer_can_delete_tutor_comment(self): - self._login() - self._write_comment() - username = 'rev' - password = 'p' - fact.UserAccountFactory( - username=username, password=password, role=models.UserAccount.REVIEWER - ) - reset_browser_after_test(self.browser, self.live_server_url) - login(self.browser, self.live_server_url, username, password) - sub_types = self.browser.find_element_by_id('submission-types-list') - sub_types.find_element_by_tag_name('div').click() - solution_table = self.browser.find_element_by_class_name('solution-table') - solution_table.find_element_by_class_name('delete-button').click() - # self.browser.find_element_by_id('confirm-delete-comment').click() - delete_btn = self.browser.find_element_by_id('confirm-delete-comment') - ActionChains(self.browser).move_to_element(delete_btn).click().perform() - WebDriverWait(self.browser, 10).until_not( - ec.presence_of_element_located((By.CLASS_NAME, 'dialog-box')) - ) - WebDriverWait(self.browser, 10).until_not( - query_returns_object(models.SolutionComment), - "Solution comment not deleted." - ) diff --git a/grady/functional_tests/util.py b/grady/functional_tests/util.py deleted file mode 100644 index 920e06d37eedcf5d9de459cb0544e1335a8a6fa2..0000000000000000000000000000000000000000 --- a/grady/functional_tests/util.py +++ /dev/null @@ -1,221 +0,0 @@ -import os -from itertools import islice -from typing import Sequence -import time - -from selenium import webdriver -from selenium.webdriver import FirefoxProfile -from selenium.webdriver.common.keys import Keys -from selenium.webdriver.firefox.options import Options -from selenium.webdriver.remote.webelement import WebElement -from selenium.webdriver.support import expected_conditions as ec -from selenium.webdriver.support.ui import WebDriverWait -from selenium.common.exceptions import StaleElementReferenceException, NoSuchElementException -from selenium.webdriver.common.by import By -from django.core.exceptions import ObjectDoesNotExist -from django.test import LiveServerTestCase - -SCREENSHOTS = os.path.join(os.path.dirname(__file__), 'screenshots') - - -class GradyTestCase(LiveServerTestCase): - browser: webdriver.Firefox = None - - @classmethod - def setUpClass(cls): - super().setUpClass() - cls.browser = create_browser() - - @classmethod - def tearDownClass(cls): - super().tearDownClass() - cls.browser.quit() - - def saveScreenshots(self): - try: - os.mkdir(SCREENSHOTS) - except FileExistsError: - pass - for method, error in self._outcome.errors: - if error: - self.browser.get_screenshot_as_file( - os.path.join(SCREENSHOTS, self.id() + ".png") - ) - - -def create_browser() -> webdriver.Firefox: - options = Options() - options.headless = bool(os.environ.get('HEADLESS_TESTS', False)) - options.set_capability('unhandledPromptBehavior', 'accept') - options.set_capability('strictFileInteractability', False) - profile = FirefoxProfile() - profile.set_preference("dom.disable_beforeunload", True) - profile.set_preference("browser.download.folderList", 2) - profile.set_preference("browser.download.dir", os.path.dirname(__file__)) - profile.set_preference("browser.download.useDownloadDir", True) - profile.set_preference("browser.download.panel.shown", False) - profile.set_preference("browser.helperApps.neverAsk.saveToDisk", 'application/vnd.hzn-3d-crossword;video/3gpp;video/3gpp2;application/vnd.mseq;application/vnd.3m.post-it-notes;application/vnd.3gpp.pic-bw-large;application/vnd.3gpp.pic-bw-small;application/vnd.3gpp.pic-bw-var;application/vnd.3gp2.tcap;application/x-7z-compressed;application/x-abiword;application/x-ace-compressed;application/vnd.americandynamics.acc;application/vnd.acucobol;application/vnd.acucorp;audio/adpcm;application/x-authorware-bin;application/x-athorware-map;application/x-authorware-seg;application/vnd.adobe.air-application-installer-package+zip;application/x-shockwave-flash;application/vnd.adobe.fxp;application/pdf;application/vnd.cups-ppd;application/x-director;applicaion/vnd.adobe.xdp+xml;application/vnd.adobe.xfdf;audio/x-aac;application/vnd.ahead.space;application/vnd.airzip.filesecure.azf;application/vnd.airzip.filesecure.azs;application/vnd.amazon.ebook;application/vnd.amiga.ami;applicatin/andrew-inset;application/vnd.android.package-archive;application/vnd.anser-web-certificate-issue-initiation;application/vnd.anser-web-funds-transfer-initiation;application/vnd.antix.game-component;application/vnd.apple.installe+xml;application/applixware;application/vnd.hhe.lesson-player;application/vnd.aristanetworks.swi;text/x-asm;application/atomcat+xml;application/atomsvc+xml;application/atom+xml;application/pkix-attr-cert;audio/x-aiff;video/x-msvieo;application/vnd.audiograph;image/vnd.dxf;model/vnd.dwf;text/plain-bas;application/x-bcpio;application/octet-stream;image/bmp;application/x-bittorrent;application/vnd.rim.cod;application/vnd.blueice.multipass;application/vnd.bm;application/x-sh;image/prs.btif;application/vnd.businessobjects;application/x-bzip;application/x-bzip2;application/x-csh;text/x-c;application/vnd.chemdraw+xml;text/css;chemical/x-cdx;chemical/x-cml;chemical/x-csml;application/vn.contact.cmsg;application/vnd.claymore;application/vnd.clonk.c4group;image/vnd.dvb.subtitle;application/cdmi-capability;application/cdmi-container;application/cdmi-domain;application/cdmi-object;application/cdmi-queue;applicationvnd.cluetrust.cartomobile-config;application/vnd.cluetrust.cartomobile-config-pkg;image/x-cmu-raster;model/vnd.collada+xml;text/csv;application/mac-compactpro;application/vnd.wap.wmlc;image/cgm;x-conference/x-cooltalk;image/x-cmx;application/vnd.xara;application/vnd.cosmocaller;application/x-cpio;application/vnd.crick.clicker;application/vnd.crick.clicker.keyboard;application/vnd.crick.clicker.palette;application/vnd.crick.clicker.template;application/vn.crick.clicker.wordbank;application/vnd.criticaltools.wbs+xml;application/vnd.rig.cryptonote;chemical/x-cif;chemical/x-cmdf;application/cu-seeme;application/prs.cww;text/vnd.curl;text/vnd.curl.dcurl;text/vnd.curl.mcurl;text/vnd.crl.scurl;application/vnd.curl.car;application/vnd.curl.pcurl;application/vnd.yellowriver-custom-menu;application/dssc+der;application/dssc+xml;application/x-debian-package;audio/vnd.dece.audio;image/vnd.dece.graphic;video/vnd.dec.hd;video/vnd.dece.mobile;video/vnd.uvvu.mp4;video/vnd.dece.pd;video/vnd.dece.sd;video/vnd.dece.video;application/x-dvi;application/vnd.fdsn.seed;application/x-dtbook+xml;application/x-dtbresource+xml;application/vnd.dvb.ait;applcation/vnd.dvb.service;audio/vnd.digital-winds;image/vnd.djvu;application/xml-dtd;application/vnd.dolby.mlp;application/x-doom;application/vnd.dpgraph;audio/vnd.dra;application/vnd.dreamfactory;audio/vnd.dts;audio/vnd.dts.hd;imag/vnd.dwg;application/vnd.dynageo;application/ecmascript;application/vnd.ecowin.chart;image/vnd.fujixerox.edmics-mmr;image/vnd.fujixerox.edmics-rlc;application/exi;application/vnd.proteus.magazine;application/epub+zip;message/rfc82;application/vnd.enliven;application/vnd.is-xpr;image/vnd.xiff;application/vnd.xfdl;application/emma+xml;application/vnd.ezpix-album;application/vnd.ezpix-package;image/vnd.fst;video/vnd.fvt;image/vnd.fastbidsheet;application/vn.denovo.fcselayout-link;video/x-f4v;video/x-flv;image/vnd.fpx;image/vnd.net-fpx;text/vnd.fmi.flexstor;video/x-fli;application/vnd.fluxtime.clip;application/vnd.fdf;text/x-fortran;application/vnd.mif;application/vnd.framemaker;imae/x-freehand;application/vnd.fsc.weblaunch;application/vnd.frogans.fnc;application/vnd.frogans.ltf;application/vnd.fujixerox.ddd;application/vnd.fujixerox.docuworks;application/vnd.fujixerox.docuworks.binder;application/vnd.fujitu.oasys;application/vnd.fujitsu.oasys2;application/vnd.fujitsu.oasys3;application/vnd.fujitsu.oasysgp;application/vnd.fujitsu.oasysprs;application/x-futuresplash;application/vnd.fuzzysheet;image/g3fax;application/vnd.gmx;model/vn.gtw;application/vnd.genomatix.tuxedo;application/vnd.geogebra.file;application/vnd.geogebra.tool;model/vnd.gdl;application/vnd.geometry-explorer;application/vnd.geonext;application/vnd.geoplan;application/vnd.geospace;applicatio/x-font-ghostscript;application/x-font-bdf;application/x-gtar;application/x-texinfo;application/x-gnumeric;application/vnd.google-earth.kml+xml;application/vnd.google-earth.kmz;application/vnd.grafeq;image/gif;text/vnd.graphviz;aplication/vnd.groove-account;application/vnd.groove-help;application/vnd.groove-identity-message;application/vnd.groove-injector;application/vnd.groove-tool-message;application/vnd.groove-tool-template;application/vnd.groove-vcar;video/h261;video/h263;video/h264;application/vnd.hp-hpid;application/vnd.hp-hps;application/x-hdf;audio/vnd.rip;application/vnd.hbci;application/vnd.hp-jlyt;application/vnd.hp-pcl;application/vnd.hp-hpgl;application/vnd.yamaha.h-script;application/vnd.yamaha.hv-dic;application/vnd.yamaha.hv-voice;application/vnd.hydrostatix.sof-data;application/hyperstudio;application/vnd.hal+xml;text/html;application/vnd.ibm.rights-management;application/vnd.ibm.securecontainer;text/calendar;application/vnd.iccprofile;image/x-icon;application/vnd.igloader;image/ief;application/vnd.immervision-ivp;application/vnd.immervision-ivu;application/reginfo+xml;text/vnd.in3d.3dml;text/vnd.in3d.spot;mode/iges;application/vnd.intergeo;application/vnd.cinderella;application/vnd.intercon.formnet;application/vnd.isac.fcs;application/ipfix;application/pkix-cert;application/pkixcmp;application/pkix-crl;application/pkix-pkipath;applicaion/vnd.insors.igm;application/vnd.ipunplugged.rcprofile;application/vnd.irepository.package+xml;text/vnd.sun.j2me.app-descriptor;application/java-archive;application/java-vm;application/x-java-jnlp-file;application/java-serializd-object;text/x-java-source,java;application/javascript;application/json;application/vnd.joost.joda-archive;video/jpm;image/jpeg;video/jpeg;application/vnd.kahootz;application/vnd.chipnuts.karaoke-mmd;application/vnd.kde.karbon;aplication/vnd.kde.kchart;application/vnd.kde.kformula;application/vnd.kde.kivio;application/vnd.kde.kontour;application/vnd.kde.kpresenter;application/vnd.kde.kspread;application/vnd.kde.kword;application/vnd.kenameaapp;applicatin/vnd.kidspiration;application/vnd.kinar;application/vnd.kodak-descriptor;application/vnd.las.las+xml;application/x-latex;application/vnd.llamagraphics.life-balance.desktop;application/vnd.llamagraphics.life-balance.exchange+xml;application/vnd.jam;application/vnd.lotus-1-2-3;application/vnd.lotus-approach;application/vnd.lotus-freelance;application/vnd.lotus-notes;application/vnd.lotus-organizer;application/vnd.lotus-screencam;application/vnd.lotus-wordro;audio/vnd.lucent.voice;audio/x-mpegurl;video/x-m4v;application/mac-binhex40;application/vnd.macports.portpkg;application/vnd.osgeo.mapguide.package;application/marc;application/marcxml+xml;application/mxf;application/vnd.wolfrm.player;application/mathematica;application/mathml+xml;application/mbox;application/vnd.medcalcdata;application/mediaservercontrol+xml;application/vnd.mediastation.cdkey;application/vnd.mfer;application/vnd.mfmp;model/mesh;appliation/mads+xml;application/mets+xml;application/mods+xml;application/metalink4+xml;application/vnd.ms-powerpoint.template.macroenabled.12;application/vnd.ms-word.document.macroenabled.12;application/vnd.ms-word.template.macroenabed.12;application/vnd.mcd;application/vnd.micrografx.flo;application/vnd.micrografx.igx;application/vnd.eszigno3+xml;application/x-msaccess;video/x-ms-asf;application/x-msdownload;application/vnd.ms-artgalry;application/vnd.ms-ca-compressed;application/vnd.ms-ims;application/x-ms-application;application/x-msclip;image/vnd.ms-modi;application/vnd.ms-fontobject;application/vnd.ms-excel;application/vnd.ms-excel.addin.macroenabled.12;application/vnd.ms-excelsheet.binary.macroenabled.12;application/vnd.ms-excel.template.macroenabled.12;application/vnd.ms-excel.sheet.macroenabled.12;application/vnd.ms-htmlhelp;application/x-mscardfile;application/vnd.ms-lrm;application/x-msmediaview;aplication/x-msmoney;application/vnd.openxmlformats-officedocument.presentationml.presentation;application/vnd.openxmlformats-officedocument.presentationml.slide;application/vnd.openxmlformats-officedocument.presentationml.slideshw;application/vnd.openxmlformats-officedocument.presentationml.template;application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;application/vnd.openxmlformats-officedocument.spreadsheetml.template;application/vnd.openxmformats-officedocument.wordprocessingml.document;application/vnd.openxmlformats-officedocument.wordprocessingml.template;application/x-msbinder;application/vnd.ms-officetheme;application/onenote;audio/vnd.ms-playready.media.pya;vdeo/vnd.ms-playready.media.pyv;application/vnd.ms-powerpoint;application/vnd.ms-powerpoint.addin.macroenabled.12;application/vnd.ms-powerpoint.slide.macroenabled.12;application/vnd.ms-powerpoint.presentation.macroenabled.12;appliation/vnd.ms-powerpoint.slideshow.macroenabled.12;application/vnd.ms-project;application/x-mspublisher;application/x-msschedule;application/x-silverlight-app;application/vnd.ms-pki.stl;application/vnd.ms-pki.seccat;application/vn.visio;video/x-ms-wm;audio/x-ms-wma;audio/x-ms-wax;video/x-ms-wmx;application/x-ms-wmd;application/vnd.ms-wpl;application/x-ms-wmz;video/x-ms-wmv;video/x-ms-wvx;application/x-msmetafile;application/x-msterminal;application/msword;application/x-mswrite;application/vnd.ms-works;application/x-ms-xbap;application/vnd.ms-xpsdocument;audio/midi;application/vnd.ibm.minipay;application/vnd.ibm.modcap;application/vnd.jcp.javame.midlet-rms;application/vnd.tmobile-ivetv;application/x-mobipocket-ebook;application/vnd.mobius.mbk;application/vnd.mobius.dis;application/vnd.mobius.plc;application/vnd.mobius.mqy;application/vnd.mobius.msl;application/vnd.mobius.txf;application/vnd.mobius.daf;tex/vnd.fly;application/vnd.mophun.certificate;application/vnd.mophun.application;video/mj2;audio/mpeg;video/vnd.mpegurl;video/mpeg;application/mp21;audio/mp4;video/mp4;application/mp4;application/vnd.apple.mpegurl;application/vnd.msician;application/vnd.muvee.style;application/xv+xml;application/vnd.nokia.n-gage.data;application/vnd.nokia.n-gage.symbian.install;application/x-dtbncx+xml;application/x-netcdf;application/vnd.neurolanguage.nlu;application/vnd.na;application/vnd.noblenet-directory;application/vnd.noblenet-sealer;application/vnd.noblenet-web;application/vnd.nokia.radio-preset;application/vnd.nokia.radio-presets;text/n3;application/vnd.novadigm.edm;application/vnd.novadim.edx;application/vnd.novadigm.ext;application/vnd.flographit;audio/vnd.nuera.ecelp4800;audio/vnd.nuera.ecelp7470;audio/vnd.nuera.ecelp9600;application/oda;application/ogg;audio/ogg;video/ogg;application/vnd.oma.dd2+xml;applicatin/vnd.oasis.opendocument.text-web;application/oebps-package+xml;application/vnd.intu.qbo;application/vnd.openofficeorg.extension;application/vnd.yamaha.openscoreformat;audio/webm;video/webm;application/vnd.oasis.opendocument.char;application/vnd.oasis.opendocument.chart-template;application/vnd.oasis.opendocument.database;application/vnd.oasis.opendocument.formula;application/vnd.oasis.opendocument.formula-template;application/vnd.oasis.opendocument.grapics;application/vnd.oasis.opendocument.graphics-template;application/vnd.oasis.opendocument.image;application/vnd.oasis.opendocument.image-template;application/vnd.oasis.opendocument.presentation;application/vnd.oasis.opendocumen.presentation-template;application/vnd.oasis.opendocument.spreadsheet;application/vnd.oasis.opendocument.spreadsheet-template;application/vnd.oasis.opendocument.text;application/vnd.oasis.opendocument.text-master;application/vnd.asis.opendocument.text-template;image/ktx;application/vnd.sun.xml.calc;application/vnd.sun.xml.calc.template;application/vnd.sun.xml.draw;application/vnd.sun.xml.draw.template;application/vnd.sun.xml.impress;application/vnd.sun.xl.impress.template;application/vnd.sun.xml.math;application/vnd.sun.xml.writer;application/vnd.sun.xml.writer.global;application/vnd.sun.xml.writer.template;application/x-font-otf;application/vnd.yamaha.openscoreformat.osfpvg+xml;application/vnd.osgi.dp;application/vnd.palm;text/x-pascal;application/vnd.pawaafile;application/vnd.hp-pclxl;application/vnd.picsel;image/x-pcx;image/vnd.adobe.photoshop;application/pics-rules;image/x-pict;application/x-chat;aplication/pkcs10;application/x-pkcs12;application/pkcs7-mime;application/pkcs7-signature;application/x-pkcs7-certreqresp;application/x-pkcs7-certificates;application/pkcs8;application/vnd.pocketlearn;image/x-portable-anymap;image/-portable-bitmap;application/x-font-pcf;application/font-tdpfr;application/x-chess-pgn;image/x-portable-graymap;image/png;image/x-portable-pixmap;application/pskc+xml;application/vnd.ctc-posml;application/postscript;application/xfont-type1;application/vnd.powerbuilder6;application/pgp-encrypted;application/pgp-signature;application/vnd.previewsystems.box;application/vnd.pvi.ptid1;application/pls+xml;application/vnd.pg.format;application/vnd.pg.osasli;tex/prs.lines.tag;application/x-font-linux-psf;application/vnd.publishare-delta-tree;application/vnd.pmi.widget;application/vnd.quark.quarkxpress;application/vnd.epson.esf;application/vnd.epson.msf;application/vnd.epson.ssf;applicaton/vnd.epson.quickanime;application/vnd.intu.qfx;video/quicktime;application/x-rar-compressed;audio/x-pn-realaudio;audio/x-pn-realaudio-plugin;application/rsd+xml;application/vnd.rn-realmedia;application/vnd.realvnc.bed;applicatin/vnd.recordare.musicxml;application/vnd.recordare.musicxml+xml;application/relax-ng-compact-syntax;application/vnd.data-vision.rdz;application/rdf+xml;application/vnd.cloanto.rp9;application/vnd.jisp;application/rtf;text/richtex;application/vnd.route66.link66+xml;application/rss+xml;application/shf+xml;application/vnd.sailingtracker.track;image/svg+xml;application/vnd.sus-calendar;application/sru+xml;application/set-payment-initiation;application/set-reistration-initiation;application/vnd.sema;application/vnd.semd;application/vnd.semf;application/vnd.seemail;application/x-font-snf;application/scvp-vp-request;application/scvp-vp-response;application/scvp-cv-request;application/svp-cv-response;application/sdp;text/x-setext;video/x-sgi-movie;application/vnd.shana.informed.formdata;application/vnd.shana.informed.formtemplate;application/vnd.shana.informed.interchange;application/vnd.shana.informed.package;application/thraud+xml;application/x-shar;image/x-rgb;application/vnd.epson.salt;application/vnd.accpac.simply.aso;application/vnd.accpac.simply.imp;application/vnd.simtech-mindmapper;application/vnd.commonspace;application/vnd.ymaha.smaf-audio;application/vnd.smaf;application/vnd.yamaha.smaf-phrase;application/vnd.smart.teacher;application/vnd.svd;application/sparql-query;application/sparql-results+xml;application/srgs;application/srgs+xml;application/sml+xml;application/vnd.koan;text/sgml;application/vnd.stardivision.calc;application/vnd.stardivision.draw;application/vnd.stardivision.impress;application/vnd.stardivision.math;application/vnd.stardivision.writer;application/vnd.tardivision.writer-global;application/vnd.stepmania.stepchart;application/x-stuffit;application/x-stuffitx;application/vnd.solent.sdkm+xml;application/vnd.olpc-sugar;audio/basic;application/vnd.wqd;application/vnd.symbian.install;application/smil+xml;application/vnd.syncml+xml;application/vnd.syncml.dm+wbxml;application/vnd.syncml.dm+xml;application/x-sv4cpio;application/x-sv4crc;application/sbml+xml;text/tab-separated-values;image/tiff;application/vnd.to.intent-module-archive;application/x-tar;application/x-tcl;application/x-tex;application/x-tex-tfm;application/tei+xml;text/plain;application/vnd.spotfire.dxp;application/vnd.spotfire.sfs;application/timestamped-data;applicationvnd.trid.tpt;application/vnd.triscape.mxs;text/troff;application/vnd.trueapp;application/x-font-ttf;text/turtle;application/vnd.umajin;application/vnd.uoml+xml;application/vnd.unity;application/vnd.ufdl;text/uri-list;application/nd.uiq.theme;application/x-ustar;text/x-uuencode;text/x-vcalendar;text/x-vcard;application/x-cdlink;application/vnd.vsf;model/vrml;application/vnd.vcx;model/vnd.mts;model/vnd.vtu;application/vnd.visionary;video/vnd.vivo;applicatin/ccxml+xml,;application/voicexml+xml;application/x-wais-source;application/vnd.wap.wbxml;image/vnd.wap.wbmp;audio/x-wav;application/davmount+xml;application/x-font-woff;application/wspolicy+xml;image/webp;application/vnd.webturb;application/widget;application/winhlp;text/vnd.wap.wml;text/vnd.wap.wmlscript;application/vnd.wap.wmlscriptc;application/vnd.wordperfect;application/vnd.wt.stf;application/wsdl+xml;image/x-xbitmap;image/x-xpixmap;image/x-xwindowump;application/x-x509-ca-cert;application/x-xfig;application/xhtml+xml;application/xml;application/xcap-diff+xml;application/xenc+xml;application/patch-ops-error+xml;application/resource-lists+xml;application/rls-services+xml;aplication/resource-lists-diff+xml;application/xslt+xml;application/xop+xml;application/x-xpinstall;application/xspf+xml;application/vnd.mozilla.xul+xml;chemical/x-xyz;text/yaml;application/yang;application/yin+xml;application/vnd.ul;application/zip;application/vnd.handheld-entertainment+xml;application/vnd.zzazz.deck+xml') # noqa - browser = webdriver.Firefox(firefox_profile=profile, options=options) - browser.implicitly_wait(10) - browser.set_window_size(1920, 1080) - return browser - - -def login(browser, live_server_url, username, password='p'): - browser.get(live_server_url) - username_input = browser.find_element_by_xpath('//input[@id="username"]') - username_input.send_keys(username) - password_input = browser.find_element_by_xpath('//input[@id="password"]') - password_input.send_keys(password) - browser.find_element_by_xpath('//button[@type="submit"]').send_keys(Keys.ENTER) - WebDriverWait(browser, 20).until(ec.url_contains('/home')) - - -def logout(browser: webdriver.Firefox): - browser.find_element_by_id('logout').click() - - -def reset_browser_after_test(browser: webdriver.Firefox, live_server_url): - while len(browser.window_handles) > 1: - browser.close() - browser.switch_to.window(browser.window_handles[-1]) - browser.get(live_server_url) - - -def nth(iterable, n, default=None): - "Returns the nth item or a default value" - return next(islice(iterable, n, None), default) - - -def extract_hrefs_hashes(web_elements: Sequence[WebElement]): - return [nth(el.get_attribute('href').split('#'), 1, '') - for el in web_elements if el.get_attribute('href')] - - -# A function that takes the a browser client -# and returns a function that can be used as a condition for -# WebDriverWait -def subscriptions_loaded_cond(browser): - def loaded(*args): - for i in range(2): - try: - tasks_el = browser.find_element_by_name('subscription-list') - tasks_el.find_element_by_class_name('v-progress-circular') - except StaleElementReferenceException: - pass - except NoSuchElementException: - return True - return False - return loaded - - -# returns a function that can be used as a callback for WebDriverWait -# the resulting functions returns True if the given query would return at least one object -def query_returns_object(model_class, **kwargs): - def query(*args): - try: - model_class.objects.get(**kwargs) - except ObjectDoesNotExist: - return False - return True - return query - - -# stage can be 'initial', 'validate', or 'conflict' -def go_to_subscription(test_class_instance, stage='initial', sub_type=None): - WebDriverWait(test_class_instance.browser, 10).until( - subscriptions_loaded_cond(test_class_instance.browser), - ) - tasks = test_class_instance.browser.find_element_by_name('subscription-list') - tab = tasks.find_element_by_xpath(f'//*[contains(text(), "{stage}")]') - tab.click() - - # sleep here because the animation takes some time to finish - time.sleep(1) - - sub_type = sub_type if sub_type is not None else test_class_instance.sub_type - - sub_type_xpath = f'//*[contains(text(), "{sub_type.name}") ' \ - f'and not(contains(@class, "inactive-subscription")) ' \ - f'and contains(@class, "subscription") ' \ - f'and not(ancestor::div[contains(@style,"display: none;")])]' - - WebDriverWait(test_class_instance.browser, 10).until( - ec.element_to_be_clickable((By.XPATH, sub_type_xpath)), - message="SubmissionType not clickable" - ) - sub_type_el = tasks.find_element_by_xpath(sub_type_xpath) - sub_type_el.click() - WebDriverWait(test_class_instance.browser, 10).until( - ec.url_contains('correction'), - message='URL not change to correction URL' - ) - - -def correct_some_submission(test_class_instance): - go_to_subscription(test_class_instance) - code = reconstruct_submission_code(test_class_instance) - test_class_instance.browser.find_element_by_id('score-full').click() - submit_btn = test_class_instance.browser.find_element_by_id('submit-feedback') - submit_btn.click() - WebDriverWait(test_class_instance.browser, 10).until( - wait_until_code_changes(test_class_instance, code) - ) - return code - - -def reconstruct_submission_code(test_class_instance): - sub_table = test_class_instance.browser.find_element_by_class_name('submission-table') - return reconstruct_code_from_table(sub_table) - - -def reconstruct_solution_code(test_class_instance): - solution_table = test_class_instance.browser.find_element_by_class_name('solution-table') - return reconstruct_code_from_table(solution_table) - - -def reconstruct_code_from_table(table_el): - lines = table_el.find_elements_by_tag_name('tr') - line_no_code_pairs = [ - (line.get_attribute('id'), - # call get_attribute here to get non normalized text - # https://github.com/SeleniumHQ/selenium/issues/2608 - line.find_element_by_class_name('code-cell-content') - .find_element_by_class_name('code-line') - .get_attribute('textContent')) - for line in lines - ] - line_no_code_pairs.sort(key=lambda x: x[0]) # sort by ids - code_lines = list(zip(*line_no_code_pairs))[1] - return '\n'.join(code_lines) - - -def wait_until_code_changes(test_class_instance, code): - def condition(*args): - try: - # code might change during the call resulting in the exception - new_code = reconstruct_submission_code(test_class_instance) - except StaleElementReferenceException: - return False - return code != new_code - return condition - - -def wait_until_element_count_equals(test_class_instance, by, selector, count): - def condition(*args): - try: - elements = test_class_instance.browser.find_elements(by, selector) - except Exception: - return False - return len(elements) == count - return condition - - -def assertion_is_true(assertion_func): - def condition(*args): - try: - assertion_func() - except Exception: - return False - return True - return condition diff --git a/grady/grady/settings/__init__.py b/grady/grady/settings/__init__.py deleted file mode 100644 index cdbdbdffa916989e7a25eb84f63aeb9666a6f118..0000000000000000000000000000000000000000 --- a/grady/grady/settings/__init__.py +++ /dev/null @@ -1,8 +0,0 @@ -from .default import * # noqa -import os - -dev = os.environ.get('DJANGO_DEV', False) - -if not dev: - from .live import * # noqa - from .url_hack import * # noqa diff --git a/grady/grady/settings/default.py b/grady/grady/settings/default.py deleted file mode 100644 index e3a6457c0e287dc44f7affda540aa84a6e253823..0000000000000000000000000000000000000000 --- a/grady/grady/settings/default.py +++ /dev/null @@ -1,230 +0,0 @@ -""" -Django settings for grady project. - -Generated by 'django-admin startproject' using Django 1.10.6. - -For more information on this file, see -https://docs.djangoproject.com/en/1.10/topics/settings/ - -For the full list of settings and their values, see -https://docs.djangoproject.com/en/1.10/ref/settings/ -""" - -import datetime -import os - -# Build paths inside the project like this: os.path.join(BASE_DIR, ...) -BASE_DIR = os.path.dirname(os.path.dirname( - os.path.dirname(os.path.abspath(__file__)))) - -# Quick-start development settings - unsuitable for production -# See https://docs.djangoproject.com/en/1.10/howto/deployment/checklist/ - -# SECURITY WARNING: keep the secret key used in production secret! - -SECRET_KEY = '0*h29pqq9n_&5gtcd8qd2mb^uaf8ydo+ck*p72gg18jrrve(ap' - -# SECURITY WARNING: don't run with debug turned on in production! -DEBUG = True - -ALLOWED_HOSTS = [] - -# Application definition - -INSTALLED_APPS = [ - 'django.contrib.admin', - 'django.contrib.auth', - 'django.contrib.contenttypes', - 'django.contrib.sessions', - 'django.contrib.messages', - 'whitenoise.runserver_nostatic', - 'django.contrib.staticfiles', - 'django_extensions', - 'rest_framework', - 'corsheaders', - 'drf_yasg', - 'silk', - 'core', - 'constance', - 'constance.backends.database', -] - -MIDDLEWARE = [ - 'corsheaders.middleware.CorsMiddleware', - 'django.middleware.common.CommonMiddleware', - 'django.middleware.security.SecurityMiddleware', - 'django.contrib.sessions.middleware.SessionMiddleware', - 'django.middleware.common.CommonMiddleware', - 'django.middleware.csrf.CsrfViewMiddleware', - 'django.contrib.auth.middleware.AuthenticationMiddleware', - 'django.contrib.messages.middleware.MessageMiddleware', - 'django.middleware.clickjacking.XFrameOptionsMiddleware', - 'whitenoise.middleware.WhiteNoiseMiddleware', - 'silk.middleware.SilkyMiddleware', -] - -ROOT_URLCONF = 'grady.urls' - -TEMPLATES = [ - { - 'BACKEND': 'django.template.backends.django.DjangoTemplates', - 'DIRS': [], - 'APP_DIRS': True, - 'OPTIONS': { - 'context_processors': [ - 'django.template.context_processors.debug', - 'django.template.context_processors.request', - 'django.contrib.auth.context_processors.auth', - 'django.contrib.messages.context_processors.messages', - ], - }, - }, -] - - -WSGI_APPLICATION = 'grady.wsgi.application' - - -# Database -# https://docs.djangoproject.com/en/1.10/ref/settings/#databases - -DATABASES = { - 'default': { - 'ENGINE': 'django.db.backends.postgresql_psycopg2', - 'NAME': os.environ.get('DB_NAME', 'postgres'), - 'USER': os.environ.get('DB_USER', 'postgres'), - 'PASSWORD': os.environ.get('DB_PASSWORD', 'postgres'), - 'HOST': os.environ.get('DB_HOST', 'localhost'), - 'PORT': os.environ.get('DB_PORT', '5432'), - 'ATOMIC_REQUESTS': True - }, -} - - -# Internationalization -# https://docs.djangoproject.com/en/1.10/topics/i18n/ - -LANGUAGE_CODE = 'en-us' -TIME_ZONE = 'UTC' -USE_I18N = True -USE_L10N = True -USE_TZ = True - - -# Static files (CSS, JavaScript, Images) -# https://docs.djangoproject.com/en/1.10/howto/static-files/ -STATIC_URL = '/static/' -STATIC_ROOT = os.path.join(BASE_DIR, 'static') -STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage' -STATICFILES_FINDERS = ( - 'django.contrib.staticfiles.finders.FileSystemFinder', - 'django.contrib.staticfiles.finders.AppDirectoriesFinder', -) -STATICFILES_DIRS = ( - 'frontend/dist/static', -) - - -LOGIN_REDIRECT_URL = '/' -LOGIN_URL = '/' - -AUTH_USER_MODEL = 'core.UserAccount' -AUTH_PASSWORD_VALIDATORS = [ - {'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator'}, - {'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator'}, - {'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator'}, - {'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator'} -] - -CORS_ORIGIN_WHITELIST = ( - 'http://localhost:8080', - 'http://localhost:8000' -) - -REST_FRAMEWORK = { - 'TEST_REQUEST_DEFAULT_FORMAT': 'json', - 'DEFAULT_PERMISSION_CLASSES': ( - 'rest_framework.permissions.IsAuthenticated', - ), - 'DEFAULT_AUTHENTICATION_CLASSES': ( - 'rest_framework_jwt.authentication.JSONWebTokenAuthentication', - 'rest_framework.authentication.SessionAuthentication', - 'rest_framework.authentication.BasicAuthentication', - ), - 'DEFAULT_RENDERER_CLASSES': ( - 'djangorestframework_camel_case.render.CamelCaseJSONRenderer', - ), - - 'DEFAULT_PARSER_CLASSES': ( - 'djangorestframework_camel_case.parser.CamelCaseJSONParser', - ), - 'COERCE_DECIMAL_TO_STRING': False, -} - -JSON_CAMEL_CASE = { - 'JSON_UNDERSCOREIZE': { - 'no_underscore_before_number': True, - }, -} - -JWT_AUTH = { - 'JWT_EXPIRATION_DELTA': datetime.timedelta(seconds=18000), - 'JWT_ALLOW_REFRESH': True, -} - - -LOG_LEVEL = os.environ.get('GRADY_LOG_LEVEL', 'DEBUG') -LOG_FORMAT = os.environ.get('GRADY_LOG_FORMAT', 'default-format') -LOGGING = { - "version": 1, - "disable_existing_loggers": not DEBUG, - "formatters": { - 'default-format': { - # 'datefmt': the default is ISO8601 which is what we want - 'format': '[%(asctime)s] [%(levelname)s] %(name)-20s %(message)s', - }, - 'json': { - '()': 'json_log_formatter.JSONFormatter', - }, - }, - 'handlers': { - 'console': { - 'level': LOG_LEVEL, - 'class': 'logging.StreamHandler', - 'formatter': LOG_FORMAT - }, - }, - 'loggers': { - 'django': { - 'handlers': ['console'], - }, - 'django.request': { - 'handlers': ['console'], - }, - 'gunicorn.error': { - 'handlers': ['console'], - }, - 'gunicorn.access': { - 'handlers': ['console'], - }, - 'core': { - 'handlers': ['console'], - 'level': LOG_LEVEL, - } - } -} - - -CONSTANCE_BACKEND = 'constance.backends.database.DatabaseBackend' -CONSTANCE_CONFIG = { - 'STOP_ON_PASS': (False, "Stop correction when for pass " - "only students when they reach pass score"), - 'SINGLE_CORRECTION': (False, "Set submitted feedback immediately to final and skip validation"), - 'EXERCISE_MODE': (False, "Whether the application runs in exercise mode. " - "Gives tutors access to options normally reserved to reviewers"), - "SHOW_SOLUTION_TO_STUDENTS": (False, "Whether or not the students should be allowed to see the solutions"), - 'REGISTRATION_PASSWORD': ("", "The registration password to use.") -} - -# Allow request bodies up to 100MB -DATA_UPLOAD_MAX_MEMORY_SIZE = 104857600 diff --git a/grady/grady/settings/live.py b/grady/grady/settings/live.py deleted file mode 100644 index 8ac84849c3139c211665074e97da6e8790c42cb5..0000000000000000000000000000000000000000 --- a/grady/grady/settings/live.py +++ /dev/null @@ -1,70 +0,0 @@ -import secrets -import string - -from .default import REST_FRAMEWORK - -""" A live configuration for enhanced security """ -CSRF_COOKIE_SECURE = True -CSRF_COOKIE_HTTPONLY = True -SESSION_COOKIE_SECURE = True -SECURE_CONTENT_TYPE_NOSNIFF = True -SECURE_BROWSER_XSS_FILTER = True -X_FRAME_OPTIONS = 'DENY' - - -# SECURITY WARNING: don't run with debug turned on in production! -DEBUG = False - -# Read a new SECRET_KEY or generate a new one -SECRET_FILE = 'secret' -try: - SECRET_KEY = open(SECRET_FILE).read().strip() - if len(SECRET_KEY) == 0: - raise Exception -except (IOError, Exception): - try: - SECRET_KEY = ''.join(secrets.choice(string.printable) - for i in range(50)) - with open(SECRET_FILE, 'w') as secret: - secret.write(SECRET_KEY) - except IOError: - Exception('Please create a %s file with random characters \ - to generate your secret key!' % SECRET_FILE) - -# adjust this setting to your needs -ALLOWED_HOSTS = [ - 'localhost', '.grady.janmax.org', 'grady.informatik.uni-goettingen.de' -] - -# sample postgres sql database configuration -DATABASES = { - 'default': { - 'ENGINE': 'django.db.backends.postgresql_psycopg2', - 'NAME': 'postgres', - 'USER': 'postgres', - 'PASSWORD': 'postgres', - 'HOST': 'postgres', - 'PORT': '5432', - 'ATOMIC_REQUESTS': True - }, -} - -# Password validation -# https://docs.djangoproject.com/en/1.10/ref/settings/#auth-password-validators - -AUTH_PASSWORD_VALIDATORS = [ - {'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator'}, - {'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator'}, - {'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator'}, - {'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator'} -] - -REST_FRAMEWORK = { - **REST_FRAMEWORK, - 'DEFAULT_THROTTLE_CLASSES': ( - 'rest_framework.throttling.AnonRateThrottle', - ), - 'DEFAULT_THROTTLE_RATES': { - 'anon': '300/day', - } -} diff --git a/grady/grady/settings/test.py b/grady/grady/settings/test.py deleted file mode 100644 index d8eca64b83f3171d73d5e9adf613d14aaa62b7b3..0000000000000000000000000000000000000000 --- a/grady/grady/settings/test.py +++ /dev/null @@ -1,4 +0,0 @@ -from .default import * -from .live import * - -REST_FRAMEWORK['DEFAULT_THROTTLE_RATES']['anon'] = '1000/minute' diff --git a/grady/grady/settings/url_hack.py b/grady/grady/settings/url_hack.py deleted file mode 100644 index a4443f3ece6371a91e945f7a298be8676fd3255a..0000000000000000000000000000000000000000 --- a/grady/grady/settings/url_hack.py +++ /dev/null @@ -1,17 +0,0 @@ -""" Ok, what the hell? This is especially ugly, hence I keep it hidden in -this file. We have the requirement that the application instances should -run under http://$host/$instancename/. And therefore the frontend, whitenoise, -django, gunicorn and the top http proxy all have to handle this stuff. - -Usage: Just set the SCRIPT_NAME env variable to /<name of your instance> - and things will work. """ - -import os - -FORCE_SCRIPT_NAME = os.environ.get('SCRIPT_NAME', '') -if FORCE_SCRIPT_NAME: - FORCE_SCRIPT_NAME += '/' - -STATIC_URL_BASE = '/static/' -STATIC_URL = os.path.join(FORCE_SCRIPT_NAME + STATIC_URL_BASE) -WHITENOISE_STATIC_PREFIX = STATIC_URL_BASE diff --git a/grady/grady/urls.py b/grady/grady/urls.py deleted file mode 100644 index 30c8dad16edf639a8db8a639be950f0ab9d5bd8c..0000000000000000000000000000000000000000 --- a/grady/grady/urls.py +++ /dev/null @@ -1,16 +0,0 @@ -from django.conf import settings -from django.contrib import admin -from django.urls import include, path -from django.views.generic.base import TemplateView -from rest_framework_jwt.views import obtain_jwt_token, refresh_jwt_token - -urlpatterns = [ - path('admin/', admin.site.urls), - path('api/', include('core.urls')), - path('api/get-token/', obtain_jwt_token), - path('api/refresh-token/', refresh_jwt_token), - path('api-auth/', include('rest_framework.urls', - namespace='rest_framework')), - path('', TemplateView.as_view(template_name='index.html')), - path('silk/', include('silk.urls', namespace='silk')), -] diff --git a/grady/grady/wsgi.py b/grady/grady/wsgi.py deleted file mode 100644 index 012844d105dcc7ba8ced93ef1878c32e49e52d16..0000000000000000000000000000000000000000 --- a/grady/grady/wsgi.py +++ /dev/null @@ -1,16 +0,0 @@ -""" -WSGI config for grady project. - -It exposes the WSGI callable as a module-level variable named ``application``. - -For more information on this file, see -https://docs.djangoproject.com/en/1.10/howto/deployment/wsgi/ -""" - -import os - -from django.core.wsgi import get_wsgi_application - -os.environ.setdefault("DJANGO_SETTINGS_MODULE", "grady.settings") - -application = get_wsgi_application() diff --git a/grady/manage.py b/grady/manage.py deleted file mode 100755 index bd8354c16cac6d4da448ff9baf50c1e50440451b..0000000000000000000000000000000000000000 --- a/grady/manage.py +++ /dev/null @@ -1,22 +0,0 @@ -#!/usr/bin/env python -import os -import sys - -if __name__ == "__main__": - os.environ.setdefault("DJANGO_SETTINGS_MODULE", "grady.settings") - try: - from django.core.management import execute_from_command_line - except ImportError: - # The above import may fail for some other reason. Ensure that the - # issue is really that Django is missing to avoid masking other - # exceptions on Python 2. - try: - import django - except ImportError: - raise ImportError( - "Couldn't import Django. Are you sure it's installed and " - "available on your PYTHONPATH environment variable? Did you " - "forget to activate a virtual environment?" - ) - raise - execute_from_command_line(sys.argv) diff --git a/grady/settings/live.py b/grady/settings/live.py index 405c0bed4e887cb8084347ab75da65a1e25ea82f..8ac84849c3139c211665074e97da6e8790c42cb5 100644 --- a/grady/settings/live.py +++ b/grady/settings/live.py @@ -32,7 +32,9 @@ except (IOError, Exception): to generate your secret key!' % SECRET_FILE) # adjust this setting to your needs -ALLOWED_HOSTS = [ 'localhost', '.informatik.uni-goettingen.de' ] +ALLOWED_HOSTS = [ + 'localhost', '.grady.janmax.org', 'grady.informatik.uni-goettingen.de' +] # sample postgres sql database configuration DATABASES = { diff --git a/grady/setup.cfg b/grady/setup.cfg deleted file mode 100644 index 68c89dfba87c7e32ffe29bdb3916d6d32b93b87c..0000000000000000000000000000000000000000 --- a/grady/setup.cfg +++ /dev/null @@ -1,7 +0,0 @@ -[flake8] - -max-line-length = 100 - -[pep8] - -max-line-length = 100 diff --git a/grady/swagger-api-specification.json b/grady/swagger-api-specification.json deleted file mode 100644 index 29c9f7d385dcf94e0408908be37510818539bcc1..0000000000000000000000000000000000000000 --- a/grady/swagger-api-specification.json +++ /dev/null @@ -1 +0,0 @@ -{"swagger": "2.0", "info": {"title": "Grady API", "description": "Blub", "version": "v1"}, "host": "localhost:8000", "schemes": ["http"], "basePath": "/api", "consumes": ["application/json"], "produces": ["application/json"], "securityDefinitions": {"basic": {"type": "basic"}}, "security": [{"basic": []}], "paths": {"/assignment/": {"get": {"operationId": "assignment_list", "description": "", "parameters": [], "responses": {"200": {"description": "", "schema": {"type": "array", "items": {"$ref": "#/definitions/Assignment"}}}}, "tags": ["assignment"]}, "post": {"operationId": "assignment_create", "description": "", "parameters": [{"name": "data", "in": "body", "required": true, "schema": {"$ref": "#/definitions/Assignment"}}], "responses": {"201": {"description": "", "schema": {"$ref": "#/definitions/Assignment"}}}, "tags": ["assignment"]}, "parameters": []}, "/assignment/{assignment_id}/": {"get": {"operationId": "assignment_read", "description": "", "parameters": [], "responses": {"200": {"description": "", "schema": {"$ref": "#/definitions/Assignment"}}}, "tags": ["assignment"]}, "delete": {"operationId": "assignment_delete", "description": "Stop working on the assignment before it is finished", "parameters": [], "responses": {"204": {"description": ""}}, "tags": ["assignment"]}, "parameters": [{"name": "assignment_id", "in": "path", "description": "A UUID string identifying this tutor submission assignment.", "required": true, "type": "string", "format": "uuid"}]}, "/examtype/": {"get": {"operationId": "examtype_list", "description": "Gets a list of an individual exam by Id if provided", "parameters": [], "responses": {"200": {"description": "", "schema": {"type": "array", "items": {"$ref": "#/definitions/Exam"}}}}, "tags": ["examtype"]}, "parameters": []}, "/examtype/{exam_type_id}/": {"get": {"operationId": "examtype_read", "description": "Gets a list of an individual exam by Id if provided", "parameters": [], "responses": {"200": {"description": "", "schema": {"$ref": "#/definitions/Exam"}}}, "tags": ["examtype"]}, "parameters": [{"name": "exam_type_id", "in": "path", "description": "A UUID string identifying this ExamType.", "required": true, "type": "string", "format": "uuid"}]}, "/export/csv/": {"get": {"operationId": "export_csv_list", "description": "", "parameters": [], "responses": {"200": {"description": ""}}, "produces": ["text/csv"], "tags": ["export"]}, "parameters": []}, "/feedback-comment/{comment_id}/": {"patch": {"operationId": "feedback-comment_partial_update", "description": "Gets a list of an individual exam by Id if provided", "parameters": [{"name": "data", "in": "body", "required": true, "schema": {"$ref": "#/definitions/FeedbackComment"}}], "responses": {"200": {"description": "", "schema": {"$ref": "#/definitions/FeedbackComment"}}}, "tags": ["feedback-comment"]}, "delete": {"operationId": "feedback-comment_delete", "description": "Gets a list of an individual exam by Id if provided", "parameters": [], "responses": {"204": {"description": ""}}, "tags": ["feedback-comment"]}, "parameters": [{"name": "comment_id", "in": "path", "description": "A UUID string identifying this Feedback Comment.", "required": true, "type": "string", "format": "uuid"}]}, "/feedback/": {"get": {"operationId": "feedback_list", "description": "Gets a list of an individual exam by Id if provided", "parameters": [], "responses": {"200": {"description": "", "schema": {"type": "array", "items": {"$ref": "#/definitions/Feedback"}}}}, "tags": ["feedback"]}, "post": {"operationId": "feedback_create", "description": "Gets a list of an individual exam by Id if provided", "parameters": [{"name": "data", "in": "body", "required": true, "schema": {"$ref": "#/definitions/Feedback"}}], "responses": {"201": {"description": "", "schema": {"$ref": "#/definitions/Feedback"}}}, "tags": ["feedback"]}, "parameters": []}, "/feedback/{submission_pk}/": {"get": {"operationId": "feedback_read", "description": "Gets a list of an individual exam by Id if provided", "parameters": [], "responses": {"200": {"description": "", "schema": {"$ref": "#/definitions/Feedback"}}}, "tags": ["feedback"]}, "patch": {"operationId": "feedback_partial_update", "description": "Gets a list of an individual exam by Id if provided", "parameters": [{"name": "data", "in": "body", "required": true, "schema": {"$ref": "#/definitions/Feedback"}}], "responses": {"200": {"description": "", "schema": {"$ref": "#/definitions/Feedback"}}}, "tags": ["feedback"]}, "parameters": [{"name": "submission_pk", "in": "path", "required": true, "type": "string"}]}, "/get-token/": {"post": {"operationId": "get-token_create", "description": "API View that receives a POST with a user's username and password.\n\nReturns a JSON Web Token that can be used for authenticated requests.", "parameters": [{"name": "data", "in": "body", "required": true, "schema": {"$ref": "#/definitions/JSONWebToken"}}], "responses": {"201": {"description": "", "schema": {"$ref": "#/definitions/JSONWebToken"}}}, "tags": ["get-token"]}, "parameters": []}, "/jwt-time-delta/": {"get": {"operationId": "jwt-time-delta_list", "description": "", "parameters": [], "responses": {"200": {"description": ""}}, "tags": ["jwt-time-delta"]}, "parameters": []}, "/refresh-token/": {"post": {"operationId": "refresh-token_create", "description": "API View that returns a refreshed token (with new expiration) based on\nexisting token\n\nIf 'orig_iat' field (original issued-at-time) is found, will first check\nif it's within expiration window, then copy it to the new token", "parameters": [{"name": "data", "in": "body", "required": true, "schema": {"$ref": "#/definitions/RefreshJSONWebToken"}}], "responses": {"201": {"description": "", "schema": {"$ref": "#/definitions/RefreshJSONWebToken"}}}, "tags": ["refresh-token"]}, "parameters": []}, "/statistics/": {"get": {"operationId": "statistics_list", "description": "", "parameters": [], "responses": {"200": {"description": ""}}, "tags": ["statistics"]}, "parameters": []}, "/student-page/": {"get": {"operationId": "student-page_read", "description": "Gets all data that belongs to one student", "parameters": [], "responses": {"200": {"description": "", "schema": {"$ref": "#/definitions/StudentInfo"}}}, "tags": ["student-page"]}, "parameters": []}, "/student-submissions/": {"get": {"operationId": "student-submissions_list", "description": "", "parameters": [], "responses": {"200": {"description": "", "schema": {"type": "array", "items": {"$ref": "#/definitions/Submission"}}}}, "tags": ["student-submissions"]}, "parameters": []}, "/student/": {"get": {"operationId": "student_list", "description": "Gets a list of all students without individual submissions", "parameters": [], "responses": {"200": {"description": "", "schema": {"type": "array", "items": {"$ref": "#/definitions/StudentInfoForListView"}}}}, "tags": ["student"]}, "parameters": []}, "/student/activate/": {"post": {"operationId": "student_activate", "description": "Gets a list of all students without individual submissions", "parameters": [{"name": "data", "in": "body", "required": true, "schema": {"$ref": "#/definitions/StudentInfoForListView"}}], "responses": {"201": {"description": "", "schema": {"$ref": "#/definitions/StudentInfoForListView"}}}, "tags": ["student"]}, "parameters": []}, "/student/deactivate/": {"post": {"operationId": "student_deactivate", "description": "Gets a list of all students without individual submissions", "parameters": [{"name": "data", "in": "body", "required": true, "schema": {"$ref": "#/definitions/StudentInfoForListView"}}], "responses": {"201": {"description": "", "schema": {"$ref": "#/definitions/StudentInfoForListView"}}}, "tags": ["student"]}, "parameters": []}, "/student/{student_id}/": {"get": {"operationId": "student_read", "description": "Gets a list of all students without individual submissions", "parameters": [], "responses": {"200": {"description": "", "schema": {"$ref": "#/definitions/StudentInfoForListView"}}}, "tags": ["student"]}, "parameters": [{"name": "student_id", "in": "path", "description": "A UUID string identifying this Student.", "required": true, "type": "string", "format": "uuid"}]}, "/submission/": {"get": {"operationId": "submission_list", "description": "", "parameters": [], "responses": {"200": {"description": "", "schema": {"type": "array", "items": {"$ref": "#/definitions/SubmissionNoType"}}}}, "tags": ["submission"]}, "parameters": []}, "/submission/{submission_id}/": {"get": {"operationId": "submission_read", "description": "", "parameters": [], "responses": {"200": {"description": "", "schema": {"$ref": "#/definitions/SubmissionNoType"}}}, "tags": ["submission"]}, "parameters": [{"name": "submission_id", "in": "path", "description": "A UUID string identifying this Submission.", "required": true, "type": "string", "format": "uuid"}]}, "/submissiontype/": {"get": {"operationId": "submissiontype_list", "description": "Gets a list or a detail view of a single SubmissionType", "parameters": [], "responses": {"200": {"description": "", "schema": {"type": "array", "items": {"$ref": "#/definitions/SubmissionType"}}}}, "tags": ["submissiontype"]}, "parameters": []}, "/submissiontype/{submission_type_id}/": {"get": {"operationId": "submissiontype_read", "description": "Gets a list or a detail view of a single SubmissionType", "parameters": [], "responses": {"200": {"description": "", "schema": {"$ref": "#/definitions/SubmissionType"}}}, "tags": ["submissiontype"]}, "parameters": [{"name": "submission_type_id", "in": "path", "description": "A UUID string identifying this SubmissionType.", "required": true, "type": "string", "format": "uuid"}]}, "/subscription/": {"get": {"operationId": "subscription_list", "description": "", "parameters": [], "responses": {"200": {"description": "", "schema": {"type": "array", "items": {"$ref": "#/definitions/Subscription"}}}}, "tags": ["subscription"]}, "post": {"operationId": "subscription_create", "description": "", "parameters": [{"name": "data", "in": "body", "required": true, "schema": {"$ref": "#/definitions/Subscription"}}], "responses": {"201": {"description": "", "schema": {"$ref": "#/definitions/Subscription"}}}, "tags": ["subscription"]}, "parameters": []}, "/subscription/{subscription_id}/": {"get": {"operationId": "subscription_read", "description": "", "parameters": [], "responses": {"200": {"description": "", "schema": {"$ref": "#/definitions/Subscription"}}}, "tags": ["subscription"]}, "delete": {"operationId": "subscription_delete", "description": "", "parameters": [], "responses": {"204": {"description": ""}}, "tags": ["subscription"]}, "parameters": [{"name": "subscription_id", "in": "path", "description": "A UUID string identifying this submission subscription.", "required": true, "type": "string", "format": "uuid"}]}, "/tutor/": {"get": {"operationId": "tutor_list", "description": "Api endpoint for creating, listing, viewing or deleting tutors", "parameters": [], "responses": {"200": {"description": "", "schema": {"type": "array", "items": {"$ref": "#/definitions/Tutor"}}}}, "tags": ["tutor"]}, "post": {"operationId": "tutor_create", "description": "Api endpoint for creating, listing, viewing or deleting tutors", "parameters": [{"name": "data", "in": "body", "required": true, "schema": {"$ref": "#/definitions/Tutor"}}], "responses": {"201": {"description": "", "schema": {"$ref": "#/definitions/Tutor"}}}, "tags": ["tutor"]}, "parameters": []}, "/tutor/register/": {"post": {"operationId": "tutor_register", "description": "Api endpoint for creating, listing, viewing or deleting tutors", "parameters": [{"name": "data", "in": "body", "required": true, "schema": {"$ref": "#/definitions/Tutor"}}], "responses": {"201": {"description": "", "schema": {"$ref": "#/definitions/Tutor"}}}, "tags": ["tutor"]}, "parameters": []}, "/tutor/{user_id}/": {"get": {"operationId": "tutor_read", "description": "Api endpoint for creating, listing, viewing or deleting tutors", "parameters": [], "responses": {"200": {"description": "", "schema": {"$ref": "#/definitions/Tutor"}}}, "tags": ["tutor"]}, "put": {"operationId": "tutor_update", "description": "Api endpoint for creating, listing, viewing or deleting tutors", "parameters": [{"name": "data", "in": "body", "required": true, "schema": {"$ref": "#/definitions/Tutor"}}], "responses": {"200": {"description": "", "schema": {"$ref": "#/definitions/Tutor"}}}, "tags": ["tutor"]}, "patch": {"operationId": "tutor_partial_update", "description": "Api endpoint for creating, listing, viewing or deleting tutors", "parameters": [{"name": "data", "in": "body", "required": true, "schema": {"$ref": "#/definitions/Tutor"}}], "responses": {"200": {"description": "", "schema": {"$ref": "#/definitions/Tutor"}}}, "tags": ["tutor"]}, "delete": {"operationId": "tutor_delete", "description": "Api endpoint for creating, listing, viewing or deleting tutors", "parameters": [], "responses": {"204": {"description": ""}}, "tags": ["tutor"]}, "parameters": [{"name": "user_id", "in": "path", "description": "A UUID string identifying this user.", "required": true, "type": "string", "format": "uuid"}]}, "/user-role/": {"get": {"operationId": "user-role_list", "description": "", "parameters": [], "responses": {"200": {"description": ""}}, "tags": ["user-role"]}, "parameters": []}, "/user/": {"get": {"operationId": "user_list", "description": "", "parameters": [], "responses": {"200": {"description": "", "schema": {"type": "array", "items": {"$ref": "#/definitions/UserAccount"}}}}, "tags": ["user"]}, "parameters": []}, "/user/me/": {"get": {"operationId": "user_me", "description": "", "parameters": [], "responses": {"200": {"description": "", "schema": {"type": "array", "items": {"$ref": "#/definitions/UserAccount"}}}}, "tags": ["user"]}, "parameters": []}, "/user/{user_id}/": {"get": {"operationId": "user_read", "description": "", "parameters": [], "responses": {"200": {"description": "", "schema": {"$ref": "#/definitions/UserAccount"}}}, "tags": ["user"]}, "parameters": [{"name": "user_id", "in": "path", "description": "A UUID string identifying this user.", "required": true, "type": "string", "format": "uuid"}]}, "/user/{user_id}/change_active/": {"patch": {"operationId": "user_change_active", "description": "", "parameters": [{"name": "data", "in": "body", "required": true, "schema": {"$ref": "#/definitions/UserAccount"}}], "responses": {"200": {"description": "", "schema": {"$ref": "#/definitions/UserAccount"}}}, "tags": ["user"]}, "parameters": [{"name": "user_id", "in": "path", "description": "A UUID string identifying this user.", "required": true, "type": "string", "format": "uuid"}]}, "/user/{user_id}/change_password/": {"patch": {"operationId": "user_change_password", "description": "", "parameters": [{"name": "data", "in": "body", "required": true, "schema": {"$ref": "#/definitions/UserAccount"}}], "responses": {"200": {"description": "", "schema": {"$ref": "#/definitions/UserAccount"}}}, "tags": ["user"]}, "parameters": [{"name": "user_id", "in": "path", "description": "A UUID string identifying this user.", "required": true, "type": "string", "format": "uuid"}]}}, "definitions": {"Assignment": {"type": "object", "properties": {"pk": {"title": "Assignment id", "type": "string", "format": "uuid", "readOnly": true}, "submission": {"title": "Submission", "type": "string", "format": "uuid", "readOnly": true}, "isDone": {"title": "Is done", "type": "boolean", "readOnly": true}, "owner": {"title": "Owner", "type": "string", "readOnly": true}, "stage": {"title": "Stage", "type": "string", "readOnly": true}}}, "Exam": {"required": ["moduleReference", "totalScore", "passScore"], "type": "object", "properties": {"pk": {"title": "Exam type id", "type": "string", "format": "uuid", "readOnly": true}, "moduleReference": {"title": "Module reference", "type": "string", "maxLength": 50, "minLength": 1}, "totalScore": {"title": "Total score", "type": "integer", "maximum": 2147483647, "minimum": 0}, "passScore": {"title": "Pass score", "type": "integer", "maximum": 2147483647, "minimum": 0}, "passOnly": {"title": "Pass only", "type": "boolean"}}}, "FeedbackComment": {"required": ["text"], "type": "object", "properties": {"pk": {"title": "Comment id", "type": "string", "format": "uuid", "readOnly": true}, "text": {"title": "Text", "type": "string", "minLength": 1}, "created": {"title": "Created", "type": "string", "format": "date-time", "readOnly": true}, "ofTutor": {"title": "Of tutor", "type": "string", "readOnly": true}, "ofLine": {"title": "Of line", "type": "integer", "maximum": 2147483647, "minimum": 0}, "visibleToStudent": {"title": "Visible to student", "type": "boolean"}}}, "Feedback": {"required": ["ofSubmission"], "type": "object", "properties": {"pk": {"title": "ID", "type": "integer", "readOnly": true}, "ofSubmission": {"title": "Of submission", "type": "string", "format": "uuid"}, "isFinal": {"title": "Is final", "type": "boolean"}, "score": {"title": "Score", "type": "integer", "maximum": 2147483647, "minimum": 0}, "feedbackLines": {"type": "array", "items": {"$ref": "#/definitions/FeedbackComment"}}, "created": {"title": "Created", "type": "string", "format": "date-time", "readOnly": true}, "ofSubmissionType": {"title": "Of submission type", "type": "string", "readOnly": true}, "feedbackStageForUser": {"title": "Feedback stage for user", "type": "string", "readOnly": true}}}, "JSONWebToken": {"required": ["username", "password"], "type": "object", "properties": {"username": {"title": "Username", "type": "string", "minLength": 1}, "password": {"title": "Password", "type": "string", "minLength": 1}}}, "RefreshJSONWebToken": {"required": ["token"], "type": "object", "properties": {"token": {"title": "Token", "type": "string", "minLength": 1}}}, "SubmissionTypeList": {"title": "Type", "required": ["name"], "type": "object", "properties": {"pk": {"title": "Submission type id", "type": "string", "format": "uuid", "readOnly": true}, "name": {"title": "Name", "type": "string", "maxLength": 100, "minLength": 1}, "fullScore": {"title": "Full score", "type": "integer", "maximum": 2147483647, "minimum": 0}}}, "SubmissionList": {"required": ["type", "feedback"], "type": "object", "properties": {"pk": {"title": "Submission id", "type": "string", "format": "uuid", "readOnly": true}, "type": {"$ref": "#/definitions/SubmissionTypeList"}, "feedback": {"$ref": "#/definitions/Feedback"}}}, "StudentInfo": {"required": ["user", "exam", "submissions"], "type": "object", "properties": {"pk": {"title": "Student id", "type": "string", "format": "uuid", "readOnly": true}, "name": {"title": "Name", "type": "string", "readOnly": true}, "user": {"title": "User", "type": "string", "format": "uuid"}, "matrikelNo": {"title": "Matrikel no", "type": "string", "readOnly": true}, "exam": {"$ref": "#/definitions/Exam"}, "submissions": {"type": "array", "items": {"$ref": "#/definitions/SubmissionList"}}, "passesExam": {"title": "Passes exam", "type": "boolean"}}}, "SubmissionType": {"title": "Type", "required": ["name", "description", "solution"], "type": "object", "properties": {"pk": {"title": "Submission type id", "type": "string", "format": "uuid", "readOnly": true}, "name": {"title": "Name", "type": "string", "maxLength": 100, "minLength": 1}, "fullScore": {"title": "Full score", "type": "integer", "maximum": 2147483647, "minimum": 0}, "description": {"title": "Description", "type": "string", "minLength": 1}, "solution": {"title": "Solution", "type": "string", "minLength": 1}, "programmingLanguage": {"title": "Programming language", "type": "string", "enum": ["c", "java"]}}}, "VisibleCommentFeedback": {"title": "Feedback", "required": ["ofSubmission"], "type": "object", "properties": {"pk": {"title": "ID", "type": "integer", "readOnly": true}, "ofSubmission": {"title": "Of submission", "type": "string", "format": "uuid"}, "isFinal": {"title": "Is final", "type": "boolean"}, "score": {"title": "Score", "type": "integer", "maximum": 2147483647, "minimum": 0}, "feedbackLines": {"title": "Feedback lines", "type": "string", "readOnly": true}, "created": {"title": "Created", "type": "string", "format": "date-time", "readOnly": true}, "ofSubmissionType": {"title": "Of submission type", "type": "string", "readOnly": true}}}, "Test": {"required": ["name", "label", "annotation"], "type": "object", "properties": {"pk": {"title": "Test id", "type": "string", "format": "uuid", "readOnly": true}, "name": {"title": "Name", "type": "string", "maxLength": 30, "minLength": 1}, "label": {"title": "Label", "type": "string", "maxLength": 50, "minLength": 1}, "annotation": {"title": "Annotation", "type": "string", "minLength": 1}}}, "Submission": {"required": ["type", "feedback", "tests"], "type": "object", "properties": {"pk": {"title": "Submission id", "type": "string", "format": "uuid", "readOnly": true}, "type": {"$ref": "#/definitions/SubmissionType"}, "text": {"title": "Text", "type": "string"}, "feedback": {"$ref": "#/definitions/VisibleCommentFeedback"}, "tests": {"type": "array", "items": {"$ref": "#/definitions/Test"}}}}, "SubmissionNoTextFields": {"required": ["type"], "type": "object", "properties": {"pk": {"title": "Submission id", "type": "string", "format": "uuid", "readOnly": true}, "type": {"title": "Type", "type": "string", "format": "uuid"}, "score": {"title": "Score", "type": "string", "readOnly": true}, "final": {"title": "Final", "type": "string", "readOnly": true}, "fullScore": {"title": "Full score", "type": "string", "readOnly": true}}}, "StudentInfoForListView": {"required": ["submissions", "isActive"], "type": "object", "properties": {"pk": {"title": "Student id", "type": "string", "format": "uuid", "readOnly": true}, "name": {"title": "Name", "type": "string", "readOnly": true}, "user": {"title": "User", "type": "string", "readOnly": true}, "userPk": {"title": "User pk", "type": "string", "readOnly": true}, "exam": {"title": "Exam", "type": "string", "readOnly": true}, "submissions": {"type": "array", "items": {"$ref": "#/definitions/SubmissionNoTextFields"}}, "matrikelNo": {"title": "Matrikel no", "type": "string", "maxLength": 30, "minLength": 1}, "passesExam": {"title": "Passes exam", "type": "boolean"}, "isActive": {"title": "Is active", "type": "boolean"}}}, "SubmissionNoType": {"required": ["type", "feedback", "tests"], "type": "object", "properties": {"pk": {"title": "Submission id", "type": "string", "format": "uuid", "readOnly": true}, "type": {"title": "Type", "type": "string", "format": "uuid"}, "fullScore": {"title": "Full score", "type": "string", "readOnly": true}, "text": {"title": "Text", "type": "string"}, "feedback": {"$ref": "#/definitions/Feedback"}, "tests": {"type": "array", "items": {"$ref": "#/definitions/Test"}}}}, "Subscription": {"type": "object", "properties": {"pk": {"title": "Subscription id", "type": "string", "format": "uuid", "readOnly": true}, "owner": {"title": "Owner", "type": "string", "readOnly": true}, "queryType": {"title": "Query type", "type": "string", "enum": ["random", "student", "exam", "submission_type"], "default": "random"}, "queryKey": {"title": "Query key", "type": "string", "format": "uuid"}, "feedbackStage": {"title": "Feedback stage", "type": "string", "enum": ["feedback-creation", "feedback-validation", "feedback-conflict-resolution"], "default": "feedback-creation"}, "deactivated": {"title": "Deactivated", "type": "boolean", "readOnly": true}, "assignments": {"title": "Assignments", "type": "string", "readOnly": true}, "remaining": {"title": "Remaining", "type": "string", "readOnly": true}, "available": {"title": "Available", "type": "string", "readOnly": true}}}, "Tutor": {"required": ["username"], "type": "object", "properties": {"pk": {"title": "User id", "type": "string", "format": "uuid", "readOnly": true}, "password": {"title": "Password", "type": "string", "minLength": 1}, "isActive": {"title": "Active", "description": "Designates whether this user should be treated as active. Unselect this instead of deleting accounts.", "type": "boolean"}, "username": {"title": "Username", "description": "Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.", "type": "string", "pattern": "^[\\w.@+-]+$", "maxLength": 150, "minLength": 1}, "feedbackCreated": {"title": "Feedback created", "type": "string", "readOnly": true}, "feedbackValidated": {"title": "Feedback validated", "type": "string", "readOnly": true}}}, "UserAccount": {"required": ["password"], "type": "object", "properties": {"pk": {"title": "User id", "type": "string", "format": "uuid", "readOnly": true}, "username": {"title": "Username", "description": "Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.", "type": "string", "readOnly": true, "minLength": 1}, "role": {"title": "Role", "type": "string", "enum": ["Student", "Tutor", "Reviewer"], "readOnly": true}, "isAdmin": {"title": "Is admin", "type": "boolean", "readOnly": true}, "password": {"title": "Password", "type": "string", "maxLength": 128, "minLength": 1}}}}} \ No newline at end of file diff --git a/grady/util/__init__.py b/grady/util/__init__.py deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/grady/util/factories.py b/grady/util/factories.py deleted file mode 100644 index d8dd98da7e94654320f8e7934bbed478dee085b8..0000000000000000000000000000000000000000 --- a/grady/util/factories.py +++ /dev/null @@ -1,525 +0,0 @@ -import configparser -from xkcdpass import xkcd_password as xp - -from core import models -from core.models import (ExamType, Feedback, StudentInfo, Submission, - SubmissionType, UserAccount, Group) - -STUDENTS = 'students' -TUTORS = 'tutors' -REVIEWERS = 'reviewers' - -PASSWORDS = '.importer_passwords' - -words = xp.generate_wordlist(wordfile=xp.locate_wordfile(), min_length=5, max_length=8) - - -def get_random_password(numwords=4): - """ Returns a cryptographically random string of specified length """ - return xp.generate_xkcdpassword(words, numwords=numwords, delimiter='-') - - -def store_password(username, groupname, password): - storage = configparser.ConfigParser() - storage.read(PASSWORDS) - - if groupname not in storage: - storage[groupname] = {} - - storage[groupname][username] = password - - with open(PASSWORDS, 'w') as passwd_file: - storage.write(passwd_file) - - -class GradyUserFactory: - - def __init__(self, - make_password=get_random_password, - password_storge=store_password, - *args, **kwargs): - self.make_password = make_password - self.password_storge = password_storge - - def _get_random_name(self, prefix='', suffix='', k=4): - return ''.join((prefix, self.make_password(k), suffix)) - - def _get_group_for_user_role(self, role): - """ Returns the groupname for a role """ - return { - 'Student': 'students', - 'Tutor': 'tutors', - 'Reviewer': 'reviewers' - }[role] - - def _make_base_user(self, username, role, password=None, - store_pw=False, fullname='', exam=None, exercise_groups=None, **kwargs): - """ This is a specific wrapper for the django update_or_create method of - objects. - * If now username is passed, a generic one will be generated - * A new user is created and password and role are set accordingly - * If the user was there before password IS changed - * A user must only have one role. - - Returns: - (User object, str): The user object that was added to the role and - the password of that user if it was created. - """ - if not username: - username = self._get_random_name(prefix=role.lower() + '_') - - username = username.strip() - - user, created = UserAccount.objects.update_or_create( - username=username, - fullname=fullname, - role=role, - defaults=kwargs) - - if exercise_groups is None: - exercise_groups = [] - - groups_in_db = [] - for group in exercise_groups: - groups_in_db.append(Group.objects.get_or_create(name=group, exam=exam)[0].pk) - - user.set_groups(groups_in_db) - - if created or password is not None: - password = self.make_password() if password is None else password - user.set_password(password) - user.save() - - if created and store_pw: - self.password_storge( - username, - self._get_group_for_user_role(role), - password) - - return user - - def make_student(self, username=None, identifier=None, - exam=None, submissions=None, **kwargs): - """ Creates a student. Defaults can be passed via kwargs like in - relation managers objects.update method. """ - user = self._make_base_user(username, 'Student', exam=exam, **kwargs) - student_info = StudentInfo.objects.get_or_create(user=user)[0] - student_info.add_exam(exam) - if identifier: - student_info.matrikel_no = identifier - student_info.save() - return user - - def make_tutor(self, username=None, exam=None, **kwargs): - """ Creates or updates a tutor if needed with defaults """ - return self._make_base_user(username, 'Tutor', exam=exam, **kwargs) - - def make_reviewer(self, username=None, exam=None, **kwargs): - """ Creates or updates a reviewer if needed with defaults """ - return self._make_base_user(username, 'Reviewer', exam=exam, **kwargs) - - -def make_exams(exams=None, **kwargs): - if exams is None: - exams = [] - - return [ExamType.objects.get_or_create( - module_reference=exam['module_reference'], - defaults=exam)[0] for exam in exams] - - -def make_groups(groups=None, **kwargs): - if groups is None: - groups = [] - - return [Group.objects.get_or_create( - name=group['name'], - exam=group['exam'])[0] for group in groups] - - -def make_submission_types(type_id=None, submission_types=[], **kwargs): - return [SubmissionType.objects.get_or_create( - name=submission_type['name'], exam_type=type_id, - defaults=submission_type)[0] - for submission_type in submission_types] - - -def make_students(students=None, **kwargs): - if students is None: - students = [] - - return [GradyUserFactory().make_student( - username=student['username'], - exam=ExamType.objects.get( - module_reference=student['exam']) if 'exam' in student else None, - password=student.get('password'), - exercise_groups=student.get('exercise_groups') - ) for student in students] - - -def make_tutors(tutors=None, **kwargs): - if tutors is None: - tutors = [] - - return [GradyUserFactory().make_tutor(**tutor) - for tutor in tutors] - - -def make_reviewers(reviewers=None, **kwargs): - if reviewers is None: - reviewers = [] - - return [GradyUserFactory().make_reviewer(**reviewer) - for reviewer in reviewers] - - -def make_feedback(feedback, submission_object): - feedback_obj = Feedback.objects.update_or_create( - of_submission=submission_object, - score=feedback['score'], - is_final=feedback.get('is_final', False) - )[0] - for line_index, comment_list in feedback['feedback_lines'].items(): - for comment in comment_list: - tutor = models.UserAccount.objects.get( - username=comment.pop('of_tutor')) - ret, c = models.FeedbackComment.objects.update_or_create( - of_line=line_index, - of_feedback=feedback_obj, - of_tutor=tutor, - defaults=comment - ) - - -def make_submissions(type_id=None, submissions=[], **kwargs): - submission_objects = [] - for submission in submissions: - submission_type, _ = SubmissionType.objects.get_or_create( - name=submission.get('type', 'Auto generated type'), exam_type=type_id) - student, _ = StudentInfo.objects.get_or_create( - user=UserAccount.objects.get( - username=submission.get('user', 'default_user'))) - submission_object, _ = Submission.objects.get_or_create( - type=submission_type, student=student, defaults={ - 'seen_by_student': submission.get('seen_by_student', False), - 'text': submission.get('text', ''), - }) - if 'feedback' in submission: - make_feedback(submission['feedback'], submission_object) - submission_objects.append(submission_object) - return submission_objects - - -def make_test_data(data_dict): - type_id = (make_exams(**data_dict))[0].exam_type_id - return { - 'exams': make_exams(**data_dict), - 'submission_types': make_submission_types(type_id, **data_dict), - 'students': make_students(**data_dict), - 'tutors': make_tutors(**data_dict), - 'reviewers': make_reviewers(**data_dict), - 'submissions': make_submissions(type_id, **data_dict) - } - - -def init_test_instance(): - return make_test_data( - data_dict={ - 'exams': [{ - 'module_reference': 'Test Exam 01', - 'total_score': 100, - 'pass_score': 60, - }], - 'submission_types': [ - { - 'name': '01. Sort this or that', - 'full_score': 35, - 'description': 'Very complicated', - 'solution': 'Trivial!' - }, - { - 'name': '02. Merge this or that or maybe even this', - 'full_score': 35, - 'description': 'Very complicated', - 'solution': 'Trivial!' - }, - { - 'name': '03. This one exists for the sole purpose to test', - 'full_score': 30, - 'description': 'Very complicated', - 'solution': 'Trivial!' - } - ], - 'students': [ - { - 'username': 'student01', - 'exam': 'Test Exam 01', - 'password': 'p' - }, - { - 'username': 'student02', - 'exam': 'Test Exam 01', - 'password': 'p' - }, - { - 'username': 'student03', - 'exam': 'Test Exam 01', - 'password': 'p' - }, - { - 'username': 'student04', - 'exam': 'Test Exam 01', - 'password': 'p' - }, - { - 'username': 'student05', - 'exam': 'Test Exam 01', - 'password': 'p' - }, - { - 'username': 'student06', - 'exam': 'Test Exam 01', - 'password': 'p' - }, - { - 'username': 'student07', - 'exam': 'Test Exam 01', - 'password': 'p' - }, - ], - 'tutors': [ - { - 'username': 'tutor01', - 'password': 'p' - }, - { - 'username': 'tutor02', - 'password': 'p' - } - ], - 'reviewers': [{ - 'username': 'reviewer01', - 'password': 'p' - }], - 'submissions': [ - { - 'text': 'function blabl\n' - ' on multi lines\n' - ' for blabla in bla:\n' - ' arrrgh\n' - ' asasxasx\n' - ' lorem ipsum und so\n', - 'type': '01. Sort this or that', - 'user': 'student01', - 'feedback': { - 'score': 5, - 'is_final': True, - 'feedback_lines': { - '1': [ - { - 'text': 'This is very bad!', - 'of_tutor': 'tutor01' - }, - { - 'text': 'I agree', - 'of_tutor': 'tutor02' - } - ], - '3': [ - { - 'text': 'Even worse!', - 'of_tutor': 'tutor02' - } - ] - } - } - }, - { - 'text': 'function blabl\n' - ' on multi lines\n' - ' for blabla in bla:\n' - ' arrrgh\n' - ' asasxasx\n' - ' lorem ipsum und so\n', - 'type': '02. Merge this or that or maybe even this', - 'user': 'student01', - 'feedback': { - 'score': 5, - 'is_final': True, - 'feedback_lines': { - '1': [ - { - 'text': 'This is very bad!', - 'of_tutor': 'tutor01' - }, - { - 'text': 'I agree', - 'of_tutor': 'tutor02' - } - ], - '3': [ - { - 'text': 'Even worse!', - 'of_tutor': 'tutor02' - } - ] - } - } - }, - { - 'text': 'function blabl\n' - ' on multi lines\n' - ' for blabla in bla:\n' - ' arrrgh\n' - ' asasxasx\n' - ' lorem ipsum und so\n', - 'type': '03. This one exists for the sole purpose to test', - 'user': 'student01', - 'feedback': { - 'score': 5, - 'is_final': True, - 'feedback_lines': { - '1': [ - { - 'text': 'This is very bad!', - 'of_tutor': 'tutor01' - }, - { - 'text': 'I agree', - 'of_tutor': 'tutor02' - } - ], - '3': [ - { - 'text': 'Even worse!', - 'of_tutor': 'tutor02' - } - ] - } - } - }, - - { - 'text': 'function blabl\n' - ' on multi lines\n' - ' for blabla in bla:\n' - ' arrrgh\n' - ' asasxasx\n' - ' lorem ipsum und so\n', - 'type': '01. Sort this or that', - 'user': 'student02', - }, - { - 'text': 'function blabl\n' - ' on multi lines\n' - ' for blabla in bla:\n' - ' arrrgh\n' - ' asasxasx\n' - ' lorem ipsum und so\n', - 'type': '02. Merge this or that or maybe even this', - 'user': 'student02', - }, - { - 'text': 'function blabl\n' - ' on multi lines\n' - ' for blabla in bla:\n' - ' arrrgh\n' - ' asasxasx\n' - ' lorem ipsum und so\n', - 'type': '03. This one exists for the sole purpose to test', - 'user': 'student02', - }, - { - 'text': 'function blabl\n' - ' on multi lines\n' - ' for blabla in bla:\n' - ' arrrgh\n' - ' asasxasx\n' - ' lorem ipsum und so\n', - 'type': '01. Sort this or that', - 'user': 'student03', - }, - { - 'text': 'function blabl\n' - ' on multi lines\n' - ' for blabla in bla:\n' - ' arrrgh\n' - ' asasxasx\n' - ' lorem ipsum und so\n', - 'type': '02. Merge this or that or maybe even this', - 'user': 'student03', - }, - { - 'text': 'function blabl\n' - ' on multi lines\n' - ' for blabla in bla:\n' - ' arrrgh\n' - ' asasxasx\n' - ' lorem ipsum und so\n', - 'type': '03. This one exists for the sole purpose to test', - 'user': 'student03', - }, - - { - 'text': 'function blabl\n' - ' on multi lines\n' - ' for blabla in bla:\n' - ' arrrgh\n' - ' asasxasx\n' - ' lorem ipsum und so\n', - 'type': '01. Sort this or that', - 'user': 'student04', - }, - { - 'text': 'function blabl\n' - ' on multi lines\n' - ' for blabla in bla:\n' - ' arrrgh\n' - ' asasxasx\n' - ' lorem ipsum und so\n', - 'type': '02. Merge this or that or maybe even this', - 'user': 'student04', - }, - { - 'text': 'function blabl\n' - ' on multi lines\n' - ' for blabla in bla:\n' - ' arrrgh\n' - ' asasxasx\n' - ' lorem ipsum und so\n', - 'type': '03. This one exists for the sole purpose to test', - 'user': 'student04', - }, - - { - 'text': 'function blabl\n' - ' on multi lines\n' - ' for blabla in bla:\n' - ' arrrgh\n' - ' asasxasx\n' - ' lorem ipsum und so\n', - 'type': '01. Sort this or that', - 'user': 'student05', - }, - { - 'text': 'function blabl\n' - ' on multi lines\n' - ' for blabla in bla:\n' - ' arrrgh\n' - ' asasxasx\n' - ' lorem ipsum und so\n', - 'type': '02. Merge this or that or maybe even this', - 'user': 'student05', - }, - { - 'text': 'function blabl\n' - ' on multi lines\n' - ' for blabla in bla:\n' - ' arrrgh\n' - ' asasxasx\n' - ' lorem ipsum und so\n', - 'type': '03. This one exists for the sole purpose to test', - 'user': 'student05', - }, - ]} - ) diff --git a/grady/util/factory_boys.py b/grady/util/factory_boys.py deleted file mode 100644 index 75faa8ae8930a3aa5e693eab4e690dcf9d7db27a..0000000000000000000000000000000000000000 --- a/grady/util/factory_boys.py +++ /dev/null @@ -1,115 +0,0 @@ -import factory -from factory.django import DjangoModelFactory -from faker import Faker -from core import models - -Faker.seed(42) -fake = Faker() - - -class ExamTypeFactory(DjangoModelFactory): - class Meta: - model = models.ExamType - django_get_or_create = ('module_reference',) - - module_reference = 'B.Inf.4242 Test Module' - total_score = 90 - pass_score = 45 - pass_only = False - - -class SubmissionTypeFactory(DjangoModelFactory): - class Meta: - model = models.SubmissionType - name = factory.Sequence(lambda n: f"[{n}] Example submission type") - full_score = 15 - description = factory.Sequence( - lambda n: f'Type {n} \n<h1>This</h1> is a description containing html') - solution = factory.Sequence(lambda n: f'//This is a solution\n#include<stdio.h>\n\nint main() {{\n\tprintf("Hello World\\n");\n\treturn {n};\n}}') # noqa - programming_language = models.SubmissionType.C - exam_type = factory.SubFactory(ExamTypeFactory) - - -class GroupFactory(DjangoModelFactory): - class Meta: - model = models.Group - name = factory.Sequence(lambda n: f"Group [{n}]") - exam = factory.SubFactory(ExamTypeFactory) - - -class UserAccountFactory(DjangoModelFactory): - class Meta: - model = models.UserAccount - django_get_or_create = ('username',) - - role = models.UserAccount.TUTOR - fullname = fake.name - username = factory.Sequence(lambda n: f"{fake.user_name()}-{n}") - password = factory.PostGenerationMethodCall('set_password', 'redrum-is-murder-reversed') - - @factory.post_generation - def exercise_groups(self, create, extracted, **kwargs): - name = "Default Group: " - default_group, _ = models.Group.objects.get_or_create(name=name) - self.exercise_groups.add(default_group) - - -class ExamInfoFactory(DjangoModelFactory): - class Meta: - model = models.ExamInfo - - exam = factory.SubFactory(ExamTypeFactory) - total_score = 90 - passes_exam = True - - -class StudentInfoFactory(DjangoModelFactory): - class Meta: - model = models.StudentInfo - - student_info = factory.RelatedFactory( - ExamInfoFactory, - factory_related_name='student', - ) - user = factory.SubFactory(UserAccountFactory, role=models.UserAccount.STUDENT) - - -class TestFactory(DjangoModelFactory): - class Meta: - model = models.Test - - name = 'EmptyTest' - label = 'Empty' - annotation = factory.Sequence(lambda n: f'Test: {n} This is an annotation') - - -class SubmissionFactory(DjangoModelFactory): - class Meta: - model = models.Submission - - text = factory.Sequence(lambda n: f'#include<stdio.h>\n\nint main() {{\n\tprintf("Hello World\\n");\n\treturn {n};\n}}') # noqa - type = factory.SubFactory(SubmissionTypeFactory) - student = factory.SubFactory(StudentInfoFactory) - - -class FeedbackFactory(DjangoModelFactory): - class Meta: - model = models.Feedback - - of_submission = factory.SubFactory(SubmissionTypeFactory) - - -class FeedbackCommentFactory(DjangoModelFactory): - class Meta: - model = models.FeedbackComment - - text = 'Well, this is bad...' - of_tutor = factory.SubFactory(UserAccountFactory) - of_feedback = factory.SubFactory(FeedbackFactory) - - -class TutorSubmissionAssignmentFactory(DjangoModelFactory): - class Meta: - model = models.TutorSubmissionAssignment - - submission = factory.SubFactory(SubmissionFactory) diff --git a/grady/util/format_index.py b/grady/util/format_index.py deleted file mode 100644 index e6ef6a5fc1bca6f43f0192f591ee3cf32396d40b..0000000000000000000000000000000000000000 --- a/grady/util/format_index.py +++ /dev/null @@ -1,16 +0,0 @@ -import fileinput -import sys -import re - -file = 'core/templates/index.html' - -STATIC_FILES_REGEX = re.compile("=/static/(.*?)([ >])") -SUB_PATTERN = r"={% static '\1' %}\2" - -with open(file, "r+") as f: - s = f.read() - f.seek(0) - f.write("{% load static %}\n" + s) - -for line in fileinput.input(file, inplace=1): - sys.stdout.write(STATIC_FILES_REGEX.sub(SUB_PATTERN, line)) diff --git a/grady/util/importer.py b/grady/util/importer.py deleted file mode 100644 index 04b474faf5dc9addcba1c4e232081f5b270e9f66..0000000000000000000000000000000000000000 --- a/grady/util/importer.py +++ /dev/null @@ -1,225 +0,0 @@ -import json -import os -import readline -import logging -import constance - -from rest_framework.exceptions import ValidationError -from util.messages import warn -from core.models import ExamType, Feedback, Submission, SubmissionType, Test, FeedbackLabel -from core.models import UserAccount as User -from util.factories import GradyUserFactory - -import xkcdpass.xkcd_password as xp -import semver - -log = logging.getLogger(__name__) -config = constance.config - -WELCOME = r''' - ______ __ ____ __ - / ____/________ _____/ /_ __ / _/___ ___ ____ ____ _____/ /____ _____ - / / __/ ___/ __ `/ __ / / / / / // __ `__ \/ __ \/ __ \/ ___/ __/ _ \/ ___/ -/ /_/ / / / /_/ / /_/ / /_/ / _/ // / / / / / /_/ / /_/ / / / /_/ __/ / -\____/_/ \__,_/\__,_/\__, / /___/_/ /_/ /_/ .___/\____/_/ \__/\___/_/ - /____/ /_/ -''' - -HISTFILE = '.importer_history' -PASSWORDS = '.importer_passwords' - -YES = 'Y/n' -NO = 'y/N' - -RUSTY_HEKTOR_MIN_VER = ">=6.0.0" -RUSTY_HEKTOR_MAX_VER = "<7.0.0" - -valid = {"yes": True, "y": True, "ye": True, "no": False, "n": False} - -user_factory = GradyUserFactory() -words = xp.generate_wordlist(wordfile=xp.locate_wordfile(), min_length=5, max_length=8) - - -def start(): - - if os.path.exists(HISTFILE): - readline.read_history_file(HISTFILE) - - print(WELCOME + ''' - - Welcome to the Grady import script! - - This script aims at making the setup of the database as easy as possible. - At the same time it serves as a documentation on how data is imported into - Grady. Let\'s dive right in.\n''') - - try: - print('The following sub importers are available:\n') - for fid, func in enumerate(call_order): - print(f'\t[{fid}] {func.__name__}') - print('\t[q] exit') - print() - - fid = i('Choose a number or hit enter to start at the beginning') - - if not fid: - for func in call_order: - func() - elif fid in ('q', 'quit', 'exit'): - return - elif not 0 <= int(fid) < len(call_order): - warn('There is no loader with this number') - else: - call_order[int(fid)]() - - except (EOFError, KeyboardInterrupt): - print() - return - except FileNotFoundError: - raise - except Exception: - import traceback - traceback.print_exc() - finally: - readline.write_history_file(HISTFILE) - - -def i(prompt: str, default: str = '', is_path: bool = False, is_file: bool = False): - if default is YES or default is NO: - answer = valid[input(f'[Q] {prompt} ({default}): ').lower() or ( - 'y' if YES == default else 'n')] - elif default: - answer = input(f'[Q] {prompt} ({default}): ') or default - else: - answer = input(f'[Q] {prompt}: ') - - if (is_path or is_file) and \ - not os.path.exists(answer) or is_file and \ - not os.path.isfile(answer): - path_or_type = "path" if is_path else "file" - warn(f'The {path_or_type} does not exist. Please try again.') - return i(prompt, default, is_path, is_file) - - return answer - - -def load_hektor_json(): - file = i('Get me the file with the output from rusty-hektor', - 'submissions.json', is_file=True) - - with open(file, 'r') as f: - hektor_data = json.JSONDecoder().decode(f.read()) - - parse_and_import_hektor_json(hektor_data) - - -def parse_and_import_hektor_json(hektor_data): - hektor_version = hektor_data['meta']['version'] - if not (semver.match(hektor_version, RUSTY_HEKTOR_MIN_VER) and - semver.match(hektor_version, RUSTY_HEKTOR_MAX_VER)): - raise ValidationError( - f'The data you\'re trying to import has the wrong version {hektor_version}\n' - f'Requirements: {RUSTY_HEKTOR_MIN_VER}, {RUSTY_HEKTOR_MAX_VER}' - ) - - exam_data = hektor_data['data'] - - exam, _ = ExamType.objects.get_or_create(**exam_data['module']) - - for submission_type in exam_data['submission_types']: - _, created = SubmissionType.objects.update_or_create( - name=submission_type['name'], exam_type=exam, defaults=submission_type) - if not created: - raise ValidationError(f"Updated submission type: {submission_type['name']}") - - for student in exam_data['students']: - # student accounts will be automatically enabled when in exercise mode - student_obj = user_factory.make_student(exam=exam, is_active=config.EXERCISE_MODE, - **student).student - for submission_obj in student['submissions']: - add_submission(student_obj, **submission_obj) - - -def load_reviewers(): - print('Please import reviewer users by providing one name per line') - reviewers = i('List of reviewers', 'reviewers', is_file=True) - - with open(reviewers) as reviewers_f: - for reviewer in reviewers_f: - rev = reviewer.strip() - if len(rev) > 0: - user_factory.make_reviewer(rev, - is_staff=True, - store_pw=True) - - -def set_registration_password(): - pw = xp.generate_xkcdpassword(words, numwords=4, delimiter='-') - setattr(config, 'REGISTRATION_PASSWORD', pw) - print('The password will be set to', pw) - - -def add_submission(student_obj, code, tests, type=None, source_code=None): - submission_type_obj = SubmissionType.objects.get(name=type) - - submission_obj, _ = Submission.objects.update_or_create( - type=submission_type_obj, - student=student_obj, - defaults={ - 'text': code, - 'source_code': source_code, - 'source_code_available': source_code is not None - } - ) - - if tests: - add_tests(submission_obj, tests) - - -def add_tests(submission_obj, tests): - auto_correct, _ = User.objects.get_or_create( - username='auto_correct', - defaults={'is_active': False} - ) - - for test_data in tests: - test_obj, created = Test.objects.update_or_create( - name=test_data['name'], - submission=submission_obj, - defaults={ - 'label': test_data['label'], - 'annotation': test_data['annotation'], - } - ) - add_feedback_if_test_recommends_it(test_obj) - add_label_to_feedback_if_test_recommends_it(test_obj) - - -def add_feedback_if_test_recommends_it(test_obj): - # TODO rework this brittle code - if (test_obj.label == 'EMPTY' or test_obj.label == 'COMPILATION_FAILED') \ - and not hasattr(test_obj.submission, 'feedback'): - return Feedback.objects.update_or_create( - of_submission=test_obj.submission, - defaults={ - 'score': 0, - 'is_final': True, - } - ) - - -def add_label_to_feedback_if_test_recommends_it(test_obj): - if (test_obj.label == 'EMPTY' or test_obj.label == 'COMPILATION_FAILED') \ - and hasattr(test_obj.submission, 'feedback'): - feedback = test_obj.submission.feedback - label, _ = FeedbackLabel.objects.get_or_create( - name=test_obj.label, - defaults={'description': test_obj.label}) - feedback.labels.add(label) - - -call_order = [ - load_hektor_json, - load_reviewers, - set_registration_password, -] diff --git a/grady/util/messages.py b/grady/util/messages.py deleted file mode 100644 index 7f1aeac441028341a09f0d688e62ce55d32e892a..0000000000000000000000000000000000000000 --- a/grady/util/messages.py +++ /dev/null @@ -1,26 +0,0 @@ -import sys - - -def warn(*message): - print('[W]', *message) - - -def debug(*message): - print('[DEBUG]', *message) - - -def info(*message): - print('[I]', *message) - - -def error(*message): - print('[E]', *message) - - -def abort(*message): - print('[FATAL]', *message) - sys.exit('exiting...') - - -def exit(message='exiting...'): - sys.exit(*message) diff --git a/grady/yarn.lock b/grady/yarn.lock deleted file mode 100644 index fb57ccd13afbd082ad82051c2ffebef4840661ec..0000000000000000000000000000000000000000 --- a/grady/yarn.lock +++ /dev/null @@ -1,4 +0,0 @@ -# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. -# yarn lockfile v1 - -