diff --git a/.dockerignore b/.dockerignore deleted file mode 100644 index 9dc5e4a..0000000 --- a/.dockerignore +++ /dev/null @@ -1,18 +0,0 @@ -# Logs -logs -*.log - -# Runtime data -pids -*.pid -*.seed - -# Coverage directory used by tools like istanbul -coverage - -# Documentation directory -docs - -# Common garbage -node_modules -npm-debug.log diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml deleted file mode 100644 index 61d5373..0000000 --- a/.github/workflows/continuous-integration.yml +++ /dev/null @@ -1,80 +0,0 @@ -name: Source Code CI/CD - -on: - push: - branches: - - master - pull_request: - branches: - - master -env: - ACTIONS_ALLOW_UNSECURE_COMMANDS: true -jobs: - ci: - runs-on: ubuntu-latest - container: - image: node:12-alpine - services: -# More explanation about that here : -# https://github.com/actions/example-services/blob/master/.github/workflows/postgres-service.yml - postgres: - image: postgres:12-alpine - env: - POSTGRES_USER: postgres - POSTGRES_PASSWORD: jy95 - POSTGRES_DB: sourcecode - ports: ["5432:5432"] - options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5 - env: - POSTGRES_USER: postgres - POSTGRES_PASSWORD: jy95 - POSTGRES_DB: sourcecode - # use postgres for the host here because we have specified a container for the job. - # If we were running the job on the VM this would be localhost - POSTGRES_HOST: postgres - # To specify the schema we want to use - DATABASE_SCHEMA: exercises_library - steps: - - uses: actions/checkout@v2 - - name: Set DB Port - env: - POSTGRES_PORT: ${{ job.services.postgres.ports[5432] }} - run: | - echo "::set-env name=POSTGRES_PORT::$POSTGRES_PORT" - - name: Install - run: | - npm install -g npm@latest - npm ci - - name: Tests - env: - DATABASE_URL: 'postgresql://${{ env.POSTGRES_USER }}:${{ env.POSTGRES_PASSWORD }}@${{ env.POSTGRES_HOST }}:${{env.POSTGRES_PORT}}/${{env.POSTGRES_DB}}' - run: | - npm test - - name: Upload report to Codecov - run: | - apk add curl - apk add bash - curl -s https://codecov.io/bash > .codecov - chmod +x .codecov - ./.codecov -t ${{ secrets.CODECOV_TOKEN }} - cd: - runs-on: ubuntu-latest - needs: ci - - steps: - - uses: actions/checkout@v2 - - name: Docker login - run: docker login -u ${{ secrets.DOCKER_USER }} -p ${{ secrets.DOCKER_PASSWORD }} - - name: Build - run: docker build -t sourcecode_api . - - name: Tags - run: | - docker tag sourcecode_api ${{ secrets.DOCKER_USER }}/sourcecode_api:${{ github.sha }} - docker tag sourcecode_api ${{ secrets.DOCKER_USER }}/sourcecode_api:latest - - name: Push version - run: | - docker push ${{ secrets.DOCKER_USER }}/sourcecode_api:${{ github.sha }} - - name: Push release ( only on master ) - if: github.ref == 'refs/heads/master' - run: | - docker push ${{ secrets.DOCKER_USER }}/sourcecode_api:latest diff --git a/.github/workflows/documentation-changes.yml b/.github/workflows/documentation-changes.yml deleted file mode 100644 index 375f92a..0000000 --- a/.github/workflows/documentation-changes.yml +++ /dev/null @@ -1,102 +0,0 @@ -name: Source Code API Breaking Changes -# Everyone is happy with breaking changes ^^ -on: - pull_request: -env: - ACTIONS_ALLOW_UNSECURE_COMMANDS: true -jobs: - build-oas-artefacts: - runs-on: ubuntu-latest - steps: - - uses: actions/setup-node@v1 - with: - node-version: '12.x' - - name: Install required tools - run: | - npm install speccy -g - npm install -g @openapitools/openapi-generator-cli@1.0.10-4.2.3 - - name: Set up env variables - run: | - echo "::set-env name=CURRENT_BRANCH::$(echo ${{ github.head_ref }} | sed 's|.*/||')" - echo "::set-env name=TARGET_BRANCH::$(echo ${{ github.base_ref }} | sed 's|.*/||')" - - name: Clone repository in branch ${{ env.TARGET_BRANCH }} - uses: actions/checkout@v2 - with: - path: 'A' - ref: ${{ github.base_ref }} - - name: Clone repository in branch ${{ env.CURRENT_BRANCH }} - uses: actions/checkout@v2 - with: - path: 'B' - - name: Check if OAS from ${{ env.CURRENT_BRANCH }} is valid - run: | - npx openapi-generator validate -i B/api.yml - - name: Check if OAS from ${{ env.TARGET_BRANCH }} is valid - run: | - npx openapi-generator validate -i A/api.yml - - name: Build OAS specifications - run: | - npx speccy resolve A/api.yml -o original-spec.yaml - npx speccy resolve B/api.yml -o modified-spec.yaml - - name: Upload single OAS file from ${{ env.TARGET_BRANCH }} - uses: actions/upload-artifact@v1 - with: - name: original-spec.yaml - path: original-spec.yaml - - name: Upload single OAS file from ${{ env.CURRENT_BRANCH }} - uses: actions/upload-artifact@v1 - with: - name: modified-spec.yaml - path: modified-spec.yaml - build-report: - needs: build-oas-artefacts - runs-on: ubuntu-latest - steps: - - uses: actions/setup-node@v1 - with: - node-version: '13.x' - - name: Install required tools - run: | - npm install openapi-diff -g - - name: Download OAS file from SOURCE branch - uses: actions/download-artifact@v1 - with: - name: original-spec.yaml - path: specs/ - - name: Download OAS file from TARGET branch - uses: actions/download-artifact@v1 - with: - name: modified-spec.yaml - path: specs/ - - name: Set up env variables - run: | - echo "::set-env name=ORIGIN_SPEC::$(echo "$(pwd)/specs/original-spec.yaml" )" - echo "::set-env name=MODIFIED_SPEC::$(echo "$(pwd)/specs/modified-spec.yaml" )" - echo "::set-env name=SPECS_LOG::$(echo "$(pwd)/breaking-changes.log" )" - echo "::set-env name=JSON_DIFF_FILE::$(echo "$(pwd)/breaking-changes.json" )" - echo "::set-env name=GH_COMMENT_FILE::$(echo "$(pwd)/Github-comment.md" )" -# See : https://github.com/actions/download-artifact/issues/14 - - name: Restore permissions - run: | - chmod -R 777 ${{ env.ORIGIN_SPEC }} - chmod -R 777 ${{ env.MODIFIED_SPEC }} - - name: Generate report - run: | - openapi-diff ${{ env.ORIGIN_SPEC }} ${{ env.MODIFIED_SPEC }} | tee ${{ env.SPECS_LOG }} - sed -n '1!p' ${{ env.SPECS_LOG }} > ${{ env.JSON_DIFF_FILE }} - - uses: actions/upload-artifact@v1 - with: - name: openapi-diff.json - path: breaking-changes.json - - name: Prepare comment on Github PR - run: | - sed -n '1p' ${{ env.SPECS_LOG }} >> ${{ env.GH_COMMENT_FILE }} - printf "\n\n\`\`\`yaml\n" >> ${{ env.GH_COMMENT_FILE }} - sed -n '1!p' ${{ env.SPECS_LOG }} >> ${{ env.GH_COMMENT_FILE }} - printf "\n\`\`\`\n" >> ${{ env.GH_COMMENT_FILE }} - - name: comment PR - uses: machine-learning-apps/pr-comment@master - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - path: Github-comment.md diff --git a/.github/workflows/oas-documentation.yml b/.github/workflows/oas-documentation.yml deleted file mode 100644 index 22d24aa..0000000 --- a/.github/workflows/oas-documentation.yml +++ /dev/null @@ -1,41 +0,0 @@ -name: OAS Documentation - -on: - push: - -jobs: - validate-oas-spec: - runs-on: ubuntu-18.04 - steps: - - uses: actions/checkout@v2 - - name: Use Node.js - uses: actions/setup-node@v1 - with: - node-version: '12.x' - - name: Set up - run: | - npm install -g @openapitools/openapi-generator-cli@1.0.10-4.2.3 - - name: Validate OpenAPI documentation - run: | - npx openapi-generator validate -i api.yml - deploy-oas-spec: - runs-on: ubuntu-18.04 - if: github.ref == 'refs/heads/master' - needs: validate-oas-spec - steps: - - uses: actions/checkout@v2 - - name: Use Node.js - uses: actions/setup-node@v1 - with: - node-version: '12.x' - - name: Set up - run: | - npm install -g redoc-cli - - name: Generate documentation - run: | - npx redoc-cli bundle api.yml -o docs/index.html - - name: Deploy - uses: peaceiris/actions-gh-pages@v3 - with: - github_token: ${{ secrets.GITHUB_TOKEN }} - publish_dir: ./docs diff --git a/.gitignore b/.gitignore deleted file mode 100644 index 814f80a..0000000 --- a/.gitignore +++ /dev/null @@ -1,191 +0,0 @@ - -# Created by https://www.gitignore.io/api/node,intellij -# Edit at https://www.gitignore.io/?templates=node,intellij - -### Intellij ### -# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm -# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 - -# User-specific stuff -.idea/**/workspace.xml -.idea/**/tasks.xml -.idea/**/usage.statistics.xml -.idea/**/dictionaries -.idea/**/shelf - -# Generated files -.idea/**/contentModel.xml - -# Sensitive or high-churn files -.idea/**/dataSources/ -.idea/**/dataSources.ids -.idea/**/dataSources.local.xml -.idea/**/sqlDataSources.xml -.idea/**/dynamic.xml -.idea/**/uiDesigner.xml -.idea/**/dbnavigator.xml - -# Gradle -.idea/**/gradle.xml -.idea/**/libraries - -# Gradle and Maven with auto-import -# When using Gradle or Maven with auto-import, you should exclude module files, -# since they will be recreated, and may cause churn. Uncomment if using -# auto-import. -# .idea/modules.xml -# .idea/*.iml -# .idea/modules -# *.iml -# *.ipr - -# CMake -cmake-build-*/ - -# Mongo Explorer plugin -.idea/**/mongoSettings.xml - -# File-based project format -*.iws - -# IntelliJ -out/ - -# mpeltonen/sbt-idea plugin -.idea_modules/ - -# JIRA plugin -atlassian-ide-plugin.xml - -# Cursive Clojure plugin -.idea/replstate.xml - -# Crashlytics plugin (for Android Studio and IntelliJ) -com_crashlytics_export_strings.xml -crashlytics.properties -crashlytics-build.properties -fabric.properties - -# Editor-based Rest Client -.idea/httpRequests - -# Android studio 3.1+ serialized cache file -.idea/caches/build_file_checksums.ser - -### Intellij Patch ### -# Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721 - -# *.iml -# modules.xml -# .idea/misc.xml -# *.ipr - -# Sonarlint plugin -.idea/**/sonarlint/ - -# SonarQube Plugin -.idea/**/sonarIssues.xml - -# Markdown Navigator plugin -.idea/**/markdown-navigator.xml -.idea/**/markdown-navigator/ - -### Node ### -# Logs -logs -*.log -npm-debug.log* -yarn-debug.log* -yarn-error.log* -lerna-debug.log* - -# Diagnostic reports (https://nodejs.org/api/report.html) -report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json - -# Runtime data -pids -*.pid -*.seed -*.pid.lock - -# Directory for instrumented libs generated by jscoverage/JSCover -lib-cov - -# Coverage directory used by tools like istanbul -coverage -*.lcov - -# nyc test coverage -.nyc_output - -# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) -.grunt - -# Bower dependency directory (https://bower.io/) -bower_components - -# node-waf configuration -.lock-wscript - -# Compiled binary addons (https://nodejs.org/api/addons.html) -build/Release - -# Dependency directories -node_modules/ -jspm_packages/ - -# TypeScript v1 declaration files -typings/ - -# TypeScript cache -*.tsbuildinfo - -# Optional npm cache directory -.npm - -# Optional eslint cache -.eslintcache - -# Optional REPL history -.node_repl_history - -# Output of 'npm pack' -*.tgz - -# Yarn Integrity file -.yarn-integrity - -# dotenv environment variables file -.env -.env.test - -# parcel-bundler cache (https://parceljs.org/) -.cache - -# next.js build output -.next - -# nuxt.js build output -.nuxt - -# react / gatsby -public/ - -# vuepress build output -.vuepress/dist - -# Serverless directories -.serverless/ - -# FuseBox cache -.fusebox/ - -# DynamoDB Local files -.dynamodb/ - -# End of https://www.gitignore.io/api/node,intellij -.idea/ - -# file uploads -uploads/ -files/ \ No newline at end of file diff --git a/.nojekyll b/.nojekyll new file mode 100644 index 0000000..e69de29 diff --git a/.npmignore b/.npmignore deleted file mode 100644 index bb778f7..0000000 --- a/.npmignore +++ /dev/null @@ -1,7 +0,0 @@ -# Not useful folder for API -cli/ -coverage/ -docs/ -uploads/ -files/ -.idea \ No newline at end of file diff --git a/.sequelizerc b/.sequelizerc deleted file mode 100644 index 2071813..0000000 --- a/.sequelizerc +++ /dev/null @@ -1,8 +0,0 @@ -const path = require('path'); - -module.exports = { - 'config': path.resolve('config', 'config.js'), - 'models-path': path.resolve('./models'), - 'seeders-path': path.resolve('./seeders'), - 'migrations-path': path.resolve('./migrations') -} diff --git a/Dockerfile b/Dockerfile deleted file mode 100644 index 0604127..0000000 --- a/Dockerfile +++ /dev/null @@ -1,68 +0,0 @@ -FROM node:12-alpine - -# Create app directory -WORKDIR /api - -# Install app dependencies -# A wildcard is used to ensure both package.json AND package-lock.json are copied -# where available (npm@5+) -COPY package*.json ./ - -# RUN npm install -# If you are building your code for production -RUN npm ci --only=production - -# Bundle app source -COPY . . - -# Removes unnecessary files/folders in node modules -# Files -RUN find "$(pwd)/node_modules" -type f \( \ - -name "*.ts" -o \ - -name "*.md" -o \ - -name "*.swp" -o \ - -name "*.tgz" -o \ - -name ".npm*" -o \ - -name "LICENSE" -o \ - -name "AUTHORS" -o \ - -name "CONTRIBUTORS" -o \ - -name "CHANGES" -o \ - -name ".DS_Store" -o \ - -name ".babelrc" -o \ - -name "jest.config.js" -o \ - -name "tslint.json" -o \ - -name "eslint" -o \ - -name ".eslintrc.js" -o \ - -name ".eslintrc.json" -o \ - -name ".eslintrc.yml" -o \ - -name ".prettierrc*" -o \ - -name ".travis.yml" -o \ - -name ".gitlab-ci.yml" -o \ - -name "appveyor.yml" -o \ - -name ".coveralls.yml" \ -\) -exec rm -f {} \; - -# Folders -RUN find "$(pwd)/node_modules" -type d \( \ - -name "docs" -o \ - -name "doc" -o \ - -name "tests" -o \ - -name "test" -o \ - -name "__tests__" -o \ - -name "example" -o \ - -name "examples" -o \ - -name ".nyc_output" -o \ - -name ".idea" -o \ - -name ".vscode" -o \ - -name "coverage" -o \ - -name ".github" -o \ - -name ".circleci" \ -\) -prune -exec rm -rf {} +; - -# Set to production -ENV NODE_ENV=production - -# Notification about what port is going to expose our app. -EXPOSE 3000 -# Command to start our container. -CMD ["npm", "start"] diff --git a/LICENSE b/LICENSE deleted file mode 100644 index e72bfdd..0000000 --- a/LICENSE +++ /dev/null @@ -1,674 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The GNU General Public License is a free, copyleft license for -software and other kinds of works. - - The licenses for most software and other practical works are designed -to take away your freedom to share and change the works. By contrast, -the GNU General Public License is intended to guarantee your freedom to -share and change all versions of a program--to make sure it remains free -software for all its users. We, the Free Software Foundation, use the -GNU General Public License for most of our software; it applies also to -any other work released this way by its authors. You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -them if you wish), that you receive source code or can get it if you -want it, that you can change the software or use pieces of it in new -free programs, and that you know you can do these things. - - To protect your rights, we need to prevent others from denying you -these rights or asking you to surrender the rights. Therefore, you have -certain responsibilities if you distribute copies of the software, or if -you modify it: responsibilities to respect the freedom of others. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must pass on to the recipients the same -freedoms that you received. You must make sure that they, too, receive -or can get the source code. And you must show them these terms so they -know their rights. - - Developers that use the GNU GPL protect your rights with two steps: -(1) assert copyright on the software, and (2) offer you this License -giving you legal permission to copy, distribute and/or modify it. - - For the developers' and authors' protection, the GPL clearly explains -that there is no warranty for this free software. For both users' and -authors' sake, the GPL requires that modified versions be marked as -changed, so that their problems will not be attributed erroneously to -authors of previous versions. - - Some devices are designed to deny users access to install or run -modified versions of the software inside them, although the manufacturer -can do so. This is fundamentally incompatible with the aim of -protecting users' freedom to change the software. The systematic -pattern of such abuse occurs in the area of products for individuals to -use, which is precisely where it is most unacceptable. Therefore, we -have designed this version of the GPL to prohibit the practice for those -products. If such problems arise substantially in other domains, we -stand ready to extend this provision to those domains in future versions -of the GPL, as needed to protect the freedom of users. - - Finally, every program is threatened constantly by software patents. -States should not allow patents to restrict development and use of -software on general-purpose computers, but in those that do, we wish to -avoid the special danger that patents applied to a free program could -make it effectively proprietary. To prevent this, the GPL assures that -patents cannot be used to render the program non-free. - - The precise terms and conditions for copying, distribution and -modification follow. - - TERMS AND CONDITIONS - - 0. Definitions. - - "This License" refers to version 3 of the GNU General Public License. - - "Copyright" also means copyright-like laws that apply to other kinds of -works, such as semiconductor masks. - - "The Program" refers to any copyrightable work licensed under this -License. Each licensee is addressed as "you". "Licensees" and -"recipients" may be individuals or organizations. - - To "modify" a work means to copy from or adapt all or part of the work -in a fashion requiring copyright permission, other than the making of an -exact copy. The resulting work is called a "modified version" of the -earlier work or a work "based on" the earlier work. - - A "covered work" means either the unmodified Program or a work based -on the Program. - - To "propagate" a work means to do anything with it that, without -permission, would make you directly or secondarily liable for -infringement under applicable copyright law, except executing it on a -computer or modifying a private copy. Propagation includes copying, -distribution (with or without modification), making available to the -public, and in some countries other activities as well. - - To "convey" a work means any kind of propagation that enables other -parties to make or receive copies. Mere interaction with a user through -a computer network, with no transfer of a copy, is not conveying. - - An interactive user interface displays "Appropriate Legal Notices" -to the extent that it includes a convenient and prominently visible -feature that (1) displays an appropriate copyright notice, and (2) -tells the user that there is no warranty for the work (except to the -extent that warranties are provided), that licensees may convey the -work under this License, and how to view a copy of this License. If -the interface presents a list of user commands or options, such as a -menu, a prominent item in the list meets this criterion. - - 1. Source Code. - - The "source code" for a work means the preferred form of the work -for making modifications to it. "Object code" means any non-source -form of a work. - - A "Standard Interface" means an interface that either is an official -standard defined by a recognized standards body, or, in the case of -interfaces specified for a particular programming language, one that -is widely used among developers working in that language. - - The "System Libraries" of an executable work include anything, other -than the work as a whole, that (a) is included in the normal form of -packaging a Major Component, but which is not part of that Major -Component, and (b) serves only to enable use of the work with that -Major Component, or to implement a Standard Interface for which an -implementation is available to the public in source code form. A -"Major Component", in this context, means a major essential component -(kernel, window system, and so on) of the specific operating system -(if any) on which the executable work runs, or a compiler used to -produce the work, or an object code interpreter used to run it. - - The "Corresponding Source" for a work in object code form means all -the source code needed to generate, install, and (for an executable -work) run the object code and to modify the work, including scripts to -control those activities. However, it does not include the work's -System Libraries, or general-purpose tools or generally available free -programs which are used unmodified in performing those activities but -which are not part of the work. For example, Corresponding Source -includes interface definition files associated with source files for -the work, and the source code for shared libraries and dynamically -linked subprograms that the work is specifically designed to require, -such as by intimate data communication or control flow between those -subprograms and other parts of the work. - - The Corresponding Source need not include anything that users -can regenerate automatically from other parts of the Corresponding -Source. - - The Corresponding Source for a work in source code form is that -same work. - - 2. Basic Permissions. - - All rights granted under this License are granted for the term of -copyright on the Program, and are irrevocable provided the stated -conditions are met. This License explicitly affirms your unlimited -permission to run the unmodified Program. The output from running a -covered work is covered by this License only if the output, given its -content, constitutes a covered work. This License acknowledges your -rights of fair use or other equivalent, as provided by copyright law. - - You may make, run and propagate covered works that you do not -convey, without conditions so long as your license otherwise remains -in force. You may convey covered works to others for the sole purpose -of having them make modifications exclusively for you, or provide you -with facilities for running those works, provided that you comply with -the terms of this License in conveying all material for which you do -not control copyright. Those thus making or running the covered works -for you must do so exclusively on your behalf, under your direction -and control, on terms that prohibit them from making any copies of -your copyrighted material outside their relationship with you. - - Conveying under any other circumstances is permitted solely under -the conditions stated below. Sublicensing is not allowed; section 10 -makes it unnecessary. - - 3. Protecting Users' Legal Rights From Anti-Circumvention Law. - - No covered work shall be deemed part of an effective technological -measure under any applicable law fulfilling obligations under article -11 of the WIPO copyright treaty adopted on 20 December 1996, or -similar laws prohibiting or restricting circumvention of such -measures. - - When you convey a covered work, you waive any legal power to forbid -circumvention of technological measures to the extent such circumvention -is effected by exercising rights under this License with respect to -the covered work, and you disclaim any intention to limit operation or -modification of the work as a means of enforcing, against the work's -users, your or third parties' legal rights to forbid circumvention of -technological measures. - - 4. Conveying Verbatim Copies. - - You may convey verbatim copies of the Program's source code as you -receive it, in any medium, provided that you conspicuously and -appropriately publish on each copy an appropriate copyright notice; -keep intact all notices stating that this License and any -non-permissive terms added in accord with section 7 apply to the code; -keep intact all notices of the absence of any warranty; and give all -recipients a copy of this License along with the Program. - - You may charge any price or no price for each copy that you convey, -and you may offer support or warranty protection for a fee. - - 5. Conveying Modified Source Versions. - - You may convey a work based on the Program, or the modifications to -produce it from the Program, in the form of source code under the -terms of section 4, provided that you also meet all of these conditions: - - a) The work must carry prominent notices stating that you modified - it, and giving a relevant date. - - b) The work must carry prominent notices stating that it is - released under this License and any conditions added under section - 7. This requirement modifies the requirement in section 4 to - "keep intact all notices". - - c) You must license the entire work, as a whole, under this - License to anyone who comes into possession of a copy. This - License will therefore apply, along with any applicable section 7 - additional terms, to the whole of the work, and all its parts, - regardless of how they are packaged. This License gives no - permission to license the work in any other way, but it does not - invalidate such permission if you have separately received it. - - d) If the work has interactive user interfaces, each must display - Appropriate Legal Notices; however, if the Program has interactive - interfaces that do not display Appropriate Legal Notices, your - work need not make them do so. - - A compilation of a covered work with other separate and independent -works, which are not by their nature extensions of the covered work, -and which are not combined with it such as to form a larger program, -in or on a volume of a storage or distribution medium, is called an -"aggregate" if the compilation and its resulting copyright are not -used to limit the access or legal rights of the compilation's users -beyond what the individual works permit. Inclusion of a covered work -in an aggregate does not cause this License to apply to the other -parts of the aggregate. - - 6. Conveying Non-Source Forms. - - You may convey a covered work in object code form under the terms -of sections 4 and 5, provided that you also convey the -machine-readable Corresponding Source under the terms of this License, -in one of these ways: - - a) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by the - Corresponding Source fixed on a durable physical medium - customarily used for software interchange. - - b) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by a - written offer, valid for at least three years and valid for as - long as you offer spare parts or customer support for that product - model, to give anyone who possesses the object code either (1) a - copy of the Corresponding Source for all the software in the - product that is covered by this License, on a durable physical - medium customarily used for software interchange, for a price no - more than your reasonable cost of physically performing this - conveying of source, or (2) access to copy the - Corresponding Source from a network server at no charge. - - c) Convey individual copies of the object code with a copy of the - written offer to provide the Corresponding Source. This - alternative is allowed only occasionally and noncommercially, and - only if you received the object code with such an offer, in accord - with subsection 6b. - - d) Convey the object code by offering access from a designated - place (gratis or for a charge), and offer equivalent access to the - Corresponding Source in the same way through the same place at no - further charge. You need not require recipients to copy the - Corresponding Source along with the object code. If the place to - copy the object code is a network server, the Corresponding Source - may be on a different server (operated by you or a third party) - that supports equivalent copying facilities, provided you maintain - clear directions next to the object code saying where to find the - Corresponding Source. Regardless of what server hosts the - Corresponding Source, you remain obligated to ensure that it is - available for as long as needed to satisfy these requirements. - - e) Convey the object code using peer-to-peer transmission, provided - you inform other peers where the object code and Corresponding - Source of the work are being offered to the general public at no - charge under subsection 6d. - - A separable portion of the object code, whose source code is excluded -from the Corresponding Source as a System Library, need not be -included in conveying the object code work. - - A "User Product" is either (1) a "consumer product", which means any -tangible personal property which is normally used for personal, family, -or household purposes, or (2) anything designed or sold for incorporation -into a dwelling. In determining whether a product is a consumer product, -doubtful cases shall be resolved in favor of coverage. For a particular -product received by a particular user, "normally used" refers to a -typical or common use of that class of product, regardless of the status -of the particular user or of the way in which the particular user -actually uses, or expects or is expected to use, the product. A product -is a consumer product regardless of whether the product has substantial -commercial, industrial or non-consumer uses, unless such uses represent -the only significant mode of use of the product. - - "Installation Information" for a User Product means any methods, -procedures, authorization keys, or other information required to install -and execute modified versions of a covered work in that User Product from -a modified version of its Corresponding Source. The information must -suffice to ensure that the continued functioning of the modified object -code is in no case prevented or interfered with solely because -modification has been made. - - If you convey an object code work under this section in, or with, or -specifically for use in, a User Product, and the conveying occurs as -part of a transaction in which the right of possession and use of the -User Product is transferred to the recipient in perpetuity or for a -fixed term (regardless of how the transaction is characterized), the -Corresponding Source conveyed under this section must be accompanied -by the Installation Information. But this requirement does not apply -if neither you nor any third party retains the ability to install -modified object code on the User Product (for example, the work has -been installed in ROM). - - The requirement to provide Installation Information does not include a -requirement to continue to provide support service, warranty, or updates -for a work that has been modified or installed by the recipient, or for -the User Product in which it has been modified or installed. Access to a -network may be denied when the modification itself materially and -adversely affects the operation of the network or violates the rules and -protocols for communication across the network. - - Corresponding Source conveyed, and Installation Information provided, -in accord with this section must be in a format that is publicly -documented (and with an implementation available to the public in -source code form), and must require no special password or key for -unpacking, reading or copying. - - 7. Additional Terms. - - "Additional permissions" are terms that supplement the terms of this -License by making exceptions from one or more of its conditions. -Additional permissions that are applicable to the entire Program shall -be treated as though they were included in this License, to the extent -that they are valid under applicable law. If additional permissions -apply only to part of the Program, that part may be used separately -under those permissions, but the entire Program remains governed by -this License without regard to the additional permissions. - - When you convey a copy of a covered work, you may at your option -remove any additional permissions from that copy, or from any part of -it. (Additional permissions may be written to require their own -removal in certain cases when you modify the work.) You may place -additional permissions on material, added by you to a covered work, -for which you have or can give appropriate copyright permission. - - Notwithstanding any other provision of this License, for material you -add to a covered work, you may (if authorized by the copyright holders of -that material) supplement the terms of this License with terms: - - a) Disclaiming warranty or limiting liability differently from the - terms of sections 15 and 16 of this License; or - - b) Requiring preservation of specified reasonable legal notices or - author attributions in that material or in the Appropriate Legal - Notices displayed by works containing it; or - - c) Prohibiting misrepresentation of the origin of that material, or - requiring that modified versions of such material be marked in - reasonable ways as different from the original version; or - - d) Limiting the use for publicity purposes of names of licensors or - authors of the material; or - - e) Declining to grant rights under trademark law for use of some - trade names, trademarks, or service marks; or - - f) Requiring indemnification of licensors and authors of that - material by anyone who conveys the material (or modified versions of - it) with contractual assumptions of liability to the recipient, for - any liability that these contractual assumptions directly impose on - those licensors and authors. - - All other non-permissive additional terms are considered "further -restrictions" within the meaning of section 10. If the Program as you -received it, or any part of it, contains a notice stating that it is -governed by this License along with a term that is a further -restriction, you may remove that term. If a license document contains -a further restriction but permits relicensing or conveying under this -License, you may add to a covered work material governed by the terms -of that license document, provided that the further restriction does -not survive such relicensing or conveying. - - If you add terms to a covered work in accord with this section, you -must place, in the relevant source files, a statement of the -additional terms that apply to those files, or a notice indicating -where to find the applicable terms. - - Additional terms, permissive or non-permissive, may be stated in the -form of a separately written license, or stated as exceptions; -the above requirements apply either way. - - 8. Termination. - - You may not propagate or modify a covered work except as expressly -provided under this License. Any attempt otherwise to propagate or -modify it is void, and will automatically terminate your rights under -this License (including any patent licenses granted under the third -paragraph of section 11). - - However, if you cease all violation of this License, then your -license from a particular copyright holder is reinstated (a) -provisionally, unless and until the copyright holder explicitly and -finally terminates your license, and (b) permanently, if the copyright -holder fails to notify you of the violation by some reasonable means -prior to 60 days after the cessation. - - Moreover, your license from a particular copyright holder is -reinstated permanently if the copyright holder notifies you of the -violation by some reasonable means, this is the first time you have -received notice of violation of this License (for any work) from that -copyright holder, and you cure the violation prior to 30 days after -your receipt of the notice. - - Termination of your rights under this section does not terminate the -licenses of parties who have received copies or rights from you under -this License. If your rights have been terminated and not permanently -reinstated, you do not qualify to receive new licenses for the same -material under section 10. - - 9. Acceptance Not Required for Having Copies. - - You are not required to accept this License in order to receive or -run a copy of the Program. Ancillary propagation of a covered work -occurring solely as a consequence of using peer-to-peer transmission -to receive a copy likewise does not require acceptance. However, -nothing other than this License grants you permission to propagate or -modify any covered work. These actions infringe copyright if you do -not accept this License. Therefore, by modifying or propagating a -covered work, you indicate your acceptance of this License to do so. - - 10. Automatic Licensing of Downstream Recipients. - - Each time you convey a covered work, the recipient automatically -receives a license from the original licensors, to run, modify and -propagate that work, subject to this License. You are not responsible -for enforcing compliance by third parties with this License. - - An "entity transaction" is a transaction transferring control of an -organization, or substantially all assets of one, or subdividing an -organization, or merging organizations. If propagation of a covered -work results from an entity transaction, each party to that -transaction who receives a copy of the work also receives whatever -licenses to the work the party's predecessor in interest had or could -give under the previous paragraph, plus a right to possession of the -Corresponding Source of the work from the predecessor in interest, if -the predecessor has it or can get it with reasonable efforts. - - You may not impose any further restrictions on the exercise of the -rights granted or affirmed under this License. For example, you may -not impose a license fee, royalty, or other charge for exercise of -rights granted under this License, and you may not initiate litigation -(including a cross-claim or counterclaim in a lawsuit) alleging that -any patent claim is infringed by making, using, selling, offering for -sale, or importing the Program or any portion of it. - - 11. Patents. - - A "contributor" is a copyright holder who authorizes use under this -License of the Program or a work on which the Program is based. The -work thus licensed is called the contributor's "contributor version". - - A contributor's "essential patent claims" are all patent claims -owned or controlled by the contributor, whether already acquired or -hereafter acquired, that would be infringed by some manner, permitted -by this License, of making, using, or selling its contributor version, -but do not include claims that would be infringed only as a -consequence of further modification of the contributor version. For -purposes of this definition, "control" includes the right to grant -patent sublicenses in a manner consistent with the requirements of -this License. - - Each contributor grants you a non-exclusive, worldwide, royalty-free -patent license under the contributor's essential patent claims, to -make, use, sell, offer for sale, import and otherwise run, modify and -propagate the contents of its contributor version. - - In the following three paragraphs, a "patent license" is any express -agreement or commitment, however denominated, not to enforce a patent -(such as an express permission to practice a patent or covenant not to -sue for patent infringement). To "grant" such a patent license to a -party means to make such an agreement or commitment not to enforce a -patent against the party. - - If you convey a covered work, knowingly relying on a patent license, -and the Corresponding Source of the work is not available for anyone -to copy, free of charge and under the terms of this License, through a -publicly available network server or other readily accessible means, -then you must either (1) cause the Corresponding Source to be so -available, or (2) arrange to deprive yourself of the benefit of the -patent license for this particular work, or (3) arrange, in a manner -consistent with the requirements of this License, to extend the patent -license to downstream recipients. "Knowingly relying" means you have -actual knowledge that, but for the patent license, your conveying the -covered work in a country, or your recipient's use of the covered work -in a country, would infringe one or more identifiable patents in that -country that you have reason to believe are valid. - - If, pursuant to or in connection with a single transaction or -arrangement, you convey, or propagate by procuring conveyance of, a -covered work, and grant a patent license to some of the parties -receiving the covered work authorizing them to use, propagate, modify -or convey a specific copy of the covered work, then the patent license -you grant is automatically extended to all recipients of the covered -work and works based on it. - - A patent license is "discriminatory" if it does not include within -the scope of its coverage, prohibits the exercise of, or is -conditioned on the non-exercise of one or more of the rights that are -specifically granted under this License. You may not convey a covered -work if you are a party to an arrangement with a third party that is -in the business of distributing software, under which you make payment -to the third party based on the extent of your activity of conveying -the work, and under which the third party grants, to any of the -parties who would receive the covered work from you, a discriminatory -patent license (a) in connection with copies of the covered work -conveyed by you (or copies made from those copies), or (b) primarily -for and in connection with specific products or compilations that -contain the covered work, unless you entered into that arrangement, -or that patent license was granted, prior to 28 March 2007. - - Nothing in this License shall be construed as excluding or limiting -any implied license or other defenses to infringement that may -otherwise be available to you under applicable patent law. - - 12. No Surrender of Others' Freedom. - - If conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot convey a -covered work so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you may -not convey it at all. For example, if you agree to terms that obligate you -to collect a royalty for further conveying from those to whom you convey -the Program, the only way you could satisfy both those terms and this -License would be to refrain entirely from conveying the Program. - - 13. Use with the GNU Affero General Public License. - - Notwithstanding any other provision of this License, you have -permission to link or combine any covered work with a work licensed -under version 3 of the GNU Affero General Public License into a single -combined work, and to convey the resulting work. The terms of this -License will continue to apply to the part which is the covered work, -but the special requirements of the GNU Affero General Public License, -section 13, concerning interaction through a network will apply to the -combination as such. - - 14. Revised Versions of this License. - - The Free Software Foundation may publish revised and/or new versions of -the GNU General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - - Each version is given a distinguishing version number. If the -Program specifies that a certain numbered version of the GNU General -Public License "or any later version" applies to it, you have the -option of following the terms and conditions either of that numbered -version or of any later version published by the Free Software -Foundation. If the Program does not specify a version number of the -GNU General Public License, you may choose any version ever published -by the Free Software Foundation. - - If the Program specifies that a proxy can decide which future -versions of the GNU General Public License can be used, that proxy's -public statement of acceptance of a version permanently authorizes you -to choose that version for the Program. - - Later license versions may give you additional or different -permissions. However, no additional obligations are imposed on any -author or copyright holder as a result of your choosing to follow a -later version. - - 15. Disclaimer of Warranty. - - THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY -APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT -HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY -OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, -THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM -IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF -ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. Limitation of Liability. - - IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS -THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY -GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE -USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF -DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD -PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), -EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF -SUCH DAMAGES. - - 17. Interpretation of Sections 15 and 16. - - If the disclaimer of warranty and limitation of liability provided -above cannot be given local legal effect according to their terms, -reviewing courts shall apply local law that most closely approximates -an absolute waiver of all civil liability in connection with the -Program, unless a warranty or assumption of liability accompanies a -copy of the Program in return for a fee. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -state the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - -Also add information on how to contact you by electronic and paper mail. - - If the program does terminal interaction, make it output a short -notice like this when it starts in an interactive mode: - - Copyright (C) - This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, your program's commands -might be different; for a GUI interface, you would use an "about box". - - You should also get your employer (if you work as a programmer) or school, -if any, to sign a "copyright disclaimer" for the program, if necessary. -For more information on this, and how to apply and follow the GNU GPL, see -. - - The GNU General Public License does not permit incorporating your program -into proprietary programs. If your program is a subroutine library, you -may consider it more useful to permit linking proprietary applications with -the library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. But first, please read -. \ No newline at end of file diff --git a/README.md b/README.md deleted file mode 100644 index 931b157..0000000 --- a/README.md +++ /dev/null @@ -1,93 +0,0 @@ -# Source Code API [![codecov](https://codecov.io/gh/SourceCodeOER/sourcecode_api/branch/master/graph/badge.svg)](https://codecov.io/gh/SourceCodeOER/sourcecode_api) [![Codacy Badge](https://api.codacy.com/project/badge/Grade/c0bf96d3b3c54be286f4174c50fd6490)](https://www.codacy.com/gh/SourceCodeOER/sourcecode_api?utm_source=github.com&utm_medium=referral&utm_content=SourceCodeOER/sourcecode_api&utm_campaign=Badge_Grade) [![Greenkeeper badge](https://badges.greenkeeper.io/SourceCodeOER/sourcecode_api.svg)](https://greenkeeper.io/) ![](https://github.com/SourceCodeOER/sourcecode_api/workflows/Source%20Code%20CI%2FCD/badge.svg) ![](https://github.com/SourceCodeOER/sourcecode_api/workflows/OAS%20Documentation/badge.svg) -> the new open source catalogue of computer exercises - -Like Open Educational Resources, Source Code offers the possibility for educational teams to -collaborate on the problem of creating and sharing exercises. -The latter consists in referencing IT resources, by allowing a diverse audience to benefit from all contributions. -As the catalogue expands, it will become an essential resource for all. - -## Requirements - -- PostgreSQL 12 -- Node.js 10+ - -## Documentation - -For more examples and API details, see [API documentation](https://sourcecodeoer.github.io/sourcecode_api/) ([or build it yourself !](#how-to-generate--)) - -## Set up - -1. Install dependencies - -``` -npm install -``` - -2. Creates a database (settings are stored in `config/config.js`) -``` -npx sequelize db:create -``` - -3. Creates the schema `exercises_library` in this database and - Apply all Sequelize migrations to let Sequelize initialize your models in database : -``` -npm run setUp -``` - -## How do I populate the database quickly with my exercises ? - -This API is delivered with a very complete [CLI tool](https://github.com/SourceCodeOER/cli) to handle the different possible situations. You will find more information on its [documentation](https://github.com/SourceCodeOER/cli/blob/master/README.md). - -## Starting the API - -``` -npm start -``` - -This will start the API that you reach on [http://localhost:3000](http://localhost:3000). - -## How to generate ... ? - -### Clients - -Using [openapi-generator](https://openapi-generator.tech/) : - -``` -npx openapi-generator generate -g typescript-axios -i api.yml -o out -``` - -### Documentation - -Using [redoc-cli](https://github.com/Redocly/redoc): - -``` -npx redoc-cli bundle api.yml -o docs/index.html -``` - -### How to validate API documentation ? - -Using [openapi-generator](https://openapi-generator.tech/) : -``` -npx openapi-generator validate -i api.yml -``` - -### A single yaml file that contains all the API (Useful for Postman for instance) ? - -Using [speccy](https://github.com/wework/speccy) : -``` -npx speccy resolve api.yml -o spec-output.yaml -``` - -## Environment variables - -You can customize some parts of the API using the following environment variables : - -| Environment variable name | Purpose | Default value | -|---|---|---| -| PORT | The port to use for the API | 3000 | -| TOKEN_TTL | A [zeit/ms](https://github.com/zeit/ms) string that expresses in how much time a JWT token should expire | '1h' | -| SECRET_PHRASE | The secretOrPrivateKey for [jwt.sign](https://github.com/auth0/node-jsonwebtoken#jwtsignpayload-secretorprivatekey-options-callback) | "Super secured passphrase" | -| DEBUG | To print relevant logs using [debug](https://www.npmjs.com/package/debug). Currently, you have the following choices :

- `sourcecode_api:error_handler` : Print all errors
- `sourcecode_api:error_tracker` : Print only failed requests errors
- `sourcecode_api:files` : Print only files that couldn't deleted
- `sequelize:*` : Print [sequelize](https://www.npmjs.com/package/sequelize) logs
... | | -| DATABASE_URL | The postgresql connection URI ( [See postgresl docs for more information](https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-CONNSTRING) ) | | -| DATABASE_SCHEMA | The schema we want to use on the database | | -| | | | diff --git a/api.yml b/api.yml deleted file mode 100644 index a635b44..0000000 --- a/api.yml +++ /dev/null @@ -1,79 +0,0 @@ -openapi: 3.0.0 -info: - description: "API for Source Code" - version: "1.0.0" - title: "Source Code API" - license: - name: "GPL-3.0-or-later" - url: "https://choosealicense.com/licenses/gpl-3.0/" - -# Pas utile pour l'instant mais c'est mieux pour après -servers: - - url: http://localhost:3000 - description: Internal staging server for testing - - url: http://api.example.com/v1 - description: Optional server description, e.g. Main (production) server - -# To fast distinguish what could be done by guest, user and admin -tags: - - name: guest - description: "Everything a(n) visitor / not authentified user could do" - - name: user - description: "Everything an authentified user could do (more than a guest)" - - name: admin - description: "Everything an administrator could do (more than an user)" - - name: super_admin - description: "Everything an administrator could do (more than an admin)" - -paths: - /auth/login: - $ref: 'openapi/paths/auth.yaml#/paths/~1auth~1login' - /auth/register: - $ref: 'openapi/paths/auth.yaml#/paths/~1auth~1register' - /auth/verify: - $ref: 'openapi/paths/auth.yaml#/paths/~1auth~1verify' - /auth/me: - $ref: 'openapi/paths/users.yaml#/paths/~1auth~1me' - /auth/update: - $ref: 'openapi/paths/users.yaml#/paths/~1auth~1update' - /api/create_exercise: - $ref: 'openapi/paths/create_exercise.yaml#/paths/~1api~1create_exercise' - /api/exercises/{id}: - $ref: 'openapi/paths/exercise.yaml#/paths/~1api~1exercises~1%7Bid%7D' - /api/export: - $ref: 'openapi/paths/exercise.yaml#/paths/~1api~1export' - /api/search: - $ref: 'openapi/paths/search.yaml#/paths/~1api~1search' - /api/tags: - $ref: 'openapi/paths/tags.yaml#/paths/~1api~1tags' - /api/tags_categories: - $ref: 'openapi/paths/tags_categories.yaml#/paths/~1api~1tags_categories' - /api/tags_by_categories: - $ref: 'openapi/paths/tags_by_categories.yaml#/paths/~1api~1tags_by_categories' - /api/bulk/create_exercises: - $ref: 'openapi/paths/bulk.yaml#/paths/~1api~1bulk~1create_exercises' - /api/bulk/create_or_find_tag_categories: - $ref: 'openapi/paths/bulk.yaml#/paths/~1api~1bulk~1create_or_find_tag_categories' - /api/bulk/modify_exercises_status: - $ref: 'openapi/paths/bulk.yaml#/paths/~1api~1bulk~1modify_exercises_status' - /api/bulk/delete_exercises: - $ref: 'openapi/paths/bulk.yaml#/paths/~1api~1bulk~1delete_exercises' - /api/bulk/delete_tags: - $ref: 'openapi/paths/bulk.yaml#/paths/~1api~1bulk~1delete_tags' - /api/bulk/delete_tags_categories: - $ref: 'openapi/paths/bulk.yaml#/paths/~1api~1bulk~1delete_tags_categories' - /api/bulk/create_tags: - $ref: 'openapi/paths/bulk.yaml#/paths/~1api~1bulk~1create_tags' - /api/vote_for_exercise: - $ref: 'openapi/paths/vote_for_exercise.yaml#/paths/~1api~1vote_for_exercise' - /api/configurations: - $ref: 'openapi/paths/configurations.yaml#/paths/~1api~1configurations' - /api/users: - $ref: 'openapi/paths/users.yaml#/paths/~1api~1users' - /files/{file}: - $ref: 'openapi/paths/miscellaneous.yaml#/paths/~1files~1%7Bfile%7D' - -components: - securitySchemes: - bearerAuth: - $ref: "openapi/security.yaml#/components/securitySchemes/bearerAuth" diff --git a/app.js b/app.js deleted file mode 100644 index c0ea89f..0000000 --- a/app.js +++ /dev/null @@ -1,98 +0,0 @@ -const express = require('express'); -const path = require('path'); -const logger = require('morgan'); -const cookieParser = require('cookie-parser'); -const bodyParser = require('body-parser'); - -// miscellaneous passport things -const passport = require('passport'); - -// own middlewares -const error_prettier = require("./middlewares/errors-beautifier"); -const default_error_handler = require("./middlewares/default_error_handler"); -const not_found_handler = require("./middlewares/not_found"); -const securityCheck = require("./middlewares/security"); -const removeTempFiles = require("./middlewares/remove_temp_files"); - -// location of stored files to serve as static -const {FILES_FOLDER} = require("./config/storage_paths"); - -// helmet for classic security measures -const helmet = require('helmet'); - -// OpenAPI V3 validation middleware -const Enforcer = require("openapi-enforcer-middleware"); -const enforcerMulter = require('openapi-enforcer-multer'); -const spec = path.join(__dirname, 'api.yml'); -const controllerDirectory = path.resolve(__dirname, 'controllers'); - -// Initialize passport ( Passport is a singleton ) -require('./config/passport'); - -module.exports = new Promise((resolve, reject) => { - - // storage for multer - const storage = require("./config/storage")(); - - let app = express(); - - // common middleware - app.use(helmet()); - app.use(logger('dev')); - app.use(bodyParser.json({limit: '10mb'})); - app.use(bodyParser.urlencoded({extended: true})); - app.use(cookieParser()); - - // Gives the Swagger UI Viewer - /* istanbul ignore next */ - app.use('/api-docs', function (_, res) { - res.redirect("http://petstore.swagger.io/?url=https://raw.githubusercontent.com/SourceCodeOER/sourcecode_api/master/api.yml"); - }); - - // Serves stored files with this endpoint - /* istanbul ignore next */ - app.use("/files", express.static(FILES_FOLDER)); - - // main API setup - try { - // initialize the enforcer - const enforcer = Enforcer(spec, { - componentOptions: { - requestBodyAllowedMethods: {"delete": true}, - exceptionSkipCodes: ["WSCH001", "WMED001"] - }, - resValidate: false - }); - // check if the client is allowed on this endpoint - enforcer.use(securityCheck()); - enforcer - .controllers(controllerDirectory) - .then(() => { - // Passport Js must have that - app.use(passport.initialize()); - - // add enforcer multer middleware - app.use(enforcerMulter(enforcer, storage)); - - // add the enforcer middleware runner to the express app - app.use(enforcer.middleware()); - - // remove temp files if an error occurs (if provided) - app.use(removeTempFiles()); - // catch 404 and forward to error handler - app.use(not_found_handler()); - // for production, hides Sequelize messages under "general" message - app.use(error_prettier()); - // error handler - app.use(default_error_handler(app.get('env') === 'development')); - - resolve(app); - }) - .catch(/* istanbul ignore next */err => { - throw err; - }); - } catch (err) { - /* istanbul ignore next */ - reject(err); - } -}); diff --git a/bin/create_schema.js b/bin/create_schema.js deleted file mode 100644 index 9f53715..0000000 --- a/bin/create_schema.js +++ /dev/null @@ -1,37 +0,0 @@ -'use strict'; - -const Sequelize = require("sequelize"); -const env = process.env.NODE_ENV /* istanbul ignore next */ || 'development'; -const debug = require(__dirname + '/../controllers/_common/debug'); -let config = require(__dirname + '/../config/config.js')[env]; -const createSchema = ` - DROP SCHEMA IF EXISTS ${config.schema} CASCADE; - CREATE SCHEMA ${config.schema}; -`; - -try { - let sequelize; - // remove schema from config as it may not exist yet - delete config.schema; - /* istanbul ignore else */ - if (config.use_env_variable) { - sequelize = new Sequelize(process.env[config.use_env_variable], config); - } else { - sequelize = new Sequelize(config.database, config.username, config.password, config); - } - - sequelize - .query(createSchema, { - type: sequelize.QueryTypes.RAW - }) - .then( () => { - process.exit(0); - }) - .catch( (err) => { - debug.errors("%O", err); - throw err; - }); - -} catch (e) { - process.exit(1); -} diff --git a/bin/www b/bin/www deleted file mode 100644 index f6b3d29..0000000 --- a/bin/www +++ /dev/null @@ -1,94 +0,0 @@ -#!/usr/bin/env node - -/** - * Module dependencies. - */ - -const debug = require('debug')('sourcecode_api:start'); -const http = require('http'); -const models = require('../models'); - -/** - * Get port from environment and store in Express. - */ - -const port = normalizePort(process.env.PORT || '3000'); - -require('../app').then(app => { - app.set('port', port); - /** - * Create HTTP server. - */ - const server = http.createServer(app); - - /** - * Event listener for HTTP server "listening" event. - */ - // must be defined here because of async code before - function onListening() { - const addr = server.address(); - const bind = typeof addr === 'string' - ? 'pipe ' + addr - : 'port ' + addr.port; - debug('Listening on ' + bind); - } - - models.sequelize.sync().then(function() { - /** - * Listen on provided port, on all network interfaces. - */ - server.listen(port, function() { - debug('Express server listening on port ' + server.address().port); - }); - server.on('error', onError); - server.on('listening', onListening); - }); -}); - -/** - * Normalize a port into a number, string, or false. - */ - -function normalizePort(val) { - const port = parseInt(val, 10); - - if (isNaN(port)) { - // named pipe - return val; - } - - if (port >= 0) { - // port number - return port; - } - - return false; -} - -/** - * Event listener for HTTP server "error" event. - */ - -function onError(error) { - if (error.syscall !== 'listen') { - throw error; - } - - const bind = typeof port === 'string' - ? 'Pipe ' + port - : 'Port ' + port; - - // handle specific listen errors with friendly messages - switch (error.code) { - case 'EACCES': - console.error(bind + ' requires elevated privileges'); - process.exit(1); - break; - case 'EADDRINUSE': - console.error(bind + ' is already in use'); - process.exit(1); - break; - default: - throw error; - } -} \ No newline at end of file diff --git a/config/config.js b/config/config.js deleted file mode 100644 index f98aced..0000000 --- a/config/config.js +++ /dev/null @@ -1,27 +0,0 @@ -const devConfig = { - "username": "postgres", - "password": "jy95", - "host": "127.0.0.1", - "dialect": "postgres", - "database": "database_test", - "schema": "exercises_library", - "logging": false -}; - -let defaultConfig = { - "dialect": "postgres", - "logging": false, - "use_env_variable": "DATABASE_URL" -}; - -// If a schema was specified -/* istanbul ignore else */ -if (process.env.DATABASE_SCHEMA) { - defaultConfig["schema"] = process.env.DATABASE_SCHEMA; -} - -module.exports = { - "development": devConfig, - "production": defaultConfig, - "test": defaultConfig -}; diff --git a/config/passport.js b/config/passport.js deleted file mode 100644 index 3a37c6c..0000000 --- a/config/passport.js +++ /dev/null @@ -1,84 +0,0 @@ -const passport = require('passport'); - -const JsonStrategy = require('passport-json').Strategy; -const passportJWT = require('passport-jwt'); -const ExtractJWT = passportJWT.ExtractJwt; -const JWTStrategy = passportJWT.Strategy; - -const models = require('../models'); - -// https://github.com/zapstar/node-sequelize-passport -// To get a JWT Token -passport.use(new JsonStrategy({ - usernameProp: "email", - passwordProp: "password" -}, function (email, password, done) { - models.User - .findOne({where: {email: email}}) - .then(function (user) { // successful query to database - if (!user) { - return done(null, false, {message: 'Unknown user ' + email}); - } - models.User.comparePassword(password, user.password, function (err, isMatch) { - /* istanbul ignore next */ - if (err) { - return done(err); - } - if (isMatch) { - return done(null, user); - } else { - return done(null, false, {message: 'Invalid password'}); - } - }); - }) - // something went wrong with query to db - .catch(/* istanbul ignore next */ - err => done(err) - ); -})); - -passport.use(new JWTStrategy({ - jwtFromRequest: ExtractJWT.fromAuthHeaderAsBearerToken(), - secretOrKey: process.env.SECRET_PHRASE || "Super secured passphrase" - }, - (jwtPayload, done) => { - - process.nextTick(_ => { - - const userAttributes = { - id: jwtPayload.id - }; - - models.User - .findOne({where: userAttributes}) - .then(function (user) { // successful query to database - return done(null, user); - }) - // something went wrong with query to db - .catch(/* istanbul ignore next */ - error => done(error) - ); - }) - } -)); - - -// Si on veut avoir des sessions ( HIGHLY IMPROBABLE ) : - -/* -// serialize session, only store user id in the session information -passport.serializeUser(function(user, done) { - done(null, user.id); -}); - -// from the user id, figure out who the user is... -passport.deserializeUser(function(userId, done){ - models.User - .find({ where: { id: userId } }) - .then(function(user){ - done(null, user); - }).catch(function(err){ - done(err, null); - }); -}); - */ \ No newline at end of file diff --git a/config/storage.js b/config/storage.js deleted file mode 100644 index 5137a62..0000000 --- a/config/storage.js +++ /dev/null @@ -1,45 +0,0 @@ -const uuidv1 = require('uuid/v1'); // uuid timestamp -const {existsSync, mkdirSync} = require("fs"); -const mimeTypes = require("mime-types"); -const multer = require("multer"); -const {FILES_FOLDER, UPLOAD_FOLDER} = require("./storage_paths"); - -// to check existence of given path -const exists = (dir) => { - try { - return existsSync(dir); - } catch (/* istanbul ignore next */ e) { - /* istanbul ignore next */ - return false; - } -}; - -module.exports = function () { - // create if not exist yet this folder for multer ( temp storage ) - /* istanbul ignore next */ - if (!exists(UPLOAD_FOLDER)) { - mkdirSync(UPLOAD_FOLDER, { recursive: true }); - } - /* istanbul ignore next */ - // same for definitive storage - if (!exists(FILES_FOLDER)) { - mkdirSync(FILES_FOLDER, { recursive: true }); - } - - return multer({ - storage: multer.diskStorage({ - destination: function (req, file, cb) { - cb(null, UPLOAD_FOLDER) - }, - filename: function (req, file, cb) { - // whatever the file extension, give unique uuid based on timestamp - const extension = mimeTypes.extension(file.mimetype) /* istanbul ignore next */ || "zip"; - const generate_unique_filename = `sources-${uuidv1()}.${extension}`; - cb(null, generate_unique_filename) - } - }), - //limits: { fileSize: 200000 } - }); -} - -; \ No newline at end of file diff --git a/config/storage_paths.js b/config/storage_paths.js deleted file mode 100644 index 5e169ba..0000000 --- a/config/storage_paths.js +++ /dev/null @@ -1,7 +0,0 @@ -const path = require("path"); - -module.exports = { - // location to store temp / definitive file - "UPLOAD_FOLDER": path.resolve(__dirname, "..", "uploads/"), - "FILES_FOLDER": path.resolve(__dirname, "..", "files/") -} \ No newline at end of file diff --git a/controllers/_common/constants.js b/controllers/_common/constants.js deleted file mode 100644 index ec8af73..0000000 --- a/controllers/_common/constants.js +++ /dev/null @@ -1,20 +0,0 @@ -module.exports = { - "EXERCISES": { - DRAFT: "DRAFT", - PENDING: "PENDING", - VALIDATED: "VALIDATED", - NOT_VALIDATED: "NOT_VALIDATED", - ARCHIVED: "ARCHIVED", - }, - "TAGS": { - NOT_VALIDATED: "NOT_VALIDATED", - VALIDATED: "VALIDATED", - DEPRECATED: "DEPRECATED", - PENDING: "PENDING" - }, - "USERS": { - ADMIN: "admin", - SUPER_ADMIN: "super_admin", - USER: "user", - } -}; diff --git a/controllers/_common/debug.js b/controllers/_common/debug.js deleted file mode 100644 index 7dc2355..0000000 --- a/controllers/_common/debug.js +++ /dev/null @@ -1,7 +0,0 @@ -const Debug = require('debug'); - -module.exports = { - "errors": Debug("sourcecode_api:error_handler"), - "tracker": Debug("sourcecode_api:error_tracker"), - "files": Debug("sourcecode_api:files"), -}; \ No newline at end of file diff --git a/controllers/_common/files_manager.js b/controllers/_common/files_manager.js deleted file mode 100644 index 6cdd013..0000000 --- a/controllers/_common/files_manager.js +++ /dev/null @@ -1,42 +0,0 @@ -const Promise = require("bluebird"); -const moveFile = require('move-file'); -const del = require('del'); -const {resolve: path_resolve} = require("path"); -const {FILES_FOLDER} = require("../../config/storage_paths"); -const debug = require("./debug"); - -// function to remove given files array -// if it is a multer object, we can extract the storage (else rely on given paths ) -// even if delete failed, we will say that it works : the simple reason is that then/catch will have the same content -/* istanbul ignore next */ -function delete_files(filesArray, isMulterObject = true) { - const paths = (isMulterObject) - ? filesArray.map(file => file.path) - : filesArray; - return new Promise((resolve) => { - del(paths) - .then(() => resolve()) - .catch(/* istanbul ignore next */() => { - debug.files("One or multiple couldn't be deleted - You should probably delete them manually"); - debug.files("%O", paths); - resolve() - }) - }); - -} - -module.exports = { - // fct that moves a multer file object to destination - move_file_to_destination_folder: (file) => moveFile( - file.path, - path_resolve(FILES_FOLDER, file.filename), {overwrite: false} - ), - // for files uploaded by multer in temp folder ( here UPLOAD_FOLDER ) - delete_temp_files: /* istanbul ignore next */ (files) => delete_files(files), - - // for files stored - delete_stored_files: /* istanbul ignore next */ (files) => delete_files( - files.map(file => path_resolve(FILES_FOLDER, file)), - false - ) -}; \ No newline at end of file diff --git a/controllers/_common/utlis_fct.js b/controllers/_common/utlis_fct.js deleted file mode 100644 index a4a96fe..0000000 --- a/controllers/_common/utlis_fct.js +++ /dev/null @@ -1,559 +0,0 @@ -const models = require('../../models'); -const fileManager = require("./files_manager"); -const Promise = require("bluebird"); - -const Sequelize = require("sequelize"); -const Op = Sequelize.Op; - -const partition = require('lodash.partition'); -const groupBy = require('lodash.groupby'); -const uniqWith = require('lodash.uniqwith'); -const isEqual = require('lodash.isequal'); - -// state -const {TAGS: tagState, EXERCISES: exerciseState, USERS: userRoles} = require("./constants"); - -// Some utilities functions commonly used -module.exports = { - // return "data" result for /search and /exercise/{id} - // This function takes 3 parameters (only the first one is mandatory) - // - ids : the ordered list of exercises ids we have to generate - // - the include options : to generate what the user asks - // - request : the full body of request - build_search_result(ids, - { - includeCreator = false, - includeMetrics = true, - includeDescription = true, - includeTags = true, - } = {}, - request - ) { - - return new Promise((resolve, reject) => { - // For Postgres, we have a much better way to handle this case - // decompose this complex task to several sub queries - // Why ? - // 1. Database can more easily cache rows - // 2. Inner join with more of 3 tables with millions of rows is a memory leak - // 3. More easily to maintain that - - // Default scope for Exercise - let exerciseScope = [ - "default_attributes_for_bulk", - {method: ["filter_exercises_ids", ids]}, - ]; - - // If asked, add the metrics exercises - if (includeMetrics) { - exerciseScope.push("with_exercise_metrics"); - } - - // If asked, add the creator of exercise - if (includeCreator) { - exerciseScope.push("with_exercise_creator"); - } - - // If asked, don't include description - if (!includeDescription) { - exerciseScope.push("without_exercise_description"); - } - - // If asked, include the tags - if (includeTags) { - exerciseScope.push( - {method: ["with_related_tags_with_their_category", request.filterOptions]} - ); - } - - return models - .Exercise - .scope(exerciseScope) - .findAll() - .then((exercises_data) => { - // key : exercise_id - const exercises_data_map = groupBy(exercises_data, "id"); - resolve( - ids - // handle the case if the exercise doesn't exist anymore because someone deleted it - .filter(id => exercises_data_map.hasOwnProperty(id)) - // manually build the good result - .map(id => { - let exercise = exercises_data_map[id][0]; - let exercise_json = exercise.toJSON(); - - // only apply this logic when we have a metric object inside exercise - if (includeMetrics) { - // metrics.avg_score should be a number with only 2 decimal - exercise_json["metrics"]["avg_score"] = Number( - parseFloat(exercise_json["metrics"]["avg_score"]).toFixed(2) - ); - } - - return Object.assign({}, exercise_json) - }) - ); - }).catch(/* istanbul ignore next */ - err => reject(err)); - - }) - }, - - // Promise that try to match new_tags with the result in DB - matching_process: matching_process, - - // Promise to retrieve possible matches for new tag - find_tag_matches: find_tag_matches, - // to create the dictionary used for matching_process - "build_dictionary_for_matching_process": build_dictionary_for_matching_process, - - "check_credentials_on_exercises": check_credentials_on_exercises, - - // To check that we have at least N validated tags - validated_tag_count(ids, required_number) { - return new Promise((resolve, reject) => { - // As https://github.com/sequelize/sequelize/issues/5732 is not implemented - // I will use a workaround ( like my scope "count_summary" ) - const filterGen = (where) => Sequelize.literal(`COUNT(*) FILTER ${where}`); - models - .Tag - .findAll({ - attributes: [ - [ - filterGen(`(WHERE "Tag"."state" = '${tagState.VALIDATED}')`), - "total" - ] - ], - where: { - id: { - [Op.in]: ids - } - } - }).then(([result]) => { - let count = parseInt(result.get("total")); - if (count >= required_number) { - resolve(); - } else { - let error = new Error("Bad Request"); - error.message = `Required ${required_number} validated tag(s) - only ${count} is/are validated`; - error.status = 400; - reject(error); - } - }).catch(/* istanbul ignore next */ - err => reject(err)) - }); - }, - - // To store a single exercise - store_single_exercise(user, exercise_data, existent_tags, really_new_tags) { - return new Promise((resolve, reject) => { - models - .sequelize - .transaction({ - isolationLevel: Sequelize.Transaction.ISOLATION_LEVELS.READ_COMMITTED - }, (t) => { - return store_single_exercise(user, exercise_data, existent_tags, really_new_tags, t) - }) - .then((_) => { - // OK work as expected - resolve() - }) - .catch(/* istanbul ignore next */ - err => reject(err)) - }); - }, - - // Promise to store bulky exercise(s) - bulky_store_exercises(user, exercises) { - const creationDate = new Date(); - const no_file = [null, undefined]; - return new Promise((resolve, reject) => { - return models - .sequelize - .transaction({ - isolationLevel: Sequelize.Transaction.ISOLATION_LEVELS.READ_COMMITTED - }, (t) => { - // separate tags proposal from existent tags in exercises - let exercises_with_tags_partition = exercises.map(exercise => { - // apart the tags field, nothing changes in the exercise object - return Object.assign({}, exercise, { - // here partition is necessary to separate existent tags from no existent yet - tags: partition(exercise.tags, obj => Number.isInteger(obj)) - }); - }); - - // collect all the tags to be inserted ( thanks to partition ) - // to prevent dummy insert, only takes unique elements - const all_tags_in_exercises = [].concat( - ...exercises_with_tags_partition.map(exercise => exercise.tags[1]) - ); - const tags_to_be_inserted = find_unique_tags(all_tags_in_exercises); - - // find possible match for not existent tags - return find_tag_matches(tags_to_be_inserted) - .then(result => { - const tag_dictionary = build_dictionary_for_matching_process(result); - const reduced_dictionary = dictionary_for_similarity(tag_dictionary); - return matching_process2(tags_to_be_inserted, tag_dictionary, reduced_dictionary); - }).then( - ([existent_tags, really_new_tags]) => { - return Promise.all([ - Promise.resolve(existent_tags), - // insert new tags and retrieve ids - models - .Tag - .bulkCreate( - really_new_tags.map(tag => { - return { - // by default, creating tags like that should be reviewed - // (except if it is created by an admin) - state: (tag.hasOwnProperty("state")) ? tag.state : tagState.PENDING, - text: tag.text, - category_id: tag.category_id, - // some timestamps must be inserted - updatedAt: creationDate, - createdAt: creationDate - } - }), - { - transaction: t, - returning: ["id", "text", "category_id"] - } - ) - ]) - } - ).then(([existent_tags, inserted_tags]) => { - // now time to bind inserted tags with their exercise - // merge both array for reconciliation - let tags_dictionary = build_dictionary_for_matching_process(existent_tags.concat(...inserted_tags)); - const exercises_with_tags = reconcile_exercises_with_tags(exercises_with_tags_partition, tags_dictionary); - // Finally bulk insert all of these - return Promise.all(exercises_with_tags.map( - // I don't use the really new tags here since in bulk insert, - // we may have the same new tag to insert : This is handled above - ([exercise, tags]) => { - return store_single_exercise( - user, - exercise, - tags, - [], - t - ); - }) - ); - }); - }).then((_) => { - // OK work as expected - resolve() - }).catch(/* istanbul ignore next */ - err => { - const files_to_be_deleted = exercises - .filter((exercise) => !no_file.includes(exercise.file)) - .map(exercise => exercise.file); - - fileManager - .delete_temp_files(files_to_be_deleted) - .then(() => reject(err)); - }); - }); - } -}; - -// private functions here -// where condition builder for tag matching process -const conditionBuilder = (array_data) => ({ - [Op.or]: array_data.map(tag => ({ - [Op.and]: [ - Sequelize.where( - Sequelize.col("category_id"), - Op.eq, - tag.category_id - ), - Sequelize.where( - Sequelize.fn("LOWER", Sequelize.col("text")), - Op.eq, - tag.text.toLowerCase() - ) - ] - })) -}); - -// to create the dictionary used for matching_process -function build_dictionary_for_matching_process(result_in_db) { - // set up structure for matching - let tag_dictionary = groupBy(result_in_db, "text"); - Object.keys(tag_dictionary).forEach(item => { - tag_dictionary[item] = groupBy(tag_dictionary[item], "category_id"); - }); - return tag_dictionary; -} - -// to store a single exercise -function store_single_exercise(user, exercise_data, existent_tags, really_new_tags, t) { - // create exercise and new tags together - const creationDate = new Date(); - // data to be inserted - let exerciseData = { - title: exercise_data.title, - description: exercise_data.description /* istanbul ignore next */ || "", - user_id: user.id, - // some timestamps must be inserted - updatedAt: creationDate, - createdAt: creationDate, - // optional properties to add - url: exercise_data.url || null, - file: (exercise_data.file !== null) ? exercise_data.file.filename : null, - state: (exercise_data.state) ? exerciseState[exercise_data.state] : exerciseState.DRAFT - }; - - return new Promise((resolve, reject) => { - Promise.all( - [ - // if a file was provided, we must be able to store it - (exercise_data.file !== null) - ? fileManager.move_file_to_destination_folder(exercise_data.file) - : Promise.resolve(), - // create the exercise with given information - models - .Exercise - .create( - exerciseData, - { - transaction: t, - returning: ["id"] - } - ) - , - // bulky create the new tags into the systems - models - .Tag - .bulkCreate( - really_new_tags.map(tag => { - return { - // by default, creating tags like that should be reviewed - // (except if it is created by an admin) - state: (tag.hasOwnProperty("state")) ? tag.state : tagState.PENDING, - text: tag.text, - category_id: tag.category_id, - // some timestamps must be inserted - updatedAt: creationDate, - createdAt: creationDate - } - }), - { - transaction: t, - returning: ["id"] - } - ) - ]) - .then(([_, exercise, tags]) => { - // add the newly created tags ids to array so that I can bulk insert easily - const all_tags_ids = existent_tags.concat( - tags.map(tag => tag.id) - ); - return models - .Exercise_Tag - .bulkCreate( - all_tags_ids.map(tag => ({ - tag_id: tag, - exercise_id: exercise.id - })), - { - transaction: t - } - ) - }) - .then((result) => resolve(result)) - .catch(/* istanbul ignore next */(err) => { - - // delete uploaded file in storage folder - // let the middleware destroy the file in temp folder - const storedFile = (exercise_data.file !== null) ? [exercise_data.file.filename] : []; - fileManager - .delete_stored_files(storedFile) - .then(() => reject(err)); - }) - }); -} - -// Promise to retrieve possible matches for new tag -function find_tag_matches(new_tags) { - return new Promise((resolve, reject) => { - // no need to query DB if no new - if (new_tags.length === 0) { - resolve([]); - } else { - // query database to find possible match before creating new tags - models - .Tag - .findAll({ - attributes: [ - "id", - [Sequelize.fn("LOWER", Sequelize.col("text")), "text"], - "category_id" - ], - where: conditionBuilder(new_tags) - }) - .then(result => resolve(result)) - .catch(/* istanbul ignore next */ - err => reject(err)) - } - }) -} - -// Promise that try to match new_tags with the result in DB -// As I only -function matching_process(already_present_tags, new_tags, tag_dictionary) { - return new Promise(resolve => { - // I must rely on my function to correctly find a good match for tag - const reduced_dictionary = dictionary_for_similarity(tag_dictionary); - const [has_match, no_match] = super_matching_process(new_tags, tag_dictionary, reduced_dictionary); - resolve([ - // Using a Set to prevent duplicate entries ( very rare case that could occur in some scenarios ) - [...new Set( - already_present_tags.concat( - ...has_match.map(tag => tag.id) - ) - )], - no_match - ]); - }); -} - -// ONLY FOR BULK INSERT, we need a mutated version of the matching_process -// As we need all the information for later, I cannot use only ID like the original version -function matching_process2(new_tags, tag_dictionary, reduced_dictionary) { - return new Promise(resolve => { - // do the matching process here - const [has_match, no_match] = super_matching_process(new_tags, tag_dictionary, reduced_dictionary); - resolve( - [ - has_match, - no_match - ] - ); - }); -} - -// Dictionary to handle similar tag contents -function dictionary_for_similarity(tag_dictionary) { - return Object - .entries(tag_dictionary) - .map(([key, values]) => ({ - "original_key": key, - "lower_key": key.toLowerCase(), - "categories": Object.keys(values) - }) - ); -} - -// To find similar tags and match them -// to handle multiple case, we need the real keys of the dictionary and the categories linked to that name -// reduced_dictionary should be dictionary_for_similarity(tag_dictionary) -// PS: I pass that by argument because of multiple exercise ( recreates n times the same time is a performance issue ) -function super_matching_process(new_tags, tag_dictionary, reduced_dictionary) { - // try to find matches - const new_tags_with_maybe_the_existent_tag = new_tags.map( - tag => { - const maybeAKeyMatch = reduced_dictionary.find(t => { - return isEqual(tag.text.toLowerCase(), t.lower_key) && t.categories.includes(tag.category_id.toString()) - }); - - // Handle both cases : if we found a match or not - return [ - maybeAKeyMatch !== undefined, - (maybeAKeyMatch !== undefined) - ? tag_dictionary[maybeAKeyMatch.original_key][tag.category_id][0] - : tag - ]; - } - ); - // Does something similar to partition method of Lodash but here I have no choice ^^ - return new_tags_with_maybe_the_existent_tag.reduce((acc, curr) => { - const index = (curr[0] === true) ? 0 : 1; - acc[index] = acc[index].concat(curr[1]); - return acc; - }, [[], []]); -} - -// for bulky insert, we need a function close to matching_process but adapted to this situation -// since it is required to have a match for each tags, we could simplify that -function reconcile_exercises_with_tags(exercises_with_tags_partition, tag_dictionary) { - // useful for later - const reduced_dictionary = dictionary_for_similarity(tag_dictionary); - - return exercises_with_tags_partition.map(exercise => { - // concat the existent tags with newly created - const uniqTags = find_unique_tags(exercise.tags[1]); - const [has_match, _no_match] = super_matching_process(uniqTags, tag_dictionary, reduced_dictionary); - - const found_matches = has_match.map(tag => tag.id); - - const tags = exercise.tags[0].concat( - // We must handle the case where a similar text already exist in database (but not the same typo ) - // Thanks to super_matching_process and previous pre/post conditions, every tag will have a match - // and an id - ...found_matches - ); - return [exercise, tags]; - }); -} - -// To find unique tags given in an array -function find_unique_tags(tags_array) { - return uniqWith( - tags_array, - (tag1, tag2) => { - // the perfect case (but life isn't perfect ^^) - /* istanbul ignore if */ - if (isEqual(tag1, tag2)) { - return true; - } else { - // similar tag : same category but different case ("c" and "C") - - return tag1.category_id === tag2.category_id - && isEqual(tag1.text.toLowerCase(), tag2.text.toLowerCase()); - } - } - ); -} - -// For UPDATE / DELETE operations on exercises, we must verify that user is allowed to do that -function check_credentials_on_exercises({role, id}, exercises_ids) { - return new Promise((resolve, reject) => { - if ([userRoles.ADMIN, userRoles.SUPER_ADMIN].includes(role)) { - resolve(); - } else { - models - .Exercise - .findAll({ - attributes: [[Sequelize.fn('DISTINCT', Sequelize.col('user_id')), 'user']], - where: { - id: { - [Op.in]: exercises_ids - } - } - }, { - rejectOnEmpty: true - }) - .then((exercises_creators) => { - const all_from_this_user = exercises_creators - .map(creator => creator.get("user")) - .every((creator) => creator === id); - // I don't want to create a complete test case just for that - /* istanbul ignore if */ - if (all_from_this_user) { - resolve(); - } else { - let error = new Error("FORBIDDEN"); - error.message = "It seems you tried to update / delete somebody else exercise(s) : " + - "This incident will be reported"; - error.status = 403; - reject(error); - } - }) - .catch(/* istanbul ignore next */ - (err) => reject(err)); - } - }) -} diff --git a/controllers/auth.js b/controllers/auth.js deleted file mode 100644 index 3289c8b..0000000 --- a/controllers/auth.js +++ /dev/null @@ -1,16 +0,0 @@ -const login = require("./auth/login"); -const register = require("./auth/register"); -const verify = require("./auth/verify"); - -module.exports = function () { - // useful for Dependency Injection - // https://byu-oit.github.io/openapi-enforcer-middleware/guide/controllers#dependency-injection - const controller = {}; - - // add endpoints - controller.register = register; - controller.signIn = login; - controller.verify = verify; - - return controller; -}; \ No newline at end of file diff --git a/controllers/auth/login.js b/controllers/auth/login.js deleted file mode 100644 index cb4310c..0000000 --- a/controllers/auth/login.js +++ /dev/null @@ -1,19 +0,0 @@ -const jwt = require('jsonwebtoken'); - -module.exports = function (req, res) { - // For more information : http://www.passportjs.org/docs/authenticate/ - // `req.user` contains the authenticated user. - res.send({ - token: jwt.sign( - { - id: req.user.id - }, - process.env.SECRET_PHRASE || "Super secured passphrase", - { expiresIn: process.env.TOKEN_TTL || '1h' } - ), - user: { - role: req.user.role, - fullName: req.user.fullName - } - }); -}; diff --git a/controllers/auth/register.js b/controllers/auth/register.js deleted file mode 100644 index 684dc91..0000000 --- a/controllers/auth/register.js +++ /dev/null @@ -1,33 +0,0 @@ -const models = require('../../models'); -const Sequelize = require("sequelize"); -const {USERS} = require("../_common/constants"); - -module.exports = function (req, res, next) { - models - .User - .findAll({ - attributes: [Sequelize.literal(1)], - where: { - role: USERS.SUPER_ADMIN - }, - limit: 1 - }).then(hasAAdmin => { - const user_role = (hasAAdmin.length === 0) ? USERS.SUPER_ADMIN : USERS.USER; - return models - .User - .create({ - email: req.body.email, - password: req.body.password, - role: user_role, - fullName: req.body.fullName - }, { - returning: false // no need to retrieve the created item as we simply care about insert - }); - }).then(() => { - res.status(200).end() // see - }).catch(err => { - // changes the error as it already exist - err.status = 409; - next(err) - }); -}; diff --git a/controllers/auth/verify.js b/controllers/auth/verify.js deleted file mode 100644 index 07e92a2..0000000 --- a/controllers/auth/verify.js +++ /dev/null @@ -1,17 +0,0 @@ -const jwt = require('jsonwebtoken'); - -module.exports = function (req, res, next) { - - jwt.verify( - req.body.token, - process.env.SECRET_PHRASE || "Super secured passphrase", - (err, _) => { - if (err) { - next(err); - } else { - res.status(200).end(); - } - } - ) - -}; diff --git a/controllers/bulk.js b/controllers/bulk.js deleted file mode 100644 index f451ead..0000000 --- a/controllers/bulk.js +++ /dev/null @@ -1,24 +0,0 @@ -const createOrFindTagCategories = require("./bulk/createOrFindTagCategories"); -const createMultipleExercises = require("./bulk/createMultipleExercises"); -const createMultipleTags = require("./bulk/createMultipleTags"); -const DeleteExercises = require("./bulk/DeleteExercises"); -const ChangeExercisesStatus = require("./bulk/ChangeExercisesStatus"); -const DeleteTagCategories = require("./bulk/DeleteTagCategories"); -const DeleteTags = require("./bulk/DeleteTags"); - -module.exports = function () { - // useful for Dependency Injection - // https://byu-oit.github.io/openapi-enforcer-middleware/guide/controllers#dependency-injection - const controller = {}; - - // add endpoints - controller.createOrFindTagCategories = createOrFindTagCategories; - controller.createMultipleExercises = createMultipleExercises; - controller.createMultipleTags = createMultipleTags; - controller.DeleteExercises = DeleteExercises; - controller.ChangeExercisesStatus = ChangeExercisesStatus; - controller.DeleteTagCategories = DeleteTagCategories; - controller.DeleteTags = DeleteTags; - - return controller; -}; \ No newline at end of file diff --git a/controllers/bulk/ChangeExercisesStatus.js b/controllers/bulk/ChangeExercisesStatus.js deleted file mode 100644 index 75ddd93..0000000 --- a/controllers/bulk/ChangeExercisesStatus.js +++ /dev/null @@ -1,39 +0,0 @@ -const models = require('../../models'); -const Promise = require("bluebird"); - -const Sequelize = require("sequelize"); -const Op = Sequelize.Op; - -module.exports = function (req, res, next) { - - const state = req.body.state; - - return models - .sequelize - .transaction({ - isolationLevel: Sequelize.Transaction.ISOLATION_LEVELS.READ_COMMITTED - }, (t) => { - return models - .Exercise - .findAll({ - where: { - id: { - [Op.in]: req.body.exercises - } - } - }, { - transaction: t - }).then((exercises) => { - return Promise.all( - exercises.map( (exercise) => exercise.update({ - state: state - }, { - transaction: t - })) - ); - }); - }) - .then((_) => res.status(200).end()) - .catch(/* istanbul ignore next */ - (err) => next(err)); -}; \ No newline at end of file diff --git a/controllers/bulk/DeleteExercises.js b/controllers/bulk/DeleteExercises.js deleted file mode 100644 index 467594d..0000000 --- a/controllers/bulk/DeleteExercises.js +++ /dev/null @@ -1,65 +0,0 @@ -const Promise = require("bluebird"); -const Sequelize = require("sequelize"); -const Op = Sequelize.Op; - -const models = require('../../models'); -const fileManager = require("../_common/files_manager"); - -module.exports = function (req, res, next) { - - return delete_exercises(req.body) - .then(([files, _]) => { - fileManager - .delete_stored_files(files) - .then(() => res.status(200).end()); - }) - .catch(/* istanbul ignore next */ - (err) => next(err)); -}; - -function delete_exercises(exercises_ids) { - // transaction here as if anything bad happens, we don't commit that to database - // Here we need the serializable level because we should be able to prevent an user - // to modify one of these exercises while we deleted them - return models - .sequelize - .transaction({ - isolationLevel: Sequelize.Transaction.ISOLATION_LEVELS.SERIALIZABLE - }, (t) => { - // first step : retrieve all stored files (if any) - return models - .Exercise - .findAll({ - attributes: ["file"], - where: { - file: { - [Op.ne]: null - }, - id: { - [Op.in]: exercises_ids - } - } - }, { - transaction: t - }).then((files) => { - return Promise.all([ - // return the filenames that should be deleted - Promise.resolve( - files.map(file => file.file) - ), - // delete exercises (and everything else related too) - models - .Exercise - .destroy({ - force: true, // even if it is in paranoid mode ;) - transaction: t, - where: { - id: { - [Op.in]: exercises_ids - } - } - }) - ]); - }); - }); -} diff --git a/controllers/bulk/DeleteTagCategories.js b/controllers/bulk/DeleteTagCategories.js deleted file mode 100644 index 4cb8f24..0000000 --- a/controllers/bulk/DeleteTagCategories.js +++ /dev/null @@ -1,61 +0,0 @@ -const models = require('../../models'); -const Sequelize = require("sequelize"); -const Op = Sequelize.Op; - -module.exports = function (req, res, next) { - - // transaction here as if anything bad happens, we don't commit that to database - return models - .sequelize - .transaction({ - isolationLevel: Sequelize.Transaction.ISOLATION_LEVELS.SERIALIZABLE - }, (t) => { - // first remove ExerciseTag rows to trigger hook - return models - .Tag - .findAll({ - attributes: [ - "id" - ], - where: { - category_id: { - [Op.in]: req.body - } - }, - transaction: t - }) - .then((rows) => { - // extract tags ids - return Promise.resolve(rows.map(r => r.get("id"))); - }) - .then((tags_ids) => { - return models - .Exercise_Tag - .destroy({ - transaction: t, - where: { - tag_id: { - [Op.in]: tags_ids - } - } - }) - }) - .then(() => { - // Finally remove the category with force ( so drop cascade ) - return models - .Tag_Category - .destroy({ - force: true, // even if it is in paranoid mode ;) - transaction: t, - where: { - id: { - [Op.in]: req.body - } - } - }); - }); - }) - .then(() => res.status(200).end()) - .catch(/* istanbul ignore next */ - (err) => next(err)); -}; \ No newline at end of file diff --git a/controllers/bulk/DeleteTags.js b/controllers/bulk/DeleteTags.js deleted file mode 100644 index 8230286..0000000 --- a/controllers/bulk/DeleteTags.js +++ /dev/null @@ -1,41 +0,0 @@ -const models = require('../../models'); -const Sequelize = require("sequelize"); -const Op = Sequelize.Op; - -module.exports = function (req, res, next) { - - // transaction here as if anything bad happens, we don't commit that to database - return models - .sequelize - .transaction({ - isolationLevel: Sequelize.Transaction.ISOLATION_LEVELS.SERIALIZABLE - }, (t) => { - return models - .Exercise_Tag - .destroy({ - transaction: t, - where: { - tag_id: { - [Op.in]: req.body - } - } - }) - .then(() => { - // Finally remove the tags with force ( so drop cascade ) - return models - .Tag - .destroy({ - force: true, // even if it is in paranoid mode ;) - transaction: t, - where: { - id: { - [Op.in]: req.body - } - } - }) - }); - }) - .then(() => res.status(200).end()) - .catch(/* istanbul ignore next */ - (err) => next(err)); -}; \ No newline at end of file diff --git a/controllers/bulk/createMultipleExercises.js b/controllers/bulk/createMultipleExercises.js deleted file mode 100644 index f7ed19b..0000000 --- a/controllers/bulk/createMultipleExercises.js +++ /dev/null @@ -1,77 +0,0 @@ -const { - bulky_store_exercises -} = require("../_common/utlis_fct"); -const del = require('del'); - -module.exports = function (req, res, next) { - - // to handle both cases (depending of the content type) - const {exercises, unmatched_files} = handle_both_content_type(req); - - // delete unused files first , and after bulk insert - del(unmatched_files) - .then(() => bulky_store_exercises(req.user, exercises)) - .then((_) => res.status(200).end()) - .catch(/* istanbul ignore next */ - (err) => next(err)); - -}; - -// as this endpoint has different schemas for content-type, I need this method for a clean code -function handle_both_content_type(req) { - // content-type is json : the most simple case (no files to store ) - if (req.is('json')) { - return { - // to delete directly files that shouldn't be add as there is n - "unmatched_files": [], - // exercises with their file (here as we have - "exercises": req.body.map(exercise => Object.assign({}, exercise, {file: null})) - } - } else { - // multipart/form-data : the most horrible case ( at least one files to add ) - - // mapping between uploaded filename and exercise - const filesMapping = arrayToObject(req.body.filesMapping, "exercise"); - // map that uses "filename" as key and file - const files = arrayToObject(req.files.files, "originalname"); - - // exercises with(out) file - const exercises = req.body.exercisesData.map((exercise, index) => { - // By default, consider that the exercise has no file attached - let addFile = {"file": null}; - - // if a file exists for this exercise, add it - if (filesMapping.hasOwnProperty(index)) { - // use the original name as it is the name given by uploader - const original_name = filesMapping[index].filename; - addFile["file"] = files[original_name]; - } - - return Object.assign({}, exercise, addFile); - }); - - // It might be possible the uploader has send file(s) we couldn't match : delete them without mercy - // ( to save storage folder space ) - - const matched_files = exercises - .filter(e => e.hasOwnProperty("file") && e.file !== null) - .map(e => e.file.originalname); - - // It will work but I don't want to test that ;) - /* istanbul ignore next */ - const unmatched_files = req.files.files - .filter(f => !matched_files.includes(f.originalname)) - .map(f => f.path); - - return { - "unmatched_files": unmatched_files, - "exercises": exercises - } - } - -} - -// Thanks to Taq Karim , this one line -// https://medium.com/dailyjs/rewriting-javascript-converting-an-array-of-objects-to-an-object-ec579cafbfc7 -/* istanbul ignore next */ -const arrayToObject = (arr, keyField) => Object.assign({}, ...arr.map(item => ({[item[keyField]]: item}))); \ No newline at end of file diff --git a/controllers/bulk/createMultipleTags.js b/controllers/bulk/createMultipleTags.js deleted file mode 100644 index db428d5..0000000 --- a/controllers/bulk/createMultipleTags.js +++ /dev/null @@ -1,57 +0,0 @@ -const models = require('../../models'); -const Sequelize = require("sequelize"); - -const {TAGS: TagState} = require("../_common/constants"); - -// to prevent duplicates in database -const { - find_tag_matches, - build_dictionary_for_matching_process, - matching_process -} = require("../_common/utlis_fct"); - -module.exports = (req, res, next) => { - const creationDate = new Date(); - - // find the tags that really doesn't exist in database - return find_tag_matches(req.body) - .then(result => { - // try to match them - const tag_dictionary = build_dictionary_for_matching_process(result); - return matching_process([], req.body, tag_dictionary); - }) - .then( - ([_, really_new_tags]) => { - // bulky create the new tags into the systems - return models - .sequelize - .transaction({ - isolationLevel: Sequelize.Transaction.ISOLATION_LEVELS.READ_COMMITTED - }, (t) => { - return models - .Tag - .bulkCreate( - really_new_tags.map(tag => { - return { - // if admin has set explicitly the isValidated - state: (tag.hasOwnProperty("state")) - ? TagState[tag.state] - : TagState.PENDING, - text: tag.text, - category_id: tag.category_id, - // some timestamps must be inserted - updatedAt: creationDate, - createdAt: creationDate - } - }), - { - transaction: t - } - ); - }) - } - ) - .then(() => res.status(200).end()) - .catch(/* istanbul ignore next */ - err => next(err)); -}; diff --git a/controllers/bulk/createOrFindTagCategories.js b/controllers/bulk/createOrFindTagCategories.js deleted file mode 100644 index c4516e2..0000000 --- a/controllers/bulk/createOrFindTagCategories.js +++ /dev/null @@ -1,44 +0,0 @@ -const models = require('../../models'); -const Promise = require("bluebird"); - -module.exports = function (req, res, next) { - Promise.all( - req.body.map(tag_category => { - return models - .Tag_Category - .findOrCreate({ - where: findOrCreateCategory(tag_category) - }) - }) - ).then(results => { - // As explained in docs, it return something like [instance, isCreated] - // https://sequelize.org/master/class/lib/model.js~Model.html#static-method-findOrCreate - // I just need the instance - res.send(results.map(result => ({ - id: result[0].id, - category: result[0].kind - }))); - }).catch(/* istanbul ignore next */ - err => next(err)); -}; - -// credits to https://webbjocke.com/javascript-check-data-types/#javascript-string -const isString = (value) => typeof value === 'string' /* istanbul ignore next */ || value instanceof String; - -// Generate where conditions -// TODO handle case with sub category LATER -function findOrCreateCategory(tag_category) { - // default case - /* istanbul ignore next */ - if (isString(tag_category)) { - return { - kind: tag_category - } - } else { - // Complex case - return { - kind: tag_category.text, - parent_category: tag_category.category - } - } -} \ No newline at end of file diff --git a/controllers/configurations.js b/controllers/configurations.js deleted file mode 100644 index 7d97b68..0000000 --- a/controllers/configurations.js +++ /dev/null @@ -1,18 +0,0 @@ -const CreateConfiguration = require("./configurations/createConfiguration"); -const FetchOwnConfigurations = require("./configurations/fetchOwnConfigurations"); -const UpdateConfiguration = require("./configurations/updateConfiguration"); -const DeleteConfiguration = require("./configurations/deleteConfiguration"); - -module.exports = function () { - // useful for Dependency Injection - // https://byu-oit.github.io/openapi-enforcer-middleware/guide/controllers#dependency-injection - const controller = {}; - - // add endpoints - controller.CreateConfiguration = CreateConfiguration; - controller.FetchOwnConfigurations = FetchOwnConfigurations; - controller.UpdateConfiguration = UpdateConfiguration; - controller.DeleteConfiguration = DeleteConfiguration; - - return controller; -}; \ No newline at end of file diff --git a/controllers/configurations/createConfiguration.js b/controllers/configurations/createConfiguration.js deleted file mode 100644 index c577d3d..0000000 --- a/controllers/configurations/createConfiguration.js +++ /dev/null @@ -1,37 +0,0 @@ -const models = require('../../models'); -const Sequelize = require("sequelize"); - -module.exports = (req, res, next) => { - // transaction here as if anything bad happens, we don't commit that to database - return models - .sequelize - .transaction({ - isolationLevel: Sequelize.Transaction.ISOLATION_LEVELS.READ_COMMITTED - }, (t) => { - return models - .Configuration - .create({ - user_id: req.user.id, - name: req.body.name, - title: req.body.title /* istanbul ignore next */ || "" - }, { - transaction: t - }) - .then(configuration => { - return models - .Configuration_Tag - .bulkCreate( - (req.body.tags || []) - .map(tag => ({ - tag_id: tag, - configuration_id: configuration.id - })), { - transaction: t - } - ); - }); - }) - .then(() => res.status(200).end()) - .catch(/* istanbul ignore next */ - err => next(err)); -}; \ No newline at end of file diff --git a/controllers/configurations/deleteConfiguration.js b/controllers/configurations/deleteConfiguration.js deleted file mode 100644 index d8bea6e..0000000 --- a/controllers/configurations/deleteConfiguration.js +++ /dev/null @@ -1,25 +0,0 @@ -const models = require('../../models'); -const Sequelize = require("sequelize"); - -module.exports = (req, res, next) => { - // transaction here as if anything bad happens, we don't commit that to database - return models - .sequelize - .transaction({ - isolationLevel: Sequelize.Transaction.ISOLATION_LEVELS.READ_COMMITTED - }, (t) => { - return models - .Configuration - .destroy({ - force: true, // even if it is in paranoid mode ;) - transaction: t, - where: { - "user_id" : req.user.id, - "id": req.body.id - } - }) - }) - .then(() => res.status(200).end()) - .catch(/* istanbul ignore next */ - err => next(err)); -}; \ No newline at end of file diff --git a/controllers/configurations/fetchOwnConfigurations.js b/controllers/configurations/fetchOwnConfigurations.js deleted file mode 100644 index 181766e..0000000 --- a/controllers/configurations/fetchOwnConfigurations.js +++ /dev/null @@ -1,65 +0,0 @@ -const models = require('../../models'); -const Sequelize = require("sequelize"); -const Op = Sequelize.Op; - -module.exports = (req, res, next) => { - const params = req.query; - const ids = params["ids"] || []; - - const tagAttributes = [ - ["id", "tag_id"], - ["text", "tag_text"], - "category_id", - "state", - "version" - ]; - - let whereConditions = []; - // at least fetch only the ones for users - whereConditions.push({ - user_id: req.user.id - }); - - if (ids.length > 0) { - whereConditions.push({ - id: { - [Op.in]: ids - } - }) - } - - return models - .Configuration - .findAll({ - attributes: { - exclude: ["user_id"] - }, - include: [{ - model: models.Tag, - as: "Tags", - attributes: tagAttributes, - through: { - attributes: [] - }, - required: false, - }], - where: Object.assign({}, ...whereConditions), - order: [ - ["id", "ASC"] - ] - }) - .then(configurations => - res.send( - configurations.map( - configuration => ({ - name: configuration.get("name"), - title: configuration.get("title"), - id: configuration.get("id"), - tags: configuration.get("Tags").map(tag => tag.toJSON()) - }) - ) - ) - ) - .catch(/* istanbul ignore next */ - err => next(err)); -}; diff --git a/controllers/configurations/updateConfiguration.js b/controllers/configurations/updateConfiguration.js deleted file mode 100644 index a9dfa39..0000000 --- a/controllers/configurations/updateConfiguration.js +++ /dev/null @@ -1,58 +0,0 @@ -const models = require('../../models'); -const Sequelize = require("sequelize"); - -module.exports = (req, res, next) => { - // transaction here as if anything bad happens, we don't commit that to database - return models - .sequelize - .transaction({ - isolationLevel: Sequelize.Transaction.ISOLATION_LEVELS.READ_COMMITTED - }, (t) => { - return models - .Configuration - .findAll({ - where: { - user_id: req.user.id, - id: req.body.id - }, - transaction: t, - rejectOnEmpty: true - }) - .then(([configuration]) => { - return Promise.all([ - // update this row with new values - configuration.update({ - name: req.body.name, - title: req.body.title /* istanbul ignore next */ || "" - }, { - transaction: t - }), - // delete old rows - // here we don't care about performance ^^ - models - .Configuration_Tag - .destroy({ - where: { - configuration_id: configuration.id - }, - transaction: t - }) - ]) - .then(() => { - return models - .Configuration_Tag - .bulkCreate( - (req.body.tags /* istanbul ignore next */ || []) - .map(tag => ({ - tag_id: tag, - configuration_id: configuration.id - })), { - transaction: t - }); - }); - }); - }) - .then(() => res.status(200).end()) - .catch(/* istanbul ignore next */ - err => next(err)); -}; \ No newline at end of file diff --git a/controllers/exercises.js b/controllers/exercises.js deleted file mode 100644 index 90f378b..0000000 --- a/controllers/exercises.js +++ /dev/null @@ -1,22 +0,0 @@ -const getExerciseByID = require("./exercises/getExerciseByID"); -const UpdateExercise = require("./exercises/updateExercise"); -const createSingleExercise = require("./exercises/createSingleExercise"); -const searchExercises = require("./exercises/searchExercises"); -const voteForExercise = require("./exercises/voteForExercise"); -const ExportExercises = require("./exercises/exportExercises"); - -module.exports = function () { - // useful for Dependency Injection - // https://byu-oit.github.io/openapi-enforcer-middleware/guide/controllers#dependency-injection - const controller = {}; - - // add endpoints - controller.getExerciseByID = getExerciseByID; - controller.UpdateExercise = UpdateExercise; - controller.createSingleExercise = createSingleExercise; - controller.searchExercises = searchExercises; - controller.voteForExercise = voteForExercise; - controller.ExportExercises = ExportExercises; - - return controller; -}; diff --git a/controllers/exercises/createSingleExercise.js b/controllers/exercises/createSingleExercise.js deleted file mode 100644 index b283e4c..0000000 --- a/controllers/exercises/createSingleExercise.js +++ /dev/null @@ -1,45 +0,0 @@ -const partition = require('lodash.partition'); - -// delegate tag matching process to specialized functions -const { - find_tag_matches, - matching_process, - build_dictionary_for_matching_process, - store_single_exercise -} = require("../_common/utlis_fct"); - - -module.exports = function (req, res, next) { - - // distinguish already present tags from new tags - const [already_present_tags, new_tags] = partition(req.body.tags, obj => Number.isInteger(obj)); - - // did the user provide us a file to store ? - const file = (req.files && req.files.exerciseFile) ? req.files.exerciseFile : null; - - // find tag matches for new_tags if already existing - find_tag_matches(new_tags) - .then(result => { - // try to match them - const tag_dictionary = build_dictionary_for_matching_process(result); - return matching_process(already_present_tags, new_tags, tag_dictionary); - }) - .then( - ([existent_tags, really_new_tags]) => { - return store_single_exercise( - req.user, - Object.assign({}, req.body, { - file: file - } - ), - existent_tags, - really_new_tags - ); - } - ) - .then(() => { - res.status(200).end() - }) - .catch(/* istanbul ignore next */ - err => next(err)); -}; \ No newline at end of file diff --git a/controllers/exercises/exportExercises.js b/controllers/exercises/exportExercises.js deleted file mode 100644 index 057979b..0000000 --- a/controllers/exercises/exportExercises.js +++ /dev/null @@ -1,47 +0,0 @@ -const models = require('../../models'); -const Promise = require("bluebird"); - -module.exports = (req, res, next) => { - - // parameters for exports - const parameters = req.body; - - // scopes for export - let exercise_scopes = [ - // handle the filtering - {method: ["find_exercises_ids_with_given_criteria", {"parameters": parameters}]}, - // include the tags - {method: ["with_related_tags", parameters.filterOptions]}, - // default attributes for bulk select - "default_attributes_for_bulk", - ]; - - // handle sorting - /* istanbul ignore else */ - if (Array.isArray(parameters.orderBy)) { - exercise_scopes.push({ - method: ["orderByClauses", parameters.orderBy] - }) - } - - return Promise.all([ - // tag categories as an object - models - .Tag_Category - .scope("allTagsCategoriesAsObject") - .findAll(), - // exercises with relevant scope - models - .Exercise - .scope(exercise_scopes) - .findAll(), - ]).then(([[tagCategories], exercises]) => { - const result = Object.assign( - {}, - tagCategories.toJSON(), - {"exercises": exercises.map(ex => ex.toJSON())} - ); - res.send(result); - }).catch(/* istanbul ignore next */ - err => next(err)); -}; diff --git a/controllers/exercises/getExerciseByID.js b/controllers/exercises/getExerciseByID.js deleted file mode 100644 index bdae610..0000000 --- a/controllers/exercises/getExerciseByID.js +++ /dev/null @@ -1,70 +0,0 @@ -// function for bulky inner select -const models = require('../../models'); -const {build_search_result} = require("../_common/utlis_fct"); -const {EXERCISES: exerciseState, USERS: userRoles} = require("../_common/constants"); - -module.exports = (req, res, next) => { - - const id = parseInt(req.params.id, 10); - // query parameters - const options = (req.query["includeOptions"]) ? req.query["includeOptions"] : undefined; - - // check if id exist in database - return models - .Exercise - .findByPk(id, { - attributes: [ - ["user_id", "user"], - ["state", "state"] - ], - rejectOnEmpty: true - }).then((result) => { - return new Promise((resolve, reject) => { - // If exercise is ARCHIVED and this exercise was not access by its creator or admin, - // a HTTP error should occur - const authorizedUsers = [userRoles.ADMIN, userRoles.SUPER_ADMIN]; - if (result.get("state") === exerciseState.ARCHIVED) { - const passCriteria = [ - req.user && authorizedUsers.includes(req.user.role), - req.user && !authorizedUsers.includes(req.user.role) && result.get("user") === req.user.id, - ]; - if (passCriteria.includes(true)) { - resolve(); - } else { - let error = new Error("GONE"); - error.message = "This exercise was archived and thus no more publicly visible"; - error.status = 410; - reject(error); - } - } else { - resolve(); - } - }); - }).then((_) => { - // If we have a user, we should try to fetch its vote for this exercise - return Promise.all([ - build_search_result([id], options, req.query), - (req.user) ? models.Notation.findAll({ - attributes: [ - ["note", "vote"] - ], - where: { - "exercise_id": id, - "user_id": req.user.id - } - }) : [] - ]); - }).then(([data, vote]) => { - // data is an array : I just need the first item - return res.send( - (vote.length === 0) - ? data[0] - : Object.assign({}, data[0], { - vote: Number(vote[0].get("vote")) - }) - ); - }).catch(err => { - next(err); - }) - -}; diff --git a/controllers/exercises/searchExercises.js b/controllers/exercises/searchExercises.js deleted file mode 100644 index caf4918..0000000 --- a/controllers/exercises/searchExercises.js +++ /dev/null @@ -1,91 +0,0 @@ -const models = require('../../models'); -const Promise = require("bluebird"); - -// function for bulky inner select -const build_search_result = require("../_common/utlis_fct").build_search_result; - -// Default limit in this endpoint -const METADATA = { - page: 1, - size: 10 -}; - -// return ids of exercises that match -function find_exercises_ids_with_given_criteria(parameters, metadata) { - - let exercise_scopes = []; - - // handle the filtering here - exercise_scopes.push({ - method: ["find_exercises_ids_with_given_criteria", {parameters, metadata}] - }); - - // handle sorting - if (Array.isArray(parameters.orderBy)) { - exercise_scopes.push({ - method: ["orderByClauses", parameters.orderBy] - }) - } - - return models - .Exercise - .scope(exercise_scopes) - .findAndCountAll({ - attributes: ["id"] - }); -} - -// build the full result -function buildResult(params) { - const { - result: {count: totalItems, rows: exercise_ids}, - metadata: {page, size}, - } = params; - return new Promise((resolve, reject) => { - const ids = exercise_ids.map(exercise => exercise.id); - // if ids is a empty array, it is simple : empty array - if (ids.length === 0) { - resolve({ - metadata: { - currentPage: page, - pageSize: size, - totalItems: totalItems, - totalPages: Math.ceil(totalItems / size) - }, - data: [] - }) - } else { - build_search_result(ids, params["request"]["includeOptions"], params["request"]) - .then(data => { - resolve({ - metadata: { - currentPage: page, - pageSize: size, - totalItems: totalItems, - totalPages: Math.ceil(totalItems / size) - }, - data: data - }) - }).catch(/* istanbul ignore next */ - err => reject(err)); - } - - }); -} - -module.exports = function (req, res, next) { - - // merge page criteria - const updated_metadata = {...METADATA, ...(req.body.hasOwnProperty("metadata") ? req.body.metadata : {})}; - find_exercises_ids_with_given_criteria(req.body, updated_metadata) - .then(result => { - return buildResult({ - result: result, - metadata: updated_metadata, - request: req.body, - }); - }) - .then(result => res.send(result)) - .catch(/* istanbul ignore next */ - err => next(err)); -}; diff --git a/controllers/exercises/updateExercise.js b/controllers/exercises/updateExercise.js deleted file mode 100644 index f73cda6..0000000 --- a/controllers/exercises/updateExercise.js +++ /dev/null @@ -1,318 +0,0 @@ -const Promise = require("bluebird"); -const Sequelize = require("sequelize"); -const Op = Sequelize.Op; - -const partition = require('lodash.partition'); -const difference = require('lodash.difference'); - -const models = require('../../models'); -const filesManager = require("../_common/files_manager"); -const { - find_tag_matches, - build_dictionary_for_matching_process, - matching_process, -} = require("../_common/utlis_fct"); -const { EXERCISES: exerciseState, TAGS: tagState, USERS: usersRoles } = require("../_common/constants"); - -module.exports = (req, res, next) => { - - const id = parseInt(req.params.id, 10); - // distinguish already present tags from new tags - const [already_present_tags, new_tags] = partition(req.body.tags, obj => Number.isInteger(obj)); - - // did the user provide us a file to store ? - const exercise_data = Object.assign({}, req.body, { - file: (req.files && req.files.exerciseFile) ? req.files.exerciseFile : null - }); - - return find_exercise_tags_and_search_possible_new_tags_match( - [id, req.user, req.body.version, new_tags, already_present_tags] - ) - .then(result => compute_tag_changes(result)) - .then(([changes, tags_to_be_inserted]) => { - - // transaction here as if anything bad happens, we don't commit that to database - return models - .sequelize - .transaction({ - isolationLevel: Sequelize.Transaction.ISOLATION_LEVELS.READ_COMMITTED - }, (t) => { - // if new tags to insert, do that - // if not, do nothing - return insert_new_tags_if_there_is_at_least_one(tags_to_be_inserted, t) - .then((created_tags) => handle_all_cases_for_tags([id, changes, created_tags, t])) - .then(() => - update_exercise([ - id, - exercise_data, - t - ]) - ) - }) - }) - .then(() => { - // everything works as expected : tell that to user - res.status(200).end(); - }) - .catch(/* istanbul ignore next */ - err => { - const better_error = handle_upload_error(err); - next(better_error); - }) - -}; - -// some methods that made life easier with this hell of promise chaining -function find_exercise_tags_and_search_possible_new_tags_match([id, user, version, new_tags, already_present_tags]) { - - // an admin is allowed to modify whatever exercise but - // a user should only be allowed to change exercise metadata if he/she is the owner of that one - let whereOptions = []; - - whereOptions.push({ - id: id, - version: version - }); - - /* istanbul ignore next */ - if ( ![usersRoles.ADMIN, usersRoles.SUPER_ADMIN].includes(user.role) ) { - whereOptions.push({ - user_id: user.id - }) - } - - - return Promise.all([ - // Find current exercise version with its tags - models - .Exercise - .findAll({ - attributes: ["id"], - where: Object.assign({}, ...whereOptions), - include: [ - { - model: models.Exercise_Tag, - as: "tag_entries", - require: true, - attributes: [ - "tag_id" - ] - } - ], - rejectOnEmpty: true - }), - // Find possible match for new tag(s) - find_tag_matches(new_tags) - .then(result => { - const tag_dictionary = build_dictionary_for_matching_process(result); - return matching_process(already_present_tags, new_tags, tag_dictionary); - }) - ]) -} - -function compute_tag_changes([[exercise_with_tag_records], [new_tags, tags_to_be_inserted]]) { - const old_tags = exercise_with_tag_records - .get("tag_entries") - .map(tag => tag.get("tag_id")); - // computes the changes in order to insert (or not) minimal number of new rows - // as we could add and remove tags, we must handle both cases at once - let changes = { - "added": difference(new_tags, old_tags), - "deleted": difference(old_tags, new_tags) - }; - // delegate work to other promise - return Promise.resolve([changes, tags_to_be_inserted]); -} - -function insert_new_tags_if_there_is_at_least_one(tags_to_be_inserted, t) { - const creationDate = new Date(); - if (tags_to_be_inserted.length === 0) { - return Promise.resolve([]) - } else { - return models - .Tag - .bulkCreate(tags_to_be_inserted.map(tag => ({ - // by default, creating tags like that should be reviewed - // (except if it is created by an admin) - state: (tag.hasOwnProperty("state")) ? tag.state : tagState.PENDING, - text: tag.text, - category_id: tag.category_id, - // some timestamps must be inserted - updatedAt: creationDate, - createdAt: creationDate - })), { - transaction: t, - // I must retrieve the inserted row(s) ids for later - returning: ["id"] - }) - } -} - -function handle_all_cases_for_tags([id, changes, created_tags, t]) { - - // add the newly created tag(s) into "added" key - // if empty, it does nothing ^^ - changes["added"] = changes["added"].concat( - created_tags.map(tag => tag.id) - ); - - // if there is only additions in tags, we will use our hook to deal with the update part of precomputed data - // if not, we have to do that manually - const onlyAdditions = (changes["added"].length > 0 && changes["deleted"].length === 0); - - // multiple cases can occur here - switch (true) { - // 1. no changes in the tags : the PERFECT case - case (changes["added"].length === 0 && changes["deleted"].length === 0): - return Promise.resolve(); - - // 2. Only additions in tags : The AVERAGE case - // ( we can rely on the hook in Exercise_Tag to update precomputed data eg : "tags_ids" ) - case onlyAdditions: - return models - .Exercise_Tag - .bulkCreate(changes["added"].map(tag => ({ - tag_id: tag, - exercise_id: id - })), { - transaction: t - }); - - // 3. additions and deletes : The HARD case - // We have to manually do what the hook in Exercise_Tag does - // as there is no "instances" with their API for bulkDestroy - default: - return Promise.all([ - // insert the new tags - models - .Exercise_Tag - .bulkCreate(changes["added"].map(tag => ({ - tag_id: tag, - exercise_id: id - })), { - transaction: t, - hooks: false // we have to disable the hook on them for no recompute things two times - }), - // delete the old tags - models - .Exercise_Tag - .destroy({ - where: { - [Op.and]: [ - {exercise_id: id}, - { - tag_id: { - [Op.in]: changes["deleted"] - } - } - ] - }, - transaction: t, - hooks: false // we have to disable the hook on them for no recompute things two times - }) - ]).then(() => { - // retrieve the new "tags_ids" array & update the Exercise_metrics row - return models - .Exercise_Tag - .scope([ - {method: ["filter_by_exercise_ids", [id]]}, - {method: ["tags_summary", {transaction: t}]} - ]) - .findAll({ - transaction: t, - rejectOnEmpty: true - }) - }).then(([data]) => { - // as Exercise_Metrics doesn't use version lock and/or timestamps, more easily to update - return models - .Exercise_Metrics - .update({ - "tags_ids": data.get("tags") - }, { - where: { - exercise_id: data.get("exercise_id") - }, - transaction: t - }) - }) - } -} - -function update_exercise([id, body, t]) { - return new Promise((resolve, reject) => { - return models - .Exercise - .scope([ - {method: ["filter_exercises_ids", [id]]} - ]) - .findAll({ - transaction: t, - rejectOnEmpty: true, - where: { - version: body.version - } - }) - .then(([instance]) => { - // common properties for all exercises - let properties = { - title: body.title, - description: body.description, // by default it will be empty thanks openapi-enforcer - }; - // handle optional properties updates - if (body.hasOwnProperty("url")) { - properties["url"] = body.url; - } - if (body.hasOwnProperty("state")) { - properties["state"] = exerciseState[body.state]; - } - - // user has the possibility to delete/replace his/her own file - const shouldRemovePreviousFile = (body.file !== null) - || (body.hasOwnProperty("removePreviousFile") && body["removePreviousFile"]) - || false; - if (shouldRemovePreviousFile) { - properties["file"] = (body.file !== null) ? body.file.filename : null; - } - - // upload the new file (if asked) together the modification in database - return Promise.all( - [ - // get the previously inserted filename - Promise.resolve({ - file: instance.get("file"), - shouldRemove: shouldRemovePreviousFile - }), - // upload the new file (if asked) - (body.file !== null) - ? filesManager.move_file_to_destination_folder(body.file) - : Promise.resolve(), - // modify the row in db - instance.update(properties, {transaction: t}) - ]); - }) - .then(([{file, shouldRemove}, _a, _b]) => { - // if provided, the new file was correctly uploaded : we still have to destroy the old one (if exist) - filesManager - .delete_stored_files((shouldRemove && file !== null) ? [file] : []) - .then(() => resolve()) - }) - .catch(/* istanbul ignore next */ (err) => reject(err)) - }); - -} - -// to handle errors when updating an exercise -/* istanbul ignore next */ -function handle_upload_error(err) { - if (err instanceof Sequelize.EmptyResultError) { - let error = new Error("Resource not found / Outdated version"); - error.message = "It seems you are using an outdated version of this resource : Operation denied"; - error.status = 409; - return error; - } else { - // default handler - return err; - } -} - -// Prevent not authorized user to modify a diff --git a/controllers/exercises/voteForExercise.js b/controllers/exercises/voteForExercise.js deleted file mode 100644 index 61e02fd..0000000 --- a/controllers/exercises/voteForExercise.js +++ /dev/null @@ -1,38 +0,0 @@ -const models = require('../../models'); -const Promise = require("bluebird"); -const Sequelize = require("sequelize"); - -module.exports = function (req, res, next) { - - // Here we need the serializable isolation level as : - // - Multiple user can vote on the same exercise on the same time - // - Precomputed fields in Exercise_metrics need to be accurate ( no phantom row ) - // - A user could try to modify exercise tags whereas other users votes - // ( two transactions running in the same time ... ) - return models - .sequelize - .transaction({ - isolationLevel: Sequelize.Transaction.ISOLATION_LEVELS.SERIALIZABLE - }, (t) => { - return models - .Notation - .findOrCreate({ - where: { - exercise_id: req.body.exercise_id, - user_id: req.user.id - }, - defaults: { - note: req.body.score - }, - transaction: t - }) - .then(([note, created]) => { - return (created) - ? Promise.resolve() // nothing else to do as findOrCreate already did the job - : note.update({note: req.body.score}, {transaction: t}) - }) - }) - .then(() => res.status(200).end()) - .catch(/* istanbul ignore next */ - err => next(err)); -}; \ No newline at end of file diff --git a/controllers/tags.js b/controllers/tags.js deleted file mode 100644 index 932cd5d..0000000 --- a/controllers/tags.js +++ /dev/null @@ -1,16 +0,0 @@ -const getTags = require("./tags/getTags"); -const submitTagProposal = require("./tags/submitTagProposal"); -const updateTag = require("./tags/updateTag"); - -module.exports = function () { - // useful for Dependency Injection - // https://byu-oit.github.io/openapi-enforcer-middleware/guide/controllers#dependency-injection - const controller = {}; - - // add endpoints - controller.updateTag = updateTag; - controller.submitTagProposal = submitTagProposal; - controller.getTags = getTags; - - return controller; -}; \ No newline at end of file diff --git a/controllers/tags/getTags.js b/controllers/tags/getTags.js deleted file mode 100644 index 832b084..0000000 --- a/controllers/tags/getTags.js +++ /dev/null @@ -1,61 +0,0 @@ -const models = require('../../models'); - -const Sequelize = require("sequelize"); -const Op = Sequelize.Op; - -module.exports = (req, res, next) => { - const params = req.query; - - const settings = { - tags_ids: params.tags_ids || [], - categories_ids: params.categories_ids || [], - state: params.state || [], - title: params.title || "", - }; - - let conditions = []; - - // must we include conditions or not - if (settings.state.length > 0) { - conditions.push({ - state: { - [Op.in]: settings.state - } - }) - } - if (settings.tags_ids.length > 0) { - conditions.push({ - id: { - [Op.in]: settings.tags_ids - } - }) - } - if (settings.categories_ids.length > 0) { - conditions.push({ - category_id: { - [Op.in]: settings.categories_ids - } - }) - } - if (settings.title.length > 0) { - conditions.push({ - text: { - [Op.iLike]: `%${settings.title}%` - } - }); - } - - // create the findOptions - const options = { - // dynamic create the where clause - where: Object.assign({}, ...conditions) - }; - - return models - .Tag - .scope('common_attributes') - .findAll(options) - .then(result => res.send(result.map(tag => tag.toJSON()))) - .catch(/* istanbul ignore next */ - err => next(err)); -}; diff --git a/controllers/tags/submitTagProposal.js b/controllers/tags/submitTagProposal.js deleted file mode 100644 index f5c57c1..0000000 --- a/controllers/tags/submitTagProposal.js +++ /dev/null @@ -1,35 +0,0 @@ -const models = require('../../models'); - -// to prevent duplicates in database -const {find_tag_matches} = require("../_common/utlis_fct"); -const { TAGS: tagState } = require("../_common/constants"); - -module.exports = (req, res, next) => { - const creationDate = new Date(); - const { - text, - category_id - } = req.body; - - // find tag matches for new_tags if already existing - return find_tag_matches([{category_id, text}]) - .then(result => { - // if no match, this is truly a new tag to be add ( otherwise do nothing ) - return (result.length > 0) - ? Promise.resolve() - : models - .Tag - .create({ - text: text, - category_id: category_id, - // by default, consider a tag as not official - state: tagState.PENDING, - // some date - updateAt: creationDate, - createAt: creationDate - }) - }) - .then(() => res.status(200).end()) - .catch(/* istanbul ignore next */ - err => next(err)); -}; diff --git a/controllers/tags/updateTag.js b/controllers/tags/updateTag.js deleted file mode 100644 index 64020d5..0000000 --- a/controllers/tags/updateTag.js +++ /dev/null @@ -1,47 +0,0 @@ -const models = require('../../models'); -const Sequelize = require("sequelize"); - -const tagState = require("../_common/constants")["TAGS"]; - -module.exports = (req, res, next) => { - const { - tag_id, - tag_text, - category_id, - state, - version - } = req.body; - - // cannot use here findByPk as it ignores my where clause - return models - .Tag - .findAll({ - where: { - id: tag_id, - version: version - }, - rejectOnEmpty: true - }) - .then(([instance]) => { - return instance.update({ - category_id: category_id, - text: tag_text, - state: tagState[state] - }); - }) - .then(() => { - res.status(200).end(); - }) - .catch(/* istanbul ignore next */ - err => { - if (err instanceof Sequelize.EmptyResultError) { - let error = new Error("Resource not found / Outdated version"); - error.message = "It seems you are using an outdated version of this resource : Operation denied"; - error.status = 409; - next(error); - } else { - // default handler - next(err); - } - }); -}; diff --git a/controllers/tags_categories.js b/controllers/tags_categories.js deleted file mode 100644 index ee710d7..0000000 --- a/controllers/tags_categories.js +++ /dev/null @@ -1,16 +0,0 @@ -const getTagCategories = require("./tags_categories/getTagCategories"); -const updateTagCategory = require("./tags_categories/updateTagCategory"); -const getTagCategoriesWithTags = require("./tags_categories/getTagCategoriesWithTags"); - -module.exports = function () { - // useful for Dependency Injection - // https://byu-oit.github.io/openapi-enforcer-middleware/guide/controllers#dependency-injection - const controller = {}; - - // add endpoints - controller.getTagCategories = getTagCategories; - controller.updateTagCategory = updateTagCategory; - controller.getTagCategoriesWithTags = getTagCategoriesWithTags; - - return controller; -}; \ No newline at end of file diff --git a/controllers/tags_categories/getTagCategories.js b/controllers/tags_categories/getTagCategories.js deleted file mode 100644 index 01fd9e3..0000000 --- a/controllers/tags_categories/getTagCategories.js +++ /dev/null @@ -1,57 +0,0 @@ -const models = require('../../models'); - -module.exports = (req, res, next) => { - - let options = { - attributes: [ - "id", - ["kind", "category"] - ] - }; - - // if categories ids were given - if (req.query.category_ids) { - options.where = { - id: req.query.category_ids - } - } - - /* - * If in any way the scope "count_summary" stop working ( should never happen but who knows ?) - * Here is the raw query to got the same result : - * */ - // SELECT - // "Tag_Category"."id", - // "Tag_Category"."kind" AS "category", - // COUNT(*) FILTER (WHERE "tags"."id" IS NOT NULL) AS "total", - // COUNT(*) FILTER (WHERE "tags"."state" = "VALIDATED") AS "total_validated", - // COUNT(*) FILTER(WHERE "tags"."state" = "NOT_VALIDATED") AS "total_unvalidated" - // COUNT(*) FILTER(WHERE "tags"."state" = "DEPRECATED") AS "total_deprecated" - // FROM "exercises_library"."Tag_Categories" AS "Tag_Category" - // LEFT OUTER JOIN "exercises_library"."Tags" AS "tags" ON "Tag_Category"."id" = "tags"."category_id" - // GROUP BY "Tag_Category"."id", "Tag_Category"."kind"; - - // Do we wish the simplest version of this endpoint or the most complex - const withStats = req.query["fetchStats"] && req.query["fetchStats"] === 1; - ( - (withStats) - ? models.Tag_Category.scope("count_summary").findAll(options) - : models.Tag_Category.findAll(options) - ) - .then((result) => res.send( - result.map(cat => { - // Sequelize doesn't seem to map count variables into integer so I have to do that myself - return (!withStats) - ? cat.toJSON() - : Object.assign({}, cat.toJSON(), { - "total": parseInt(cat.get("total")), - "total_validated": parseInt(cat.get("total_validated")), - "total_unvalidated": parseInt(cat.get("total_unvalidated")), - "total_deprecated": parseInt(cat.get("total_deprecated")), - "total_pending": parseInt(cat.get("total_pending")), - }); - })) - ) - .catch(/* istanbul ignore next */ - err => next(err)); -}; diff --git a/controllers/tags_categories/getTagCategoriesWithTags.js b/controllers/tags_categories/getTagCategoriesWithTags.js deleted file mode 100644 index 6334ebe..0000000 --- a/controllers/tags_categories/getTagCategoriesWithTags.js +++ /dev/null @@ -1,105 +0,0 @@ -const models = require('../../models'); -const {Op, literal: SequelizeLitteral} = require("sequelize"); -const {TAGS: TagState, EXERCISES} = require("../_common/constants"); -// to map request exercise state(s) to column in database, as Sequelize cannot use views yet :( -// !! Should be rewritten one day !! -const mapToDb = { - [EXERCISES.PENDING]: "total_pending", - [EXERCISES.NOT_VALIDATED]: "total_not_validated", - [EXERCISES.VALIDATED]: "total_validated", - [EXERCISES.ARCHIVED]: "total_archived", - [EXERCISES.DRAFT]: "total_draft", -}; -const schema = models.sequelize.options.schema; -/* istanbul ignore next */ -const WithSchema = (schema, table) => (schema) ? `"${schema}"."${table}"` : `"${table}"`; - -module.exports = function (req, res, next) { - const params = req.query; - - const settings = { - state: params.state || [], - onlySelected: params.onlySelected /* istanbul ignore next */ || [], - countStates: params.countStates || Object.values(EXERCISES), - }; - - let criteria = []; - - /* istanbul ignore if */ - if (settings.onlySelected.length > 0) { - criteria.push({ - id: { - [Op.in]: settings.onlySelected - } - }); - } - - let options = { - attributes: [ - "id", - ["kind", "category"] - ], - // dynamic create the where clause - where: Object.assign({}, ...criteria), - include: [ - { - // WORKAROUND : normally I should use "required: true" but Sequelize has an bug on empty row cases - required: false, - model: models.Tag, - attributes: [ - ["id", "tag_id"], - ["text", "tag_text"], - "category_id", - "state", - "version", - // Honestly it is quite of ugly but no choice : as explained, sequelize don't support views yet - [ - SequelizeLitteral(`( - SELECT COALESCE(SUM(${settings.countStates.map(s => "stats." + mapToDb[s]).join(" + ")}) ,0) - FROM ${WithSchema(schema, "tags_by_exercise_state")} AS stats - WHERE stats.tag_id = tags.id - )`), - "total" - ] - ], - as: "tags", - where: Object - .assign({}, - ...( - (settings.state.length > 0) - /* istanbul ignore next */ - ? [{ - state: { - [Op.in]: settings.state.map(s => TagState[s]) - } - }] - : [] - ) - ) - } - ], - order: [ - ["id", "ASC"], - [SequelizeLitteral(`"tags.total"`), "DESC"] - ] - }; - - return models - .Tag_Category - .findAll(options) - .then(result => { - let categories = result - .filter(cat => cat.get("tags").length > 0) - .map(cat => { - let newCat = cat.toJSON(); - newCat["tags"] = newCat["tags"].map(tag => { - tag["total"] = Number(tag["total"]); - return tag; - }); - return newCat; - }); - res.send(categories); - }) - .catch(/* istanbul ignore next */ - err => next(err)); -}; diff --git a/controllers/tags_categories/updateTagCategory.js b/controllers/tags_categories/updateTagCategory.js deleted file mode 100644 index 0743059..0000000 --- a/controllers/tags_categories/updateTagCategory.js +++ /dev/null @@ -1,21 +0,0 @@ -const models = require('../../models'); - -module.exports = (req, res, next) => { - return models - .Tag_Category - .findAll({ - where: { - id: req.body.id - }, - limit: 1, - rejectOnEmpty: true - }) - .then(([instance]) => { - return instance.update({ - kind: req.body.category - }); - }) - .then((_) => res.status(200).end()) - .catch(/* istanbul ignore next */ - err => next(err)) -}; \ No newline at end of file diff --git a/controllers/users.js b/controllers/users.js deleted file mode 100644 index ac75119..0000000 --- a/controllers/users.js +++ /dev/null @@ -1,16 +0,0 @@ -const me = require("./users/me"); -const updateUser = require("./users/updateUser"); -const ListUsers = require("./users/ListUsers"); - -module.exports = function () { - // useful for Dependency Injection - // https://byu-oit.github.io/openapi-enforcer-middleware/guide/controllers#dependency-injection - const controller = {}; - - // add endpoints - controller.me = me; - controller.updateUser = updateUser; - controller.ListUsers = ListUsers; - - return controller; -}; \ No newline at end of file diff --git a/controllers/users/ListUsers.js b/controllers/users/ListUsers.js deleted file mode 100644 index bba99a6..0000000 --- a/controllers/users/ListUsers.js +++ /dev/null @@ -1,64 +0,0 @@ -const {Op} = require("sequelize"); - -const models = require('../../models'); - -const DEFAULT_SIZE_LIMIT = 10; -const DEFAULT_PAGE = 1; - -module.exports = function (req, res, next) { - const settings = { - size: (req.query.metadata) ? req.query.metadata.size : DEFAULT_SIZE_LIMIT, - page: (req.query.metadata) ? req.query.metadata.page : DEFAULT_PAGE, - roles: req.query.roles /* istanbul ignore next */ || [], - fullName: req.query.fullName || "", - email: req.query.email || "" - }; - - // if additional filters were given - let criteria = []; - - if (settings.roles.length > 0) { - criteria.push({ - role: { - [Op.in]: settings.roles - } - }) - } - ["fullName", "email"] - .filter(field => settings[field].length > 0) - .forEach(field => { - criteria.push({ - [field]: { - [Op.iLike]: `%${settings[field]}%` - } - }); - }); - - let options = { - limit: settings.size, - offset: (settings.page - 1) * settings.size, - attributes: [ - ["fullName", "fullName"], - ["email", "email"], - ["role", "role"], - ["id", "id"] - ], - where: Object.assign({}, ...criteria) - }; - - return models - .User - .findAndCountAll(options) - .then(({rows, count}) => { - res.send({ - metadata: { - currentPage: settings.page, - pageSize: settings.size, - totalItems: count, - totalPages: Math.ceil(count / settings.size) - }, - data: rows.map(row => row.toJSON()) - }) - }).catch(/* istanbul ignore next */ - err => next(err)); -}; diff --git a/controllers/users/me.js b/controllers/users/me.js deleted file mode 100644 index 871a132..0000000 --- a/controllers/users/me.js +++ /dev/null @@ -1,15 +0,0 @@ -const models = require('../../models'); -const Sequelize = require("sequelize"); - -module.exports = function (req, res, next) { - models - .User - .findByPk(req.user.id, { - attributes: {exclude: ['password']} - }) - .then((user) => { - res.send(user.toJSON()); - }) - .catch(/* istanbul ignore next */ - err => next(err)); -}; \ No newline at end of file diff --git a/controllers/users/updateUser.js b/controllers/users/updateUser.js deleted file mode 100644 index eb42bbe..0000000 --- a/controllers/users/updateUser.js +++ /dev/null @@ -1,32 +0,0 @@ -const models = require('../../models'); - -module.exports = function (req, res, next) { - const userId = req.body.id /* istanbul ignore next */ || req.user.id; - let newProperties = {}; - - /* istanbul ignore else */ - if (req.body.fullName) { - newProperties["fullName"] = req.body.fullName; - } - - /* istanbul ignore else */ - if (req.body.password) { - newProperties["password"] = req.body.password; - } - - /* istanbul ignore else */ - if (req.body.role) { - newProperties["role"] = req.body.role; - } - - return models - .User - .update(newProperties, { - where: { - id: userId - } - }) - .then(() => res.status(200).end()) - .catch(/* istanbul ignore next */ - err => next(err)); -}; diff --git a/index.html b/index.html new file mode 100644 index 0000000..7787e7f --- /dev/null +++ b/index.html @@ -0,0 +1,1028 @@ + + + + + + Source Code API + + + + + + + + + +

Source Code API (1.0.0)

Download OpenAPI specification:Download

License: GPL-3.0-or-later

API for Source Code

+

Authentication

bearerAuth

Security Scheme Type HTTP
HTTP Authorization Scheme bearer
Bearer format "JWT"

guest

Everything a(n) visitor / not authentified user could do

+

Logs user into the system

Request Body schema: application/json
email
required
string <email>
password
required
string <password>

Responses

Request samples

Content type
application/json
{
  • "email": "jy95@perdu.com",
  • "password": "42"
}

Response samples

Content type
application/json
{
  • "token": "string",
  • "user": {
    }
}

Creates a new user into the system

Request Body schema: application/json
email
required
string <email>
password
required
string <password>
fullName
required
string [ 1 .. 50 ] characters

The full name of this new user

+

Responses

Request samples

Content type
application/json
{
  • "email": "jy95@perdu.com",
  • "password": "42",
  • "fullName": "Alexandre Dewit"
}

Response samples

Content type
application/json
{
  • "message": "string",
  • "errors": [
    ]
}

Verify if given JWT token is valid (and not expired)

Request Body schema: application/json
token
required
string^[A-Za-z0-9-_=]+\.[A-Za-z0-9-_=]+\.?[A-Za-z0-...

An JWT Token string

+

Responses

Request samples

Content type
application/json
{
  • "token": "string"
}

Response samples

Content type
application/json
{
  • "message": "string",
  • "errors": [
    ]
}

Retrieve this specific exercise data

Authorizations:
path Parameters
id
required
integer

The exercise ID

+
query Parameters
object (IncludeOptions)

To include additional properties when fetching exercise

+

Responses

Response samples

Content type
application/json
{
  • "title": "A Super Exercise",
  • "description": "...",
  • "id": 42,
  • "version": 42,
  • "createdAt": "2019-12-22T15:18:31.090Z",
  • "updatedAt": "2019-12-22T15:19:33.473Z",
  • "state": "PENDING",
  • "file": "sources-88af5adc-1837-11ea-8d71-362b9e155667.zip",
  • "metrics": {
    },
  • "tags": [
    ],
  • "creator": {
    },
  • "vote": 5
}

Search exercises that matches criteria

Request Body schema: application/json
Array of objects <= 6 items

If you wish to order the provided result, use this parameter.

+

For example, if you wish to first sort by date descending then by title ascending, you could achieve that with :

+
  [
+    {"field": "date", "value": "DESC"},
+    {"field": "title", "value": "ASC"}
+  ]
object (SearchDataCriterias)

Search criterias

+
object (FilteringOptions)

To filter some properties when fetching exercise(s)

+
object (PaginationCriterias)

Fields for pagination

+
object (IncludeOptions)

To include additional properties when fetching exercise(s)

+

Responses

Request samples

Content type
application/json
Example

Search the first 10 exercises that have 'Java' in their title and have some specific tags ( 1 AND (2 OR 3 OR 4) )

+
{
  • "data": {
    }
}

Response samples

Content type
application/json
{
  • "metadata": {
    },
  • "data": [
    ]
}

Retrieve all tags

query Parameters
tags_ids
Array of integers non-empty

Only consider the given tag ID(S)

+
categories_ids
Array of integers non-empty

Only consider the given tag categories ID(S)

+
state
Array of strings (TagState) <= 4 items
Items Enum: "NOT_VALIDATED" "VALIDATED" "DEPRECATED" "PENDING"
Example: state=DEPRECATED

Filter the tags by their state. By default, no filtering is done.

+
title
string <= 100 characters

Filter the tags by their text (case-insensitive comparison)

+

Responses

Response samples

Content type
application/json
[
  • {
    }
]

Retrieve only Tag categories

query Parameters
fetchStats
integer
Enum: 0 1

If enabled, you can retrieve extra properties with the tag category

+
category_ids
Array of integers

Take only the given categories

+

Responses

Response samples

Content type
application/json
[
  • {
    }
]

Retrieve Tag categories with their related tags

query Parameters
state
Array of strings (TagState) <= 4 items
Items Enum: "NOT_VALIDATED" "VALIDATED" "DEPRECATED" "PENDING"
Example: state=DEPRECATED

Filter the tags by their state. By default, no filtering is done.

+
onlySelected
Array of integers unique
Default: []
Example: onlySelected=42

If not empty, only consider the given tag categories ID(S). If empty, no tag category is ignored

+
countStates
Array of strings (State) <= 5 items
Items Enum: "DRAFT" "PENDING" "VALIDATED" "NOT_VALIDATED" "ARCHIVED"
Example: countStates=PENDING

If not empty, only consider the given exercise state(s) to compute the field "total" inside each tag.
If empty, every exercise state will be considered for the sum.

+

Responses

Response samples

Content type
application/json
[
  • {
    }
]

Download a stored file on the API

path Parameters
file
required
string
Example: someFile.zip

The path to the file we want to access

+

Responses

Response samples

Content type
application/json
{
  • "message": "string",
  • "errors": [
    ]
}

user

Everything an authentified user could do (more than a guest)

+

Fetch information about the current logged user

Authorizations:

Responses

Response samples

Content type
application/json
{
  • "email": "jy95@perdu.com",
  • "fullName": "Alexandre Dewit",
  • "role": "user",
  • "id": 42
}

Update information about an user

Any user can freely any information about (him/her)self (except the optional "id" / "role" fields ).
An super admin can freely update any user and it is the only one that can use the "id" / "role" fields.

+
Authorizations:
Request Body schema: application/json
fullName
string [ 1 .. 50 ] characters

The full name of the user

+
password
string <password>
role
string (Roles)
Default: "user"
Enum: "super_admin" "admin" "user"

The type of user. Currently, 3 types are possibles :

+
    +
  1. user : The defaut ( an simple registered user )
  2. +
  3. admin : User with additional credentials
  4. +
  5. super_admin : More powerful than an admin
  6. +
+
id
integer

The UUID of this user. By default, it will take the one of logged user

+

Responses

Request samples

Content type
application/json
{
  • "fullName": "Alexandre Dewit",
  • "password": "42",
  • "role": "user",
  • "id": 42
}

Response samples

Content type
application/json
{
  • "message": "string",
  • "errors": [
    ]
}

Creates a new exercise into the system

Creates a new exercise into the system. +By default (if nothing specified), the exercise will be in state "DRAFT".
You are free to add new tags / keywords but you must add at least 3 validated tags.

+

The following restrictions are applied on simple user(s) (no restriction for admin):

+
    +
  1. He/She can only modify his/her own exercises
  2. +
  3. Only the following states are allowed for the field "state" :
      +
    • DRAFT
    • +
    • PENDING
    • +
    +
  4. +
  5. He/She can't use the field "state" inside an tag object of "tags" array
  6. +
+
Authorizations:
Request Body schema:
title
required
string [ 3 .. 100 ] characters

The title of this exercise

+
description
string <= 5000 characters
Default: ""

The preamble of this exercise

+
required
Array of integers or TagProposalWithState (object) [ 3 .. 25 ] items unique

Mixed array that contains existent tag(s) or not

+
url
string Nullable ^https?:\/\/[^\s$.?#].[^\s]*$

If not null, the link to the exercise on a plateform

+
state
string (State)
Enum: "DRAFT" "PENDING" "VALIDATED" "NOT_VALIDATED" "ARCHIVED"

Status of the exercise into the system. Currently, 5 states are possibles :

+
    +
  1. DRAFT : The default state (for example when an exercise is inserted into the system)
  2. +
  3. PENDING : When an exercise is ready for review
  4. +
  5. VALIDATED : When an exercise is validated by an admin
  6. +
  7. NOT_VALIDATED : When an exercise is refused by an admin
  8. +
  9. ARCHIVED : When an exercise is archived / soft deleted
  10. +
+

Responses

Request samples

Content type
{}

Response samples

Content type
application/json
{
  • "message": "string",
  • "errors": [
    ]
}

Retrieve this specific exercise data

Authorizations:
path Parameters
id
required
integer

The exercise ID

+
query Parameters
object (IncludeOptions)

To include additional properties when fetching exercise

+

Responses

Response samples

Content type
application/json
{
  • "title": "A Super Exercise",
  • "description": "...",
  • "id": 42,
  • "version": 42,
  • "createdAt": "2019-12-22T15:18:31.090Z",
  • "updatedAt": "2019-12-22T15:19:33.473Z",
  • "state": "PENDING",
  • "file": "sources-88af5adc-1837-11ea-8d71-362b9e155667.zip",
  • "metrics": {
    },
  • "tags": [
    ],
  • "creator": {
    },
  • "vote": 5
}

Update this specific exercise data

Update this specific exercise data
You are free to add new tags / keywords but you must add at least 3 validated tags. +The following restrictions are applied on simple user(s) (no restriction for admin) :

+
    +
  1. He/She can only modify his/her own exercises
  2. +
  3. Only the following states are allowed for the field "state" :
      +
    • DRAFT
    • +
    • PENDING
    • +
    +
  4. +
  5. He/She can't use the field "state" inside an tag object of "tags" array
  6. +
+
Authorizations:
path Parameters
id
required
integer

The exercise ID

+
query Parameters
object (IncludeOptions)

To include additional properties when fetching exercise

+
Request Body schema:
title
required
string [ 3 .. 100 ] characters

The title of this exercise

+
description
string <= 5000 characters
Default: ""

The preamble of this exercise

+
required
Array of integers or TagProposalWithState (object) [ 3 .. 25 ] items unique

Mixed array that contains existent tag(s) or not

+
url
string Nullable ^https?:\/\/[^\s$.?#].[^\s]*$

If not null, the link to the exercise on a plateform

+
state
string (State)
Enum: "DRAFT" "PENDING" "VALIDATED" "NOT_VALIDATED" "ARCHIVED"

Status of the exercise into the system. Currently, 5 states are possibles :

+
    +
  1. DRAFT : The default state (for example when an exercise is inserted into the system)
  2. +
  3. PENDING : When an exercise is ready for review
  4. +
  5. VALIDATED : When an exercise is validated by an admin
  6. +
  7. NOT_VALIDATED : When an exercise is refused by an admin
  8. +
  9. ARCHIVED : When an exercise is archived / soft deleted
  10. +
+
version
required
integer >= 0

The version of this exercise (optimistic lock)

+
removePreviousFile
boolean
Default: false

If set to true, the API will delete the previous file when updating the exercise

+

Responses

Request samples

Content type
{}

Response samples

Content type
application/json
{
  • "message": "string",
  • "errors": [
    ]
}

Submit a tag proposal

Authorizations:
Request Body schema: application/json
text
required
string [ 1 .. 100 ] characters

The text of this Tag

+
category_id
required
integer >= 0

the category id to which this tag is related

+

Responses

Request samples

Content type
application/json
{
  • "text": "easy",
  • "category_id": 42
}

Response samples

Content type
application/json
{
  • "message": "string",
  • "errors": [
    ]
}

Change the status of given exercises

Change the status of given exercises.

+

The following restrictions are applied on simple user(s) (no restriction for admin):

+
    +
  1. He/She can only modify his/her own exercises
  2. +
  3. Only the following states are allowed :
      +
    • DRAFT
    • +
    • PENDING
    • +
    • ARCHIVED
    • +
    +
  4. +
+
Authorizations:
Request Body schema: application/json
exercises
required
Array of integers non-empty unique

An array of exercises IDs

+
state
required
string (State)
Enum: "DRAFT" "PENDING" "VALIDATED" "NOT_VALIDATED" "ARCHIVED"

Status of the exercise into the system. Currently, 5 states are possibles :

+
    +
  1. DRAFT : The default state (for example when an exercise is inserted into the system)
  2. +
  3. PENDING : When an exercise is ready for review
  4. +
  5. VALIDATED : When an exercise is validated by an admin
  6. +
  7. NOT_VALIDATED : When an exercise is refused by an admin
  8. +
  9. ARCHIVED : When an exercise is archived / soft deleted
  10. +
+

Responses

Request samples

Content type
application/json
{
  • "exercises": [
    ],
  • "state": "PENDING"
}

Response samples

Content type
application/json
{
  • "message": "string",
  • "errors": [
    ]
}

Creates multiple tags into the system

Creates multiple tags into the system.

+

Warning : the "state" property can only be used by authorized people (no simple user can use it)

+
Authorizations:
Request Body schema: application/json
Array ()
text
required
string [ 1 .. 100 ] characters

The text of this Tag

+
category_id
required
integer >= 0

the category id to which this tag is related

+
state
string (TagState)
Enum: "NOT_VALIDATED" "VALIDATED" "DEPRECATED" "PENDING"

Status of the tag into the system. Currently, 4 states are possibles :

+
    +
  1. NOT_VALIDATED : When a tag is officially not recognized
  2. +
  3. PENDING : The default state ( for example when an exercise is inserted into the system)
  4. +
  5. DEPRECATED : When a tag should not be used anymore
  6. +
  7. VALIDATED : When a tag is officially recognized
  8. +
+

Responses

Request samples

Content type
application/json
[
  • {
    }
]

Response samples

Content type
application/json
{
  • "message": "string",
  • "errors": [
    ]
}

Vote (or update the vote) of the current logged user for given exercise

Authorizations:
Request Body schema: application/json
exercise_id
required
integer >= 0

The ID of the exercise we want to vote / modify a vote

+
score
required
number <double> >= 0

The score we want to give to this exercise

+

Responses

Request samples

Content type
application/json
{
  • "exercise_id": 42,
  • "score": 5
}

Response samples

Content type
application/json
{
  • "message": "string",
  • "errors": [
    ]
}

FetchOwnConfigurations

Get all configurations of the current logged user

+
Authorizations:
query Parameters
ids
Array of integers

Array of configuration ids you want to search

+

Responses

Response samples

Content type
application/json
[
  • {
    }
]

UpdateConfiguration

Update a configuration

+
Authorizations:
Request Body schema: application/json
name
required
string

The name of this configuration

+
title
string [ 0 .. 100 ] characters

The used title for search

+
tags
Array of integers

An array of tags IDS

+
id
required
integer >= 0

The id of this configuration

+

Responses

Request samples

Content type
application/json
{
  • "name": "All Java exercises",
  • "title": "[LSINF1252]",
  • "tags": [
    ],
  • "id": 42
}

Response samples

Content type
application/json
{
  • "message": "string",
  • "errors": [
    ]
}

CreateConfiguration

Create a configuration

+
Authorizations:
Request Body schema: application/json
name
required
string

The name of this configuration

+
title
string [ 0 .. 100 ] characters

The used title for search

+
tags
Array of integers

An array of tags IDS

+

Responses

Request samples

Content type
application/json
{
  • "name": "All Java exercises",
  • "title": "[LSINF1252]",
  • "tags": [
    ]
}

Response samples

Content type
application/json
{
  • "message": "string",
  • "errors": [
    ]
}

DeleteConfiguration

Delete a configuration

+
Authorizations:
Request Body schema: application/json
id
integer >= 0

The id of the configuration you want to delete

+

Responses

Request samples

Content type
application/json
{
  • "id": 42
}

Response samples

Content type
application/json
{
  • "message": "string",
  • "errors": [
    ]
}

admin

Everything an administrator could do (more than an user)

+

ExportExercises

To export exercises that match optional criteria.

+

The JSON result is compliant with the format +of our cli which means that if you wish to reupload the exercises in the future, +it's simple as you just have to rely on the cli command "uploader". +Please consider the following facts before using it :

+
    +
  1. Don't forget to rename the key "categories" to "own_categories"

    +
  2. +
  3. If you wish to upload them without their files, remove the property "file" in each exercise :

    +
     let json_result = { /* ... */ };
    + const exercisesWithoutFile = json_result["exercises"].map(exercise => {
    +     delete exercise["file"]
    +     return exercise;
    + });
    + Object.assign(json_result, { "exercises": exercisesWithoutFile });
    +
  4. +
  5. If you wish to upload them with their files, download their files and modify each property "file" according our format +of our cli.

    +
  6. +
+
Authorizations:
Request Body schema: application/json
Array of objects <= 6 items

If you wish to order the provided result, use this parameter.

+

For example, if you wish to first sort by date descending then by title ascending, you could achieve that with :

+
  [
+    {"field": "date", "value": "DESC"},
+    {"field": "title", "value": "ASC"}
+  ]
object (SearchDataCriterias)

Search criterias

+
object (FilteringOptions)

To filter some properties when fetching exercise(s)

+

Responses

Request samples

Content type
application/json
{
  • "orderBy": [
    ],
  • "data": {
    },
  • "filterOptions": {
    }
}

Response samples

Content type
application/json
{
  • "exercises": [
    ],
  • "categories": {
    }
}

Modify a Tag

Authorizations:
Request Body schema: application/json
tag_id
required
integer >= 0

The Id of this Tag

+
tag_text
required
string [ 1 .. 100 ] characters

The text of this Tag

+
category_id
required
integer >= 0

the category id to which it is related

+
state
required
string (TagState)
Enum: "NOT_VALIDATED" "VALIDATED" "DEPRECATED" "PENDING"

Status of the tag into the system. Currently, 4 states are possibles :

+
    +
  1. NOT_VALIDATED : When a tag is officially not recognized
  2. +
  3. PENDING : The default state ( for example when an exercise is inserted into the system)
  4. +
  5. DEPRECATED : When a tag should not be used anymore
  6. +
  7. VALIDATED : When a tag is officially recognized
  8. +
+
version
required
integer >= 0

The version of this exercise (optimistic lock)

+

Responses

Request samples

Content type
application/json
{
  • "tag_id": 42,
  • "tag_text": "easy",
  • "category_id": 42,
  • "state": "DEPRECATED",
  • "version": 42
}

Response samples

Content type
application/json
{
  • "message": "string",
  • "errors": [
    ]
}

Update a Tag category

Authorizations:
Request Body schema: application/json
id
required
integer >= 0

The Id of this Tag_Category

+
category
required
string [ 3 .. 100 ] characters

The text of this Tag_Category

+

Responses

Request samples

Content type
application/json
{
  • "id": 42,
  • "category": "difficulty"
}

Response samples

Content type
application/json
{
  • "message": "string",
  • "errors": [
    ]
}

Creates multiple exercises into the system

Creates multiple exercises into the system +By default (if nothing specified), an exercise will be in state "DRAFT".

+
Authorizations:
Request Body schema:
Array ()
title
required
string [ 3 .. 100 ] characters

The title of this exercise

+
description
string <= 5000 characters
Default: ""

The preamble of this exercise

+
required
Array of integers or TagProposalWithState (object) [ 3 .. 25 ] items unique

Mixed array that contains existent tag(s) or not

+
url
string Nullable ^https?:\/\/[^\s$.?#].[^\s]*$

If not null, the link to the exercise on a plateform

+
state
string (State)
Enum: "DRAFT" "PENDING" "VALIDATED" "NOT_VALIDATED" "ARCHIVED"

Status of the exercise into the system. Currently, 5 states are possibles :

+
    +
  1. DRAFT : The default state (for example when an exercise is inserted into the system)
  2. +
  3. PENDING : When an exercise is ready for review
  4. +
  5. VALIDATED : When an exercise is validated by an admin
  6. +
  7. NOT_VALIDATED : When an exercise is refused by an admin
  8. +
  9. ARCHIVED : When an exercise is archived / soft deleted
  10. +
+

Responses

Request samples

Content type
[]

Response samples

Content type
application/json
{
  • "message": "string",
  • "errors": [
    ]
}

Creates or Find tag categories

Authorizations:
Request Body schema: application/json
Array ()
One of
string

The name of the Tag Category

+

Responses

Request samples

Content type
application/json
[
  • "author"
]

Response samples

Content type
application/json
[
  • {
    }
]

Change the status of given exercises

Change the status of given exercises.

+

The following restrictions are applied on simple user(s) (no restriction for admin):

+
    +
  1. He/She can only modify his/her own exercises
  2. +
  3. Only the following states are allowed :
      +
    • DRAFT
    • +
    • PENDING
    • +
    • ARCHIVED
    • +
    +
  4. +
+
Authorizations:
Request Body schema: application/json
exercises
required
Array of integers non-empty unique

An array of exercises IDs

+
state
required
string (State)
Enum: "DRAFT" "PENDING" "VALIDATED" "NOT_VALIDATED" "ARCHIVED"

Status of the exercise into the system. Currently, 5 states are possibles :

+
    +
  1. DRAFT : The default state (for example when an exercise is inserted into the system)
  2. +
  3. PENDING : When an exercise is ready for review
  4. +
  5. VALIDATED : When an exercise is validated by an admin
  6. +
  7. NOT_VALIDATED : When an exercise is refused by an admin
  8. +
  9. ARCHIVED : When an exercise is archived / soft deleted
  10. +
+

Responses

Request samples

Content type
application/json
{
  • "exercises": [
    ],
  • "state": "PENDING"
}

Response samples

Content type
application/json
{
  • "message": "string",
  • "errors": [
    ]
}

List users

Authorizations:
query Parameters
object (PaginationCriterias)

Fields for pagination

+
roles
Array of strings (Roles) <= 3 items unique
Default: []
Items Enum: "super_admin" "admin" "user"

If not empty, only consider the given user role(s). If empty, no user role is ignored

+
fullName
string [ 1 .. 100 ] characters
email
string <email> [ 1 .. 100 ] characters

Responses

Response samples

Content type
application/json
{
  • "metadata": {
    },
  • "data": [
    ]
}

super_admin

Everything an administrator could do (more than an admin)

+

Update information about an user

Any user can freely any information about (him/her)self (except the optional "id" / "role" fields ).
An super admin can freely update any user and it is the only one that can use the "id" / "role" fields.

+
Authorizations:
Request Body schema: application/json
fullName
string [ 1 .. 50 ] characters

The full name of the user

+
password
string <password>
role
string (Roles)
Default: "user"
Enum: "super_admin" "admin" "user"

The type of user. Currently, 3 types are possibles :

+
    +
  1. user : The defaut ( an simple registered user )
  2. +
  3. admin : User with additional credentials
  4. +
  5. super_admin : More powerful than an admin
  6. +
+
id
integer

The UUID of this user. By default, it will take the one of logged user

+

Responses

Request samples

Content type
application/json
{
  • "fullName": "Alexandre Dewit",
  • "password": "42",
  • "role": "user",
  • "id": 42
}

Response samples

Content type
application/json
{
  • "message": "string",
  • "errors": [
    ]
}

Delete given exercises

Permanently remove from system the given exercises. (No way to retrieve them after this)
Otherwise, if you simply want to soft delete/hide these exercises, use this endpoint to change their status to ARCHIVED.

+
Authorizations:
Request Body schema: application/json
Array ()
integer >= 0

An exercise ID

+

Responses

Request samples

Content type
application/json
[
  • 42
]

Response samples

Content type
application/json
{
  • "message": "string",
  • "errors": [
    ]
}

Delete given tags

Delete given tags.

+
Authorizations:
Request Body schema: application/json
Array ()
integer >= 0

A tag ID

+

Responses

Request samples

Content type
application/json
[
  • 42
]

Response samples

Content type
application/json
{
  • "message": "string",
  • "errors": [
    ]
}

Delete given tags categories

Delete given tags categories.

+
Authorizations:
Request Body schema: application/json
Array ()
integer >= 0

A tag category ID

+

Responses

Request samples

Content type
application/json
[
  • 42
]

Response samples

Content type
application/json
{
  • "message": "string",
  • "errors": [
    ]
}
+ + + + \ No newline at end of file diff --git a/jest.config.js b/jest.config.js deleted file mode 100644 index a0e5864..0000000 --- a/jest.config.js +++ /dev/null @@ -1,189 +0,0 @@ -// For a detailed explanation regarding each configuration property, visit: -// https://jestjs.io/docs/en/configuration.html - -module.exports = { - // All imported modules in your tests should be mocked automatically - // automock: false, - - // Stop running tests after `n` failures - // bail: 0, - - // Respect "browser" field in package.json when resolving modules - // browser: false, - - // The directory where Jest should store its cached dependency information - // cacheDirectory: "C:\\Users\\jy95\\AppData\\Local\\Temp\\jest", - - // Automatically clear mock calls and instances between every test - // clearMocks: false, - - // Indicates whether the coverage information should be collected while executing the test - collectCoverage: true, - - // An array of glob patterns indicating a set of files for which coverage information should be collected - // collectCoverageFrom: null, - - // The directory where Jest should output its coverage files - coverageDirectory: "coverage", - - // An array of regexp pattern strings used to skip coverage collection - coveragePathIgnorePatterns: [ - "\\\\node_modules\\\\", - "/node_modules/" - ], - - // A list of reporter names that Jest uses when writing coverage reports - // coverageReporters: [ - // "json", - // "text", - // "lcov", - // "clover" - // ], - - // An object that configures minimum threshold enforcement for coverage results - // coverageThreshold: null, - - // A path to a custom dependency extractor - // dependencyExtractor: null, - - // Make calling deprecated APIs throw helpful error messages - // errorOnDeprecated: false, - - // Force coverage collection from ignored files using an array of glob patterns - // forceCoverageMatch: [], - - // A path to a module which exports an async function that is triggered once before all test suites - // globalSetup: null, - - // A path to a module which exports an async function that is triggered once after all test suites - // globalTeardown: null, - - // A set of global variables that need to be available in all test environments - // globals: {}, - - // The maximum amount of workers used to run your tests. Can be specified as % or a number. E.g. maxWorkers: 10% will use 10% of your CPU amount + 1 as the maximum worker number. maxWorkers: 2 will use a maximum of 2 workers. - // maxWorkers: "50%", - - // An array of directory names to be searched recursively up from the requiring module's location - // moduleDirectories: [ - // "node_modules" - // ], - - // An array of file extensions your modules use - // moduleFileExtensions: [ - // "js", - // "json", - // "jsx", - // "ts", - // "tsx", - // "node" - // ], - - // A map from regular expressions to module names that allow to stub out resources with a single module - // moduleNameMapper: {}, - - // An array of regexp pattern strings, matched against all module paths before considered 'visible' to the module loader - // modulePathIgnorePatterns: [], - - // Activates notifications for test results - // notify: false, - - // An enum that specifies notification mode. Requires { notify: true } - // notifyMode: "failure-change", - - // A preset that is used as a base for Jest's configuration - // preset: null, - - // Run tests from one or more projects - // projects: null, - - // Use this configuration option to add custom reporters to Jest - // reporters: undefined, - - // Automatically reset mock state between every test - // resetMocks: false, - - // Reset the module registry before running each individual test - // resetModules: false, - - // A path to a custom resolver - // resolver: null, - - // Automatically restore mock state between every test - // restoreMocks: false, - - // The root directory that Jest should scan for tests and modules within - // rootDir: null, - - // A list of paths to directories that Jest should use to search for files in - // roots: [ - // "" - // ], - - // Allows you to use a custom runner instead of Jest's default test runner - // runner: "jest-runner", - - // The paths to modules that run some code to configure or set up the testing environment before each test - // setupFiles: [], - - // A list of paths to modules that run some code to configure or set up the testing framework before each test - // setupFilesAfterEnv: [], - - // A list of paths to snapshot serializer modules Jest should use for snapshot testing - // snapshotSerializers: [], - - // The test environment that will be used for testing - testEnvironment: "node", - - // Options that will be passed to the testEnvironment - // testEnvironmentOptions: {}, - - // Adds a location field to test results - // testLocationInResults: false, - - // The glob patterns Jest uses to detect test files - // testMatch: [ - // "**/__tests__/**/*.[jt]s?(x)", - // "**/?(*.)+(spec|test).[tj]s?(x)" - // ], - - // An array of regexp pattern strings that are matched against all test paths, matched tests are skipped - // testPathIgnorePatterns: [ - // "\\\\node_modules\\\\" - // ], - - // The regexp pattern or array of patterns that Jest uses to detect test files - // testRegex: [], - - // This option allows the use of a custom results processor - // testResultsProcessor: null, - - // This option allows use of a custom test runner - // testRunner: "jasmine2", - - // This option sets the URL for the jsdom environment. It is reflected in properties such as location.href - // testURL: "http://localhost", - - // Setting this value to "fake" allows the use of fake timers for functions such as "setTimeout" - // timers: "real", - - // A map from regular expressions to paths to transformers - // transform: null, - - // An array of regexp pattern strings that are matched against all source file paths, matched files will skip transformation - // transformIgnorePatterns: [ - // "\\\\node_modules\\\\" - // ], - - // An array of regexp pattern strings that are matched against all modules before the module loader will automatically return a mock for them - // unmockedModulePathPatterns: undefined, - - // Indicates whether each individual test should be reported during the run - // verbose: null, - - // An array of regexp patterns that are matched against all source file paths before re-running tests in watch mode - // watchPathIgnorePatterns: [], - - // Whether to use watchman for file crawling - // watchman: true, -}; diff --git a/middlewares/check_user_role.js b/middlewares/check_user_role.js deleted file mode 100644 index 0e7d9d9..0000000 --- a/middlewares/check_user_role.js +++ /dev/null @@ -1,14 +0,0 @@ -// allowedTypeArray is an array with all allowed types of user that can -module.exports = function (allowedTypeArray) { - /* istanbul ignore next */ - return function (req, res, next) { - if (allowedTypeArray.includes(req.user.role)) { - next(); - } else { - let err = new Error('FORBIDDEN'); - err.message = `You are not allowed on this endpoint`; - err.status = 403; - next(err); - } - } -}; \ No newline at end of file diff --git a/middlewares/default_error_handler.js b/middlewares/default_error_handler.js deleted file mode 100644 index 9b8e583..0000000 --- a/middlewares/default_error_handler.js +++ /dev/null @@ -1,13 +0,0 @@ -// no stacktraces leaked to user unless in development environment -module.exports = function (inDevelopment) { - return function (err, req, res, next) { - // if error thrown by validation, give everything else depending of the environment - const shouldGiveFullContext = (inDevelopment /* istanbul ignore next */ && err.hasOwnProperty("is_custom")); - const { dev_errors, ...rest } = err; - const errors = (shouldGiveFullContext) /* istanbul ignore next */ ? err.dev_errors : [rest]; - res.status(err.status /* istanbul ignore next */ || 500).json({ - message: err.message, - errors: errors - }); - } -}; diff --git a/middlewares/errors-beautifier.js b/middlewares/errors-beautifier.js deleted file mode 100644 index 9d715a8..0000000 --- a/middlewares/errors-beautifier.js +++ /dev/null @@ -1,79 +0,0 @@ -// Sequelize for error handeling -const Sequelize = require("sequelize"); -const debug = require("../controllers/_common/debug"); - -module.exports = function () { - return function (err, req, res, next) { - - // looks nice ; found on some angular code - let custom_err = new Error(); - // to check it is not an expected error of these - let is_custom = true; - switch (true) { - case err instanceof Sequelize.EmptyResultError: - // resource not found - custom_err.message = "Resource not found"; - custom_err.status = 404; - break; - /* istanbul ignore next */ - case err instanceof Sequelize.DatabaseError: - // constraints violations - custom_err.message = "Problem with the database : Constraints not satisfied , etc"; - custom_err.status = 400; - break; - /* istanbul ignore next */ - case err instanceof Sequelize.ConnectionError: - // Connection issues : cannot reach , timeout, etc - custom_err.message = "The database cannot be reached : Please try later"; - custom_err.status = 503; - break; - /* istanbul ignore next */ - case err instanceof Sequelize.OptimisticLockError: - // catch locking issues with version - custom_err.message = "It seems you are using an outdated version of this resource : Operation denied"; - custom_err.status = 409; - break; - case err instanceof Sequelize.UniqueConstraintError: - custom_err.message = "You violated a unique constraint and thus generated a conflict"; - custom_err.status = 409; - break; - /* istanbul ignore next */ - case err instanceof Sequelize.BaseError: - // catch all unwatched exceptions coming from Sequelize - custom_err.message = "Unexpected error"; - break; - /* istanbul ignore next */ - default: - // An error of the validator has always a status code we can extract - if (err.hasOwnProperty("exception")) { - custom_err.status = err.statusCode; - custom_err.message = err.message; - } else { - is_custom = true; - custom_err.status = err.status || 500; - custom_err.message = (custom_err.status === 500) - ? "An Internal Error occurs : A team of highly trained monkeys has been dispatched" - : err.message; - } - } - /* istanbul ignore else */ - if (is_custom) { - custom_err.is_custom = true; - custom_err.dev_errors = [err]; - } - // just log - debug.tracker("%s %s - %d : %s", - req.method, - req.url, - custom_err.status /* istanbul ignore next */ || 500, - /* istanbul ignore next */ (req.is("json")) - ? "application/json" - : (req.is("multipart")) - ? "multipart/*" - : "urlencoded", - ); - // if we want to inspect that later - debug.errors("%O", err); - next(custom_err) - } -}; \ No newline at end of file diff --git a/middlewares/not_found.js b/middlewares/not_found.js deleted file mode 100644 index bb4e36f..0000000 --- a/middlewares/not_found.js +++ /dev/null @@ -1,8 +0,0 @@ -module.exports = function () { - /* istanbul ignore next */ - return function (req, res, next) { - let err = new Error('Not Found'); - err.status = 404; - next(err); - } -}; \ No newline at end of file diff --git a/middlewares/remove_temp_files.js b/middlewares/remove_temp_files.js deleted file mode 100644 index d21bcff..0000000 --- a/middlewares/remove_temp_files.js +++ /dev/null @@ -1,20 +0,0 @@ -const filesManager = require("../controllers/_common/files_manager"); - -// Just to be sure that files in temp folder are deleted in any case -module.exports = () => (err, req, res, next) => { - if (req.files) { - const files = Object - .values(req.files) - .reduce((acc, val) => { - /* istanbul ignore next */ - const filesArr = (Array.isArray(val)) ? val : [val]; - acc.push(...filesArr); - return acc; - }, []); - filesManager - .delete_temp_files(files) - .then(() => next(err)); - } else { - next(err); - } -}; \ No newline at end of file diff --git a/middlewares/rules/auth.js b/middlewares/rules/auth.js deleted file mode 100644 index f994bff..0000000 --- a/middlewares/rules/auth.js +++ /dev/null @@ -1,13 +0,0 @@ -const passport = require('passport'); -const login_verification = passport.authenticate('json', { - failWithError: true, - session: false -}); - -module.exports = (operation) => (req, res, next) => { - if (operation["x-operation"] === "signIn") { - login_verification(req, res, next); - } else { - next(); - } -}; \ No newline at end of file diff --git a/middlewares/rules/bulk.js b/middlewares/rules/bulk.js deleted file mode 100644 index 21ea23a..0000000 --- a/middlewares/rules/bulk.js +++ /dev/null @@ -1,91 +0,0 @@ -const chain = require('connect-chain-if'); -const {check_credentials_on_exercises} = require("../../controllers/_common/utlis_fct"); - -const {pass_middleware, check_exercise_state, check_tags_state} = require("./common_sub_middlewares"); -const check_user_role = require("../check_user_role"); -const {USERS} = require("../../controllers/_common/constants"); - -// Arrays for check -const check_credentials_endpoints = ["DeleteExercises", "ChangeExercisesStatus"]; - -module.exports = (operation) => (req, res, next) => { - // some endpoints need additional verification before allowing access - chain([ - chain.if( - check_credentials_endpoints.includes(operation["x-operation"]), - // First check that user is allowed to touch these exercises - (_req, _res, _next) => { - const ids = (check_credentials_endpoints[0] === operation["x-operation"]) - ? _req.body - : _req.body.exercises; - check_credentials_on_exercises(_req.user, ids) - .then(() => _next()) - .catch(/* istanbul ignore next */(err) => _next(err)); - }, - pass_middleware - ), - // If endpoint === ChangeExercisesStatus, only user must endure another check - chain.if( - operation["x-operation"] === "ChangeExercisesStatus", - check_exercise_state([req.body.state].filter(s => s !== undefined)), - pass_middleware - ), - // If endpoint === createMultipleExercises , we should check the state given in exercise - chain.if( - operation["x-operation"] === "createMultipleExercises", - check_exercise_state( - // as this endpoint use 2 different schema, extraction is a little different - Array - .from( - (req.is("json")) - ? req.body - : req.body.exercisesData, - ex => ex.state - ) - .filter(s => s !== undefined) - ), - pass_middleware - ), - // If endpoint === createMultipleExercises , we should check the state given in exercise tags - chain.if( - operation["x-operation"] === "createMultipleExercises", - // as this endpoint use 2 different schema, extraction is a little different - check_tags_state( - Array - .from( - (req.is("json")) - ? req.body - : req.body.exercisesData, - // Only takes tags objects - ex => ex.tags - ) - // if no tags were given - .filter(s => s !== undefined) - // Only takes tags objects - .filter(tags => tags.filter(tag => isNaN(tag))) - // reduce result to an array of dimension 1 (needed for middelware) - .reduce((acc, val) => acc.concat(val), []) - ) - ), - // If endpoint === createMultipleTags , we should check if the user is authorized to include "state" property - chain.if( - operation["x-operation"] === "createMultipleTags", - (_req, _res, _next) => { - let allowed = [USERS.ADMIN, USERS.SUPER_ADMIN]; - // state property is reserved for admin only ; if simple user don't use it - he/she is allowed - if (!_req.body.some(t => t.hasOwnProperty("state"))) { - allowed.push(USERS.USER); - } - check_user_role(allowed)(_req, _res, _next); - }, - pass_middleware - ) - ])(req, res, (err) => { - /* istanbul ignore if */ - if (err) { - next(err); - } else { - next(); - } - }); -}; diff --git a/middlewares/rules/common_sub_middlewares/index.js b/middlewares/rules/common_sub_middlewares/index.js deleted file mode 100644 index 71b9ee1..0000000 --- a/middlewares/rules/common_sub_middlewares/index.js +++ /dev/null @@ -1,43 +0,0 @@ -// Arrays for check -const {USERS, TAGS} = require("../../../controllers/_common/constants"); -const not_allowed_for_user = [TAGS.VALIDATED, TAGS.NOT_VALIDATED]; -const authorizedUsers = [USERS.ADMIN, USERS.SUPER_ADMIN]; - -// Create an Forbidden message -function create_forbidden_error() { - let error = new Error("FORBIDDEN"); - error.message = "It seems you tried to set a state reserved for admin : " + - "This incident will be reported"; - error.status = 403; - return error; -} - -module.exports = { - // check if states given are allowed in this case - check_exercise_state: function (states) { - return (_req, _res, _next) => { - /* istanbul ignore next */ - if (!authorizedUsers.includes(_req.user.role) && states.some(state => not_allowed_for_user.includes(state))) { - let error = create_forbidden_error(); - _next(error); - } else { - _next() - } - }; - }, - // check if given tag(s) are allowed in this case - check_tags_state: function(tags) { - return (_req, _res, _next) => { - if (!authorizedUsers.includes(_req.user.role) && tags.some(tag => tag.hasOwnProperty("state")) ) { - let error = create_forbidden_error(); - _next(error); - } else { - _next() - } - } - }, - // Nothing to do - pass_middleware: function (req, res, next) { - next(); - } -}; diff --git a/middlewares/rules/configurations.js b/middlewares/rules/configurations.js deleted file mode 100644 index d473e46..0000000 --- a/middlewares/rules/configurations.js +++ /dev/null @@ -1,3 +0,0 @@ -module.exports = (operation) => (req, res, next) => { - next(); -}; \ No newline at end of file diff --git a/middlewares/rules/exercises.js b/middlewares/rules/exercises.js deleted file mode 100644 index 0c135d9..0000000 --- a/middlewares/rules/exercises.js +++ /dev/null @@ -1,58 +0,0 @@ -const chain = require('connect-chain-if'); -const {check_credentials_on_exercises, validated_tag_count} = require("../../controllers/_common/utlis_fct"); -const {pass_middleware, check_exercise_state, check_tags_state} = require("./common_sub_middlewares"); - -// Arrays for check -const check_credentials_endpoints = ["UpdateExercise", "createSingleExercise"]; -const REQUIRED_NUMBER_OF_VALIDATED_TAGS = 3; - -module.exports = (operation) => (req, res, next) => { - // some endpoints need additional verification before allowing access - chain([ - // First check that user is allowed to touch this exercise - chain.if( - operation["x-operation"] === "UpdateExercise", - (_req, _res, _next) => { - const id = parseInt(_req.params.id, 10); - check_credentials_on_exercises(_req.user, [id]) - .then(() => _next()) - .catch(/* istanbul ignore next */ - (err) => _next(err)); - }, - pass_middleware - ), - // Second check that user is allowed to use the given state - chain.if( - check_credentials_endpoints.includes(operation["x-operation"]), - check_exercise_state([req.body.state].filter(s => s !== undefined)), - pass_middleware - ), - // Third check that user is allowed to use stats for tag(s) - chain.if( - check_credentials_endpoints.includes(operation["x-operation"]), - // to deal with the fact this security middelware deal with other endpoint that might not have this property - check_tags_state( (req.body.tags || []).filter(tag => isNaN(tag))), - pass_middleware - ), - // Fourth check that user have add at least 3 validated tags - chain.if( - check_credentials_endpoints.includes(operation["x-operation"]), - (_req, _res, _next) => { - const tags = _req.body.tags.filter(tag => !isNaN(tag)); - validated_tag_count( - tags, - REQUIRED_NUMBER_OF_VALIDATED_TAGS - ) - .then(() => _next()) - .catch((err) => _next(err)); - }, - pass_middleware - ) - ])(req, res, (err) => { - if (err) { - next(err); - } else { - next(); - } - }); -}; diff --git a/middlewares/rules/index.js b/middlewares/rules/index.js deleted file mode 100644 index c70914d..0000000 --- a/middlewares/rules/index.js +++ /dev/null @@ -1,9 +0,0 @@ -module.exports = { - "auth": require("./auth"), - "bulk": require("./bulk"), - "configurations": require("./configurations"), - "exercises": require("./exercises"), - "tags": require("./tags"), - "tags_categories": require("./tags_categories"), - "users": require("./users") -}; \ No newline at end of file diff --git a/middlewares/rules/tags.js b/middlewares/rules/tags.js deleted file mode 100644 index d473e46..0000000 --- a/middlewares/rules/tags.js +++ /dev/null @@ -1,3 +0,0 @@ -module.exports = (operation) => (req, res, next) => { - next(); -}; \ No newline at end of file diff --git a/middlewares/rules/tags_categories.js b/middlewares/rules/tags_categories.js deleted file mode 100644 index d473e46..0000000 --- a/middlewares/rules/tags_categories.js +++ /dev/null @@ -1,3 +0,0 @@ -module.exports = (operation) => (req, res, next) => { - next(); -}; \ No newline at end of file diff --git a/middlewares/rules/users.js b/middlewares/rules/users.js deleted file mode 100644 index b94e834..0000000 --- a/middlewares/rules/users.js +++ /dev/null @@ -1,32 +0,0 @@ -const {USERS} = require("../../controllers/_common/constants"); - -module.exports = (operation) => (req, res, next) => { - const action = operation["x-operation"]; - if (action === "updateUser") { - handleUserUpdate(req, res, next); - } else { - next(); - } -}; - -function handleUserUpdate(req, res, next) { - const isAdmin = req.user.role === USERS.SUPER_ADMIN; - const prohibitedPropertiesForUser = ["id", "role"]; - - if (isAdmin) { - next(); - } else { - const bypassCheck = Object - .keys(req.body) - .some(s => prohibitedPropertiesForUser.includes(s) ); - /* istanbul ignore else */ - if (bypassCheck){ - const err = new Error("Forbidden"); - err.message = "It seems you tried to bypass our security : this incident will be reported"; - err.status = 403; - next(err); - } else { - next(); - } - } -} diff --git a/middlewares/security.js b/middlewares/security.js deleted file mode 100644 index 22b6b91..0000000 --- a/middlewares/security.js +++ /dev/null @@ -1,75 +0,0 @@ -const passport = require('passport'); -const chain = require('connect-chain-if'); -let {USERS} = require("../controllers/_common/constants"); - -// middleware -const check_user_role = require("./check_user_role"); -// Additional Rule for endpoints -// Mostly useless from now but it can help if we have to add additional middleware(s) -const rules = require("./rules"); -// common middleware(s) -const only_authenticated_user = passport.authenticate("jwt", { - failWithError: true, - session: false -}); -const pass_middleware = function (req, res, next) { - next(); -}; -// Add guest role for validation -const user_roles = Object.values(USERS).concat("guest"); - -/* istanbul ignore next */ -function extract_required_roles(tags= []) { - let requiredRoles = tags.filter(tag => user_roles.includes(tag)); - // an admin is also capable to do what a simple user can do - if (requiredRoles.includes(USERS.USER)) { - requiredRoles.push(USERS.ADMIN); - } - if (requiredRoles.includes(USERS.ADMIN)) { - requiredRoles.push(USERS.SUPER_ADMIN); - } - return requiredRoles; -} - -module.exports = () => (req, res, next) => { - const operation = (req.operation) ? req.operation /* istanbul ignore next */ : {}; - - // each controller has it own rules but some common behaviour can be inferred using some properties - const extracted_required_roles = extract_required_roles(operation.tags); - const needSecurity = operation.hasOwnProperty("security") && operation.security.every(s => s.hasOwnProperty("bearerAuth")); - const bearerAuthProvided = (req.headers['Authorization'] || req.headers['authorization'] || undefined) !== undefined; - - const options = {operation, roles: extracted_required_roles, needSecurity, bearerAuthProvided}; - // run the middleware - const subChain = main_middleware_chain(options); - chain(subChain)(req, res, (err) => { - if (err) { - next(err); - } else { - next(); - } - }); -}; - -// operation.hasOwnProperty("security") && operation.security.every(s => s.hasOwnProperty("bearerAuth")) -// middleware chains -const main_middleware_chain = ({operation, roles, needSecurity, bearerAuthProvided}) => [ - // First check : if we need security or have a bearerAuth, we must check that - chain.if( - bearerAuthProvided || needSecurity, - only_authenticated_user, - pass_middleware - ), - // Second check : the type of user allowed in this endpoint - chain.if( - roles.length > 0 && !roles.includes("guest"), - check_user_role(roles), - pass_middleware - ), - // if extra rules / middleware(s) should be used inside this controller - chain.if( - rules.hasOwnProperty(operation["x-controller"]), - rules[operation["x-controller"]](operation), - pass_middleware - ) -]; diff --git a/migrations/20191024150545-default_migration.js b/migrations/20191024150545-default_migration.js deleted file mode 100644 index a03d3c7..0000000 --- a/migrations/20191024150545-default_migration.js +++ /dev/null @@ -1,297 +0,0 @@ -'use strict'; -// to construct the string for table -const WithSchema = (schema, table) => (schema) ? `"${schema}"."${table}"` : `"${table}"`; - -module.exports = { - up: (queryInterface, Sequelize) => { - // if using a schema - let schema; - if (queryInterface.sequelize.options.schema) { - schema = queryInterface.sequelize.options.schema; - } - let query = ` - -- Dumped from database version 12.0 - -- Dumped by pg_dump version 12.0 - - SET statement_timeout = 0; - SET lock_timeout = 0; - SET idle_in_transaction_session_timeout = 0; - SET client_encoding = 'UTF8'; - SET standard_conforming_strings = on; - SELECT pg_catalog.set_config('search_path', '', false); - SET check_function_bodies = false; - SET xmloption = content; - SET client_min_messages = warning; - SET row_security = off; - - -- This line is not accepted on travis - SET default_table_access_method = heap; - - CREATE TYPE ${WithSchema(schema, "enum_Users_role")} AS ENUM ( - 'admin', - 'user' - ); - - CREATE TABLE ${WithSchema(schema, "Configurations")} ( - id integer NOT NULL, - name character varying(255) NOT NULL, - user_id integer NOT NULL - ); - - CREATE TABLE ${WithSchema(schema, "Configurations_Tags")} ( - configuration_id integer NOT NULL, - tag_id integer NOT NULL - ); - - CREATE SEQUENCE ${WithSchema(schema, "Configurations_id_seq")} - AS integer - START WITH 1 - INCREMENT BY 1 - NO MINVALUE - NO MAXVALUE - CACHE 1; - - ALTER SEQUENCE ${WithSchema(schema, "Configurations_id_seq")} OWNED BY ${WithSchema(schema, "Configurations")}.id; - - CREATE TABLE ${WithSchema(schema, "Exercises")} ( - id integer NOT NULL, - title character varying(255) NOT NULL, - description text DEFAULT ''::text, - "createdAt" timestamp with time zone NOT NULL, - "updatedAt" timestamp with time zone NOT NULL, - version integer DEFAULT 0 NOT NULL, - user_id integer NOT NULL - ); - - CREATE TABLE ${WithSchema(schema, "Exercises_Metrics")} ( - id integer NOT NULL, - vote_count integer DEFAULT 0 NOT NULL, - avg_vote_score numeric(3,2) DEFAULT 0 NOT NULL, - tags_ids integer[] DEFAULT ARRAY[]::integer[] NOT NULL, - exercise_id integer NOT NULL - ); - - CREATE SEQUENCE ${WithSchema(schema, "Exercises_Metrics_id_seq")} - AS integer - START WITH 1 - INCREMENT BY 1 - NO MINVALUE - NO MAXVALUE - CACHE 1; - - ALTER SEQUENCE ${WithSchema(schema, "Exercises_Metrics_id_seq")} OWNED BY ${WithSchema(schema, "Exercises_Metrics")}.id; - - CREATE TABLE ${WithSchema(schema, "Exercises_Tags")} ( - exercise_id integer NOT NULL, - tag_id integer NOT NULL - ); - - CREATE SEQUENCE ${WithSchema(schema, "Exercises_id_seq")} - AS integer - START WITH 1 - INCREMENT BY 1 - NO MINVALUE - NO MAXVALUE - CACHE 1; - - ALTER SEQUENCE ${WithSchema(schema, "Exercises_id_seq")} OWNED BY ${WithSchema(schema, "Exercises")}.id; - - CREATE TABLE ${WithSchema(schema, "Notations")} ( - id integer NOT NULL, - note numeric(3,2) NOT NULL, - exercise_id integer NOT NULL, - user_id integer NOT NULL - ); - - CREATE SEQUENCE ${WithSchema(schema, "Notations_id_seq")} - AS integer - START WITH 1 - INCREMENT BY 1 - NO MINVALUE - NO MAXVALUE - CACHE 1; - - ALTER SEQUENCE ${WithSchema(schema, "Notations_id_seq")} OWNED BY ${WithSchema(schema, "Notations")}.id; - - CREATE TABLE ${WithSchema(schema, "Tag_Categories")} ( - id integer NOT NULL, - kind character varying(255) NOT NULL - ); - - CREATE SEQUENCE ${WithSchema(schema, "Tag_Categories_id_seq")} - AS integer - START WITH 1 - INCREMENT BY 1 - NO MINVALUE - NO MAXVALUE - CACHE 1; - - ALTER SEQUENCE ${WithSchema(schema, "Tag_Categories_id_seq")} OWNED BY ${WithSchema(schema, "Tag_Categories")}.id; - - CREATE TABLE ${WithSchema(schema, "Tags")} ( - id integer NOT NULL, - text character varying(255) NOT NULL, - "isValidated" boolean DEFAULT false NOT NULL, - "createdAt" timestamp with time zone NOT NULL, - "updatedAt" timestamp with time zone NOT NULL, - version integer DEFAULT 0 NOT NULL, - category_id integer NOT NULL - ); - - CREATE SEQUENCE ${WithSchema(schema, "Tags_id_seq")} - AS integer - START WITH 1 - INCREMENT BY 1 - NO MINVALUE - NO MAXVALUE - CACHE 1; - - ALTER SEQUENCE ${WithSchema(schema, "Tags_id_seq")} OWNED BY ${WithSchema(schema, "Tags")}.id; - - CREATE TABLE ${WithSchema(schema, "Users")} ( - id integer NOT NULL, - email character varying(255) NOT NULL, - password character varying(255) NOT NULL, - "fullName" character varying(255) NOT NULL, - role ${WithSchema(schema, "enum_Users_role")} NOT NULL - ); - - CREATE SEQUENCE ${WithSchema(schema, "Users_id_seq")} - AS integer - START WITH 1 - INCREMENT BY 1 - NO MINVALUE - NO MAXVALUE - CACHE 1; - - ALTER SEQUENCE ${WithSchema(schema, "Users_id_seq")} OWNED BY ${WithSchema(schema, "Users")}.id; - - ALTER TABLE ONLY ${WithSchema(schema, "Configurations")} - ALTER COLUMN id - SET DEFAULT nextval('${WithSchema(schema, "Configurations_id_seq")}'::regclass); - - ALTER TABLE ONLY ${WithSchema(schema, "Exercises")} - ALTER COLUMN id - SET DEFAULT nextval('${WithSchema(schema, "Exercises_id_seq")}'::regclass); - - ALTER TABLE ONLY ${WithSchema(schema, "Exercises_Metrics")} - ALTER COLUMN id - SET DEFAULT nextval('${WithSchema(schema, "Exercises_Metrics_id_seq")}'::regclass); - - ALTER TABLE ONLY ${WithSchema(schema, "Notations")} - ALTER COLUMN id - SET DEFAULT nextval('${WithSchema(schema, "Notations_id_seq")}'::regclass); - - ALTER TABLE ONLY ${WithSchema(schema, "Tag_Categories")} - ALTER COLUMN id - SET DEFAULT nextval('${WithSchema(schema, "Tag_Categories_id_seq")}'::regclass); - - ALTER TABLE ONLY ${WithSchema(schema, "Tags")} - ALTER COLUMN id - SET DEFAULT nextval('${WithSchema(schema, "Tags_id_seq")}'::regclass); - - ALTER TABLE ONLY ${WithSchema(schema, "Users")} - ALTER COLUMN id - SET DEFAULT nextval('${WithSchema(schema, "Users_id_seq")}'::regclass); - - ALTER TABLE ONLY ${WithSchema(schema, "Configurations_Tags")} - ADD CONSTRAINT "Configurations_Tags_pkey" PRIMARY KEY (configuration_id, tag_id); - - ALTER TABLE ONLY ${WithSchema(schema, "Configurations")} - ADD CONSTRAINT "Configurations_pkey" PRIMARY KEY (id); - - ALTER TABLE ONLY ${WithSchema(schema, "Exercises_Metrics")} - ADD CONSTRAINT "Exercises_Metrics_pkey" PRIMARY KEY (id); - - ALTER TABLE ONLY ${WithSchema(schema, "Exercises_Tags")} - ADD CONSTRAINT "Exercises_Tags_pkey" PRIMARY KEY (exercise_id, tag_id); - - ALTER TABLE ONLY ${WithSchema(schema, "Exercises")} - ADD CONSTRAINT "Exercises_pkey" PRIMARY KEY (id); - - ALTER TABLE ONLY ${WithSchema(schema, "Notations")} - ADD CONSTRAINT "Notations_pkey" PRIMARY KEY (id); - - ALTER TABLE ONLY ${WithSchema(schema, "Tag_Categories")} - ADD CONSTRAINT "Tag_Categories_kind_key" UNIQUE (kind); - - ALTER TABLE ONLY ${WithSchema(schema, "Tag_Categories")} - ADD CONSTRAINT "Tag_Categories_pkey" PRIMARY KEY (id); - - ALTER TABLE ONLY ${WithSchema(schema, "Tags")} - ADD CONSTRAINT "Tags_pkey" PRIMARY KEY (id); - - ALTER TABLE ONLY ${WithSchema(schema, "Users")} - ADD CONSTRAINT "Users_pkey" PRIMARY KEY (id); - - ALTER TABLE ONLY ${WithSchema(schema, "Users")} - ADD CONSTRAINT "Users_email_key" UNIQUE (email); - - ALTER TABLE ONLY ${WithSchema(schema, "Configurations_Tags")} - ADD CONSTRAINT "Configurations_Tags_configuration_id_fkey" - FOREIGN KEY (configuration_id) - REFERENCES ${WithSchema(schema, "Configurations")}(id) - ON UPDATE CASCADE ON DELETE CASCADE; - - ALTER TABLE ONLY ${WithSchema(schema, "Configurations_Tags")} - ADD CONSTRAINT "Configurations_Tags_tag_id_fkey" - FOREIGN KEY (tag_id) - REFERENCES ${WithSchema(schema, "Tags")}(id) - ON UPDATE CASCADE ON DELETE CASCADE; - - ALTER TABLE ONLY ${WithSchema(schema, "Configurations")} - ADD CONSTRAINT "Configurations_user_id_fkey" - FOREIGN KEY (user_id) - REFERENCES ${WithSchema(schema, "Users")}(id) - ON UPDATE CASCADE ON DELETE CASCADE; - - ALTER TABLE ONLY ${WithSchema(schema, "Exercises_Metrics")} - ADD CONSTRAINT "Exercises_Metrics_exercise_id_fkey" - FOREIGN KEY (exercise_id) - REFERENCES ${WithSchema(schema, "Exercises")}(id) - ON UPDATE CASCADE ON DELETE CASCADE; - - ALTER TABLE ONLY ${WithSchema(schema, "Exercises_Tags")} - ADD CONSTRAINT "Exercises_Tags_exercise_id_fkey" - FOREIGN KEY (exercise_id) - REFERENCES ${WithSchema(schema, "Exercises")}(id) - ON UPDATE CASCADE ON DELETE CASCADE; - - ALTER TABLE ONLY ${WithSchema(schema, "Exercises_Tags")} - ADD CONSTRAINT "Exercises_Tags_tag_id_fkey" - FOREIGN KEY (tag_id) - REFERENCES ${WithSchema(schema, "Tags")}(id) - ON UPDATE CASCADE ON DELETE CASCADE; - - ALTER TABLE ONLY ${WithSchema(schema, "Exercises")} - ADD CONSTRAINT "Exercises_user_id_fkey" - FOREIGN KEY (user_id) - REFERENCES ${WithSchema(schema, "Users")}(id) - ON UPDATE CASCADE ON DELETE CASCADE; - - ALTER TABLE ONLY ${WithSchema(schema, "Notations")} - ADD CONSTRAINT "Notations_exercise_id_fkey" - FOREIGN KEY (exercise_id) - REFERENCES ${WithSchema(schema, "Exercises")}(id) - ON UPDATE CASCADE ON DELETE CASCADE; - - ALTER TABLE ONLY ${WithSchema(schema, "Notations")} - ADD CONSTRAINT "Notations_user_id_fkey" - FOREIGN KEY (user_id) - REFERENCES ${WithSchema(schema, "Users")}(id) - ON UPDATE CASCADE ON DELETE CASCADE; - - ALTER TABLE ONLY ${WithSchema(schema, "Tags")} - ADD CONSTRAINT "Tags_category_id_fkey" - FOREIGN KEY (category_id) - REFERENCES ${WithSchema(schema, "Tag_Categories")}(id) - ON UPDATE CASCADE ON DELETE CASCADE; - `; - return queryInterface.sequelize.query(query); - }, - - down: (queryInterface, Sequelize) => { - // delete all tables since it is the first migrations - return queryInterface.dropAllTables(); - } -}; diff --git a/migrations/20191202130021-addTitleInConfiguration.js b/migrations/20191202130021-addTitleInConfiguration.js deleted file mode 100644 index 3a0d142..0000000 --- a/migrations/20191202130021-addTitleInConfiguration.js +++ /dev/null @@ -1,22 +0,0 @@ -'use strict'; - -let opts = { tableName: 'Configurations' }; - -module.exports = { - up: (queryInterface, Sequelize) => { - if (queryInterface.sequelize.options.schema) { - opts.schema = queryInterface.sequelize.options.schema; - } - return queryInterface.addColumn(opts, "title", { - defaultValue: "", - type: Sequelize.STRING - }); - }, - - down: (queryInterface, Sequelize) => { - if (queryInterface.sequelize.options.schema) { - opts.schema = queryInterface.sequelize.options.schema; - } - return queryInterface.removeColumn(opts, "title") - } -}; diff --git a/migrations/20191204204139-addPropertiesInExercise.js b/migrations/20191204204139-addPropertiesInExercise.js deleted file mode 100644 index c6acb55..0000000 --- a/migrations/20191204204139-addPropertiesInExercise.js +++ /dev/null @@ -1,45 +0,0 @@ -'use strict'; - -let opts = {tableName: 'Exercises'}; - -module.exports = { - up: (queryInterface, Sequelize) => { - if (queryInterface.sequelize.options.schema) { - opts.schema = queryInterface.sequelize.options.schema; - } - return queryInterface.sequelize.transaction(async (t) => { - - await queryInterface.addColumn(opts, "file", { - type: Sequelize.STRING, - allowNull: true - }, {transaction: t}); - - await queryInterface.addColumn(opts, "isValidated", { - type: Sequelize.BOOLEAN, - allowNull: false, - defaultValue: false - }, {transaction: t}); - - await queryInterface.addColumn(opts, "url", { - type: Sequelize.STRING, - allowNull: true - }, {transaction: t}); - - return Promise.resolve(); - }); - }, - - down: (queryInterface, Sequelize) => { - if (queryInterface.sequelize.options.schema) { - opts.schema = queryInterface.sequelize.options.schema; - } - return queryInterface.sequelize.transaction(async (t) => { - - await queryInterface.removeColumn(opts, "file", {transaction: t}); - await queryInterface.removeColumn(opts, "isValidated", {transaction: t}); - await queryInterface.removeColumn(opts, "url", {transaction: t}); - - return Promise.resolve(); - }); - } -}; diff --git a/migrations/20191227002857-replaceIsValidatedByStatusInExercise.js b/migrations/20191227002857-replaceIsValidatedByStatusInExercise.js deleted file mode 100644 index 8275e0b..0000000 --- a/migrations/20191227002857-replaceIsValidatedByStatusInExercise.js +++ /dev/null @@ -1,31 +0,0 @@ -'use strict'; - -let opts = {tableName: 'Exercises'}; - -module.exports = { - up: (queryInterface, Sequelize) => { - if (queryInterface.sequelize.options.schema) { - opts.schema = queryInterface.sequelize.options.schema; - } - - return queryInterface.sequelize.transaction(async (t) => { - - await queryInterface.removeColumn(opts, "isValidated", {transaction: t}); - await queryInterface.addColumn(opts, "state", { - type: Sequelize.ENUM("DRAFT", "PENDING", "VALIDATED", "NOT_VALIDATED"), - defaultValue: "DRAFT" - }, {transaction: t}); - - return Promise.resolve(); - }); - }, - - down: (queryInterface, Sequelize) => { - if (queryInterface.sequelize.options.schema) { - opts.schema = queryInterface.sequelize.options.schema; - } - return Promise.all([ - queryInterface.removeColumn(opts, "state") - ]); - } -}; diff --git a/migrations/20200116145402-addNewEnumValues.js b/migrations/20200116145402-addNewEnumValues.js deleted file mode 100644 index e5513d7..0000000 --- a/migrations/20200116145402-addNewEnumValues.js +++ /dev/null @@ -1,27 +0,0 @@ -'use strict'; - -let enumName = "enum_Exercises_state"; -let enumValue = "ARCHIVED"; - -module.exports = { - up: (queryInterface, Sequelize) => { - // if using a schema - let schema; - if (queryInterface.sequelize.options.schema) { - schema = queryInterface.sequelize.options.schema; - } - let enumNameWithSchema = (schema) ? `"${schema}"."${enumName}"` : `"${enumName}"`; - return queryInterface.sequelize.query(`ALTER TYPE ${enumNameWithSchema} ADD VALUE '${enumValue}'`); - }, - - down: (queryInterface, Sequelize) => { - // whatever inside a schema or not, all enum in a database are stored inside a single location - let query = `DELETE - FROM pg_enum - WHERE enumlabel = '${enumValue}' - AND enumtypid IN ( SELECT oid FROM pg_type WHERE typname = '${enumName}') - `; - - return queryInterface.sequelize.query(query); - } -}; diff --git a/migrations/20200226152253-replaceIsValidatedByState.js b/migrations/20200226152253-replaceIsValidatedByState.js deleted file mode 100644 index 94ca3bd..0000000 --- a/migrations/20200226152253-replaceIsValidatedByState.js +++ /dev/null @@ -1,45 +0,0 @@ -'use strict'; - -let opts = {tableName: 'Tags'}; -const {TAGS: TagState} = require("../controllers/_common/constants"); -const values = Object.values(TagState); - -module.exports = { - up: (queryInterface, Sequelize) => { - // if using a schema - if (queryInterface.sequelize.options.schema) { - opts.schema = queryInterface.sequelize.options.schema; - } - return queryInterface.sequelize.transaction(async (t) => { - - // creates the enum - await queryInterface - .addColumn(opts, "state", { - type: Sequelize.ENUM(values), - defaultValue: TagState.NOT_VALIDATED - }, {transaction: t}); - - // populate the db - await queryInterface - .bulkUpdate(opts, { - state: TagState.VALIDATED - }, { - isValidated: true - }, {transaction: t}); - - // destroy old field - await queryInterface.removeColumn(opts, "isValidated", {transaction: t}); - - return Promise.resolve(); - }); - }, - - down: (queryInterface, Sequelize) => { - if (queryInterface.sequelize.options.schema) { - opts.schema = queryInterface.sequelize.options.schema; - } - return Promise.all([ - queryInterface.removeColumn(opts, "state") - ]); - } -}; diff --git a/migrations/20200301191222-addNewUserRole.js b/migrations/20200301191222-addNewUserRole.js deleted file mode 100644 index e97382d..0000000 --- a/migrations/20200301191222-addNewUserRole.js +++ /dev/null @@ -1,27 +0,0 @@ -'use strict'; - -let enumName = "enum_Users_role"; -let enumValue = "super_admin"; - -module.exports = { - up: (queryInterface, Sequelize) => { - // if using a schema - let schema; - if (queryInterface.sequelize.options.schema) { - schema = queryInterface.sequelize.options.schema; - } - let enumNameWithSchema = (schema) ? `"${schema}"."${enumName}"` : `"${enumName}"`; - return queryInterface.sequelize.query(`ALTER TYPE ${enumNameWithSchema} ADD VALUE '${enumValue}'`); - }, - - down: (queryInterface, Sequelize) => { - // whatever inside a schema or not, all enum in a database are stored inside a single location - let query = `DELETE - FROM pg_enum - WHERE enumlabel = '${enumValue}' - AND enumtypid IN ( SELECT oid FROM pg_type WHERE typname = '${enumName}') - `; - - return queryInterface.sequelize.query(query); - } -}; diff --git a/migrations/20200307114926-addMaterializedViewForTagsSummary.js b/migrations/20200307114926-addMaterializedViewForTagsSummary.js deleted file mode 100644 index cd3efc0..0000000 --- a/migrations/20200307114926-addMaterializedViewForTagsSummary.js +++ /dev/null @@ -1,96 +0,0 @@ -'use strict'; - -// to construct the string for table -const WithSchema = (schema, table) => (schema) ? `"${schema}"."${table}"` : `"${table}"`; -const functionForTrigger = "refresh_tags_summary_search"; -const materialiazedViewName = "tags_by_exercise_state"; - -module.exports = { - up: (queryInterface, Sequelize) => { - // if using a schema - let schema; - if (queryInterface.sequelize.options.schema) { - schema = queryInterface.sequelize.options.schema; - } - - - let query = ` - BEGIN; - -- the MATERIALIZED VIEW - - CREATE MATERIALIZED VIEW ${WithSchema(schema, materialiazedViewName)} - AS - SELECT - et."tag_id" AS "tag_id", - COUNT(*) FILTER (WHERE ex.state = 'DRAFT') AS "total_draft", - COUNT(*) FILTER (WHERE ex.state = 'PENDING') AS "total_pending", - COUNT(*) FILTER (WHERE ex.state = 'VALIDATED') AS "total_validated", - COUNT(*) FILTER (WHERE ex.state = 'NOT_VALIDATED') AS "total_not_validated", - COUNT(*) FILTER (WHERE ex.state = 'ARCHIVED') AS "total_archived" - FROM ${WithSchema(schema, "Exercises")} ex - LEFT JOIN ${WithSchema(schema, "Exercises_Tags")} et - ON et."exercise_id" = ex.id - GROUP BY et."tag_id" - WITH DATA; - - -- index required for MATERIALIZED VIEW CONCURRENTLY - - CREATE UNIQUE INDEX tags_by_exercise_state_tag_id - ON ${WithSchema(schema, materialiazedViewName)}(tag_id); - - -- function for trigger - - CREATE OR REPLACE FUNCTION ${WithSchema(schema, functionForTrigger)}() RETURNS TRIGGER LANGUAGE plpgsql AS $$ - BEGIN - REFRESH MATERIALIZED VIEW CONCURRENTLY ${WithSchema(schema, materialiazedViewName)}; - RETURN NULL; - END $$; - - -- triggers - - CREATE TRIGGER auto_refresh_materialized_tag_view_1 - AFTER INSERT OR DELETE OR TRUNCATE - ON ${WithSchema(schema, "Exercises_Tags")} - FOR EACH STATEMENT - EXECUTE PROCEDURE ${WithSchema(schema, functionForTrigger)}(); - - CREATE TRIGGER auto_refresh_materialized_tag_view_2 - AFTER UPDATE OR DELETE OR TRUNCATE - ON ${WithSchema(schema, "Exercises")} - FOR EACH STATEMENT - EXECUTE PROCEDURE ${WithSchema(schema, functionForTrigger)}(); - - CREATE TRIGGER auto_refresh_materialized_tag_view_3 - AFTER INSERT OR DELETE OR TRUNCATE - ON ${WithSchema(schema, "Tags")} - FOR EACH STATEMENT - EXECUTE PROCEDURE ${WithSchema(schema, functionForTrigger)}(); - - COMMIT; - `; - - return queryInterface.sequelize.query(query); - }, - - down: (queryInterface, Sequelize) => { - // if using a schema - let schema; - if (queryInterface.sequelize.options.schema) { - schema = queryInterface.sequelize.options.schema; - } - let query = ` - BEGIN; - - DROP TRIGGER IF EXISTS auto_refresh_materialized_tag_view_1 ON ${WithSchema(schema, "Exercises_Tags")}; - DROP TRIGGER IF EXISTS auto_refresh_materialized_tag_view_2 ON ${WithSchema(schema, "Exercises")}; - DROP TRIGGER IF EXISTS auto_refresh_materialized_tag_view_3 ON ${WithSchema(schema, "Tags")}; - - DROP FUNCTION IF EXISTS ${WithSchema(schema, functionForTrigger)}; - DROP MATERIALIZED VIEW IF EXISTS ${WithSchema(schema, materialiazedViewName)}; - - COMMIT; - `; - - return queryInterface.sequelize.query(query); - } -}; diff --git a/models/configuration.js b/models/configuration.js deleted file mode 100644 index fa7cd49..0000000 --- a/models/configuration.js +++ /dev/null @@ -1,49 +0,0 @@ -'use strict'; - -module.exports = (sequelize, DataTypes) => { - let Configuration = sequelize.define("Configuration",{ - name: { - type: DataTypes.STRING, - allowNull: false, - }, - title: { - type: DataTypes.STRING, - defaultValue: "" - } - },{ - // https://sequelize.org/master/manual/models-definition.html#configuration - - // don't add the timestamp attributes (updatedAt, createdAt) - timestamps: false - }); - - Configuration.associate = function (models) { - // a configuration can use multiple tags - Configuration.belongsToMany(models.Tag, { - through: models.Configuration_Tag, - foreignKey: { - name: "configuration_id", - allowNull: false - } - }); - // a configuration belongs to a user - Configuration.belongsTo(models.User, { - as: "User", - foreignKey: { - name: "user_id", - allowNull: false - }, - onDelete: "CASCADE" - }); - // to fetch tags related to this configuration - Configuration.hasMany(models.Configuration_Tag, { - as: "tags", - foreignKey: { - name: "configuration_id", - allowNull: false - } - }) - }; - - return Configuration; -}; \ No newline at end of file diff --git a/models/configuration_tag.js b/models/configuration_tag.js deleted file mode 100644 index 761293d..0000000 --- a/models/configuration_tag.js +++ /dev/null @@ -1,33 +0,0 @@ -'use strict'; - -module.exports = (sequelize, DataTypes) => { - let ConfigurationTag = sequelize.define("Configuration_Tag", { - // if we need another fields ( but probably not ) - }, { - // https://sequelize.org/master/manual/models-definition.html#configuration - timestamps: false, - tableName: "Configurations_Tags" - }); - - ConfigurationTag.associate = function (models) { - ConfigurationTag.belongsTo(models.Tag, { - foreignKey: { - name: 'tag_id', - allowNull: false - }, - targetKey: 'id', - as: 'Tag', - onDelete: "CASCADE" - }); - ConfigurationTag.belongsTo(models.Configuration, { - foreignKey: { - name: 'configuration_id', - allowNull: false - }, - targetKey: 'id', - as: 'Configuration' - }); - }; - - return ConfigurationTag; -}; \ No newline at end of file diff --git a/models/exercise.js b/models/exercise.js deleted file mode 100644 index 9b88bb5..0000000 --- a/models/exercise.js +++ /dev/null @@ -1,452 +0,0 @@ -'use strict'; - -const Sequelize = require("sequelize"); -const Op = Sequelize.Op; - -const { EXERCISES: exerciseState, TAGS: tagState } = require("../controllers/_common/constants"); -let enumValues = Object.values(exerciseState); - -// Useful for vote filtering (and maybe other things later) -const OPERATIONS = { - "<=": Op.lte, - "<": Op.lt, - ">=": Op.gte, - ">": Op.gt -}; - -module.exports = (sequelize, DataTypes) => { - let Exercise = sequelize.define('Exercise', { - title: { - type: DataTypes.STRING, - allowNull: false, - }, - description: { - type: DataTypes.TEXT, - defaultValue: "" - }, - file: { - type: DataTypes.STRING, - allowNull: true - }, - state: { - type: DataTypes.ENUM(enumValues), - allowNull: false, - defaultValue: exerciseState.DRAFT - }, - url: { - type: DataTypes.STRING, - allowNull: true - } - }, { - // https://sequelize.org/master/manual/models-definition.html#configuration - - // Enable optimistic locking. When enabled, sequelize will add a version count attribute - // to the model and throw an OptimisticLockingError error when stale instances are saved. - // Set to true or a string with the attribute name you want to use to enable. - version: true, - - // scopes : reuse more easily some common parts - // https://sequelize.org/master/manual/scopes.html - scopes: { - - // to deal with the horrible order by clauses generically generated - orderByClauses(fields) { - // To handle order by clauses - // the last item in the values array will be the choice of the user (instead of the '') - const ORDER_BY_FIELDS = { - "state": ["state", ''], - "id": ["id", ''], - "title": ["title", ''], - "date": ['updatedAt', ''], - "avg_score": [ - {model: sequelize.models.Exercise_Metrics, as: "metrics"}, - 'avg_vote_score', - '' - ], - "vote_count": [ - {model: sequelize.models.Exercise_Metrics, as: "metrics"}, - 'vote_count', - '' - ], - }; - return { - order: fields.map(field => { - let order_by_clause = ORDER_BY_FIELDS[field.field]; - // Remove the last empty value so that we can add - order_by_clause.pop(); - order_by_clause.push(field.value); - return order_by_clause; - }) - }; - }, - // to find exercise(s) that match criteria - find_exercises_ids_with_given_criteria({parameters, metadata}) { - // options for sequelize query builder - let options = { - attributes: ["id"], - // need to have access to metrics for some filtering stuff - include: [{ - model: sequelize.models.Exercise_Metrics, - required: true, - as: "metrics", - where: whereConditionBuilder(parameters), - attributes: [] - }] - }; - // if metadata were given - /* istanbul ignore else */ - if (metadata) { - options["limit"] = metadata.size; - options["offset"] = (metadata.page - 1) * metadata.size; - } - let criteria = []; - - if (parameters.hasOwnProperty("filterOptions")) { - /* istanbul ignore else */ - if (parameters.filterOptions.hasOwnProperty("state")) { - criteria.push({ - state: { - [Op.in]: parameters.filterOptions.state.map(s => exerciseState[s]) - } - }); - } - } - // if the user provide some instructions , we must add them to the where clause - if (parameters.hasOwnProperty("data")) { - - /* istanbul ignore else */ - if (parameters.data.hasOwnProperty("title")) { - criteria.push({ - title: { - [Op.iLike]: `%${parameters.data.title}%` - } - }); - } - - if (parameters.data.hasOwnProperty("user_ids")) { - criteria.push({ - user_id: { - [Op.in]: parameters.data["user_ids"] - } - }); - } - - if (parameters.data.hasOwnProperty("exercise_ids")) { - criteria.push({ - id: { - [Op.in]: parameters.data["exercise_ids"] - } - }); - } - - } - // merge multiple criteria into the where - options.where = Object.assign({}, ...criteria); - return options; - }, - // for bulky query, default attributes to show - default_attributes_for_bulk: { - attributes: { - exclude: ["user_id"] - } - }, - // if we want to exclude the description for bulky query - without_exercise_description: { - attributes: { - exclude: ["description"] - } - }, - // filter exercises ids - filter_exercises_ids(ids) { - return { - where: { - id: { - [Op.in]: ids - } - } - } - }, - // include the metrics part - with_exercise_metrics() { - return { - include: [ - // load exercise evaluation - { - model: sequelize.models.Exercise_Metrics, - as: "metrics", - required: true, - attributes: [ - ["vote_count", "votes"], - ["avg_vote_score", "avg_score"] - ] - } - ] - } - }, - // include the creator of the exercise - with_exercise_creator() { - return { - include: [ - // include basic information on exercise creator - { - model: sequelize.models.User, - as: "creator", - required: true, - attributes: [ - ["fullName", "fullName"], - ["email", "email"] - ] - } - ] - } - }, - // retrieve all the tags of this exercise - // filterOptions may be used if asked for one purpose : filter the extracted tags - with_related_tags_with_their_category(filterOptions) { - return { - include: [ - { - model: sequelize.models.Tag, - as: "tags", - attributes: [ - ["id", "tag_id"], - ["text", "tag_text"], - "state" - ], - through: {attributes: []}, - // Handle the case where no tags exists for one exercise - required: false, - // if asked, only include some tags (and not all) - where: - (![undefined].includes(filterOptions && filterOptions.tags)) - ? { - state: { - [Op.in]: filterOptions.tags.map(s => tagState[s] ) - } - } - : {} - , - include: [ - { - model: sequelize.models.Tag_Category, - as: "category", - required: true, - attributes: [ - ["kind", "category_text"], - ["id", "category_id"] - ] - } - ] - } - ] - } - }, - - // for /api/export - with_related_tags(filterOptions) { - return { - include: [ - { - model: sequelize.models.Tag, - as: "tags", - attributes: [ - ["text", "text"], - ["category_id", "category"], - "state" - ], - through: {attributes: []}, - // if asked, only include some tags (and not all) - where: - (![undefined].includes(filterOptions && filterOptions.tags)) - ? { - state: { - [Op.in]: filterOptions.tags.map(s => tagState[s] ) - } - } - : {} - , - // Handle the case where no tags exists for one exercise - required: false, - } - ] - } - } - } - }); - - Exercise.associate = function (models) { - // An exercise can be evaluated multiples times - Exercise.hasMany(models.Notation, { - as: "notes", - foreignKey: { - name: "exercise_id", - allowNull: false - } - }); - // An exercise has one metrics - Exercise.hasOne(models.Exercise_Metrics, { - as: "metrics", - foreignKey: { - name: "exercise_id", - allowNull: false - } - }); - // An exercise could have multiple tags - Exercise.belongsToMany(models.Tag, { - through: models.Exercise_Tag, - timestamps: false, - as: "tags", - foreignKey: "exercise_id" - }); - // An exercise could have many tag entries - Exercise.hasMany(models.Exercise_Tag, { - as: "tag_entries", - foreignKey: { - name: "exercise_id", - allowNull: false - } - }); - // An exercise is linked to a User - Exercise.belongsTo(models.User, { - as: "creator", - foreignKey: { - name: "user_id", - allowNull: false - }, - onDelete: "CASCADE" - }); - }; - - // when an exercise is created in database, automatically create a Exercise_Metrics row - Exercise.addHook("afterCreate", "auto_create_exercise_metrics", function (exercise, options) { - return exercise - .sequelize - .models - .Exercise_Metrics - .create({ - exercise_id: exercise.id - }, { - transaction: options.transaction - }); - }); - - return Exercise; -}; - -// utilities function for scopes - -// Tags where condition builder -const simpleCase = (array, mustBePresent) => { - // positive tags : 2 OR 3 OR 4 , etc... - // negative tags : NOT 2 OR NOT 3 , etc... - return Sequelize.where( - // for negative check, we should use contains instead - // For example (using the examples above) : - // For positive check : tags_ids && [2,3,4] - // For negative check : tags_ids @> [2,3] - Sequelize.where( - Sequelize.col("tags_ids"), - (mustBePresent) ? Op.overlap : Op.contains, - array - ), - Op.is, - mustBePresent - ) -}; -const tagsWhereBuilder = { - "simpleCase": simpleCase, - "complexCase": (must_have, must_not) => ({ - [Op.or]: [ - simpleCase(must_have, true), - simpleCase(must_not, false), - ] - }) -}; - -// tag condition builder -function tagsConditionsBuilder(tags) { - - const conditions = tags.map(tagOrTags => { - - // filter negative/positive integer(s) into array ( more efficient to check that way ) - const must_have = Array.isArray(tagOrTags) - ? tagOrTags.filter(tag => tag >= 0) - : tagOrTags >= 0 - ? [tagOrTags] - : []; - const must_not = Array.isArray(tagOrTags) - ? tagOrTags.filter(tag => !(tag >= 0)).map(tag => -tag) - : tagOrTags >= 0 - ? [] - : [-tagOrTags]; - - // multiple case can occur because of the mixin of must_have / must_not checks - // One is these case is mandatory true - const kind = (must_not.length > 0 && must_have.length > 0) ? "complexCase" : "simpleCase"; - - // in simple case, we only care about - if (kind === "simpleCase") { - return tagsWhereBuilder[kind]( - (must_have.length > 0) ? must_have : must_not, - // simplification : if must_have is not empty, mustOverlap will be true , otherwise false (must_not) - must_have.length > 0 - ) - } else { - // the most horrible case - return tagsWhereBuilder[kind](must_have, must_not) - } - - }); - - // as the expression is in Conjunctive Normal Form, we know we can combine AND and OR formulas - return { - [Op.and]: conditions - }; -} - -// properties we need to check for whereConditionBuilder -const metricsPropertiesToCheck = ["tags", "vote"]; - -// where condition builder for find_exercises_ids_with_given_criteria -function whereConditionBuilder(parameters) { - - // does the user provide us filter criteria - if ( - (!parameters.hasOwnProperty("data")) - || - metricsPropertiesToCheck - .map(key => parameters.data.hasOwnProperty(key)) - .every(b => !b) - ) { - return {} - } else { - // at least one criteria was given - const data = parameters.data; - const criteria = []; - - // tag criteria was given - /* istanbul ignore else */ - if (data.hasOwnProperty("tags")) { - criteria.push( - tagsConditionsBuilder(data.tags) - ); - } - - // vote criteria was given - if (data.hasOwnProperty("vote")) { - const {operator, value} = data.vote; - criteria.push( - Sequelize.where( - Sequelize.col("avg_vote_score"), - OPERATIONS[operator], - value - ) - ) - } - - // at least one criteria was given because of the executed path - return { - [Op.and]: criteria - }; - } -} diff --git a/models/exercise_metrics.js b/models/exercise_metrics.js deleted file mode 100644 index 9dd8793..0000000 --- a/models/exercise_metrics.js +++ /dev/null @@ -1,42 +0,0 @@ -'use strict'; - -// This sub table is useful to save computation times for search -module.exports = (sequelize, DataTypes) => { - let Exercise_Metrics = sequelize.define('Exercise_Metrics', { - // to count how many votes for this exercise - vote_count: { - type: DataTypes.INTEGER, - defaultValue: 0, - allowNull: false - }, - // the average score - avg_vote_score: { - type: DataTypes.NUMERIC(3,2), - defaultValue: 0.0, - allowNull: false - }, - // the tags ids, pre-retrieved so that search is faster - tags_ids: { - type: DataTypes.ARRAY(DataTypes.INTEGER), - allowNull: false, - defaultValue: [] - } - }, { - // https://sequelize.org/master/manual/models-definition.html#configuration - timestamps: false, - tableName: "Exercises_Metrics" - }); - - Exercise_Metrics.associate = function (models) { - // each exercise has only one Exercise Metrics - models.Exercise_Metrics.belongsTo(models.Exercise, { - as: "exercise", - foreignKey: { - name: "exercise_id", - allowNull: false - } - }) - }; - - return Exercise_Metrics; -}; diff --git a/models/exercise_tag.js b/models/exercise_tag.js deleted file mode 100644 index eebbeec..0000000 --- a/models/exercise_tag.js +++ /dev/null @@ -1,184 +0,0 @@ -"use strict"; -const Sequelize = require("sequelize"); -const Op = Sequelize.Op; -const difference = require('lodash.difference'); - -module.exports = (sequelize, DataTypes) => { - let ExerciseTag = sequelize.define( - "Exercise_Tag", - { - // if we need another fields ( but probably not ) - }, - { - // https://sequelize.org/master/manual/models-definition.html#configuration - timestamps: false, - tableName: "Exercises_Tags", - scopes: { - filter_by_exercise_ids(ids) { - return { - where: { - exercise_id: { - [Op.in]: ids - } - } - } - }, - // to compute tags array - tags_summary(/* istanbul ignore next */ options = {}) { - let settings = { - attributes: [ - "exercise_id", - [sequelize.fn("array_agg", sequelize.col("tag_id")), "tags"] - ], - group: "exercise_id", - transaction: options.transaction - }; - /* istanbul ignore next */ - if (options.hasOwnProperty("transaction")) { - settings["transaction"] = options.transaction; - } - return settings; - } - } - } - ); - - ExerciseTag.associate = function (models) { - ExerciseTag.belongsTo(models.Tag, { - foreignKey: { - name: "tag_id", - allowNull: false - }, - targetKey: "id", - onDelete: "CASCADE" - }); - ExerciseTag.belongsTo(models.Exercise, { - foreignKey: { - name: "exercise_id", - allowNull: false - }, - targetKey: "id", - onDelete: "CASCADE" - }) - }; - - // after bulk insert of tags, we must update the "tags_ids" of given exercise(s) - ExerciseTag.addHook( - "afterBulkCreate", - "auto_update_tags_exercise_metrics", - (instances, options) => { - // retrieve exercises ids of inserted row(s) - const exercises_ids = [ - ...new Set( - instances.map(value => { - return value.exercise_id; - }) - ) - ]; - - // computes the new tags array for each exercise - return ExerciseTag - .scope([ - {method: ["filter_by_exercise_ids", exercises_ids]}, - {method: ["tags_summary", options]} - ]) - .findAll() - .then(exercises_with_tags => { - // bulk update - return Promise.all( - exercises_with_tags.map( - (exercise) => { - return sequelize - .models - .Exercise_Metrics - .update({ - tags_ids: exercise.get("tags") - }, { - where: { - exercise_id: exercise.get("exercise_id") - }, - transaction: options.transaction - }) - } - ) - ) - }); - } - ); - - // When some tags are deleted ( or a category that contains tags ) - // We must update the "tags_ids" of given exercises - ExerciseTag.addHook( - "beforeBulkDestroy", - "auto_remove_tags_exercise_metrics", - (options) => { - - // first retrieve exercise(s) and tags id(s) impacted by this delete - return sequelize - .models - .Exercise_Tag - .findAll({ - attributes: [ - ["exercise_id", "exercise"], - ["tag_id", "tag"] - ], - where: options.where, - transaction: options.transaction - }) - .then((rows) => { - const exercises = rows.map(r => r.get("exercise")); - const tags = rows.map(r => r.get("tag")); - return Promise.all([ - // Exercise_Metrics for exercises that should be modified - sequelize - .models - .Exercise_Metrics - .findAll({ - attributes: [ - ["exercise_id", "exercise"], - ["tags_ids", "tags"] - ], - where: { - exercise_id: { - [Op.in]: exercises - } - }, - transaction: options.transaction - }) - , - // the tags that should be removed - tags, - ]) - }) - .then(([exercises_metrics, tagsToRemove]) => { - // Good point with this implementation : - // if there is no exercise with these tags, nothing extra will be done - return Promise.all( - exercises_metrics.map(metrics => { - // compute the tags changes and del with every case - // as empty array could occur, I must cast it every time to prevent an issue - const newTagArray = Sequelize.cast( - difference(metrics.get("tags"), tagsToRemove), - "integer[]" - ); - - // execute the change order - return sequelize - .models - .Exercise_Metrics - .update({ - tags_ids: newTagArray - }, { - where: { - exercise_id: metrics.get("exercise") - }, - transaction: options.transaction - }) - }) - ) - }) - } - ); - - return ExerciseTag; -}; diff --git a/models/index.js b/models/index.js deleted file mode 100644 index a50500a..0000000 --- a/models/index.js +++ /dev/null @@ -1,38 +0,0 @@ -'use strict'; - -const fs = require('fs'); -const path = require('path'); -const Sequelize = require('sequelize'); -const basename = path.basename(__filename); -const env = process.env.NODE_ENV /* istanbul ignore next */ || 'development'; -const config = require(__dirname + '/../config/config.js')[env]; -const db = {}; - -let sequelize; -/* istanbul ignore else */ -if (config.use_env_variable) { - sequelize = new Sequelize(process.env[config.use_env_variable], config); -} else { - sequelize = new Sequelize(config.database, config.username, config.password, config); -} - -fs - .readdirSync(__dirname) - .filter(file => { - return (file.indexOf('.') !== 0) && (file !== basename) && (file.slice(-3) === '.js'); - }) - .forEach(file => { - const model = sequelize['import'](path.join(__dirname, file)); - db[model.name] = model; - }); - -Object.keys(db).forEach(modelName => { - if (db[modelName].associate) { - db[modelName].associate(db); - } -}); - -db.sequelize = sequelize; -db.Sequelize = Sequelize; - -module.exports = db; diff --git a/models/notation.js b/models/notation.js deleted file mode 100644 index b43b9ea..0000000 --- a/models/notation.js +++ /dev/null @@ -1,97 +0,0 @@ -'use strict'; - -const Sequelize = require("sequelize"); -const Promise = require("bluebird"); - -module.exports = (sequelize, DataTypes) => { - let Notation = sequelize.define('Notation', { - // no need for more ; as notes are usually between 0 and 5 - note: { - type: DataTypes.DECIMAL(3, 2), - allowNull: false - } - }, { - // https://sequelize.org/master/manual/models-definition.html#configuration - - // don't add the timestamp attributes (updatedAt, createdAt) - timestamps: false - }); - - // common function for hooks - function exercise_metrics_hookFct(kind) { - return function (notation, options) { - // find the Exercise_Metrics related to this exercise with the AVG computed - return Promise.all([ - // Find exercise metrics for given exercise - notation - .sequelize - .models - .Exercise_Metrics - .findAll({ - attributes: ["id", "vote_count"], - where: { - exercise_id: notation.exercise_id - }, - transaction: options.transaction - }), - // Find the new avg vote score - notation - .sequelize - .models - .Notation - .findAll({ - attributes: [ - [Sequelize.fn("AVG", Sequelize.col("note")), "vote_score"] - ], - where: { - exercise_id: notation.exercise_id - }, - group: ["exercise_id"], - transaction: options.transaction - }) - ]).then( - ([[exercise_metrics], [result_in_db] ]) => { - - // to handle both cases : the first notation created / other cases - const computed_metadata = { - vote_count: (kind === "insert") - ? exercise_metrics.get("vote_count") + 1 - : exercise_metrics.get("vote_count"), - vote_score: (result_in_db !== undefined) - ? result_in_db.get("vote_score") - // by default, only one note was inserted for this exercise - // it should never happen but who knows what could happen ... - : /* istanbul ignore next */ notation.note - }; - - return notation - .sequelize - .models - .Exercise_Metrics - .update({ - vote_count: computed_metadata.vote_count, - avg_vote_score: computed_metadata.vote_score - }, { - where: {id: exercise_metrics.id}, - transaction: options.transaction - }); - }); - } - } - - // after inserting / updating a row , we must update the related Exercise_Metrics - // warning for seeding I must use that : https://github.com/sequelize/sequelize/issues/5053 - Notation.addHook( - "afterCreate", - "exercise_metrics_created", - exercise_metrics_hookFct("insert") - ); - - Notation.addHook( - "afterUpdate", - "exercise_metrics_updated", - exercise_metrics_hookFct("update") - ); - - return Notation; -}; \ No newline at end of file diff --git a/models/tag.js b/models/tag.js deleted file mode 100644 index 5f78638..0000000 --- a/models/tag.js +++ /dev/null @@ -1,71 +0,0 @@ -'use strict'; - -const tagState = require("../controllers/_common/constants")["TAGS"]; -let enumValues = Object.values(tagState); - -module.exports = (sequelize, DataTypes) => { - let Tag = sequelize.define("Tag", { - text: { - type: DataTypes.STRING, - allowNull: false - }, - state: { - type: DataTypes.ENUM(enumValues), - allowNull: false, - defaultValue: tagState.NOT_VALIDATED - }, - }, { - // https://sequelize.org/master/manual/models-definition.html#configuration - - // Enable optimistic locking. When enabled, sequelize will add a version count attribute - // to the model and throw an OptimisticLockingError error when stale instances are saved. - // Set to true or a string with the attribute name you want to use to enable. - version: true, - - // scopes : reuse more easily some common parts - // https://sequelize.org/master/manual/scopes.html - scopes: { - common_attributes: { - attributes: [ - ["id", "tag_id"], - ["text", "tag_text"], - "category_id", - "state", - "version" - ] - } - } - }); - - Tag.associate = function (models) { - // a Tag must have a Tag Category - Tag.belongsTo(models.Tag_Category, { - as: "category", - foreignKey: { - name: "category_id", - allowNull: false - }, - onDelete: "CASCADE" - }); - // a Tag can be used in multiple configurations - Tag.belongsToMany(models.Configuration, { - through: models.Configuration_Tag, - foreignKey: { - name: "tag_id", - allowNull: false - } - }); - // a Tag can be used in multiple exercises - Tag.belongsToMany(models.Exercise, { - through: models.Exercise_Tag, - timestamps: false, - as: "exercises", - foreignKey: { - name: "tag_id", - allowNull: false - } - }); - }; - - return Tag; -}; diff --git a/models/tag_category.js b/models/tag_category.js deleted file mode 100644 index 590e0dd..0000000 --- a/models/tag_category.js +++ /dev/null @@ -1,100 +0,0 @@ -'use strict'; -const Sequelize = require("sequelize"); -const {TAGS: TagState} = require("../controllers/_common/constants"); - -module.exports = (sequelize, DataTypes) => { - let Tag_Category = sequelize.define("Tag_Category", { - kind: { - type: DataTypes.STRING, - allowNull: false, - unique: true - } - }, { - // https://sequelize.org/master/manual/models-definition.html#configuration - - // don't add the timestamp attributes (updatedAt, createdAt) - timestamps: false, - - // scopes : reuse more easily some common parts - // https://sequelize.org/master/manual/scopes.html - scopes: { - - // to get the following count - // - the number of tags for a category - // - the number of validated tags for a category - // - the number of unvalidated tags for a category - count_summary: function () { - // to generate the FILTER count attribute since this issue is still active and solution not merged - // https://github.com/sequelize/sequelize/issues/5732 - // I created a simpler version of the proposal ( maybe refactor this code when this feature is on) - // more easier to do that PostgreSQL syntax directly that using litteral - // even guys at Sequelize use that kind of trick for mysql sum - // https://github.com/sequelize/sequelize/blob/master/test/integration/model/attributes/field.test.js#L483 - // https://www.postgresql.org/docs/current/sql-expressions.html#SYNTAX-AGGREGATES - const filterGen = (where) => Sequelize.literal(`COUNT(*) FILTER ${where}`); - - return { - attributes: [ - "id", - ["kind", "category"], - [ - filterGen(`(WHERE "tags"."id" IS NOT NULL)`), - "total" - ], - [ - filterGen(`(WHERE "tags"."state" = '${TagState.VALIDATED}')`), - "total_validated" - ], - [ - filterGen(`(WHERE "tags"."state" = '${TagState.NOT_VALIDATED}')`), - "total_unvalidated" - ], - [ - filterGen(`(WHERE "tags"."state" = '${TagState.DEPRECATED}')`), - "total_deprecated" - ], - [ - filterGen(`(WHERE "tags"."state" = '${TagState.PENDING}')`), - "total_pending" - ], - ], - group: ["Tag_Category.id", "Tag_Category.kind"], - include: [{ - model: sequelize.models.Tag, - as: "tags", - attributes: [] - }] - } - }, - // To fetch all tag categories in a object like - // example: { "1" : "source", "2" : "institution", "3" : "auteur" } - allTagsCategoriesAsObject: function () { - return { - attributes: [ - [ - Sequelize.fn( - "json_object_agg", - Sequelize.col("id"), - Sequelize.col("kind") - ), - "categories" - ] - ] - } - } - } - }); - - Tag_Category.associate = function (models) { - // A Tag_Category can be used in multiple tags - models.Tag_Category.hasMany(models.Tag, { - as: "tags", - foreignKey: { - name: "category_id", - allowNull: false, - } - }); - }; - - return Tag_Category; -}; diff --git a/models/user.js b/models/user.js deleted file mode 100644 index d6e1747..0000000 --- a/models/user.js +++ /dev/null @@ -1,103 +0,0 @@ -'use strict'; - -const bcrypt = require('bcryptjs'); -const {USERS} = require("../controllers/_common/constants"); - -// To encrypt password before creating / updating an instance -const SALT_WORK_FACTOR = 10; -const encryptPassword = (user, _options) => { - // to handle both creating / update scenario here - /* istanbul ignore else */ - if (user.changed("password")) { - return bcrypt - .genSalt(SALT_WORK_FACTOR) - .then(salt => { - return bcrypt.hash(user.password, salt); - }).then(hash => { - // replace the password with the hash and pass on the user object to whoever should require it. - user.password = hash; - return Promise.resolve(user); - }).catch(/* istanbul ignore next */ - err => Promise.reject(err) - ); - } else { - return Promise.resolve(user); - } -}; - -module.exports = (sequelize, DataTypes) => { - let User = sequelize.define('User', { - email: { - type: DataTypes.STRING, - unique: true, - allowNull: false - }, - password: { - type: DataTypes.STRING, - allowNull: false - }, - fullName: { - type: DataTypes.STRING, - allowNull: false - }, - role: { - type: DataTypes.ENUM(Object.values(USERS)), - allowNull: false - } - }, { - // https://sequelize.org/master/manual/models-definition.html#configuration - timestamps: false, - }); - - // Class method User.comparePassword() to compare hash vs provided password - User.comparePassword = function (password, hash, callback) { - // if bcrypt.compare() succeeds it'll call our function - // with (null, true), if password doesn't match it calls our function - // with (null, false), if it errors out it calls our function - // with (err, null) - bcrypt.compare(password, hash, function (err, isMatch) { - /* istanbul ignore next */ - if (err) { - return callback(err, null); - } else { - callback(null, isMatch); - } - }); - - }; - - User.associate = function (models) { - // a user can post multiple exercises - User.hasMany(models.Exercise, { - as: "exercises", - foreignKey: { - name: "user_id", - allowNull: false - } - }); - // a user can evaluate exercise(s) - User.hasMany(models.Notation, { - as: "notations", - foreignKey: { - name: "user_id", - allowNull: false - }, - onDelete: "CASCADE" - }); - // a user can possess configuration so that she/he didn't have to remember all her/his filters - User.hasMany(models.Configuration, { - as: "configurations", - foreignKey: { - name: "user_id", - allowNull: false - } - }); - }; - - // This hook is called when an entry is being added to the back end. - // This method is used to hash the password before storing it in our database. - User.addHook('beforeCreate', encryptPassword); - User.addHook('beforeUpdate', encryptPassword); - - return User -}; diff --git a/openapi/definitions.yaml b/openapi/definitions.yaml deleted file mode 100644 index f3e4112..0000000 --- a/openapi/definitions.yaml +++ /dev/null @@ -1,655 +0,0 @@ -components: - schemas: - ErrorObject: - type: object - properties: - message: - type: string - description: The main error message ( for example "Bad Request", "Unauthorized", etc. ) - errors: - type: array - items: - type: object - description: Explanation about an error - required: - - message - - errors -# Common enum used everywhere - State: - type: string - enum: [DRAFT,PENDING,VALIDATED,NOT_VALIDATED,ARCHIVED] - example: PENDING - description: | - Status of the exercise into the system. Currently, 5 states are possibles : - - 1. DRAFT : The default state (for example when an exercise is inserted into the system) - 2. PENDING : When an exercise is ready for review - 3. VALIDATED : When an exercise is validated by an admin - 4. NOT_VALIDATED : When an exercise is refused by an admin - 5. ARCHIVED : When an exercise is archived / soft deleted - Roles: - type: string - enum: [super_admin, admin, user] - default: user - description: | - The type of user. Currently, 3 types are possibles : - - 1. user : The defaut ( an simple registered user ) - 2. admin : User with additional credentials - 3. super_admin : More powerful than an admin - TagState: - type: string - enum: [NOT_VALIDATED, VALIDATED, DEPRECATED, PENDING] - example: DEPRECATED - description: | - Status of the tag into the system. Currently, 4 states are possibles : - - 1. NOT_VALIDATED : When a tag is officially not recognized - 2. PENDING : The default state ( for example when an exercise is inserted into the system) - 3. DEPRECATED : When a tag should not be used anymore - 4. VALIDATED : When a tag is officially recognized -# To control include for Exercise - IncludeOptions: - type: object - description: "To include additional properties when fetching exercise(s)" - properties: - includeCreator: - type: boolean - default: false - description: "Must we include the creator of exercise(s) ?" - includeMetrics: - type: boolean - default: true - description: "Must we include the metrics of exercise(s) ?" - includeDescription: - type: boolean - default: true - description: "Must we include the description of exercise(s) ?" - includeTags: - type: boolean - default: true - description: "Must we include the tags of exercise(s) ?" -# Advanced Filtering for Exercise - FilteringOptions: - type: object - description: | - To filter some properties when fetching exercise(s) - properties: - state: - type: array - description: "Filter the exercises by their state. By default, no filtering is done." - items: - $ref: "#/components/schemas/State" - maxItems: 5 - tags: - type: array - description: "Filter the tags linked to exercise by their state. By default, no filtering is done." - items: - $ref: "#/components/schemas/TagState" - maxItems: 4 -# Basic model of a Exercise - BasicExerciseModel: - type: object - properties: - title: - type: string - example: "A Super Exercise" - minLength: 3 - maxLength: 100 - description: "The title of this exercise" - description: - type: string - maxLength: 5000 - example: "..." - description: "The preamble of this exercise" - default: "" - required: - - title -# If already in database, we have other fields (in addition of the basic Model) - AlreadyPresentExerciseModel: - allOf: - - $ref: '#/components/schemas/BasicExerciseModel' - - type: object - properties: - id: - type: integer - example: 42 - minimum: 0 - description: "The Id of this exercise" - version: - type: integer - example: 42 - minimum: 0 - description: "The version of this exercise (optimistic lock)" - createdAt: - type: string - format: date-time - example: "2019-12-22T15:18:31.090Z" - description: "Date of creation of this exercise" - updatedAt: - type: string - format: date-time - example: "2019-12-22T15:19:33.473Z" - description: "Date of the latest update of this exercise" - state: - $ref: "#/components/schemas/State" - file: - type: string - nullable: true - description: "If not null, it is a uploaded file we can download with the GET endpoint /files/{file}" - example: "sources-88af5adc-1837-11ea-8d71-362b9e155667.zip" - url: - type: string - pattern: '^https?:\/\/[^\s$.?#].[^\s]*$' - example: "https://inginious.info.ucl.ac.be/course/LEPL1402/Streams" - nullable: true - description: "If not null, the link to the exercise on a plateform" - required: - - id - - version - - createdAt - - updatedAt - - state - - file - - url -# For search / get context, we have other fields (in addition of the AlreadyPresentExerciseModel ) - SearchableExerciseModel: - allOf: - - $ref: "#/components/schemas/AlreadyPresentExerciseModel" - - type: object - properties: - metrics: - type: object - description: "The metrics of the exercise (present only if includeMetrics is true)" - properties: - votes: - type: integer - example: 42 - minimum: 0 - description: "Number of votes for this exercise" - avg_score: - type: number - minimum: 0.0 - maximum: 5.0 - example: 5.0 - description: "The average score of this exercise" - required: - - votes - - avg_score - tags: - type: array - description: "The tags of the exercise (present only if includeTags is true)" - items: - $ref: '#/components/schemas/TagWithCategory' - uniqueItems: true - creator: - allOf: - - type: object - description: "The creator of the exercise (present only if includeMetrics is true)" - - $ref: "#/components/schemas/BasicUser" -# A Tag Category - Tag_Category: - type: object - properties: - id: - type: integer - minimum: 0 - example: 42 - description: "The Id of this Tag_Category" - category: - type: string - example: "difficulty" - minLength: 3 - maxLength: 100 - description: "The text of this Tag_Category" - required: - - id - - category -# A Tag - Tag: - type: object - properties: - tag_id: - type: integer - example: 42 - minimum: 0 - description: "The Id of this Tag" - tag_text: - type: string - example: "easy" - minLength: 1 - maxLength: 100 - description: "The text of this Tag" - required: - - tag_id - - tag_text -# Tag with Tag category - TagWithCategory: - allOf: - - $ref: "#/components/schemas/Tag" - - type: object - properties: - category: - type: object - properties: - category_text: - type: string - example: "difficulty" - minLength: 3 - maxLength: 100 - description: "The text of the Tag Category linked with this tag" - category_id: - type: integer - example: 42 - minimum: 0 - description: "The category ID linked with this tag" - required: - - category_text - - category_id - state: - $ref: "#/components/schemas/TagState" - required: - - category - - state - TagCategoryWithTags: - allOf: - - $ref: "#/components/schemas/Tag_Category" - - type: object - properties: - tags: - type: array - description: "An array of related tags to this Tag Category" - minItems: 1 - uniqueItems: true - items: - allOf: - - $ref: "#/components/schemas/TagFull" - - type: object - properties: - total: - type: integer - default: 0 - description: | - Counter relevant to the number of exercises that have this tag. - See the query parameters "countStates" for more information - required: - - total - required: - - tags -# Tag proposal - TagProposal: - type: object - properties: - text: - type: string - example: "easy" - minLength: 1 - maxLength: 100 - description: "The text of this Tag" - category_id: - type: integer - minimum: 0 - example: 42 - description: "the category id to which this tag is related" - required: - - text - - category_id -# TagProposal with state (only for admin) - TagProposalWithState: - allOf: - - $ref: "#/components/schemas/TagProposal" - - type: object - properties: - state: - $ref: "#/components/schemas/TagState" -# Tag updated / validated - TagFull: - allOf: - - $ref: "#/components/schemas/Tag" - - type: object - properties: - category_id: - type: integer - example: 42 - minimum: 0 - description: "the category id to which it is related" - state: - $ref: "#/components/schemas/TagState" - version: - type: integer - minimum: 0 - description: "The version of this exercise (optimistic lock)" - example: 42 - required: - - category_id - - state - - version -# When we want to upload a new exercise, we need other fields for that - ExerciseForm: - allOf: - - $ref: "#/components/schemas/BasicExerciseModel" - - type: object - properties: - tags: - type: array - items: - oneOf: - - type: integer - minimum: 0 - description: "A Tag ID ( already existent in database )" - - $ref: "#/components/schemas/TagProposalWithState" - description: "A not-existent Tag with state we want to add" - description: "Mixed array that contains existent tag(s) or not" - uniqueItems: true - minItems: 3 # We must always put at least N tag(s) in the database - maxItems: 25 # At some point, a limit is needed to prevent abuse - url: - type: string - pattern: '^https?:\/\/[^\s$.?#].[^\s]*$' - example: "https://inginious.info.ucl.ac.be/course/LEPL1402/Streams" - nullable: true - description: "If not null, the link to the exercise on a plateform" - state: - $ref: "#/components/schemas/State" - required: - - tags -# When we want to update a already existent exercise, we also need the version - ExerciseUpdateForm: - allOf: - - $ref: "#/components/schemas/ExerciseForm" - - type: object - properties: - version: - type: integer - description: "The version of this exercise (optimistic lock)" - minimum: 0 - example: 42 - required: - - version -# Result after a call to /search - SearchResult: - type: object - properties: - metadata: - $ref: "#/components/schemas/PaginationResult" - data: - type: array - items: - $ref: "#/components/schemas/SearchableExerciseModel" - description: "An array of exercise data" - required: - - metadata - - data -# Search criteria components - PaginationCriterias: - type: object - description: "Fields for pagination" - properties: - page: - type: integer - description: "Page number (start at 1)" - minimum: 1 - default: 1 - example: 1 - size: - type: integer - minimum: 0 - description: "Number of items by page" - default: 10 - example: 10 - maximum: 50 - SearchDataCriterias: - type: object - description: "Search criterias" - properties: - title: - type: string - description: "Something we want to find inside the title of exercises" - maxLength: 100 - example: "SINF2MS" - tags: - type: array - items: - oneOf: - - type: integer - format: int32 - example: 1 - - type: array - items: - type: integer - format: int32 - minItems: 1 # Not allowing empty array if we use it - description: "Tags search encoded in Conjunctive Normal Form. (for NOT predicat, use a negative integer)" - example: [-1, [2, 3]] - user_ids: - type: array - description: "Filter the exercises by their creators." - minItems: 1 - items: - type: integer - minimum: 0 - description: "An user ID" - uniqueItems: true - exercise_ids: - type: array - description: "Filter the exercises by their ids." - minItems: 1 - items: - type: integer - minimum: 0 - description: "An exercise ID" - uniqueItems: true - vote: - description: "Only take exercises that meet a given threshold" - type: object - properties: - operator: - description: "The operation we want to apply" - type: string - enum: ['<=', '<', '>=', '>'] - value: - description: "The threshold value" - type: number - minimum: 0.0 - maximum: 5.0 - example: 5.0 - required: - - operator - - value - PaginationResult: - type: object - description: "Fields for pagination" - properties: - currentPage: - type: integer - example: 1 - minimum: 1 - description: "Current number of page" - default: 1 - totalItems: - type: integer - example: 42 - minimum: 0 - description: "How much items match the given criterias" - totalPages: - type: integer - minimum: 0 - example: 5 - description: "How much pages match the given criterias" - pageSize: - type: integer - minimum: 0 - example: 10 - default: 10 - description: "How many entries on each page" - required: - - currentPage - - totalItems - - totalPages - - pageSize -# Common criteria for export and search for exercises - CommonCriterias: - type: object - properties: - orderBy: - description: | - If you wish to order the provided result, use this parameter. - - For example, if you wish to first sort by date descending then by title ascending, you could achieve that with : - ``` - [ - {"field": "date", "value": "DESC"}, - {"field": "title", "value": "ASC"} - ] - ``` - type: array - # A security to prevent mad guys to destroy API - maxItems: 6 - items: - type: object - properties: - field: - type: string - description: | - The field we want to use for sorting. Currently, you have the following possibilities : - - 1. state : the state of the exercise - 2. id : the id of the exercise - 3. title : the title of the exercise - 4. date : the date of the last modification of the exercise - 5. avg_score : the average score of the exercise - 6. vote_count : the number of voters for this exercise - enum: ['state', 'id', 'title', 'date', 'avg_score', 'vote_count'] - value: - type: string - enum: ["ASC", "DESC"] - description: | - The order we want to sort the related field : - - - ASC : ASCENDING sorting - - DESC : DESCENDING sorting - data: - $ref: "#/components/schemas/SearchDataCriterias" - filterOptions: - $ref: "#/components/schemas/FilteringOptions" -# Search criteria - SearchCriterias: - allOf: - - $ref: "#/components/schemas/CommonCriterias" - - type: object - properties: - metadata: - $ref: "#/components/schemas/PaginationCriterias" - includeOptions: - $ref: "#/components/schemas/IncludeOptions" - MultipleExercisesForm: - type: array - minItems: 1 - items: - $ref: "#/components/schemas/ExerciseForm" - description: "An array of exercises" - TagCategoriesForm: - type: array - minItems: 1 - items: - oneOf: - - type: string - description: "The name of the Tag Category" - example: "author" - - type: object - description: "Category to add, under one that already exists" - properties: - text: - type: string - description: "The name of the Tag Category" - example: "author" - minLength: 3 - maxLength: 100 - category: - type: integer - format: int32 - minimum: 0 - description: "The ID of the Tag Category parent" - required: - - text - - category -# Configurations - ConfigurationProposal: - type: object - properties: - name: - description: "The name of this configuration" - type: string - example: "All Java exercises" - title: - description: "The used title for search" - type: string - example: "[LSINF1252]" - maxLength: 100 - minLength: 0 - tags: - description: "An array of tags IDS" - type: array - example: [42] - items: - type: integer - minimum: 0 - required: - - name - ExistentConfiguration: - allOf: - - $ref: "#/components/schemas/ConfigurationProposal" - - type: object - properties: - id: - description: "The id of this configuration" - type: integer - minimum: 0 - example: 42 - required: - - id - ExistentConfigurationWithTags: - type: object - properties: - name: - description: "The name of this configuration" - type: string - example: "All Java exercises" - title: - description: "The used title for search" - type: string - example: "[LSINF1252]" - maxLength: 100 - minLength: 0 - id: - description: "The id of this configuration" - type: integer - minimum: 0 - example: 42 - tags: - type: array - description: "The linked tags to this configuration" - items: - $ref: "#/components/schemas/TagFull" - required: - - name - - title - - id - - tags - BasicUser: - type: object - properties: - email: - type: string - format: email - example: "jy95@perdu.com" - description: "The email of the user" - fullName: - type: string - example: "Alexandre Dewit" - description: "The full name of the user" - minLength: 1 - maxLength: 50 - required: - - email - - fullName diff --git a/openapi/examples.yaml b/openapi/examples.yaml deleted file mode 100644 index 783726c..0000000 --- a/openapi/examples.yaml +++ /dev/null @@ -1,17 +0,0 @@ -# Examples for /search -examples: - searchExample1: - description: "Search the first 10 exercises that have 'Java' in their title and have some specific tags ( 1 AND (2 OR 3 OR 4) )" - value: - data: - title: "Java" - tags: [1, [2, 3, 4]] - searchExample2: - description: "Search the exercises on page 2 that have 'Java' in their title but with specific tags ( (NOT 1) AND (2 OR 3) )" - value: - metadata: - page: 2 - size: 10 - data: - title: "Java" - tags: [-1, [2, 3]] \ No newline at end of file diff --git a/openapi/paths/auth.yaml b/openapi/paths/auth.yaml deleted file mode 100644 index c5a9854..0000000 --- a/openapi/paths/auth.yaml +++ /dev/null @@ -1,145 +0,0 @@ -paths: - /auth/login: - post: - summary: "Logs user into the system" - operationId: signIn - x-controller: auth - x-operation: signIn - tags: - - guest - requestBody: - required: true - content: - application/json: - schema: - $ref: "#/components/schemas/Auth" - responses: - '200': - description: A JSON containing the JWT Token and some information about the user - content: - application/json: - schema: - allOf: - - $ref: "#/components/schemas/JWTToken" - - type: object - description: Some basic information on this user - properties: - user: - type: object - properties: - fullName: - type: string - description: "The full name of this user" - example: "Alexandre Dewit" - minLength: 1 - maxLength: 50 - role: - type: string - enum: [admin, user] - description: "What kind of user are we ?" - required: - - fullName - - role - required: - - user - # Definition of all error statuses - default: - description: "Whatever error : 4XX - Client error (Bad Request, Unauthorized, etc.) , 5XX - Server error" - content: - application/json: - schema: - $ref: "../definitions.yaml#/components/schemas/ErrorObject" - /auth/register: - post: - summary: "Creates a new user into the system" - operationId: register - x-controller: auth - x-operation: register - tags: - - guest - requestBody: - required: true - content: - application/json: - schema: - allOf: - - $ref: "#/components/schemas/Auth" - - type: object - properties: - fullName: - type: string - example: "Alexandre Dewit" - description: "The full name of this new user" - minLength: 1 - maxLength: 50 - required: - - fullName - responses: - '200': - description: OK - # Definition of all error statuses - default: - description: "Whatever error : 4XX - Client error (Bad Request, Unauthorized, etc.) , 5XX - Server error" - content: - application/json: - schema: - $ref: "../definitions.yaml#/components/schemas/ErrorObject" - /auth/verify: - post: - summary: "Verify if given JWT token is valid (and not expired)" - operationId: verify - x-controller: auth - x-operation: verify - tags: - - guest - requestBody: - required: true - content: - application/json: - schema: - type: object - properties: - token: - type: string - pattern: '^[A-Za-z0-9-_=]+\.[A-Za-z0-9-_=]+\.?[A-Za-z0-9-_.+/=]*$' - description: | - An [JWT Token](https://jwt.io/) string - required: - - token - responses: - '200': - description: OK - # Definition of all error statuses - default: - description: "Whatever error : 4XX - Client error (Bad Request, Unauthorized, etc.) , 5XX - Server error" - content: - application/json: - schema: - $ref: "../definitions.yaml#/components/schemas/ErrorObject" -components: - schemas: - Auth: - type: object - properties: - email: - type: string - format: email - example: "jy95@perdu.com" - password: - type: string - format: password - example: "42" - required: - - email - - password - JWTToken: - type: object - properties: - token: - type: string - description: The JWT Token - required: - - token - securitySchemes: - bearerAuth: - $ref: "../security.yaml#/components/securitySchemes/bearerAuth" \ No newline at end of file diff --git a/openapi/paths/bulk.yaml b/openapi/paths/bulk.yaml deleted file mode 100644 index 9522647..0000000 --- a/openapi/paths/bulk.yaml +++ /dev/null @@ -1,304 +0,0 @@ -paths: - /api/bulk/delete_exercises: - delete: - summary: "Delete given exercises" - description: | - Permanently remove from system the given exercises. (No way to retrieve them after this) - Otherwise, if you simply want to soft delete/hide these exercises, use [this endpoint](#operation/ChangeExercisesStatus) to change their status to ARCHIVED. - operationId: "DeleteExercises" - x-controller: bulk - x-operation: DeleteExercises - tags: - - super_admin - security: - - bearerAuth: [] - requestBody: - required: true - content: - application/json: - schema: - type: array - description: "An array of exercises IDs" - minItems: 1 - uniqueItems: true - items: - type: integer - minimum: 0 - example: 42 - description: "An exercise ID" - responses: - '200': - description: "OK" - # Definition of all error statuses - default: - description: "Whatever error : 4XX - Client error (Bad Request, Unauthorized, etc.) , 5XX - Server error" - content: - application/json: - schema: - $ref: "../definitions.yaml#/components/schemas/ErrorObject" - /api/bulk/delete_tags: - delete: - summary: "Delete given tags" - description: "Delete given tags." - operationId: "DeleteTags" - x-controller: bulk - x-operation: DeleteTags - tags: - - super_admin - security: - - bearerAuth: [] - requestBody: - required: true - content: - application/json: - schema: - type: array - description: "An array of tags IDs" - minItems: 1 - uniqueItems: true - items: - type: integer - minimum: 0 - example: 42 - description: "A tag ID" - responses: - '200': - description: "OK" - # Definition of all error statuses - default: - description: "Whatever error : 4XX - Client error (Bad Request, Unauthorized, etc.) , 5XX - Server error" - content: - application/json: - schema: - $ref: "../definitions.yaml#/components/schemas/ErrorObject" - /api/bulk/delete_tags_categories: - delete: - summary: "Delete given tags categories" - description: "Delete given tags categories." - operationId: "DeleteTagCategories" - x-controller: bulk - x-operation: DeleteTagCategories - tags: - - super_admin - security: - - bearerAuth: [] - requestBody: - required: true - content: - application/json: - schema: - type: array - description: "An array of tag category IDs" - minItems: 1 - uniqueItems: true - items: - type: integer - minimum: 0 - example: 42 - description: "A tag category ID" - responses: - '200': - description: "OK" - # Definition of all error statuses - default: - description: "Whatever error : 4XX - Client error (Bad Request, Unauthorized, etc.) , 5XX - Server error" - content: - application/json: - schema: - $ref: "../definitions.yaml#/components/schemas/ErrorObject" - /api/bulk/modify_exercises_status: - put: - summary: "Change the status of given exercises" - description: | - Change the status of given exercises. - - The following restrictions are applied on simple user(s) (no restriction for admin): - - 1. He/She can only modify his/her own exercises - 2. Only the following states are allowed : - - DRAFT - - PENDING - - ARCHIVED - operationId: "ChangeExercisesStatus" - x-controller: bulk - x-operation: ChangeExercisesStatus - tags: - - admin - - user - security: - - bearerAuth: [] - requestBody: - required: true - content: - application/json: - schema: - $ref: "#/components/schemas/ChangeExercisesStatus" - responses: - '200': - description: "OK" - # Definition of all error statuses - default: - description: "Whatever error : 4XX - Client error (Bad Request, Unauthorized, etc.) , 5XX - Server error" - content: - application/json: - schema: - $ref: "../definitions.yaml#/components/schemas/ErrorObject" - /api/bulk/create_or_find_tag_categories: - post: - summary: "Creates or Find tag categories" - x-controller: bulk - x-operation: createOrFindTagCategories - tags: - - admin - operationId: createOrFindTagCategories - security: - - bearerAuth: [] - requestBody: - required: true - content: - application/json: - schema: - $ref: "../definitions.yaml#/components/schemas/TagCategoriesForm" - responses: - '200': - description: "An array of tag categories" - content: - application/json: - schema: - type: array - items: - $ref: "../definitions.yaml#/components/schemas/Tag_Category" - uniqueItems: true - # Definition of all error statuses - default: - description: "Whatever error : 4XX - Client error (Bad Request, Unauthorized, etc.) , 5XX - Server error" - content: - application/json: - schema: - $ref: "../definitions.yaml#/components/schemas/ErrorObject" - /api/bulk/create_exercises: - post: - summary: "Creates multiple exercises into the system" - description: | - Creates multiple exercises into the system - By default (if nothing specified), an exercise will be in state "DRAFT". - - tags: - - admin - operationId: createMultipleExercises - x-controller: bulk - x-operation: createMultipleExercises - security: - - bearerAuth: [] - requestBody: - required: true - content: - application/json: - schema: - $ref: "../definitions.yaml#/components/schemas/MultipleExercisesForm" - multipart/form-data: - schema: - type: object - properties: - exercisesData: - $ref: "../definitions.yaml#/components/schemas/MultipleExercisesForm" - files: - type: array - description: "The sources of the exercises, each in zip format" - minItems: 1 - items: - type: string - format: binary - description: "The source of an exercise, in zip format" - filesMapping: - type: array - description: "Mapping between the given file (to find out which data belong to exercise)" - minItems: 1 - items: - type: object - properties: - filename: - type: string - description: "The name of the given source file" - example: "file1.zip" - exercise: - type: integer - description: "The location of the related exercise in the exercisesData array" - required: - - filename - - exercise - required: - - exercisesData - - files - - filesMapping - responses: - '200': - description: OK - # Definition of all error statuses - default: - description: "Whatever error : 4XX - Client error (Bad Request, Unauthorized, etc.) , 5XX - Server error" - content: - application/json: - schema: - $ref: "../definitions.yaml#/components/schemas/ErrorObject" - /api/bulk/create_tags: - post: - summary: "Creates multiple tags into the system" - description: | - Creates multiple tags into the system. - - Warning : the "state" property can only be used by authorized people (no simple user can use it) - tags: - - user - operationId: createMultipleTags - x-controller: bulk - x-operation: createMultipleTags - security: - - bearerAuth: [] - requestBody: - required: true - content: - application/json: - schema: - type: array - minItems: 1 - items: - allOf: - - $ref: "../definitions.yaml#/components/schemas/TagProposal" - - type: object - properties: - state: - $ref: "../definitions.yaml#/components/schemas/TagState" - responses: - '200': - description: OK - # Definition of all error statuses - default: - description: "Whatever error : 4XX - Client error (Bad Request, Unauthorized, etc.) , 5XX - Server error" - content: - application/json: - schema: - $ref: "../definitions.yaml#/components/schemas/ErrorObject" -components: - securitySchemes: - bearerAuth: - $ref: "../security.yaml#/components/securitySchemes/bearerAuth" - schemas: - ChangeExercisesStatus: - type: object - properties: - exercises: - type: array - description: "An array of exercises IDs" - minItems: 1 - uniqueItems: true - items: - type: integer - minimum: 0 - example: 42 - description: "An exercise ID" - state: - $ref: "../definitions.yaml#/components/schemas/State" - required: - - exercises - - state \ No newline at end of file diff --git a/openapi/paths/configurations.yaml b/openapi/paths/configurations.yaml deleted file mode 100644 index 22ec0eb..0000000 --- a/openapi/paths/configurations.yaml +++ /dev/null @@ -1,122 +0,0 @@ -paths: - /api/configurations: - get: - description: "Get all configurations of the current logged user" - operationId: "FetchOwnConfigurations" - x-controller: configurations - x-operation: FetchOwnConfigurations - tags: - - user - security: - - bearerAuth: [] - parameters: - - in: "query" - name: ids - description: "Array of configuration ids you want to search" - schema: - type: array - items: - type: integer - minimum: 0 - description: An configuration ID - responses: - '200': - description: "An array of configurations with their related tags" - content: - application/json: - schema: - type: array - items: - $ref: "../definitions.yaml#/components/schemas/ExistentConfigurationWithTags" - # Definition of all error statuses - default: - description: "Whatever error : 4XX - Client error (Bad Request, Unauthorized, etc.) , 5XX - Server error" - content: - application/json: - schema: - $ref: "../definitions.yaml#/components/schemas/ErrorObject" - put: - description: "Update a configuration" - operationId: "UpdateConfiguration" - x-controller: configurations - x-operation: UpdateConfiguration - tags: - - user - security: - - bearerAuth: [] - requestBody: - required: true - content: - application/json: - schema: - $ref: "../definitions.yaml#/components/schemas/ExistentConfiguration" - responses: - '200': - description: OK - # Definition of all error statuses - default: - description: "Whatever error : 4XX - Client error (Bad Request, Unauthorized, etc.) , 5XX - Server error" - content: - application/json: - schema: - $ref: "../definitions.yaml#/components/schemas/ErrorObject" - post: - description: "Create a configuration" - operationId: "CreateConfiguration" - x-controller: configurations - x-operation: CreateConfiguration - tags: - - user - security: - - bearerAuth: [] - requestBody: - required: true - content: - application/json: - schema: - $ref: "../definitions.yaml#/components/schemas/ConfigurationProposal" - responses: - '200': - description: OK - # Definition of all error statuses - default: - description: "Whatever error : 4XX - Client error (Bad Request, Unauthorized, etc.) , 5XX - Server error" - content: - application/json: - schema: - $ref: "../definitions.yaml#/components/schemas/ErrorObject" - delete: - description: "Delete a configuration" - operationId: "DeleteConfiguration" - x-controller: configurations - x-operation: DeleteConfiguration - tags: - - user - security: - - bearerAuth: [] - requestBody: - required: true - content: - application/json: - schema: - type: object - properties: - id: - description: "The id of the configuration you want to delete" - type: integer - minimum: 0 - example: 42 - responses: - '200': - description: OK - # Definition of all error statuses - default: - description: "Whatever error : 4XX - Client error (Bad Request, Unauthorized, etc.) , 5XX - Server error" - content: - application/json: - schema: - $ref: "../definitions.yaml#/components/schemas/ErrorObject" -components: - securitySchemes: - bearerAuth: - $ref: "../security.yaml#/components/securitySchemes/bearerAuth" \ No newline at end of file diff --git a/openapi/paths/create_exercise.yaml b/openapi/paths/create_exercise.yaml deleted file mode 100644 index f65b3fd..0000000 --- a/openapi/paths/create_exercise.yaml +++ /dev/null @@ -1,59 +0,0 @@ -paths: - /api/create_exercise: - post: - summary: "Creates a new exercise into the system" - description: | - Creates a new exercise into the system. - By default (if nothing specified), the exercise will be in state "DRAFT". - You are free to add new tags / keywords but you must add at least 3 validated tags. - - The following restrictions are applied on simple user(s) (no restriction for admin): - - 1. He/She can only modify his/her own exercises - 2. Only the following states are allowed for the field "state" : - - DRAFT - - PENDING - 3. He/She can't use the field "state" inside an tag object of "tags" array - operationId: createSingleExercise - x-controller: exercises - x-operation: createSingleExercise - tags: - - user - security: - - bearerAuth: [] - requestBody: - required: true - content: - application/json: - schema: - $ref: "../definitions.yaml#/components/schemas/ExerciseForm" - multipart/form-data: - schema: - allOf: - - $ref: "../definitions.yaml#/components/schemas/ExerciseForm" - - type: object - properties: - exerciseFile: - type: string - format: binary - description: "The sources of this exercise, in zip format" - required: - - exerciseFile - encoding: - exerciseFile: - # MIME for zip https://stackoverflow.com/a/7027582/6149867 - contentType: application/zip, application/x-zip-compressed, multipart/x-zip - responses: - '200': - description: OK - # Definition of all error statuses - default: - description: "Whatever error : 4XX - Client error (Bad Request, Unauthorized, etc.) , 5XX - Server error" - content: - application/json: - schema: - $ref: "../definitions.yaml#/components/schemas/ErrorObject" - -components: - securitySchemes: - $ref: "../security.yaml#/components/securitySchemes" \ No newline at end of file diff --git a/openapi/paths/exercise.yaml b/openapi/paths/exercise.yaml deleted file mode 100644 index 99fc142..0000000 --- a/openapi/paths/exercise.yaml +++ /dev/null @@ -1,209 +0,0 @@ -paths: - /api/exercises/{id}: - parameters: - - name: id - in: path - description: "The exercise ID" - required: true - schema: - type: integer - - name: includeOptions - in: query - description: "To include additional properties when fetching exercise" - style: deepObject - schema: - $ref: "../definitions.yaml#/components/schemas/IncludeOptions" - get: - summary: "Retrieve this specific exercise data" - operationId: getExerciseByID - x-controller: exercises - x-operation: getExerciseByID - security: - - {} - - bearerAuth: [] - tags: - - guest - - user - responses: - '200': - description: "Exercise data inside a JSON" - content: - application/json: - schema: - allOf: - - $ref: "../definitions.yaml#/components/schemas/SearchableExerciseModel" - - type: object - properties: - vote: - type: number - minimum: 0.0 - example: 5.0 - description: "If this endpoint was used by an authentified user, it will fetch his/her vote if it exists" - # Definition of all error statuses - default: - description: "Whatever error : 4XX - Client error (Bad Request, Unauthorized, etc.) , 5XX - Server error" - content: - application/json: - schema: - $ref: "../definitions.yaml#/components/schemas/ErrorObject" - put: - summary: "Update this specific exercise data" - description: | - Update this specific exercise data - You are free to add new tags / keywords but you **must** add at least 3 validated tags. - The following restrictions are applied on simple user(s) (no restriction for admin) : - - 1. He/She can only modify his/her own exercises - 2. Only the following states are allowed for the field "state" : - - DRAFT - - PENDING - 3. He/She can't use the field "state" inside an tag object of "tags" array - operationId: UpdateExercise - x-controller: exercises - x-operation: UpdateExercise - tags: - - user - security: - - bearerAuth: [] - requestBody: - required: true - content: - application/json: - schema: - allOf: - - $ref: "../definitions.yaml#/components/schemas/ExerciseUpdateForm" - - type: object - properties: - removePreviousFile: - type: boolean - default: false - example: true - description: "If set to true, the API will delete the previous file when updating the exercise" - multipart/form-data: - schema: - allOf: - - $ref: "../definitions.yaml#/components/schemas/ExerciseUpdateForm" - - type: object - description: "If we want to also to change the sources zip file of this exercise" - properties: - exerciseFile: - type: string - format: binary - description: "The sources of this exercise, in zip format" - required: - - exerciseFile - encoding: - exerciseFile: - # MIME for zip https://stackoverflow.com/a/7027582/6149867 - contentType: application/zip, application/x-zip-compressed, multipart/x-zip - responses: - '200': - description: OK - # Definition of all error statuses - default: - description: "Whatever error : 4XX - Client error (Bad Request, Unauthorized, etc.) , 5XX - Server error" - content: - application/json: - schema: - $ref: "../definitions.yaml#/components/schemas/ErrorObject" - /api/export: - post: - operationId: ExportExercises - x-controller: exercises - x-operation: ExportExercises - description: | - To export exercises that match optional criteria. - - The JSON result is compliant with the [format](https://github.com/SourceCodeOER/cli#what-is-the-format-of-the-json-object-) - of our [cli](https://github.com/SourceCodeOER/cli) which means that if you wish to reupload the exercises in the future, - it's simple as you just have to rely on the [cli](https://github.com/SourceCodeOER/cli) command "uploader". - Please consider the following facts before using it : - - 1. Don't forget to rename the key "categories" to "own_categories" - - 2. If you wish to upload them without their files, remove the property "file" in each exercise : - ```js - let json_result = { /* ... */ }; - const exercisesWithoutFile = json_result["exercises"].map(exercise => { - delete exercise["file"] - return exercise; - }); - Object.assign(json_result, { "exercises": exercisesWithoutFile }); - ``` - - 3. If you wish to upload them with their files, download their files and modify each property "file" according our [format](https://github.com/SourceCodeOER/cli#what-is-the-format-of-the-json-object-) - of our [cli](https://github.com/SourceCodeOER/cli). - - tags: - - admin - security: - - bearerAuth: [] - requestBody: - required: false - content: - application/json: - schema: - $ref: "../definitions.yaml#/components/schemas/CommonCriterias" - responses: - '200': - description: "Exercises data inside a JSON" - content: - application/json: - schema: - type: object - properties: - exercises: - description: "The fetched exercises (with their tags)" - type: array - items: - allOf: - - $ref: "../definitions.yaml#/components/schemas/AlreadyPresentExerciseModel" - - type: object - properties: - tags: - type: array - description: "The tags linked to this exercise" - items: - type: object - properties: - text: - type: string - description: "The text of this Tag" - example: "INGINIOUS" - minLength: 1 - maxLength: 100 - category: - type: integer - example: 42 - minimum: 0 - description: "The category of this tag" - state: - $ref: "../definitions.yaml#/components/schemas/TagState" - required: - - state - - category - - text - required: - - tags - categories: - description: Map whose keys are the IDS of the categories and value their text - type: object - example: - "1": "source" - "2": "institution" - "3": "auteur" - required: - - exercises - - categories - # Definition of all error statuses - default: - description: "Whatever error : 4XX - Client error (Bad Request, Unauthorized, etc.) , 5XX - Server error" - content: - application/json: - schema: - $ref: "../definitions.yaml#/components/schemas/ErrorObject" - -components: - securitySchemes: - bearerAuth: - $ref: "../security.yaml#/components/securitySchemes/bearerAuth" diff --git a/openapi/paths/miscellaneous.yaml b/openapi/paths/miscellaneous.yaml deleted file mode 100644 index d9c87d3..0000000 --- a/openapi/paths/miscellaneous.yaml +++ /dev/null @@ -1,30 +0,0 @@ -paths: - /files/{file}: - parameters: - - name: file - in: path - description: "The path to the file we want to access" - example: "someFile.zip" - required: true - schema: - type: string - get: - summary: "Download a stored file on the API" - operationId: downloadFile - tags: - - guest - responses: - '200': - description: "The file" - content: - '*/*': - schema: - type: string - format: binary - # Definition of all error statuses - default: - description: "Whatever error : 4XX - Client error (Bad Request, Unauthorized, etc.) , 5XX - Server error" - content: - application/json: - schema: - $ref: "../definitions.yaml#/components/schemas/ErrorObject" \ No newline at end of file diff --git a/openapi/paths/search.yaml b/openapi/paths/search.yaml deleted file mode 100644 index 7794842..0000000 --- a/openapi/paths/search.yaml +++ /dev/null @@ -1,34 +0,0 @@ -paths: - /api/search: - post: - summary: "Search exercises that matches criteria" - tags: - - guest - operationId: searchExercises - x-controller: exercises - x-operation: searchExercises - requestBody: - required: false - content: - application/json: - schema: - $ref: "../definitions.yaml#/components/schemas/SearchCriterias" - examples: - searchExample1: - $ref: "../examples.yaml#/examples/searchExample1" - searchExample2: - $ref: "../examples.yaml#/examples/searchExample2" - responses: - '200': - description: "An object that contains the results and additionnal information" - content: - application/json: - schema: - $ref: "../definitions.yaml#/components/schemas/SearchResult" - # Definition of all error statuses - default: - description: "Whatever error : 4XX - Client error (Bad Request, Unauthorized, etc.) , 5XX - Server error" - content: - application/json: - schema: - $ref: "../definitions.yaml#/components/schemas/ErrorObject" diff --git a/openapi/paths/tags.yaml b/openapi/paths/tags.yaml deleted file mode 100644 index 970fd1c..0000000 --- a/openapi/paths/tags.yaml +++ /dev/null @@ -1,114 +0,0 @@ -paths: - /api/tags: - post: - summary: "Submit a tag proposal" - tags: - - user - operationId: submitTagProposal - x-controller: tags - x-operation: submitTagProposal - security: - - bearerAuth: [] - requestBody: - required: true - content: - application/json: - schema: - $ref: "../definitions.yaml#/components/schemas/TagProposal" - responses: - '200': - description: OK - # Definition of all error statuses - default: - description: "Whatever error : 4XX - Client error (Bad Request, Unauthorized, etc.) , 5XX - Server error" - content: - application/json: - schema: - $ref: "../definitions.yaml#/components/schemas/ErrorObject" - put: - summary: "Modify a Tag" - tags: - - admin - operationId: updateTag - x-controller: tags - x-operation: updateTag - security: - - bearerAuth: [] - requestBody: - required: true - content: - application/json: - schema: - $ref: "../definitions.yaml#/components/schemas/TagFull" - responses: - '200': - description: OK - # Definition of all error statuses - default: - description: "Whatever error : 4XX - Client error (Bad Request, Unauthorized, etc.) , 5XX - Server error" - content: - application/json: - schema: - $ref: "../definitions.yaml#/components/schemas/ErrorObject" - get: - summary: "Retrieve all tags" - tags: - - guest - operationId: getTags - x-controller: tags - x-operation: getTags - parameters: - - in: query - name: tags_ids - schema: - type: array - items: - type: integer - minimum: 0 - minItems: 1 - description: "Only consider the given tag ID(S)" - - in: query - name: categories_ids - schema: - type: array - items: - type: integer - minimum: 0 - minItems: 1 - description: "Only consider the given tag categories ID(S)" - - in: query - name: state - schema: - type: array - description: "Filter the tags by their state. By default, no filtering is done." - items: - $ref: "../definitions.yaml#/components/schemas/TagState" - maxItems: 4 - - in: query - name: title - schema: - type: string - description: "Filter the tags by their text (case-insensitive comparison)" - maxLength: 100 - responses: - '200': - description: "An array of tag" - content: - application/json: - schema: - type: array - items: - $ref: "../definitions.yaml#/components/schemas/TagFull" - uniqueItems: true - # Definition of all error statuses - default: - description: "Whatever error : 4XX - Client error (Bad Request, Unauthorized, etc.) , 5XX - Server error" - content: - application/json: - schema: - $ref: "../definitions.yaml#/components/schemas/ErrorObject" - -components: - securitySchemes: - bearerAuth: - $ref: "../security.yaml#/components/securitySchemes/bearerAuth" \ No newline at end of file diff --git a/openapi/paths/tags_by_categories.yaml b/openapi/paths/tags_by_categories.yaml deleted file mode 100644 index ae74884..0000000 --- a/openapi/paths/tags_by_categories.yaml +++ /dev/null @@ -1,62 +0,0 @@ -paths: - /api/tags_by_categories: - get: - summary: "Retrieve Tag categories with their related tags" - tags: - - guest - operationId: getTagCategoriesWithTags - x-controller: tags_categories - x-operation: getTagCategoriesWithTags - parameters: - - in: query - name: state - schema: - type: array - description: "Filter the tags by their state. By default, no filtering is done." - items: - $ref: "../definitions.yaml#/components/schemas/TagState" - maxItems: 4 - - in: query - name: onlySelected - schema: - type: array - description: "If not empty, only consider the given tag categories ID(S). If empty, no tag category is ignored" - default: [] - uniqueItems: true - items: - type: integer - minimum: 0 - example: 42 - description: "A Tag Category ID" - - in: query - name: countStates - description: | - If not empty, only consider the given exercise state(s) to compute the field "total" inside each tag. - If empty, every exercise state will be considered for the sum. - schema: - type: array - items: - $ref: "../definitions.yaml#/components/schemas/State" - maxItems: 5 - responses: - '200': - description: "An array of Tag category with their related tags" - content: - application/json: - schema: - type: array - items: - $ref: "../definitions.yaml#/components/schemas/TagCategoryWithTags" - uniqueItems: true - # Definition of all error statuses - default: - description: "Whatever error : 4XX - Client error (Bad Request, Unauthorized, etc.) , 5XX - Server error" - content: - application/json: - schema: - $ref: "../definitions.yaml#/components/schemas/ErrorObject" - -components: - securitySchemes: - bearerAuth: - $ref: "../security.yaml#/components/securitySchemes/bearerAuth" \ No newline at end of file diff --git a/openapi/paths/tags_categories.yaml b/openapi/paths/tags_categories.yaml deleted file mode 100644 index 4102390..0000000 --- a/openapi/paths/tags_categories.yaml +++ /dev/null @@ -1,97 +0,0 @@ -paths: - /api/tags_categories: - get: - summary: "Retrieve only Tag categories" - operationId: getTagCategories - x-controller: tags_categories - x-operation: getTagCategories - tags: - - guest - parameters: - - in: query - name: fetchStats - schema: - type: integer - enum: [0,1] - description: "If set to 1, it means that you enabled. Otherwise (0 or not defined), you disabled it" - description: "If enabled, you can retrieve extra properties with the tag category" - - in: query - name: category_ids - schema: - type: array - items: - type: integer - minimum: 0 - description: "An category id" - description: "Take only the given categories" - responses: - '200': - description: "An array of tag categories" - content: - application/json: - schema: - type: array - items: - allOf: - - $ref: "../definitions.yaml#/components/schemas/Tag_Category" - - type: object - description: "If queryParameter 'fetchStats' is set to 1, you can retrieve the following count properties :" - properties: - total: - type: integer - description: "The total number of tags under this tag category" - minimum: 0 - total_validated: - type: integer - description: "The total number of VALIDATED tags under this tag category" - minimum: 0 - total_unvalidated: - type: integer - description: "The total number of NOT_VALIDATED tags under this tag category" - minimum: 0 - total_deprecated: - type: integer - description: "The total number of DEPRECATED tags under this tag category" - minimum: 0 - total_pending: - type: integer - description: "The total number of PENDING tags under this tag category" - minimum: 0 - uniqueItems: true - # Definition of all error statuses - default: - description: "Whatever error : 4XX - Client error (Bad Request, Unauthorized, etc.) , 5XX - Server error" - content: - application/json: - schema: - $ref: "../definitions.yaml#/components/schemas/ErrorObject" - put: - summary: "Update a Tag category" - operationId: updateTagCategory - x-controller: tags_categories - x-operation: updateTagCategory - security: - - bearerAuth: [] - tags: - - admin - requestBody: - required: true - content: - application/json: - schema: - $ref: "../definitions.yaml#/components/schemas/Tag_Category" - responses: - '200': - description: "OK" - # Definition of all error statuses - default: - description: "Whatever error : 4XX - Client error (Bad Request, Unauthorized, etc.) , 5XX - Server error" - content: - application/json: - schema: - $ref: "../definitions.yaml#/components/schemas/ErrorObject" - -components: - securitySchemes: - bearerAuth: - $ref: "../security.yaml#/components/securitySchemes/bearerAuth" \ No newline at end of file diff --git a/openapi/paths/users.yaml b/openapi/paths/users.yaml deleted file mode 100644 index 3bdd17e..0000000 --- a/openapi/paths/users.yaml +++ /dev/null @@ -1,152 +0,0 @@ -paths: - /auth/me: - get: - summary: "Fetch information about the current logged user" - operationId: "me" - x-controller: users - x-operation: me - tags: - - user - security: - - bearerAuth: [] - responses: - '200': - description: "User data" - content: - application/json: - schema: - allOf: - - $ref: "../definitions.yaml#/components/schemas/BasicUser" - - type: object - properties: - role: - $ref: "../definitions.yaml#/components/schemas/Roles" - id: - type: integer - description: "The UUID of this user" - example: 42 - required: - - role - - id - # Definition of all error statuses - default: - description: "Whatever error : 4XX - Client error (Bad Request, Unauthorized, etc.) , 5XX - Server error" - content: - application/json: - schema: - $ref: "../definitions.yaml#/components/schemas/ErrorObject" - /auth/update: - put: - summary: "Update information about an user" - description: | - Any user can freely any information about (him/her)self (except the optional "id" / "role" fields ). - An super admin can freely update any user and it is the only one that can use the "id" / "role" fields. - operationId: "updateUser" - x-controller: users - x-operation: updateUser - tags: - - user - - super_admin - security: - - bearerAuth: [] - requestBody: - required: true - content: - application/json: - schema: - type: object - properties: - fullName: - type: string - example: "Alexandre Dewit" - description: "The full name of the user" - minLength: 1 - maxLength: 50 - password: - type: string - format: password - example: "42" - role: - $ref: "../definitions.yaml#/components/schemas/Roles" - id: - type: integer - description: "The UUID of this user. By default, it will take the one of logged user" - example: 42 - responses: - '200': - description: "OK" - # Definition of all error statuses - default: - description: "Whatever error : 4XX - Client error (Bad Request, Unauthorized, etc.) , 5XX - Server error" - content: - application/json: - schema: - $ref: "../definitions.yaml#/components/schemas/ErrorObject" - /api/users: - get: - summary: "List users" - operationId: "ListUsers" - x-controller: users - x-operation: ListUsers - tags: - - admin - security: - - bearerAuth: [] - parameters: - - in: query - name: metadata - style: deepObject - schema: - $ref: "../definitions.yaml#/components/schemas/PaginationCriterias" - - in: query - name: roles - schema: - type: array - description: "If not empty, only consider the given user role(s). If empty, no user role is ignored" - default: [] - uniqueItems: true - items: - $ref: "../definitions.yaml#/components/schemas/Roles" - maxItems: 3 - - in: query - name: fullName - schema: - type: string - minLength: 1 - maxLength: 100 - - in: query - name: email - schema: - type: string - format: email - minLength: 1 - maxLength: 100 - responses: - '200': - description: "An list of Users with some metadata" - content: - application/json: - schema: - type: object - properties: - metadata: - $ref: "../definitions.yaml#/components/schemas/PaginationResult" - data: - type: array - items: - allOf: - - $ref: "../definitions.yaml#/components/schemas/BasicUser" - - type: object - properties: - role: - $ref: "../definitions.yaml#/components/schemas/Roles" - id: - type: integer - description: "The UUID of this user" - example: 42 - required: - - role - - id - required: - - metadata - - data \ No newline at end of file diff --git a/openapi/paths/vote_for_exercise.yaml b/openapi/paths/vote_for_exercise.yaml deleted file mode 100644 index 2b10834..0000000 --- a/openapi/paths/vote_for_exercise.yaml +++ /dev/null @@ -1,47 +0,0 @@ -paths: - /api/vote_for_exercise: - post: - summary: "Vote (or update the vote) of the current logged user for given exercise" - operationId: "voteForExercise" - x-controller: exercises - x-operation: voteForExercise - tags: - - user - security: - - bearerAuth: [] - requestBody: - required: true - content: - application/json: - schema: - type: object - properties: - exercise_id: - type: integer - minimum: 0 - description: "The ID of the exercise we want to vote / modify a vote" - example: 42 - score: - type: number - format: double - minimum: 0.0 - example: 5.0 - description: "The score we want to give to this exercise" - required: - - score - - exercise_id - responses: - '200': - description: OK - # Definition of all error statuses - default: - description: "Whatever error : 4XX - Client error (Bad Request, Unauthorized, etc.) , 5XX - Server error" - content: - application/json: - schema: - $ref: "../definitions.yaml#/components/schemas/ErrorObject" - -components: - securitySchemes: - bearerAuth: - $ref: "../security.yaml#/components/securitySchemes/bearerAuth" \ No newline at end of file diff --git a/openapi/security.yaml b/openapi/security.yaml deleted file mode 100644 index 4017bc6..0000000 --- a/openapi/security.yaml +++ /dev/null @@ -1,6 +0,0 @@ -components: # Define the security scheme type (HTTP bearer) - securitySchemes: - bearerAuth: # arbitrary name for the security scheme - type: http - scheme: bearer - bearerFormat: JWT # optional, arbitrary value for documentation purposes \ No newline at end of file diff --git a/package-lock.json b/package-lock.json deleted file mode 100644 index 18a6faf..0000000 --- a/package-lock.json +++ /dev/null @@ -1,11527 +0,0 @@ -{ - "name": "sourcecode-api", - "version": "1.0.0", - "lockfileVersion": 1, - "requires": true, - "dependencies": { - "@babel/code-frame": { - "version": "7.5.5", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.5.5.tgz", - "integrity": "sha512-27d4lZoomVyo51VegxI20xZPuSHusqbQag/ztrBC7wegWoQ1nLREPVSKSW8byhTlzTKyNE4ifaTA6lCp7JjpFw==", - "dev": true, - "requires": { - "@babel/highlight": "^7.0.0" - } - }, - "@babel/core": { - "version": "7.9.0", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.9.0.tgz", - "integrity": "sha512-kWc7L0fw1xwvI0zi8OKVBuxRVefwGOrKSQMvrQ3dW+bIIavBY3/NpXmpjMy7bQnLgwgzWQZ8TlM57YHpHNHz4w==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.8.3", - "@babel/generator": "^7.9.0", - "@babel/helper-module-transforms": "^7.9.0", - "@babel/helpers": "^7.9.0", - "@babel/parser": "^7.9.0", - "@babel/template": "^7.8.6", - "@babel/traverse": "^7.9.0", - "@babel/types": "^7.9.0", - "convert-source-map": "^1.7.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.1", - "json5": "^2.1.2", - "lodash": "^4.17.13", - "resolve": "^1.3.2", - "semver": "^5.4.1", - "source-map": "^0.5.0" - }, - "dependencies": { - "@babel/code-frame": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.8.3.tgz", - "integrity": "sha512-a9gxpmdXtZEInkCSHUJDLHZVBgb1QS0jhss4cPP93EW7s+uC5bikET2twEF3KV+7rDblJcmNvTR7VJejqd2C2g==", - "dev": true, - "requires": { - "@babel/highlight": "^7.8.3" - } - }, - "@babel/generator": { - "version": "7.9.5", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.9.5.tgz", - "integrity": "sha512-GbNIxVB3ZJe3tLeDm1HSn2AhuD/mVcyLDpgtLXa5tplmWrJdF/elxB56XNqCuD6szyNkDi6wuoKXln3QeBmCHQ==", - "dev": true, - "requires": { - "@babel/types": "^7.9.5", - "jsesc": "^2.5.1", - "lodash": "^4.17.13", - "source-map": "^0.5.0" - } - }, - "@babel/helper-function-name": { - "version": "7.9.5", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.9.5.tgz", - "integrity": "sha512-JVcQZeXM59Cd1qanDUxv9fgJpt3NeKUaqBqUEvfmQ+BCOKq2xUgaWZW2hr0dkbyJgezYuplEoh5knmrnS68efw==", - "dev": true, - "requires": { - "@babel/helper-get-function-arity": "^7.8.3", - "@babel/template": "^7.8.3", - "@babel/types": "^7.9.5" - } - }, - "@babel/helper-get-function-arity": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.8.3.tgz", - "integrity": "sha512-FVDR+Gd9iLjUMY1fzE2SR0IuaJToR4RkCDARVfsBBPSP53GEqSFjD8gNyxg246VUyc/ALRxFaAK8rVG7UT7xRA==", - "dev": true, - "requires": { - "@babel/types": "^7.8.3" - } - }, - "@babel/helper-split-export-declaration": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.8.3.tgz", - "integrity": "sha512-3x3yOeyBhW851hroze7ElzdkeRXQYQbFIb7gLK1WQYsw2GWDay5gAJNw1sWJ0VFP6z5J1whqeXH/WCdCjZv6dA==", - "dev": true, - "requires": { - "@babel/types": "^7.8.3" - } - }, - "@babel/highlight": { - "version": "7.9.0", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.9.0.tgz", - "integrity": "sha512-lJZPilxX7Op3Nv/2cvFdnlepPXDxi29wxteT57Q965oc5R9v86ztx0jfxVrTcBk8C2kcPkkDa2Z4T3ZsPPVWsQ==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.9.0", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - } - }, - "@babel/parser": { - "version": "7.9.4", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.9.4.tgz", - "integrity": "sha512-bC49otXX6N0/VYhgOMh4gnP26E9xnDZK3TmbNpxYzzz9BQLBosQwfyOe9/cXUU3txYhTzLCbcqd5c8y/OmCjHA==", - "dev": true - }, - "@babel/template": { - "version": "7.8.6", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.8.6.tgz", - "integrity": "sha512-zbMsPMy/v0PWFZEhQJ66bqjhH+z0JgMoBWuikXybgG3Gkd/3t5oQ1Rw2WQhnSrsOmsKXnZOx15tkC4qON/+JPg==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.8.3", - "@babel/parser": "^7.8.6", - "@babel/types": "^7.8.6" - } - }, - "@babel/traverse": { - "version": "7.9.5", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.9.5.tgz", - "integrity": "sha512-c4gH3jsvSuGUezlP6rzSJ6jf8fYjLj3hsMZRx/nX0h+fmHN0w+ekubRrHPqnMec0meycA2nwCsJ7dC8IPem2FQ==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.8.3", - "@babel/generator": "^7.9.5", - "@babel/helper-function-name": "^7.9.5", - "@babel/helper-split-export-declaration": "^7.8.3", - "@babel/parser": "^7.9.0", - "@babel/types": "^7.9.5", - "debug": "^4.1.0", - "globals": "^11.1.0", - "lodash": "^4.17.13" - } - }, - "@babel/types": { - "version": "7.9.5", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.9.5.tgz", - "integrity": "sha512-XjnvNqenk818r5zMaba+sLQjnbda31UfUURv3ei0qPQw4u+j2jMyJ5b11y8ZHYTRSI3NnInQkkkRT4fLqqPdHg==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.9.5", - "lodash": "^4.17.13", - "to-fast-properties": "^2.0.0" - }, - "dependencies": { - "@babel/helper-validator-identifier": { - "version": "7.9.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.9.5.tgz", - "integrity": "sha512-/8arLKUFq882w4tWGj9JYzRpAlZgiWUJ+dtteNTDqrRBz9Iguck9Rn3ykuBDoUwh2TO4tSAJlrxDUOXWklJe4g==", - "dev": true - } - } - }, - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true - }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - } - } - }, - "@babel/generator": { - "version": "7.6.4", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.6.4.tgz", - "integrity": "sha512-jsBuXkFoZxk0yWLyGI9llT9oiQ2FeTASmRFE32U+aaDTfoE92t78eroO7PTpU/OrYq38hlcDM6vbfLDaOLy+7w==", - "dev": true, - "requires": { - "@babel/types": "^7.6.3", - "jsesc": "^2.5.1", - "lodash": "^4.17.13", - "source-map": "^0.5.0" - }, - "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-annotate-as-pure": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.8.3.tgz", - "integrity": "sha512-6o+mJrZBxOoEX77Ezv9zwW7WV8DdluouRKNY/IR5u/YTMuKHgugHOzYWlYvYLpLA9nPsQCAAASpCIbjI9Mv+Uw==", - "dev": true, - "requires": { - "@babel/types": "^7.8.3" - }, - "dependencies": { - "@babel/types": { - "version": "7.9.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.9.0.tgz", - "integrity": "sha512-BS9JKfXkzzJl8RluW4JGknzpiUV7ZrvTayM6yfqLTVBEnFtyowVIOu6rqxRd5cVO6yGoWf4T8u8dgK9oB+GCng==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.9.0", - "lodash": "^4.17.13", - "to-fast-properties": "^2.0.0" - } - } - } - }, - "@babel/helper-function-name": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.1.0.tgz", - "integrity": "sha512-A95XEoCpb3TO+KZzJ4S/5uW5fNe26DjBGqf1o9ucyLyCmi1dXq/B3c8iaWTfBk3VvetUxl16e8tIrd5teOCfGw==", - "dev": true, - "requires": { - "@babel/helper-get-function-arity": "^7.0.0", - "@babel/template": "^7.1.0", - "@babel/types": "^7.0.0" - } - }, - "@babel/helper-get-function-arity": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.0.0.tgz", - "integrity": "sha512-r2DbJeg4svYvt3HOS74U4eWKsUAMRH01Z1ds1zx8KNTPtpTL5JAsdFv8BNyOpVqdFhHkkRDIg5B4AsxmkjAlmQ==", - "dev": true, - "requires": { - "@babel/types": "^7.0.0" - } - }, - "@babel/helper-member-expression-to-functions": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.8.3.tgz", - "integrity": "sha512-fO4Egq88utkQFjbPrSHGmGLFqmrshs11d46WI+WZDESt7Wu7wN2G2Iu+NMMZJFDOVRHAMIkB5SNh30NtwCA7RA==", - "dev": true, - "requires": { - "@babel/types": "^7.8.3" - }, - "dependencies": { - "@babel/helper-validator-identifier": { - "version": "7.9.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.9.5.tgz", - "integrity": "sha512-/8arLKUFq882w4tWGj9JYzRpAlZgiWUJ+dtteNTDqrRBz9Iguck9Rn3ykuBDoUwh2TO4tSAJlrxDUOXWklJe4g==", - "dev": true - }, - "@babel/types": { - "version": "7.9.5", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.9.5.tgz", - "integrity": "sha512-XjnvNqenk818r5zMaba+sLQjnbda31UfUURv3ei0qPQw4u+j2jMyJ5b11y8ZHYTRSI3NnInQkkkRT4fLqqPdHg==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.9.5", - "lodash": "^4.17.13", - "to-fast-properties": "^2.0.0" - } - } - } - }, - "@babel/helper-module-imports": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.8.3.tgz", - "integrity": "sha512-R0Bx3jippsbAEtzkpZ/6FIiuzOURPcMjHp+Z6xPe6DtApDJx+w7UYyOLanZqO8+wKR9G10s/FmHXvxaMd9s6Kg==", - "dev": true, - "requires": { - "@babel/types": "^7.8.3" - }, - "dependencies": { - "@babel/types": { - "version": "7.9.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.9.0.tgz", - "integrity": "sha512-BS9JKfXkzzJl8RluW4JGknzpiUV7ZrvTayM6yfqLTVBEnFtyowVIOu6rqxRd5cVO6yGoWf4T8u8dgK9oB+GCng==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.9.0", - "lodash": "^4.17.13", - "to-fast-properties": "^2.0.0" - } - } - } - }, - "@babel/helper-module-transforms": { - "version": "7.9.0", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.9.0.tgz", - "integrity": "sha512-0FvKyu0gpPfIQ8EkxlrAydOWROdHpBmiCiRwLkUiBGhCUPRRbVD2/tm3sFr/c/GWFrQ/ffutGUAnx7V0FzT2wA==", - "dev": true, - "requires": { - "@babel/helper-module-imports": "^7.8.3", - "@babel/helper-replace-supers": "^7.8.6", - "@babel/helper-simple-access": "^7.8.3", - "@babel/helper-split-export-declaration": "^7.8.3", - "@babel/template": "^7.8.6", - "@babel/types": "^7.9.0", - "lodash": "^4.17.13" - }, - "dependencies": { - "@babel/code-frame": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.8.3.tgz", - "integrity": "sha512-a9gxpmdXtZEInkCSHUJDLHZVBgb1QS0jhss4cPP93EW7s+uC5bikET2twEF3KV+7rDblJcmNvTR7VJejqd2C2g==", - "dev": true, - "requires": { - "@babel/highlight": "^7.8.3" - } - }, - "@babel/helper-split-export-declaration": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.8.3.tgz", - "integrity": "sha512-3x3yOeyBhW851hroze7ElzdkeRXQYQbFIb7gLK1WQYsw2GWDay5gAJNw1sWJ0VFP6z5J1whqeXH/WCdCjZv6dA==", - "dev": true, - "requires": { - "@babel/types": "^7.8.3" - } - }, - "@babel/helper-validator-identifier": { - "version": "7.9.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.9.5.tgz", - "integrity": "sha512-/8arLKUFq882w4tWGj9JYzRpAlZgiWUJ+dtteNTDqrRBz9Iguck9Rn3ykuBDoUwh2TO4tSAJlrxDUOXWklJe4g==", - "dev": true - }, - "@babel/highlight": { - "version": "7.9.0", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.9.0.tgz", - "integrity": "sha512-lJZPilxX7Op3Nv/2cvFdnlepPXDxi29wxteT57Q965oc5R9v86ztx0jfxVrTcBk8C2kcPkkDa2Z4T3ZsPPVWsQ==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.9.0", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - } - }, - "@babel/parser": { - "version": "7.9.4", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.9.4.tgz", - "integrity": "sha512-bC49otXX6N0/VYhgOMh4gnP26E9xnDZK3TmbNpxYzzz9BQLBosQwfyOe9/cXUU3txYhTzLCbcqd5c8y/OmCjHA==", - "dev": true - }, - "@babel/template": { - "version": "7.8.6", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.8.6.tgz", - "integrity": "sha512-zbMsPMy/v0PWFZEhQJ66bqjhH+z0JgMoBWuikXybgG3Gkd/3t5oQ1Rw2WQhnSrsOmsKXnZOx15tkC4qON/+JPg==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.8.3", - "@babel/parser": "^7.8.6", - "@babel/types": "^7.8.6" - } - }, - "@babel/types": { - "version": "7.9.5", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.9.5.tgz", - "integrity": "sha512-XjnvNqenk818r5zMaba+sLQjnbda31UfUURv3ei0qPQw4u+j2jMyJ5b11y8ZHYTRSI3NnInQkkkRT4fLqqPdHg==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.9.5", - "lodash": "^4.17.13", - "to-fast-properties": "^2.0.0" - } - } - } - }, - "@babel/helper-optimise-call-expression": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.8.3.tgz", - "integrity": "sha512-Kag20n86cbO2AvHca6EJsvqAd82gc6VMGule4HwebwMlwkpXuVqrNRj6CkCV2sKxgi9MyAUnZVnZ6lJ1/vKhHQ==", - "dev": true, - "requires": { - "@babel/types": "^7.8.3" - }, - "dependencies": { - "@babel/helper-validator-identifier": { - "version": "7.9.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.9.5.tgz", - "integrity": "sha512-/8arLKUFq882w4tWGj9JYzRpAlZgiWUJ+dtteNTDqrRBz9Iguck9Rn3ykuBDoUwh2TO4tSAJlrxDUOXWklJe4g==", - "dev": true - }, - "@babel/types": { - "version": "7.9.5", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.9.5.tgz", - "integrity": "sha512-XjnvNqenk818r5zMaba+sLQjnbda31UfUURv3ei0qPQw4u+j2jMyJ5b11y8ZHYTRSI3NnInQkkkRT4fLqqPdHg==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.9.5", - "lodash": "^4.17.13", - "to-fast-properties": "^2.0.0" - } - } - } - }, - "@babel/helper-plugin-utils": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.8.3.tgz", - "integrity": "sha512-j+fq49Xds2smCUNYmEHF9kGNkhbet6yVIBp4e6oeQpH1RUs/Ir06xUKzDjDkGcaaokPiTNs2JBWHjaE4csUkZQ==", - "dev": true - }, - "@babel/helper-replace-supers": { - "version": "7.8.6", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.8.6.tgz", - "integrity": "sha512-PeMArdA4Sv/Wf4zXwBKPqVj7n9UF/xg6slNRtZW84FM7JpE1CbG8B612FyM4cxrf4fMAMGO0kR7voy1ForHHFA==", - "dev": true, - "requires": { - "@babel/helper-member-expression-to-functions": "^7.8.3", - "@babel/helper-optimise-call-expression": "^7.8.3", - "@babel/traverse": "^7.8.6", - "@babel/types": "^7.8.6" - }, - "dependencies": { - "@babel/code-frame": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.8.3.tgz", - "integrity": "sha512-a9gxpmdXtZEInkCSHUJDLHZVBgb1QS0jhss4cPP93EW7s+uC5bikET2twEF3KV+7rDblJcmNvTR7VJejqd2C2g==", - "dev": true, - "requires": { - "@babel/highlight": "^7.8.3" - } - }, - "@babel/generator": { - "version": "7.9.5", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.9.5.tgz", - "integrity": "sha512-GbNIxVB3ZJe3tLeDm1HSn2AhuD/mVcyLDpgtLXa5tplmWrJdF/elxB56XNqCuD6szyNkDi6wuoKXln3QeBmCHQ==", - "dev": true, - "requires": { - "@babel/types": "^7.9.5", - "jsesc": "^2.5.1", - "lodash": "^4.17.13", - "source-map": "^0.5.0" - } - }, - "@babel/helper-function-name": { - "version": "7.9.5", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.9.5.tgz", - "integrity": "sha512-JVcQZeXM59Cd1qanDUxv9fgJpt3NeKUaqBqUEvfmQ+BCOKq2xUgaWZW2hr0dkbyJgezYuplEoh5knmrnS68efw==", - "dev": true, - "requires": { - "@babel/helper-get-function-arity": "^7.8.3", - "@babel/template": "^7.8.3", - "@babel/types": "^7.9.5" - } - }, - "@babel/helper-get-function-arity": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.8.3.tgz", - "integrity": "sha512-FVDR+Gd9iLjUMY1fzE2SR0IuaJToR4RkCDARVfsBBPSP53GEqSFjD8gNyxg246VUyc/ALRxFaAK8rVG7UT7xRA==", - "dev": true, - "requires": { - "@babel/types": "^7.8.3" - } - }, - "@babel/helper-split-export-declaration": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.8.3.tgz", - "integrity": "sha512-3x3yOeyBhW851hroze7ElzdkeRXQYQbFIb7gLK1WQYsw2GWDay5gAJNw1sWJ0VFP6z5J1whqeXH/WCdCjZv6dA==", - "dev": true, - "requires": { - "@babel/types": "^7.8.3" - } - }, - "@babel/highlight": { - "version": "7.9.0", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.9.0.tgz", - "integrity": "sha512-lJZPilxX7Op3Nv/2cvFdnlepPXDxi29wxteT57Q965oc5R9v86ztx0jfxVrTcBk8C2kcPkkDa2Z4T3ZsPPVWsQ==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.9.0", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - } - }, - "@babel/parser": { - "version": "7.9.4", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.9.4.tgz", - "integrity": "sha512-bC49otXX6N0/VYhgOMh4gnP26E9xnDZK3TmbNpxYzzz9BQLBosQwfyOe9/cXUU3txYhTzLCbcqd5c8y/OmCjHA==", - "dev": true - }, - "@babel/template": { - "version": "7.8.6", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.8.6.tgz", - "integrity": "sha512-zbMsPMy/v0PWFZEhQJ66bqjhH+z0JgMoBWuikXybgG3Gkd/3t5oQ1Rw2WQhnSrsOmsKXnZOx15tkC4qON/+JPg==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.8.3", - "@babel/parser": "^7.8.6", - "@babel/types": "^7.8.6" - } - }, - "@babel/traverse": { - "version": "7.9.5", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.9.5.tgz", - "integrity": "sha512-c4gH3jsvSuGUezlP6rzSJ6jf8fYjLj3hsMZRx/nX0h+fmHN0w+ekubRrHPqnMec0meycA2nwCsJ7dC8IPem2FQ==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.8.3", - "@babel/generator": "^7.9.5", - "@babel/helper-function-name": "^7.9.5", - "@babel/helper-split-export-declaration": "^7.8.3", - "@babel/parser": "^7.9.0", - "@babel/types": "^7.9.5", - "debug": "^4.1.0", - "globals": "^11.1.0", - "lodash": "^4.17.13" - } - }, - "@babel/types": { - "version": "7.9.5", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.9.5.tgz", - "integrity": "sha512-XjnvNqenk818r5zMaba+sLQjnbda31UfUURv3ei0qPQw4u+j2jMyJ5b11y8ZHYTRSI3NnInQkkkRT4fLqqPdHg==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.9.5", - "lodash": "^4.17.13", - "to-fast-properties": "^2.0.0" - }, - "dependencies": { - "@babel/helper-validator-identifier": { - "version": "7.9.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.9.5.tgz", - "integrity": "sha512-/8arLKUFq882w4tWGj9JYzRpAlZgiWUJ+dtteNTDqrRBz9Iguck9Rn3ykuBDoUwh2TO4tSAJlrxDUOXWklJe4g==", - "dev": true - } - } - }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - } - } - }, - "@babel/helper-simple-access": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.8.3.tgz", - "integrity": "sha512-VNGUDjx5cCWg4vvCTR8qQ7YJYZ+HBjxOgXEl7ounz+4Sn7+LMD3CFrCTEU6/qXKbA2nKg21CwhhBzO0RpRbdCw==", - "dev": true, - "requires": { - "@babel/template": "^7.8.3", - "@babel/types": "^7.8.3" - }, - "dependencies": { - "@babel/code-frame": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.8.3.tgz", - "integrity": "sha512-a9gxpmdXtZEInkCSHUJDLHZVBgb1QS0jhss4cPP93EW7s+uC5bikET2twEF3KV+7rDblJcmNvTR7VJejqd2C2g==", - "dev": true, - "requires": { - "@babel/highlight": "^7.8.3" - } - }, - "@babel/highlight": { - "version": "7.9.0", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.9.0.tgz", - "integrity": "sha512-lJZPilxX7Op3Nv/2cvFdnlepPXDxi29wxteT57Q965oc5R9v86ztx0jfxVrTcBk8C2kcPkkDa2Z4T3ZsPPVWsQ==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.9.0", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - } - }, - "@babel/parser": { - "version": "7.9.4", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.9.4.tgz", - "integrity": "sha512-bC49otXX6N0/VYhgOMh4gnP26E9xnDZK3TmbNpxYzzz9BQLBosQwfyOe9/cXUU3txYhTzLCbcqd5c8y/OmCjHA==", - "dev": true - }, - "@babel/template": { - "version": "7.8.6", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.8.6.tgz", - "integrity": "sha512-zbMsPMy/v0PWFZEhQJ66bqjhH+z0JgMoBWuikXybgG3Gkd/3t5oQ1Rw2WQhnSrsOmsKXnZOx15tkC4qON/+JPg==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.8.3", - "@babel/parser": "^7.8.6", - "@babel/types": "^7.8.6" - } - }, - "@babel/types": { - "version": "7.9.5", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.9.5.tgz", - "integrity": "sha512-XjnvNqenk818r5zMaba+sLQjnbda31UfUURv3ei0qPQw4u+j2jMyJ5b11y8ZHYTRSI3NnInQkkkRT4fLqqPdHg==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.9.5", - "lodash": "^4.17.13", - "to-fast-properties": "^2.0.0" - }, - "dependencies": { - "@babel/helper-validator-identifier": { - "version": "7.9.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.9.5.tgz", - "integrity": "sha512-/8arLKUFq882w4tWGj9JYzRpAlZgiWUJ+dtteNTDqrRBz9Iguck9Rn3ykuBDoUwh2TO4tSAJlrxDUOXWklJe4g==", - "dev": true - } - } - } - } - }, - "@babel/helper-split-export-declaration": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.4.4.tgz", - "integrity": "sha512-Ro/XkzLf3JFITkW6b+hNxzZ1n5OQ80NvIUdmHspih1XAhtN3vPTuUFT4eQnela+2MaZ5ulH+iyP513KJrxbN7Q==", - "dev": true, - "requires": { - "@babel/types": "^7.4.4" - } - }, - "@babel/helper-validator-identifier": { - "version": "7.9.0", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.9.0.tgz", - "integrity": "sha512-6G8bQKjOh+of4PV/ThDm/rRqlU7+IGoJuofpagU5GlEl29Vv0RGqqt86ZGRV8ZuSOY3o+8yXl5y782SMcG7SHw==", - "dev": true - }, - "@babel/helpers": { - "version": "7.9.2", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.9.2.tgz", - "integrity": "sha512-JwLvzlXVPjO8eU9c/wF9/zOIN7X6h8DYf7mG4CiFRZRvZNKEF5dQ3H3V+ASkHoIB3mWhatgl5ONhyqHRI6MppA==", - "dev": true, - "requires": { - "@babel/template": "^7.8.3", - "@babel/traverse": "^7.9.0", - "@babel/types": "^7.9.0" - }, - "dependencies": { - "@babel/code-frame": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.8.3.tgz", - "integrity": "sha512-a9gxpmdXtZEInkCSHUJDLHZVBgb1QS0jhss4cPP93EW7s+uC5bikET2twEF3KV+7rDblJcmNvTR7VJejqd2C2g==", - "dev": true, - "requires": { - "@babel/highlight": "^7.8.3" - } - }, - "@babel/generator": { - "version": "7.9.5", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.9.5.tgz", - "integrity": "sha512-GbNIxVB3ZJe3tLeDm1HSn2AhuD/mVcyLDpgtLXa5tplmWrJdF/elxB56XNqCuD6szyNkDi6wuoKXln3QeBmCHQ==", - "dev": true, - "requires": { - "@babel/types": "^7.9.5", - "jsesc": "^2.5.1", - "lodash": "^4.17.13", - "source-map": "^0.5.0" - } - }, - "@babel/helper-function-name": { - "version": "7.9.5", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.9.5.tgz", - "integrity": "sha512-JVcQZeXM59Cd1qanDUxv9fgJpt3NeKUaqBqUEvfmQ+BCOKq2xUgaWZW2hr0dkbyJgezYuplEoh5knmrnS68efw==", - "dev": true, - "requires": { - "@babel/helper-get-function-arity": "^7.8.3", - "@babel/template": "^7.8.3", - "@babel/types": "^7.9.5" - } - }, - "@babel/helper-get-function-arity": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.8.3.tgz", - "integrity": "sha512-FVDR+Gd9iLjUMY1fzE2SR0IuaJToR4RkCDARVfsBBPSP53GEqSFjD8gNyxg246VUyc/ALRxFaAK8rVG7UT7xRA==", - "dev": true, - "requires": { - "@babel/types": "^7.8.3" - } - }, - "@babel/helper-split-export-declaration": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.8.3.tgz", - "integrity": "sha512-3x3yOeyBhW851hroze7ElzdkeRXQYQbFIb7gLK1WQYsw2GWDay5gAJNw1sWJ0VFP6z5J1whqeXH/WCdCjZv6dA==", - "dev": true, - "requires": { - "@babel/types": "^7.8.3" - } - }, - "@babel/highlight": { - "version": "7.9.0", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.9.0.tgz", - "integrity": "sha512-lJZPilxX7Op3Nv/2cvFdnlepPXDxi29wxteT57Q965oc5R9v86ztx0jfxVrTcBk8C2kcPkkDa2Z4T3ZsPPVWsQ==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.9.0", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - } - }, - "@babel/parser": { - "version": "7.9.4", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.9.4.tgz", - "integrity": "sha512-bC49otXX6N0/VYhgOMh4gnP26E9xnDZK3TmbNpxYzzz9BQLBosQwfyOe9/cXUU3txYhTzLCbcqd5c8y/OmCjHA==", - "dev": true - }, - "@babel/template": { - "version": "7.8.6", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.8.6.tgz", - "integrity": "sha512-zbMsPMy/v0PWFZEhQJ66bqjhH+z0JgMoBWuikXybgG3Gkd/3t5oQ1Rw2WQhnSrsOmsKXnZOx15tkC4qON/+JPg==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.8.3", - "@babel/parser": "^7.8.6", - "@babel/types": "^7.8.6" - } - }, - "@babel/traverse": { - "version": "7.9.5", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.9.5.tgz", - "integrity": "sha512-c4gH3jsvSuGUezlP6rzSJ6jf8fYjLj3hsMZRx/nX0h+fmHN0w+ekubRrHPqnMec0meycA2nwCsJ7dC8IPem2FQ==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.8.3", - "@babel/generator": "^7.9.5", - "@babel/helper-function-name": "^7.9.5", - "@babel/helper-split-export-declaration": "^7.8.3", - "@babel/parser": "^7.9.0", - "@babel/types": "^7.9.5", - "debug": "^4.1.0", - "globals": "^11.1.0", - "lodash": "^4.17.13" - } - }, - "@babel/types": { - "version": "7.9.5", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.9.5.tgz", - "integrity": "sha512-XjnvNqenk818r5zMaba+sLQjnbda31UfUURv3ei0qPQw4u+j2jMyJ5b11y8ZHYTRSI3NnInQkkkRT4fLqqPdHg==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.9.5", - "lodash": "^4.17.13", - "to-fast-properties": "^2.0.0" - }, - "dependencies": { - "@babel/helper-validator-identifier": { - "version": "7.9.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.9.5.tgz", - "integrity": "sha512-/8arLKUFq882w4tWGj9JYzRpAlZgiWUJ+dtteNTDqrRBz9Iguck9Rn3ykuBDoUwh2TO4tSAJlrxDUOXWklJe4g==", - "dev": true - } - } - }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - } - } - }, - "@babel/highlight": { - "version": "7.5.0", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.5.0.tgz", - "integrity": "sha512-7dV4eu9gBxoM0dAnj/BCFDW9LFU0zvTrkq0ugM7pnHEgguOEeOz1so2ZghEdzviYzQEED0r4EAgpsBChKy1TRQ==", - "dev": true, - "requires": { - "chalk": "^2.0.0", - "esutils": "^2.0.2", - "js-tokens": "^4.0.0" - } - }, - "@babel/parser": { - "version": "7.6.4", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.6.4.tgz", - "integrity": "sha512-D8RHPW5qd0Vbyo3qb+YjO5nvUVRTXFLQ/FsDxJU2Nqz4uB5EnUN0ZQSEYpvTIbRuttig1XbHWU5oMeQwQSAA+A==", - "dev": true - }, - "@babel/plugin-syntax-async-generators": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", - "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-bigint": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", - "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-class-properties": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.8.3.tgz", - "integrity": "sha512-UcAyQWg2bAN647Q+O811tG9MrJ38Z10jjhQdKNAL8fsyPzE3cCN/uT+f55cFVY4aGO4jqJAvmqsuY3GQDwAoXg==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.3" - } - }, - "@babel/plugin-syntax-json-strings": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", - "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-logical-assignment-operators": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.8.3.tgz", - "integrity": "sha512-Zpg2Sgc++37kuFl6ppq2Q7Awc6E6AIW671x5PY8E/f7MCIyPPGK/EoeZXvvY3P42exZ3Q4/t3YOzP/HiN79jDg==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.3" - } - }, - "@babel/plugin-syntax-nullish-coalescing-operator": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", - "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-numeric-separator": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.8.3.tgz", - "integrity": "sha512-H7dCMAdN83PcCmqmkHB5dtp+Xa9a6LKSvA2hiFBC/5alSHxM5VgWZXFqDi0YFe8XNGT6iCa+z4V4zSt/PdZ7Dw==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.3" - } - }, - "@babel/plugin-syntax-object-rest-spread": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", - "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-optional-catch-binding": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", - "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-optional-chaining": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", - "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/runtime": { - "version": "7.9.2", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.9.2.tgz", - "integrity": "sha512-NE2DtOdufG7R5vnfQUTehdTfNycfUANEtCa9PssN9O/xmTzP4E08UI797ixaei6hBEVL9BI/PsdJS5x7mWoB9Q==", - "dev": true, - "requires": { - "regenerator-runtime": "^0.13.4" - }, - "dependencies": { - "regenerator-runtime": { - "version": "0.13.5", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.5.tgz", - "integrity": "sha512-ZS5w8CpKFinUzOwW3c83oPeVXoNsrLsaCoLtJvAClH135j/R77RuymhiSErhm2lKcwSCIpmvIWSbDkIfAqKQlA==", - "dev": true - } - } - }, - "@babel/template": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.6.0.tgz", - "integrity": "sha512-5AEH2EXD8euCk446b7edmgFdub/qfH1SN6Nii3+fyXP807QRx9Q73A2N5hNwRRslC2H9sNzaFhsPubkS4L8oNQ==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.0.0", - "@babel/parser": "^7.6.0", - "@babel/types": "^7.6.0" - } - }, - "@babel/traverse": { - "version": "7.6.3", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.6.3.tgz", - "integrity": "sha512-unn7P4LGsijIxaAJo/wpoU11zN+2IaClkQAxcJWBNCMS6cmVh802IyLHNkAjQ0iYnRS3nnxk5O3fuXW28IMxTw==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.5.5", - "@babel/generator": "^7.6.3", - "@babel/helper-function-name": "^7.1.0", - "@babel/helper-split-export-declaration": "^7.4.4", - "@babel/parser": "^7.6.3", - "@babel/types": "^7.6.3", - "debug": "^4.1.0", - "globals": "^11.1.0", - "lodash": "^4.17.13" - } - }, - "@babel/types": { - "version": "7.6.3", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.6.3.tgz", - "integrity": "sha512-CqbcpTxMcpuQTMhjI37ZHVgjBkysg5icREQIEZ0eG1yCNwg3oy+5AaLiOKmjsCj6nqOsa6Hf0ObjRVwokb7srA==", - "dev": true, - "requires": { - "esutils": "^2.0.2", - "lodash": "^4.17.13", - "to-fast-properties": "^2.0.0" - } - }, - "@bcoe/v8-coverage": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", - "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", - "dev": true - }, - "@cnakazawa/watch": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@cnakazawa/watch/-/watch-1.0.4.tgz", - "integrity": "sha512-v9kIhKwjeZThiWrLmj0y17CWoyddASLj9O2yvbZkbvw/N3rWOYy9zkV66ursAoVr0mV15bL8g0c4QZUE6cdDoQ==", - "dev": true, - "requires": { - "exec-sh": "^0.3.2", - "minimist": "^1.2.0" - } - }, - "@emotion/is-prop-valid": { - "version": "0.8.8", - "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-0.8.8.tgz", - "integrity": "sha512-u5WtneEAr5IDG2Wv65yhunPSMLIpuKsbuOktRojfrEiEvRyC85LgPMZI63cr7NUqT8ZIGdSVg8ZKGxIug4lXcA==", - "dev": true, - "requires": { - "@emotion/memoize": "0.7.4" - } - }, - "@emotion/memoize": { - "version": "0.7.4", - "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.7.4.tgz", - "integrity": "sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw==", - "dev": true - }, - "@emotion/unitless": { - "version": "0.7.5", - "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.7.5.tgz", - "integrity": "sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg==", - "dev": true - }, - "@istanbuljs/load-nyc-config": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.0.0.tgz", - "integrity": "sha512-ZR0rq/f/E4f4XcgnDvtMWXCUJpi8eO0rssVhmztsZqLIEFA9UUP9zmpE0VxlM+kv/E1ul2I876Fwil2ayptDVg==", - "dev": true, - "requires": { - "camelcase": "^5.3.1", - "find-up": "^4.1.0", - "js-yaml": "^3.13.1", - "resolve-from": "^5.0.0" - }, - "dependencies": { - "find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "requires": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - } - }, - "locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "requires": { - "p-locate": "^4.1.0" - } - }, - "p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "requires": { - "p-limit": "^2.2.0" - } - }, - "path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true - } - } - }, - "@istanbuljs/schema": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.2.tgz", - "integrity": "sha512-tsAQNx32a8CoFhjhijUIhI4kccIAgmGhy8LZMZgGfmXcpMbPRUqn5LWmgRttILi6yeGmBJd2xsPkFMs0PzgPCw==", - "dev": true - }, - "@jest/console": { - "version": "25.4.0", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-25.4.0.tgz", - "integrity": "sha512-CfE0erx4hdJ6t7RzAcE1wLG6ZzsHSmybvIBQDoCkDM1QaSeWL9wJMzID/2BbHHa7ll9SsbbK43HjbERbBaFX2A==", - "dev": true, - "requires": { - "@jest/types": "^25.4.0", - "chalk": "^3.0.0", - "jest-message-util": "^25.4.0", - "jest-util": "^25.4.0", - "slash": "^3.0.0" - }, - "dependencies": { - "@jest/types": { - "version": "25.4.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-25.4.0.tgz", - "integrity": "sha512-XBeaWNzw2PPnGW5aXvZt3+VO60M+34RY3XDsCK5tW7kyj3RK0XClRutCfjqcBuaR2aBQTbluEDME9b5MB9UAPw==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^1.1.1", - "@types/yargs": "^15.0.0", - "chalk": "^3.0.0" - } - }, - "ansi-styles": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", - "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", - "dev": true, - "requires": { - "@types/color-name": "^1.1.1", - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", - "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", - "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "@jest/core": { - "version": "25.4.0", - "resolved": "https://registry.npmjs.org/@jest/core/-/core-25.4.0.tgz", - "integrity": "sha512-h1x9WSVV0+TKVtATGjyQIMJENs8aF6eUjnCoi4jyRemYZmekLr8EJOGQqTWEX8W6SbZ6Skesy9pGXrKeAolUJw==", - "dev": true, - "requires": { - "@jest/console": "^25.4.0", - "@jest/reporters": "^25.4.0", - "@jest/test-result": "^25.4.0", - "@jest/transform": "^25.4.0", - "@jest/types": "^25.4.0", - "ansi-escapes": "^4.2.1", - "chalk": "^3.0.0", - "exit": "^0.1.2", - "graceful-fs": "^4.2.3", - "jest-changed-files": "^25.4.0", - "jest-config": "^25.4.0", - "jest-haste-map": "^25.4.0", - "jest-message-util": "^25.4.0", - "jest-regex-util": "^25.2.6", - "jest-resolve": "^25.4.0", - "jest-resolve-dependencies": "^25.4.0", - "jest-runner": "^25.4.0", - "jest-runtime": "^25.4.0", - "jest-snapshot": "^25.4.0", - "jest-util": "^25.4.0", - "jest-validate": "^25.4.0", - "jest-watcher": "^25.4.0", - "micromatch": "^4.0.2", - "p-each-series": "^2.1.0", - "realpath-native": "^2.0.0", - "rimraf": "^3.0.0", - "slash": "^3.0.0", - "strip-ansi": "^6.0.0" - }, - "dependencies": { - "@jest/types": { - "version": "25.4.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-25.4.0.tgz", - "integrity": "sha512-XBeaWNzw2PPnGW5aXvZt3+VO60M+34RY3XDsCK5tW7kyj3RK0XClRutCfjqcBuaR2aBQTbluEDME9b5MB9UAPw==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^1.1.1", - "@types/yargs": "^15.0.0", - "chalk": "^3.0.0" - } - }, - "ansi-regex": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", - "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", - "dev": true - }, - "ansi-styles": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", - "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", - "dev": true, - "requires": { - "@types/color-name": "^1.1.1", - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", - "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "graceful-fs": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz", - "integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", - "dev": true, - "requires": { - "ansi-regex": "^5.0.0" - } - }, - "supports-color": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", - "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "@jest/environment": { - "version": "25.4.0", - "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-25.4.0.tgz", - "integrity": "sha512-KDctiak4mu7b4J6BIoN/+LUL3pscBzoUCP+EtSPd2tK9fqyDY5OF+CmkBywkFWezS9tyH5ACOQNtpjtueEDH6Q==", - "dev": true, - "requires": { - "@jest/fake-timers": "^25.4.0", - "@jest/types": "^25.4.0", - "jest-mock": "^25.4.0" - }, - "dependencies": { - "@jest/types": { - "version": "25.4.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-25.4.0.tgz", - "integrity": "sha512-XBeaWNzw2PPnGW5aXvZt3+VO60M+34RY3XDsCK5tW7kyj3RK0XClRutCfjqcBuaR2aBQTbluEDME9b5MB9UAPw==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^1.1.1", - "@types/yargs": "^15.0.0", - "chalk": "^3.0.0" - } - }, - "ansi-styles": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", - "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", - "dev": true, - "requires": { - "@types/color-name": "^1.1.1", - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", - "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", - "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "@jest/fake-timers": { - "version": "25.4.0", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-25.4.0.tgz", - "integrity": "sha512-lI9z+VOmVX4dPPFzyj0vm+UtaB8dCJJ852lcDnY0uCPRvZAaVGnMwBBc1wxtf+h7Vz6KszoOvKAt4QijDnHDkg==", - "dev": true, - "requires": { - "@jest/types": "^25.4.0", - "jest-message-util": "^25.4.0", - "jest-mock": "^25.4.0", - "jest-util": "^25.4.0", - "lolex": "^5.0.0" - }, - "dependencies": { - "@jest/types": { - "version": "25.4.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-25.4.0.tgz", - "integrity": "sha512-XBeaWNzw2PPnGW5aXvZt3+VO60M+34RY3XDsCK5tW7kyj3RK0XClRutCfjqcBuaR2aBQTbluEDME9b5MB9UAPw==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^1.1.1", - "@types/yargs": "^15.0.0", - "chalk": "^3.0.0" - } - }, - "ansi-styles": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", - "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", - "dev": true, - "requires": { - "@types/color-name": "^1.1.1", - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", - "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", - "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "@jest/reporters": { - "version": "25.4.0", - "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-25.4.0.tgz", - "integrity": "sha512-bhx/buYbZgLZm4JWLcRJ/q9Gvmd3oUh7k2V7gA4ZYBx6J28pIuykIouclRdiAC6eGVX1uRZT+GK4CQJLd/PwPg==", - "dev": true, - "requires": { - "@bcoe/v8-coverage": "^0.2.3", - "@jest/console": "^25.4.0", - "@jest/test-result": "^25.4.0", - "@jest/transform": "^25.4.0", - "@jest/types": "^25.4.0", - "chalk": "^3.0.0", - "collect-v8-coverage": "^1.0.0", - "exit": "^0.1.2", - "glob": "^7.1.2", - "istanbul-lib-coverage": "^3.0.0", - "istanbul-lib-instrument": "^4.0.0", - "istanbul-lib-report": "^3.0.0", - "istanbul-lib-source-maps": "^4.0.0", - "istanbul-reports": "^3.0.2", - "jest-haste-map": "^25.4.0", - "jest-resolve": "^25.4.0", - "jest-util": "^25.4.0", - "jest-worker": "^25.4.0", - "node-notifier": "^6.0.0", - "slash": "^3.0.0", - "source-map": "^0.6.0", - "string-length": "^3.1.0", - "terminal-link": "^2.0.0", - "v8-to-istanbul": "^4.1.3" - }, - "dependencies": { - "@jest/types": { - "version": "25.4.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-25.4.0.tgz", - "integrity": "sha512-XBeaWNzw2PPnGW5aXvZt3+VO60M+34RY3XDsCK5tW7kyj3RK0XClRutCfjqcBuaR2aBQTbluEDME9b5MB9UAPw==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^1.1.1", - "@types/yargs": "^15.0.0", - "chalk": "^3.0.0" - } - }, - "ansi-styles": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", - "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", - "dev": true, - "requires": { - "@types/color-name": "^1.1.1", - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", - "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", - "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "@jest/source-map": { - "version": "25.2.6", - "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-25.2.6.tgz", - "integrity": "sha512-VuIRZF8M2zxYFGTEhkNSvQkUKafQro4y+mwUxy5ewRqs5N/ynSFUODYp3fy1zCnbCMy1pz3k+u57uCqx8QRSQQ==", - "dev": true, - "requires": { - "callsites": "^3.0.0", - "graceful-fs": "^4.2.3", - "source-map": "^0.6.0" - }, - "dependencies": { - "graceful-fs": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz", - "integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==", - "dev": true - } - } - }, - "@jest/test-result": { - "version": "25.4.0", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-25.4.0.tgz", - "integrity": "sha512-8BAKPaMCHlL941eyfqhWbmp3MebtzywlxzV+qtngQ3FH+RBqnoSAhNEPj4MG7d2NVUrMOVfrwuzGpVIK+QnMAA==", - "dev": true, - "requires": { - "@jest/console": "^25.4.0", - "@jest/types": "^25.4.0", - "@types/istanbul-lib-coverage": "^2.0.0", - "collect-v8-coverage": "^1.0.0" - }, - "dependencies": { - "@jest/types": { - "version": "25.4.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-25.4.0.tgz", - "integrity": "sha512-XBeaWNzw2PPnGW5aXvZt3+VO60M+34RY3XDsCK5tW7kyj3RK0XClRutCfjqcBuaR2aBQTbluEDME9b5MB9UAPw==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^1.1.1", - "@types/yargs": "^15.0.0", - "chalk": "^3.0.0" - } - }, - "ansi-styles": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", - "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", - "dev": true, - "requires": { - "@types/color-name": "^1.1.1", - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", - "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", - "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "@jest/test-sequencer": { - "version": "25.4.0", - "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-25.4.0.tgz", - "integrity": "sha512-240cI+nsM3attx2bMp9uGjjHrwrpvxxrZi8Tyqp/cfOzl98oZXVakXBgxODGyBYAy/UGXPKXLvNc2GaqItrsJg==", - "dev": true, - "requires": { - "@jest/test-result": "^25.4.0", - "jest-haste-map": "^25.4.0", - "jest-runner": "^25.4.0", - "jest-runtime": "^25.4.0" - } - }, - "@jest/transform": { - "version": "25.4.0", - "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-25.4.0.tgz", - "integrity": "sha512-t1w2S6V1sk++1HHsxboWxPEuSpN8pxEvNrZN+Ud/knkROWtf8LeUmz73A4ezE8476a5AM00IZr9a8FO9x1+j3g==", - "dev": true, - "requires": { - "@babel/core": "^7.1.0", - "@jest/types": "^25.4.0", - "babel-plugin-istanbul": "^6.0.0", - "chalk": "^3.0.0", - "convert-source-map": "^1.4.0", - "fast-json-stable-stringify": "^2.0.0", - "graceful-fs": "^4.2.3", - "jest-haste-map": "^25.4.0", - "jest-regex-util": "^25.2.6", - "jest-util": "^25.4.0", - "micromatch": "^4.0.2", - "pirates": "^4.0.1", - "realpath-native": "^2.0.0", - "slash": "^3.0.0", - "source-map": "^0.6.1", - "write-file-atomic": "^3.0.0" - }, - "dependencies": { - "@jest/types": { - "version": "25.4.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-25.4.0.tgz", - "integrity": "sha512-XBeaWNzw2PPnGW5aXvZt3+VO60M+34RY3XDsCK5tW7kyj3RK0XClRutCfjqcBuaR2aBQTbluEDME9b5MB9UAPw==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^1.1.1", - "@types/yargs": "^15.0.0", - "chalk": "^3.0.0" - } - }, - "ansi-styles": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", - "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", - "dev": true, - "requires": { - "@types/color-name": "^1.1.1", - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", - "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "graceful-fs": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz", - "integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", - "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "@jest/types": { - "version": "25.4.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-25.4.0.tgz", - "integrity": "sha512-XBeaWNzw2PPnGW5aXvZt3+VO60M+34RY3XDsCK5tW7kyj3RK0XClRutCfjqcBuaR2aBQTbluEDME9b5MB9UAPw==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^1.1.1", - "@types/yargs": "^15.0.0", - "chalk": "^3.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", - "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", - "dev": true, - "requires": { - "@types/color-name": "^1.1.1", - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", - "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", - "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "@nodelib/fs.scandir": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.3.tgz", - "integrity": "sha512-eGmwYQn3gxo4r7jdQnkrrN6bY478C3P+a/y72IJukF8LjB6ZHeB3c+Ehacj3sYeSmUXGlnA67/PmbM9CVwL7Dw==", - "requires": { - "@nodelib/fs.stat": "2.0.3", - "run-parallel": "^1.1.9" - } - }, - "@nodelib/fs.stat": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.3.tgz", - "integrity": "sha512-bQBFruR2TAwoevBEd/NWMoAAtNGzTRgdrqnYCc7dhzfoNvqPzLyqlEQnzZ3kVnNrSp25iyxE00/3h2fqGAGArA==" - }, - "@nodelib/fs.walk": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.4.tgz", - "integrity": "sha512-1V9XOY4rDW0rehzbrcqAmHnz8e7SKvX27gh8Gt2WgB0+pdzdiLV83p72kZPU+jvMbS1qU5mauP2iOvO8rhmurQ==", - "requires": { - "@nodelib/fs.scandir": "2.1.3", - "fastq": "^1.6.0" - } - }, - "@openapitools/openapi-generator-cli": { - "version": "1.0.10-4.2.3", - "resolved": "https://registry.npmjs.org/@openapitools/openapi-generator-cli/-/openapi-generator-cli-1.0.10-4.2.3.tgz", - "integrity": "sha512-Xo4rbz3aPiObpVS8oBUR0pHWYU5WBG/bmsJg16yCG7/vpGE8o1YsROTWMFfaMepWfxESrLP5XOqlBkZqbre7dw==", - "dev": true - }, - "@sinonjs/commons": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.7.2.tgz", - "integrity": "sha512-+DUO6pnp3udV/v2VfUWgaY5BIE1IfT7lLfeDzPVeMT1XKkaAp9LgSI9x5RtrFQoZ9Oi0PgXQQHPaoKu7dCjVxw==", - "dev": true, - "requires": { - "type-detect": "4.0.8" - } - }, - "@types/babel__core": { - "version": "7.1.7", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.7.tgz", - "integrity": "sha512-RL62NqSFPCDK2FM1pSDH0scHpJvsXtZNiYlMB73DgPBaG1E38ZYVL+ei5EkWRbr+KC4YNiAUNBnRj+bgwpgjMw==", - "dev": true, - "requires": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0", - "@types/babel__generator": "*", - "@types/babel__template": "*", - "@types/babel__traverse": "*" - } - }, - "@types/babel__generator": { - "version": "7.6.1", - "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.1.tgz", - "integrity": "sha512-bBKm+2VPJcMRVwNhxKu8W+5/zT7pwNEqeokFOmbvVSqGzFneNxYcEBro9Ac7/N9tlsaPYnZLK8J1LWKkMsLAew==", - "dev": true, - "requires": { - "@babel/types": "^7.0.0" - } - }, - "@types/babel__template": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.0.2.tgz", - "integrity": "sha512-/K6zCpeW7Imzgab2bLkLEbz0+1JlFSrUMdw7KoIIu+IUdu51GWaBZpd3y1VXGVXzynvGa4DaIaxNZHiON3GXUg==", - "dev": true, - "requires": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0" - } - }, - "@types/babel__traverse": { - "version": "7.0.10", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.0.10.tgz", - "integrity": "sha512-74fNdUGrWsgIB/V9kTO5FGHPWYY6Eqn+3Z7L6Hc4e/BxjYV7puvBqp5HwsVYYfLm6iURYBNCx4Ut37OF9yitCw==", - "dev": true, - "requires": { - "@babel/types": "^7.3.0" - } - }, - "@types/bluebird": { - "version": "3.5.30", - "resolved": "https://registry.npmjs.org/@types/bluebird/-/bluebird-3.5.30.tgz", - "integrity": "sha512-8LhzvcjIoqoi1TghEkRMkbbmM+jhHnBokPGkJWjclMK+Ks0MxEBow3/p2/iFTZ+OIbJHQDSfpgdZEb+af3gfVw==", - "dev": true - }, - "@types/body-parser": { - "version": "1.19.0", - "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.0.tgz", - "integrity": "sha512-W98JrE0j2K78swW4ukqMleo8R7h/pFETjM2DQ90MF6XK2i4LO4W3gQ71Lt4w3bfm2EvVSyWHplECvB5sK22yFQ==", - "dev": true, - "requires": { - "@types/connect": "*", - "@types/node": "*" - } - }, - "@types/color-name": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz", - "integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==", - "dev": true - }, - "@types/connect": { - "version": "3.4.33", - "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.33.tgz", - "integrity": "sha512-2+FrkXY4zllzTNfJth7jOqEHC+enpLeGslEhpnTAkg21GkRrWV4SsAtqchtT4YS9/nODBU2/ZfsBY2X4J/dX7A==", - "dev": true, - "requires": { - "@types/node": "*" - } - }, - "@types/continuation-local-storage": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/@types/continuation-local-storage/-/continuation-local-storage-3.2.2.tgz", - "integrity": "sha512-aItm+aYPJ4rT1cHmAxO+OdWjSviQ9iB5UKb5f0Uvgln0N4hS2mcDodHtPiqicYBXViUYhqyBjhA5uyOcT+S34Q==", - "dev": true, - "requires": { - "@types/node": "*" - } - }, - "@types/cookiejar": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/@types/cookiejar/-/cookiejar-2.1.1.tgz", - "integrity": "sha512-aRnpPa7ysx3aNW60hTiCtLHlQaIFsXFCgQlpakNgDNVFzbtusSY8PwjAQgRWfSk0ekNoBjO51eQRB6upA9uuyw==", - "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==" - }, - "@types/express": { - "version": "4.17.6", - "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.6.tgz", - "integrity": "sha512-n/mr9tZI83kd4azlPG5y997C/M4DNABK9yErhFM6hKdym4kkmd9j0vtsJyjFIwfRBxtrxZtAfGZCNRIBMFLK5w==", - "dev": true, - "requires": { - "@types/body-parser": "*", - "@types/express-serve-static-core": "*", - "@types/qs": "*", - "@types/serve-static": "*" - } - }, - "@types/express-serve-static-core": { - "version": "4.17.5", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.5.tgz", - "integrity": "sha512-578YH5Lt88AKoADy0b2jQGwJtrBxezXtVe/MBqWXKZpqx91SnC0pVkVCcxcytz3lWW+cHBYDi3Ysh0WXc+rAYw==", - "dev": true, - "requires": { - "@types/node": "*", - "@types/range-parser": "*" - } - }, - "@types/glob": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.1.tgz", - "integrity": "sha512-1Bh06cbWJUHMC97acuD6UMG29nMt0Aqz1vF3guLfG+kHHJhy3AyohZFFxYk2f7Q1SQIrNwvncxAE0N/9s70F2w==", - "requires": { - "@types/events": "*", - "@types/minimatch": "*", - "@types/node": "*" - } - }, - "@types/istanbul-lib-coverage": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.1.tgz", - "integrity": "sha512-hRJD2ahnnpLgsj6KWMYSrmXkM3rm2Dl1qkx6IOFD5FnuNPXJIG5L0dhgKXCYTRMGzU4n0wImQ/xfmRc4POUFlg==", - "dev": true - }, - "@types/istanbul-lib-report": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", - "integrity": "sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "*" - } - }, - "@types/istanbul-reports": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-1.1.1.tgz", - "integrity": "sha512-UpYjBi8xefVChsCoBpKShdxTllC9pwISirfoZsUa2AAdQg/Jd2KQGtSbw+ya7GPo7x/wAPlH6JBhKhAsXUEZNA==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "*", - "@types/istanbul-lib-report": "*" - } - }, - "@types/jest": { - "version": "25.2.1", - "resolved": "https://registry.npmjs.org/@types/jest/-/jest-25.2.1.tgz", - "integrity": "sha512-msra1bCaAeEdkSyA0CZ6gW1ukMIvZ5YoJkdXw/qhQdsuuDlFTcEUrUw8CLCPt2rVRUfXlClVvK2gvPs9IokZaA==", - "dev": true, - "requires": { - "jest-diff": "^25.2.1", - "pretty-format": "^25.2.1" - } - }, - "@types/lodash": { - "version": "4.14.150", - "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.150.tgz", - "integrity": "sha512-kMNLM5JBcasgYscD9x/Gvr6lTAv2NVgsKtet/hm93qMyf/D1pt+7jeEZklKJKxMVmXjxbRVQQGfqDSfipYCO6w==", - "dev": true - }, - "@types/mime": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@types/mime/-/mime-2.0.1.tgz", - "integrity": "sha512-FwI9gX75FgVBJ7ywgnq/P7tw+/o1GUbtP0KzbtusLigAOgIgNISRK0ZPl4qertvXSIE8YbsVJueQ90cDt9YYyw==", - "dev": true - }, - "@types/minimatch": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz", - "integrity": "sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==" - }, - "@types/node": { - "version": "12.11.1", - "resolved": "https://registry.npmjs.org/@types/node/-/node-12.11.1.tgz", - "integrity": "sha512-TJtwsqZ39pqcljJpajeoofYRfeZ7/I/OMUQ5pR4q5wOKf2ocrUvBAZUMhWsOvKx3dVc/aaV5GluBivt0sWqA5A==" - }, - "@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/prettier": { - "version": "1.19.1", - "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-1.19.1.tgz", - "integrity": "sha512-5qOlnZscTn4xxM5MeGXAMOsIOIKIbh9e85zJWfBRVPlRMEVawzoPhINYbRGkBZCI8LxvBe7tJCdWiarA99OZfQ==", - "dev": true - }, - "@types/qs": { - "version": "6.9.1", - "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.1.tgz", - "integrity": "sha512-lhbQXx9HKZAPgBkISrBcmAcMpZsmpe/Cd/hY7LGZS5OfkySUBItnPZHgQPssWYUET8elF+yCFBbP1Q0RZPTdaw==", - "dev": true - }, - "@types/range-parser": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.3.tgz", - "integrity": "sha512-ewFXqrQHlFsgc09MK5jP5iR7vumV/BYayNC6PgJO2LPe8vrnNFyjQjSppfEngITi0qvfKtzFvgKymGheFM9UOA==", - "dev": true - }, - "@types/sequelize": { - "version": "4.28.8", - "resolved": "https://registry.npmjs.org/@types/sequelize/-/sequelize-4.28.8.tgz", - "integrity": "sha512-3n/iSpOtO5NynSBgEJ+738DK/ctxkqnVMvdPLZxrbZrf/rQgNm8wgDPDSarS1rmluvOe5ZMRDF8DXhts5MIbag==", - "dev": true, - "requires": { - "@types/bluebird": "*", - "@types/continuation-local-storage": "*", - "@types/lodash": "*", - "@types/validator": "*" - } - }, - "@types/serve-static": { - "version": "1.13.3", - "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.3.tgz", - "integrity": "sha512-oprSwp094zOglVrXdlo/4bAHtKTAxX6VT8FOZlBKrmyLbNvE1zxZyJ6yikMVtHIvwP45+ZQGJn+FdXGKTozq0g==", - "dev": true, - "requires": { - "@types/express-serve-static-core": "*", - "@types/mime": "*" - } - }, - "@types/stack-utils": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-1.0.1.tgz", - "integrity": "sha512-l42BggppR6zLmpfU6fq9HEa2oGPEI8yrSPL3GITjfRInppYFahObbIQOQK3UGxEnyQpltZLaPe75046NOZQikw==", - "dev": true - }, - "@types/superagent": { - "version": "4.1.7", - "resolved": "https://registry.npmjs.org/@types/superagent/-/superagent-4.1.7.tgz", - "integrity": "sha512-JSwNPgRYjIC4pIeOqLwWwfGj6iP1n5NE6kNBEbGx2V8H78xCPwx7QpNp9plaI30+W3cFEzJO7BIIsXE+dbtaGg==", - "dev": true, - "requires": { - "@types/cookiejar": "*", - "@types/node": "*" - } - }, - "@types/supertest": { - "version": "2.0.8", - "resolved": "https://registry.npmjs.org/@types/supertest/-/supertest-2.0.8.tgz", - "integrity": "sha512-wcax7/ip4XSSJRLbNzEIUVy2xjcBIZZAuSd2vtltQfRK7kxhx5WMHbLHkYdxN3wuQCrwpYrg86/9byDjPXoGMA==", - "dev": true, - "requires": { - "@types/superagent": "*" - } - }, - "@types/validator": { - "version": "13.0.0", - "resolved": "https://registry.npmjs.org/@types/validator/-/validator-13.0.0.tgz", - "integrity": "sha512-WAy5txG7aFX8Vw3sloEKp5p/t/Xt8jD3GRD9DacnFv6Vo8ubudAsRTXgxpQwU0mpzY/H8U4db3roDuCMjShBmw==", - "dev": true - }, - "@types/yargs": { - "version": "15.0.1", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.1.tgz", - "integrity": "sha512-sYlwNU7zYi6eZbMzFvG6eHD7VsEvFdoDtlD7eI1JTg7YNnuguzmiGsc6MPSq5l8n+h21AsNof0je+9sgOe4+dg==", - "dev": true, - "requires": { - "@types/yargs-parser": "*" - } - }, - "@types/yargs-parser": { - "version": "15.0.0", - "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-15.0.0.tgz", - "integrity": "sha512-FA/BWv8t8ZWJ+gEOnLLd8ygxH/2UFbAvgEonyfN6yWGLKc7zVjbpl2Y4CTjid9h2RfgPP6SEt6uHwEOply00yw==", - "dev": true - }, - "abab": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.3.tgz", - "integrity": "sha512-tsFzPpcttalNjFBCFMqsKYQcWxxen1pgJR56by//QwvJc4/OUS3kPOOttx2tSIfjsylB0pYu7f5D3K1RCxUnUg==", - "dev": true - }, - "abbrev": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", - "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" - }, - "accepts": { - "version": "1.3.7", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", - "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", - "requires": { - "mime-types": "~2.1.24", - "negotiator": "0.6.2" - } - }, - "acorn": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.1.1.tgz", - "integrity": "sha512-add7dgA5ppRPxCFJoAGfMDi7PIBXq1RtGo7BhbLaxwrXPOmw8gq48Y9ozT01hUKy9byMjlR20EJhu5zlkErEkg==", - "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" - }, - "dependencies": { - "acorn": { - "version": "6.4.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.1.tgz", - "integrity": "sha512-ZVA9k326Nwrj3Cj9jlh3wGFutC2ZornPNARZwsNYqQYgN0EsV2d53w5RN/co65Ohn4sUAUtb1rSUAOD6XN9idA==", - "dev": true - } - } - }, - "acorn-walk": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-6.2.0.tgz", - "integrity": "sha512-7evsyfH1cLOCdAzZAd43Cic04yKydNx0cF+7tiA19p1XnLLPU4dpCQOqpjqwokFe//vS0QqfqqjCS2JkiIs0cA==", - "dev": true - }, - "aggregate-error": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.0.1.tgz", - "integrity": "sha512-quoaXsZ9/BLNae5yiNoUz+Nhkwz83GhWwtYFglcjEQB2NDHCIpApbqXxIFnm4Pq/Nvhrsq5sYJFyohrrxnTGAA==", - "requires": { - "clean-stack": "^2.0.0", - "indent-string": "^4.0.0" - } - }, - "ajv": { - "version": "6.12.2", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.2.tgz", - "integrity": "sha512-k+V+hzjm5q/Mr8ef/1Y9goCmlsK4I6Sm74teeyGvFk1XrOsbsKLjEdrvny42CZ+a8sXbk8KWpY/bDwS+FLL2UQ==", - "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" - } - }, - "ansi-escapes": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.1.tgz", - "integrity": "sha512-JWF7ocqNrp8u9oqpgV+wH5ftbt+cfvv+PTjOvKLT3AdYly/LmORARfEVT1iyjwN+4MqE5UmVKoAdIBqeoCHgLA==", - "dev": true, - "requires": { - "type-fest": "^0.11.0" - }, - "dependencies": { - "type-fest": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.11.0.tgz", - "integrity": "sha512-OdjXJxnCN1AvyLSzeKIgXTXxV+99ZuXl3Hpo9XpJAv9MBcHrrJOQ5kV7ypXOuQie+AmWG25hLbiKdwYTifzcfQ==", - "dev": true - } - } - }, - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" - }, - "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==", - "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=" - }, - "anymatch": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz", - "integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==", - "dev": true, - "requires": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - } - }, - "append-field": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/append-field/-/append-field-1.0.0.tgz", - "integrity": "sha1-HjRA6RXwsSA9I3SOeO3XubW0PlY=" - }, - "argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "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=" - }, - "array-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==" - }, - "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": "4.10.1", - "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-4.10.1.tgz", - "integrity": "sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw==", - "dev": true, - "requires": { - "bn.js": "^4.0.0", - "inherits": "^2.0.1", - "minimalistic-assert": "^1.0.0" - } - }, - "assert": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/assert/-/assert-1.5.0.tgz", - "integrity": "sha512-EDsgawzwoun2CZkCgtxJbv392v4nbk9XDD06zI+kQYoBM/3RBWLlEyJARDOmhAAosBjWACEkKL6S+lIZtcAubA==", - "dev": true, - "requires": { - "object-assign": "^4.1.1", - "util": "0.10.3" - }, - "dependencies": { - "inherits": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz", - "integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE=", - "dev": true - }, - "util": { - "version": "0.10.3", - "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz", - "integrity": "sha1-evsa/lCAUkZInj23/g7TeTNqwPk=", - "dev": true, - "requires": { - "inherits": "2.0.1" - } - } - } - }, - "assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", - "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 - }, - "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 - }, - "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.9.1", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.9.1.tgz", - "integrity": "sha512-wMHVg2EOHaMRxbzgFJ9gtjOOCrI80OHLG14rxi28XwOW8ux6IiEbRCGGGqCtdAIg4FQCbW20k9RsT4y3gJlFug==", - "dev": true - }, - "axios": { - "version": "0.19.2", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.19.2.tgz", - "integrity": "sha512-fjgm5MvRHLhx+osE2xoekY70AhARk3a6hkN+3Io1jc00jtquGvxYlKlsFUhmUET0V5te6CcZI7lcv2Ym61mjHA==", - "requires": { - "follow-redirects": "1.5.10" - } - }, - "babel-jest": { - "version": "25.4.0", - "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-25.4.0.tgz", - "integrity": "sha512-p+epx4K0ypmHuCnd8BapfyOwWwosNCYhedetQey1awddtfmEX0MmdxctGl956uwUmjwXR5VSS5xJcGX9DvdIog==", - "dev": true, - "requires": { - "@jest/transform": "^25.4.0", - "@jest/types": "^25.4.0", - "@types/babel__core": "^7.1.7", - "babel-plugin-istanbul": "^6.0.0", - "babel-preset-jest": "^25.4.0", - "chalk": "^3.0.0", - "slash": "^3.0.0" - }, - "dependencies": { - "@jest/types": { - "version": "25.4.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-25.4.0.tgz", - "integrity": "sha512-XBeaWNzw2PPnGW5aXvZt3+VO60M+34RY3XDsCK5tW7kyj3RK0XClRutCfjqcBuaR2aBQTbluEDME9b5MB9UAPw==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^1.1.1", - "@types/yargs": "^15.0.0", - "chalk": "^3.0.0" - } - }, - "ansi-styles": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", - "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", - "dev": true, - "requires": { - "@types/color-name": "^1.1.1", - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", - "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", - "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "babel-plugin-istanbul": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.0.0.tgz", - "integrity": "sha512-AF55rZXpe7trmEylbaE1Gv54wn6rwU03aptvRoVIGP8YykoSxqdVLV1TfwflBCE/QtHmqtP8SWlTENqbK8GCSQ==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@istanbuljs/load-nyc-config": "^1.0.0", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-instrument": "^4.0.0", - "test-exclude": "^6.0.0" - } - }, - "babel-plugin-jest-hoist": { - "version": "25.4.0", - "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-25.4.0.tgz", - "integrity": "sha512-M3a10JCtTyKevb0MjuH6tU+cP/NVQZ82QPADqI1RQYY1OphztsCeIeQmTsHmF/NS6m0E51Zl4QNsI3odXSQF5w==", - "dev": true, - "requires": { - "@types/babel__traverse": "^7.0.6" - } - }, - "babel-plugin-styled-components": { - "version": "1.10.7", - "resolved": "https://registry.npmjs.org/babel-plugin-styled-components/-/babel-plugin-styled-components-1.10.7.tgz", - "integrity": "sha512-MBMHGcIA22996n9hZRf/UJLVVgkEOITuR2SvjHLb5dSTUyR4ZRGn+ngITapes36FI3WLxZHfRhkA1ffHxihOrg==", - "dev": true, - "requires": { - "@babel/helper-annotate-as-pure": "^7.0.0", - "@babel/helper-module-imports": "^7.0.0", - "babel-plugin-syntax-jsx": "^6.18.0", - "lodash": "^4.17.11" - } - }, - "babel-plugin-syntax-jsx": { - "version": "6.18.0", - "resolved": "https://registry.npmjs.org/babel-plugin-syntax-jsx/-/babel-plugin-syntax-jsx-6.18.0.tgz", - "integrity": "sha1-CvMqmm4Tyno/1QaeYtew9Y0NiUY=", - "dev": true - }, - "babel-preset-current-node-syntax": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-0.1.2.tgz", - "integrity": "sha512-u/8cS+dEiK1SFILbOC8/rUI3ml9lboKuuMvZ/4aQnQmhecQAgPw5ew066C1ObnEAUmlx7dv/s2z52psWEtLNiw==", - "dev": true, - "requires": { - "@babel/plugin-syntax-async-generators": "^7.8.4", - "@babel/plugin-syntax-bigint": "^7.8.3", - "@babel/plugin-syntax-class-properties": "^7.8.3", - "@babel/plugin-syntax-json-strings": "^7.8.3", - "@babel/plugin-syntax-logical-assignment-operators": "^7.8.3", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", - "@babel/plugin-syntax-numeric-separator": "^7.8.3", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", - "@babel/plugin-syntax-optional-chaining": "^7.8.3" - } - }, - "babel-preset-jest": { - "version": "25.4.0", - "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-25.4.0.tgz", - "integrity": "sha512-PwFiEWflHdu3JCeTr0Pb9NcHHE34qWFnPQRVPvqQITx4CsDCzs6o05923I10XvLvn9nNsRHuiVgB72wG/90ZHQ==", - "dev": true, - "requires": { - "babel-plugin-jest-hoist": "^25.4.0", - "babel-preset-current-node-syntax": "^0.1.2" - } - }, - "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=", - "requires": { - "core-js": "^2.4.0", - "regenerator-runtime": "^0.11.0" - } - }, - "balanced-match": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" - }, - "base": { - "version": "0.11.2", - "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", - "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", - "dev": true, - "requires": { - "cache-base": "^1.0.1", - "class-utils": "^0.3.5", - "component-emitter": "^1.2.1", - "define-property": "^1.0.0", - "isobject": "^3.0.1", - "mixin-deep": "^1.2.0", - "pascalcase": "^0.1.1" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - } - } - }, - "base64-js": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.1.tgz", - "integrity": "sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g==", - "dev": true - }, - "basic-auth": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz", - "integrity": "sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==", - "requires": { - "safe-buffer": "5.1.2" - } - }, - "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" - } - }, - "bcryptjs": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/bcryptjs/-/bcryptjs-2.4.3.tgz", - "integrity": "sha1-mrVie5PmBiH/fNrF2pczAn3x0Ms=" - }, - "better-ajv-errors": { - "version": "0.6.7", - "resolved": "https://registry.npmjs.org/better-ajv-errors/-/better-ajv-errors-0.6.7.tgz", - "integrity": "sha512-PYgt/sCzR4aGpyNy5+ViSQ77ognMnWq7745zM+/flYO4/Yisdtp9wDQW2IKCyVYPUxQt3E/b5GBSwfhd1LPdlg==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.0.0", - "@babel/runtime": "^7.0.0", - "chalk": "^2.4.1", - "core-js": "^3.2.1", - "json-to-ast": "^2.0.3", - "jsonpointer": "^4.0.1", - "leven": "^3.1.0" - }, - "dependencies": { - "core-js": { - "version": "3.6.4", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.6.4.tgz", - "integrity": "sha512-4paDGScNgZP2IXXilaffL9X7968RuvwlkK3xWtZRVqgd8SYNiVKRJvkFd1aqqEuPfN7E68ZHEp9hDj6lHj4Hyw==", - "dev": true - } - } - }, - "binary-extensions": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.0.0.tgz", - "integrity": "sha512-Phlt0plgpIIBOGTT/ehfFnbNlfsDEiqmzE2KRXoX1bLIlir4X/MR+zSyBEkL05ffWgnRSf/DXv+WrUAVr93/ow==", - "dev": true - }, - "bluebird": { - "version": "3.7.2", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", - "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==" - }, - "bn.js": { - "version": "4.11.8", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz", - "integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==", - "dev": true - }, - "body-parser": { - "version": "1.19.0", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz", - "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==", - "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": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "requires": { - "ms": "2.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - } - } - }, - "bowser": { - "version": "2.9.0", - "resolved": "https://registry.npmjs.org/bowser/-/bowser-2.9.0.tgz", - "integrity": "sha512-2ld76tuLBNFekRgmJfT2+3j5MIrP6bFict8WAIT3beq+srz1gcKNAdNKMqHqauQt63NmAa88HfP1/Ypa9Er3HA==" - }, - "brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "requires": { - "fill-range": "^7.0.1" - } - }, - "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-resolve": { - "version": "1.11.3", - "resolved": "https://registry.npmjs.org/browser-resolve/-/browser-resolve-1.11.3.tgz", - "integrity": "sha512-exDi1BYWB/6raKHmDTCicQfTkqwN5fioMFV4j8BsfMU4R2DK/QfZfK7kOVkmWCNANf0snkBzqGqAJBao9gZMdQ==", - "dev": true, - "requires": { - "resolve": "1.1.7" - }, - "dependencies": { - "resolve": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", - "integrity": "sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs=", - "dev": true - } - } - }, - "browserify-aes": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", - "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", - "dev": true, - "requires": { - "buffer-xor": "^1.0.3", - "cipher-base": "^1.0.0", - "create-hash": "^1.1.0", - "evp_bytestokey": "^1.0.3", - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" - } - }, - "browserify-cipher": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.1.tgz", - "integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==", - "dev": true, - "requires": { - "browserify-aes": "^1.0.4", - "browserify-des": "^1.0.0", - "evp_bytestokey": "^1.0.0" - } - }, - "browserify-des": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.2.tgz", - "integrity": "sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==", - "dev": true, - "requires": { - "cipher-base": "^1.0.1", - "des.js": "^1.0.0", - "inherits": "^2.0.1", - "safe-buffer": "^5.1.2" - } - }, - "browserify-rsa": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.0.1.tgz", - "integrity": "sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ=", - "dev": true, - "requires": { - "bn.js": "^4.1.0", - "randombytes": "^2.0.1" - } - }, - "browserify-sign": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.0.4.tgz", - "integrity": "sha1-qk62jl17ZYuqa/alfmMMvXqT0pg=", - "dev": true, - "requires": { - "bn.js": "^4.1.1", - "browserify-rsa": "^4.0.0", - "create-hash": "^1.1.0", - "create-hmac": "^1.1.2", - "elliptic": "^6.0.0", - "inherits": "^2.0.1", - "parse-asn1": "^5.0.0" - } - }, - "browserify-zlib": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.2.0.tgz", - "integrity": "sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==", - "dev": true, - "requires": { - "pako": "~1.0.5" - } - }, - "bser": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", - "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", - "dev": true, - "requires": { - "node-int64": "^0.4.0" - } - }, - "buffer": { - "version": "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-equal-constant-time": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", - "integrity": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk=" - }, - "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==" - }, - "buffer-writer": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/buffer-writer/-/buffer-writer-2.0.0.tgz", - "integrity": "sha512-a7ZpuTZU1TRtnwyCNW3I5dc0wWNC3VR9S++Ewyk2HHZdrO3CQJqSpd+95Us590V6AL7JqUAH2IwZ/398PmNFgw==" - }, - "buffer-xor": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", - "integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=", - "dev": true - }, - "builtin-status-codes": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz", - "integrity": "sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug=", - "dev": true - }, - "busboy": { - "version": "0.2.14", - "resolved": "https://registry.npmjs.org/busboy/-/busboy-0.2.14.tgz", - "integrity": "sha1-bCpiLvz0fFe7vh4qnDetNseSVFM=", - "requires": { - "dicer": "0.2.5", - "readable-stream": "1.1.x" - }, - "dependencies": { - "isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" - }, - "readable-stream": { - "version": "1.1.14", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", - "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "0.0.1", - "string_decoder": "~0.10.x" - } - }, - "string_decoder": { - "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" - } - } - }, - "bytes": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", - "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==" - }, - "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" - } - }, - "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=" - }, - "callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true - }, - "camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==" - }, - "camelize": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/camelize/-/camelize-1.0.0.tgz", - "integrity": "sha1-FkpUg+Yw+kMh5a8HAg5TGDGyYJs=" - }, - "capture-exit": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/capture-exit/-/capture-exit-2.0.0.tgz", - "integrity": "sha512-PiT/hQmTonHhl/HFGN+Lx3JJUznrVYJ3+AQsnthneZbvW7x+f08Tk7yLJTLEOUvBTbduLeeBkxEaYXUOUrRq6g==", - "dev": true, - "requires": { - "rsvp": "^4.8.4" - } - }, - "caseless": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", - "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", - "dev": true - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "chokidar": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.3.1.tgz", - "integrity": "sha512-4QYCEWOcK3OJrxwvyyAOxFuhpvOVCYkr33LPfFNBjAD/w3sEzWsp2BUOkI4l9bHvWioAd0rc6NlHUOEaWkTeqg==", - "dev": true, - "requires": { - "anymatch": "~3.1.1", - "braces": "~3.0.2", - "fsevents": "~2.1.2", - "glob-parent": "~5.1.0", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.3.0" - } - }, - "ci-info": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", - "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", - "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" - } - }, - "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" - } - } - } - }, - "classnames": { - "version": "2.2.6", - "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.2.6.tgz", - "integrity": "sha512-JR/iSQOSt+LQIWwrwEzJ9uk0xfN3mTVYMwt1Ir5mUcSN6pU+V4zQFFaJsclJbPuAUQH+yfWef6tm7l1quW3C8Q==", - "dev": true - }, - "clean-stack": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", - "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==" - }, - "cli-color": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/cli-color/-/cli-color-1.4.0.tgz", - "integrity": "sha512-xu6RvQqqrWEo6MPR1eixqGPywhYBHRs653F9jfXB2Hx4jdM/3WxiNE1vppRmxtMIfl16SFYTpYlrnqH/HsK/2w==", - "requires": { - "ansi-regex": "^2.1.1", - "d": "1", - "es5-ext": "^0.10.46", - "es6-iterator": "^2.0.3", - "memoizee": "^0.4.14", - "timers-ext": "^0.1.5" - } - }, - "clipboard": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/clipboard/-/clipboard-2.0.6.tgz", - "integrity": "sha512-g5zbiixBRk/wyKakSwCKd7vQXDjFnAMGHoEyBogG/bw9kTD9GvdAvaoRR1ALcEzt3pVKxZR0pViekPMIS0QyGg==", - "dev": true, - "optional": true, - "requires": { - "good-listener": "^1.2.2", - "select": "^1.1.2", - "tiny-emitter": "^2.0.0" - } - }, - "cliui": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", - "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", - "requires": { - "string-width": "^3.1.0", - "strip-ansi": "^5.2.0", - "wrap-ansi": "^5.1.0" - } - }, - "cls-bluebird": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cls-bluebird/-/cls-bluebird-2.1.0.tgz", - "integrity": "sha1-N+8eCAqP+1XC9BZPU28ZGeeWiu4=", - "requires": { - "is-bluebird": "^1.0.2", - "shimmer": "^1.1.0" - } - }, - "co": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", - "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", - "dev": true - }, - "code-error-fragment": { - "version": "0.0.230", - "resolved": "https://registry.npmjs.org/code-error-fragment/-/code-error-fragment-0.0.230.tgz", - "integrity": "sha512-cadkfKp6932H8UkhzE/gcUqhRMNf8jHzkAN7+5Myabswaghu4xABTgPHDCjW+dBAJxj/SpkTYokpzDqY4pCzQw==", - "dev": true - }, - "code-point-at": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", - "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", - "dev": true - }, - "collect-v8-coverage": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz", - "integrity": "sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg==", - "dev": true - }, - "collection-visit": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", - "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", - "dev": true, - "requires": { - "map-visit": "^1.0.0", - "object-visit": "^1.0.0" - } - }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "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=" - }, - "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.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" - }, - "component-emitter": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", - "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==", - "dev": true - }, - "concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" - }, - "concat-stream": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", - "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", - "requires": { - "buffer-from": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^2.2.2", - "typedarray": "^0.0.6" - } - }, - "config-chain": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.12.tgz", - "integrity": "sha512-a1eOIcu8+7lUInge4Rpf/n4Krkf3Dd9lqhljRzII1/Zno/kRtUWnznPO3jOKBmTEktkt3fkxisUcivoj0ebzoA==", - "requires": { - "ini": "^1.3.4", - "proto-list": "~1.2.1" - } - }, - "connect-chain-if": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/connect-chain-if/-/connect-chain-if-1.0.0.tgz", - "integrity": "sha1-N4Y8JcNYEdAs7gq00VyA5RRzCy8=" - }, - "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 - }, - "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==", - "requires": { - "safe-buffer": "5.1.2" - } - }, - "content-security-policy-builder": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/content-security-policy-builder/-/content-security-policy-builder-2.1.0.tgz", - "integrity": "sha512-/MtLWhJVvJNkA9dVLAp6fg9LxD2gfI6R2Fi1hPmfjYXSahJJzcfvoeDOxSyp4NvxMuwWv3WMssE9o31DoULHrQ==" - }, - "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==" - }, - "convert-source-map": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.7.0.tgz", - "integrity": "sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA==", - "dev": true, - "requires": { - "safe-buffer": "~5.1.1" - } - }, - "cookie": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz", - "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==" - }, - "cookie-parser": { - "version": "1.4.5", - "resolved": "https://registry.npmjs.org/cookie-parser/-/cookie-parser-1.4.5.tgz", - "integrity": "sha512-f13bPUj/gG/5mDr+xLmSxxDsB9DQiTIfhJS/sqjrmfAWiAN+x2O4i/XguTL9yDZ+/IFDanJ+5x7hC4CXT9Tdzw==", - "requires": { - "cookie": "0.4.0", - "cookie-signature": "1.0.6" - } - }, - "cookie-signature": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", - "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" - }, - "cookiejar": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/cookiejar/-/cookiejar-2.1.2.tgz", - "integrity": "sha512-Mw+adcfzPxcPeI+0WlvRrr/3lGVO0bD75SxX6811cxSh1Wbxx7xZBGK1eVtDf6si8rg2lhnUjsVLMFMfbRIuwA==", - "dev": true - }, - "copy-descriptor": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", - "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=", - "dev": true - }, - "core-js": { - "version": "2.6.10", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.10.tgz", - "integrity": "sha512-I39t74+4t+zau64EN1fE5v2W31Adtc/REhzWN+gWRRXg6WH5qAsZm62DHpQ1+Yhe4047T55jvzz7MUqF/dBBlA==" - }, - "core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" - }, - "create-ecdh": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.3.tgz", - "integrity": "sha512-GbEHQPMOswGpKXM9kCWVrremUcBmjteUaQ01T9rkKCPDXfUHX0IoP9LpHYo2NPFampa4e+/pFDc3jQdxrxQLaw==", - "dev": true, - "requires": { - "bn.js": "^4.1.0", - "elliptic": "^6.0.0" - } - }, - "create-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-env": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.2.tgz", - "integrity": "sha512-KZP/bMEOJEDCkDQAyRhu3RL2ZO/SUVrxQVI0G3YEQ+OLbRA3c6zgixe8Mq8a/z7+HKlNEjo8oiLUs8iRijY2Rw==", - "requires": { - "cross-spawn": "^7.0.1" - } - }, - "cross-spawn": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.1.tgz", - "integrity": "sha512-u7v4o84SwFpD32Z8IIcPZ6z1/ie24O6RU3RbtL5Y316l3KuHVPx9ItBgWQ6VlfAFnRnTtMUrsQ9MUUTuEZjogg==", - "requires": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - } - }, - "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-keywords": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/css-color-keywords/-/css-color-keywords-1.0.0.tgz", - "integrity": "sha1-/qJhbcZ2spYmhrOvjb2+GAskTgU=", - "dev": true - }, - "css-to-react-native": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/css-to-react-native/-/css-to-react-native-2.3.2.tgz", - "integrity": "sha512-VOFaeZA053BqvvvqIA8c9n0+9vFppVBAHCp6JgFTtTMU3Mzi+XnelJ9XC9ul3BqFzZyQ5N+H0SnwsWT2Ebchxw==", - "dev": true, - "requires": { - "camelize": "^1.0.0", - "css-color-keywords": "^1.0.0", - "postcss-value-parser": "^3.3.0" - } - }, - "cssom": { - "version": "0.4.4", - "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.4.4.tgz", - "integrity": "sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw==", - "dev": true - }, - "cssstyle": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-2.2.0.tgz", - "integrity": "sha512-sEb3XFPx3jNnCAMtqrXPDeSgQr+jojtCeNf8cvMNMh1cG970+lljssvQDzPq6lmmJu2Vhqood/gtEomBiHOGnA==", - "dev": true, - "requires": { - "cssom": "~0.3.6" - }, - "dependencies": { - "cssom": { - "version": "0.3.8", - "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", - "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==", - "dev": true - } - } - }, - "d": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz", - "integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==", - "requires": { - "es5-ext": "^0.10.50", - "type": "^1.0.1" - } - }, - "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" - } - }, - "dasherize": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/dasherize/-/dasherize-2.0.0.tgz", - "integrity": "sha1-bYCcnNDPe7iVLYD8hPoT1H3bEwg=" - }, - "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" - } - }, - "debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", - "requires": { - "ms": "^2.1.1" - } - }, - "decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=" - }, - "decko": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decko/-/decko-1.2.0.tgz", - "integrity": "sha1-/UPHNelnuAEzBohKVvvmZZlraBc=", - "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-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 - }, - "deepmerge": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", - "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", - "dev": true - }, - "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": "5.1.0", - "resolved": "https://registry.npmjs.org/del/-/del-5.1.0.tgz", - "integrity": "sha512-wH9xOVHnczo9jN2IW68BabcecVPxacIA3g/7z6vhSU/4stOKQzeCRK0yD0A24WiAAUJmmVpWqrERcTxnLo3AnA==", - "requires": { - "globby": "^10.0.1", - "graceful-fs": "^4.2.2", - "is-glob": "^4.0.1", - "is-path-cwd": "^2.2.0", - "is-path-inside": "^3.0.1", - "p-map": "^3.0.0", - "rimraf": "^3.0.0", - "slash": "^3.0.0" - }, - "dependencies": { - "rimraf": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.0.tgz", - "integrity": "sha512-NDGVxTsjqfunkds7CqsOiEnxln4Bo7Nddl3XhS4pXg5OzwkLqJ971ZVAAnB+DDLnF76N+VnDEiBHaVV8I06SUg==", - "requires": { - "glob": "^7.1.3" - } - }, - "slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==" - } - } - }, - "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 - }, - "delegate": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/delegate/-/delegate-3.2.0.tgz", - "integrity": "sha512-IofjkYBZaZivn0V8nnsMJGBr4jVLxHDheKSW88PyxS5QC4Vo9ZbZVvhzlSxY87fVq3STR6r+4cGepyHkcWOQSw==", - "dev": true, - "optional": true - }, - "depd": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", - "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" - }, - "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=" - }, - "detect-newline": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", - "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", - "dev": true - }, - "dicer": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/dicer/-/dicer-0.2.5.tgz", - "integrity": "sha1-WZbAhrszIYyBLAkL3cCc0S+stw8=", - "requires": { - "readable-stream": "1.1.x", - "streamsearch": "0.1.2" - }, - "dependencies": { - "isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" - }, - "readable-stream": { - "version": "1.1.14", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", - "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "0.0.1", - "string_decoder": "~0.10.x" - } - }, - "string_decoder": { - "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" - } - } - }, - "diff-sequences": { - "version": "25.2.6", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-25.2.6.tgz", - "integrity": "sha512-Hq8o7+6GaZeoFjtpgvRBUknSXNeJiCx7V9Fr94ZMljNiCr9n9L8H8aJqgWOQiDDGdyn29fRNcDdRVJ5fdyihfg==", - "dev": true - }, - "diffie-hellman": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", - "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==", - "dev": true, - "requires": { - "bn.js": "^4.1.0", - "miller-rabin": "^4.0.0", - "randombytes": "^2.0.0" - } - }, - "dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", - "requires": { - "path-type": "^4.0.0" - }, - "dependencies": { - "path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==" - } - } - }, - "dns-prefetch-control": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/dns-prefetch-control/-/dns-prefetch-control-0.2.0.tgz", - "integrity": "sha512-hvSnros73+qyZXhHFjx2CMLwoj3Fe7eR9EJsFsqmcI1bB2OBWL/+0YzaEaKssCHnj/6crawNnUyw74Gm2EKe+Q==" - }, - "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 - }, - "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" - } - }, - "dompurify": { - "version": "2.0.8", - "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-2.0.8.tgz", - "integrity": "sha512-vIOSyOXkMx81ghEalh4MLBtDHMx1bhKlaqHDMqM2yeitJ996SLOk5mGdDpI9ifJAgokred8Rmu219fX4OltqXw==", - "dev": true - }, - "dont-sniff-mimetype": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/dont-sniff-mimetype/-/dont-sniff-mimetype-1.1.0.tgz", - "integrity": "sha512-ZjI4zqTaxveH2/tTlzS1wFp+7ncxNZaIEWYg3lzZRHkKf5zPT/MnEG6WL0BhHMJUabkh8GeU5NL5j+rEUCb7Ug==" - }, - "dottie": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/dottie/-/dottie-2.0.2.tgz", - "integrity": "sha512-fmrwR04lsniq/uSr8yikThDTrM7epXHBAAjH9TbeH3rEA8tdCO7mRzB9hdmdGyJCxF8KERo9CITcm3kGuoyMhg==" - }, - "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" - } - }, - "ecdsa-sig-formatter": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", - "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", - "requires": { - "safe-buffer": "^5.0.1" - } - }, - "editorconfig": { - "version": "0.15.3", - "resolved": "https://registry.npmjs.org/editorconfig/-/editorconfig-0.15.3.tgz", - "integrity": "sha512-M9wIMFx96vq0R4F+gRpY3o2exzb8hEj/n9S8unZtHSvYjibBp/iMufSzvmOcV/laG0ZtuTVGtiJggPOSW2r93g==", - "requires": { - "commander": "^2.19.0", - "lru-cache": "^4.1.5", - "semver": "^5.6.0", - "sigmund": "^1.0.1" - }, - "dependencies": { - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" - } - } - }, - "ee-first": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" - }, - "elliptic": { - "version": "6.5.2", - "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.2.tgz", - "integrity": "sha512-f4x70okzZbIQl/NSRLkI/+tteV/9WqL98zx+SQ69KbXxmVrmjwsNUPn/gYJJ0sHvEak24cZgHIPegRePAtA/xw==", - "dev": true, - "requires": { - "bn.js": "^4.4.0", - "brorand": "^1.0.1", - "hash.js": "^1.0.0", - "hmac-drbg": "^1.0.0", - "inherits": "^2.0.1", - "minimalistic-assert": "^1.0.0", - "minimalistic-crypto-utils": "^1.0.0" - } - }, - "emoji-regex": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", - "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==" - }, - "encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" - }, - "end-of-stream": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", - "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", - "dev": true, - "requires": { - "once": "^1.4.0" - } - }, - "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" - } - }, - "es5-ext": { - "version": "0.10.51", - "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.51.tgz", - "integrity": "sha512-oRpWzM2WcLHVKpnrcyB7OW8j/s67Ba04JCm0WnNv3RiABSvs7mrQlutB8DBv793gKcp0XENR8Il8WxGTlZ73gQ==", - "requires": { - "es6-iterator": "~2.0.3", - "es6-symbol": "~3.1.1", - "next-tick": "^1.0.0" - } - }, - "es6-iterator": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", - "integrity": "sha1-p96IkUGgWpSwhUQDstCg+/qY87c=", - "requires": { - "d": "1", - "es5-ext": "^0.10.35", - "es6-symbol": "^3.1.1" - } - }, - "es6-promise": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-3.3.1.tgz", - "integrity": "sha1-oIzd6EzNvzTQJ6FFG8kdS80ophM=", - "dev": true - }, - "es6-symbol": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.2.tgz", - "integrity": "sha512-/ZypxQsArlv+KHpGvng52/Iz8by3EQPxhmbuz8yFG89N/caTFBSbcXONDw0aMjy827gQg26XAjP4uXFvnfINmQ==", - "requires": { - "d": "^1.0.1", - "es5-ext": "^0.10.51" - } - }, - "es6-weak-map": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.3.tgz", - "integrity": "sha512-p5um32HOTO1kP+w7PRnB+5lQ43Z6muuMuIMffvDN8ZB4GcnjLBV6zGStpbASIMk4DCAvEaamhe2zhyCb/QXXsA==", - "requires": { - "d": "1", - "es5-ext": "^0.10.46", - "es6-iterator": "^2.0.3", - "es6-symbol": "^3.1.1" - } - }, - "escape-html": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" - }, - "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.1", - "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.14.1.tgz", - "integrity": "sha512-Bmt7NcRySdIfNPfU2ZoXDrrXsG9ZjvDxcAlMfDUgRBjLOWTuIACXPBFJH7Z+cLb40JeQco5toikyc9t9P8E9SQ==", - "dev": true, - "requires": { - "esprima": "^4.0.1", - "estraverse": "^4.2.0", - "esutils": "^2.0.2", - "optionator": "^0.8.1", - "source-map": "~0.6.1" - } - }, - "esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==" - }, - "estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true - }, - "esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true - }, - "etag": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" - }, - "event-emitter": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz", - "integrity": "sha1-34xp7vFkeSPHFXuc6DhAYQsCzDk=", - "requires": { - "d": "1", - "es5-ext": "~0.10.14" - } - }, - "eventemitter3": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.0.tgz", - "integrity": "sha512-qerSRB0p+UDEssxTtm6EDKcE7W4OaoisfIMl4CngyEhjpYglocpNg6UEqCvemdGhosAsg4sO2dXJOdyBifPGCg==", - "dev": true - }, - "events": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/events/-/events-3.1.0.tgz", - "integrity": "sha512-Rv+u8MLHNOdMjTAFeT3nCjHn2aGlx435FP/sDHNaRhDEMwyI/aB22Kj2qIN8R0cw3z28psEQLYwxVKLsKrMgWg==", - "dev": true - }, - "evp_bytestokey": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", - "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", - "dev": true, - "requires": { - "md5.js": "^1.3.4", - "safe-buffer": "^5.1.1" - } - }, - "exec-sh": { - "version": "0.3.4", - "resolved": "https://registry.npmjs.org/exec-sh/-/exec-sh-0.3.4.tgz", - "integrity": "sha512-sEFIkc61v75sWeOe72qyrqg2Qg0OuLESziUDk/O/z2qgS15y2gWVFrI6f2Qn/qw/0/NCfCEsmNA4zOjkwEZT1A==", - "dev": true - }, - "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" - } - }, - "path-key": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", - "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", - "dev": true - }, - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true - }, - "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 - }, - "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" - } - } - } - }, - "exit": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", - "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=", - "dev": true - }, - "expand-brackets": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", - "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", - "dev": true, - "requires": { - "debug": "^2.3.3", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "posix-character-classes": "^0.1.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "dependencies": { - "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" - } - }, - "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" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - } - } - }, - "expect": { - "version": "25.4.0", - "resolved": "https://registry.npmjs.org/expect/-/expect-25.4.0.tgz", - "integrity": "sha512-7BDIX99BTi12/sNGJXA9KMRcby4iAmu1xccBOhyKCyEhjcVKS3hPmHdA/4nSI9QGIOkUropKqr3vv7WMDM5lvQ==", - "dev": true, - "requires": { - "@jest/types": "^25.4.0", - "ansi-styles": "^4.0.0", - "jest-get-type": "^25.2.6", - "jest-matcher-utils": "^25.4.0", - "jest-message-util": "^25.4.0", - "jest-regex-util": "^25.2.6" - }, - "dependencies": { - "@jest/types": { - "version": "25.4.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-25.4.0.tgz", - "integrity": "sha512-XBeaWNzw2PPnGW5aXvZt3+VO60M+34RY3XDsCK5tW7kyj3RK0XClRutCfjqcBuaR2aBQTbluEDME9b5MB9UAPw==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^1.1.1", - "@types/yargs": "^15.0.0", - "chalk": "^3.0.0" - } - }, - "ansi-styles": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", - "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", - "dev": true, - "requires": { - "@types/color-name": "^1.1.1", - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", - "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "jest-get-type": { - "version": "25.2.6", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-25.2.6.tgz", - "integrity": "sha512-DxjtyzOHjObRM+sM1knti6or+eOgcGU4xVSb2HNP1TqO4ahsT+rqZg+nyqHWJSvWgKC5cG3QjGFBqxLghiF/Ig==", - "dev": true - }, - "supports-color": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", - "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "expect-ct": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/expect-ct/-/expect-ct-0.2.0.tgz", - "integrity": "sha512-6SK3MG/Bbhm8MsgyJAylg+ucIOU71/FzyFalcfu5nY19dH8y/z0tBJU0wrNBXD4B27EoQtqPF/9wqH0iYAd04g==" - }, - "express": { - "version": "4.17.1", - "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz", - "integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==", - "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": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "requires": { - "ms": "2.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - } - } - }, - "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" - } - } - } - }, - "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": "3.1.1", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.1.tgz", - "integrity": "sha512-8UEa58QDLauDNfpbrX55Q9jrGHThw2ZMdOky5Gl1CDtVeJDPVrG4Jxx1N8jw2gkWaff5UUuX1KJd+9zGe2B+ZA==", - "dev": true - }, - "fast-glob": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.1.1.tgz", - "integrity": "sha512-nTCREpBY8w8r+boyFYAx21iL6faSsQynliPHM4Uf56SbkyohCNxpVPEH9xrF5TXKy+IsjkPUHDKiUkzBVRXn9g==", - "requires": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.0", - "merge2": "^1.3.0", - "micromatch": "^4.0.2" - }, - "dependencies": { - "micromatch": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz", - "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==", - "requires": { - "braces": "^3.0.1", - "picomatch": "^2.0.5" - } - } - } - }, - "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 - }, - "fast-safe-stringify": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.0.7.tgz", - "integrity": "sha512-Utm6CdzT+6xsDk2m8S6uL8VHxNwI6Jub+e9NYTcAms28T84pTa25GJQV9j0CY0N1rM8hK4x6grpF2BQf+2qwVA==", - "dev": true - }, - "fastq": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.6.0.tgz", - "integrity": "sha512-jmxqQ3Z/nXoeyDmWAzF9kH1aGZSis6e/SbfPmJpUnyZ0ogr6iscHQaml4wsEepEWSdtmpy+eVXmCRIMpxaXqOA==", - "requires": { - "reusify": "^1.0.0" - } - }, - "fb-watchman": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.1.tgz", - "integrity": "sha512-DkPJKQeY6kKwmuMretBhr7G6Vodr7bFwDYTXIkfG1gjvNpaxBTQV3PbXg6bR1c1UP4jPOX0jHUbbHANL9vRjVg==", - "dev": true, - "requires": { - "bser": "2.1.1" - } - }, - "feature-policy": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/feature-policy/-/feature-policy-0.3.0.tgz", - "integrity": "sha512-ZtijOTFN7TzCujt1fnNhfWPFPSHeZkesff9AXZj+UEjYBynWNUIYpC87Ve4wHzyexQsImicLu7WsC2LHq7/xrQ==" - }, - "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==", - "requires": { - "to-regex-range": "^5.0.1" - } - }, - "finalhandler": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", - "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", - "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" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "requires": { - "ms": "2.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - } - } - }, - "find-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", - "requires": { - "locate-path": "^3.0.0" - } - }, - "follow-redirects": { - "version": "1.5.10", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.5.10.tgz", - "integrity": "sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ==", - "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" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - } - } - }, - "for-in": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", - "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", - "dev": true - }, - "foreach": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/foreach/-/foreach-2.0.5.tgz", - "integrity": "sha1-C+4AUBiusmDQo6865ljdATbsG5k=", - "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 - }, - "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" - } - }, - "format-util": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/format-util/-/format-util-1.0.5.tgz", - "integrity": "sha512-varLbTj0e0yVyRpqQhuWV+8hlePAgaoFRhNFj50BNjEIrw1/DphHSObtqwskVCPWNgzwPoQrZAbfa/SBiicNeg==" - }, - "formidable": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/formidable/-/formidable-1.2.1.tgz", - "integrity": "sha512-Fs9VRguL0gqGHkXS5GQiMCr1VhZBxz0JnJs4JmMp/2jL18Fmbzvv7vOFRU+U8TBkHEE/CX1qDXzJplVULgsLeg==", - "dev": true - }, - "forwarded": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", - "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=" - }, - "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" - } - }, - "frameguard": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/frameguard/-/frameguard-3.1.0.tgz", - "integrity": "sha512-TxgSKM+7LTA6sidjOiSZK9wxY0ffMPY3Wta//MqwmX0nZuEHc8QrkV8Fh3ZhMJeiH+Uyh/tcaarImRy8u77O7g==" - }, - "fresh": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" - }, - "fs-extra": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz", - "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==", - "requires": { - "graceful-fs": "^4.1.2", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" - } - }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" - }, - "fsevents": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.2.tgz", - "integrity": "sha512-R4wDiBwZ0KzpgOWetKDug1FZcYhqYnUYKtfZYt4mD5SBz76q0KR4Q9o7GIPamsVPGmW3EYPPJ0dOOjvx32ldZA==", - "dev": true, - "optional": true - }, - "gensync": { - "version": "1.0.0-beta.1", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.1.tgz", - "integrity": "sha512-r8EC6NO1sngH/zdD9fiRDLdcgnbayXah+mLgManTaIZJqEC1MZstmnox8KpnI2/fxQwrp5OpCOYWLp4rBl4Jcg==", - "dev": true - }, - "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==" - }, - "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" - } - }, - "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.4", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz", - "integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==", - "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": "5.1.0", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.0.tgz", - "integrity": "sha512-qjtRgnIVmOfnKUE3NJAQEdk+lKrxfw8t5ke7SXtfMTHcjsBfOfWXCQfdb30zfDoZQ2IRSIiidmjtbHZPZ++Ihw==", - "requires": { - "is-glob": "^4.0.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 - }, - "globby": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/globby/-/globby-10.0.1.tgz", - "integrity": "sha512-sSs4inE1FB2YQiymcmTv6NWENryABjUNPeWhOvmn4SjtKybglsyPZxFB3U1/+L1bYi0rNZDqCLlHyLYDl1Pq5A==", - "requires": { - "@types/glob": "^7.1.1", - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.0.3", - "glob": "^7.1.3", - "ignore": "^5.1.1", - "merge2": "^1.2.3", - "slash": "^3.0.0" - }, - "dependencies": { - "slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==" - } - } - }, - "good-listener": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/good-listener/-/good-listener-1.2.2.tgz", - "integrity": "sha1-1TswzfkxPf+33JoNR3CWqm0UXFA=", - "dev": true, - "optional": true, - "requires": { - "delegate": "^3.1.2" - } - }, - "graceful-fs": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.2.tgz", - "integrity": "sha512-IItsdsea19BoLC7ELy13q1iJFNmd7ofZH5+X/pJr90/nRoPEX0DJo1dHDbgtYWOhJhcCgMDTOw84RZ72q6lB+Q==" - }, - "grapheme-splitter": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", - "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==", - "dev": true - }, - "growly": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/growly/-/growly-1.3.0.tgz", - "integrity": "sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE=", - "dev": true, - "optional": true - }, - "handlebars": { - "version": "4.7.6", - "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.6.tgz", - "integrity": "sha512-1f2BACcBfiwAfStCKZNrUCgqNZkGsAT7UM3kkYtXuLo0KnaVfjKOyf7PRzB6++aK9STyT1Pd2ZCPe3EGOXleXA==", - "dev": true, - "requires": { - "minimist": "^1.2.5", - "neo-async": "^2.6.0", - "source-map": "^0.6.1", - "uglify-js": "^3.1.4", - "wordwrap": "^1.0.0" - } - }, - "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.3", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz", - "integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==", - "dev": true, - "requires": { - "ajv": "^6.5.5", - "har-schema": "^2.0.0" - } - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true - }, - "has-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": { - "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" - } - } - } - }, - "kind-of": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", - "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "hash-base": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.0.4.tgz", - "integrity": "sha1-X8hoaEfs1zSZQDMZprCj8/auSRg=", - "dev": true, - "requires": { - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" - } - }, - "hash.js": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", - "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", - "dev": true, - "requires": { - "inherits": "^2.0.3", - "minimalistic-assert": "^1.0.1" - } - }, - "helmet": { - "version": "3.22.0", - "resolved": "https://registry.npmjs.org/helmet/-/helmet-3.22.0.tgz", - "integrity": "sha512-Xrqicn2nm1ZIUxP3YGuTBmbDL04neKsIT583Sjh0FkiwKDXYCMUqGqC88w3NUvVXtA75JyR2Jn6jw6ZEMOD+ZA==", - "requires": { - "depd": "2.0.0", - "dns-prefetch-control": "0.2.0", - "dont-sniff-mimetype": "1.1.0", - "expect-ct": "0.2.0", - "feature-policy": "0.3.0", - "frameguard": "3.1.0", - "helmet-crossdomain": "0.4.0", - "helmet-csp": "2.10.0", - "hide-powered-by": "1.1.0", - "hpkp": "2.0.0", - "hsts": "2.2.0", - "ienoopen": "1.1.0", - "nocache": "2.1.0", - "referrer-policy": "1.2.0", - "x-xss-protection": "1.3.0" - }, - "dependencies": { - "depd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==" - } - } - }, - "helmet-crossdomain": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/helmet-crossdomain/-/helmet-crossdomain-0.4.0.tgz", - "integrity": "sha512-AB4DTykRw3HCOxovD1nPR16hllrVImeFp5VBV9/twj66lJ2nU75DP8FPL0/Jp4jj79JhTfG+pFI2MD02kWJ+fA==" - }, - "helmet-csp": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/helmet-csp/-/helmet-csp-2.10.0.tgz", - "integrity": "sha512-Rz953ZNEFk8sT2XvewXkYN0Ho4GEZdjAZy4stjiEQV3eN7GDxg1QKmYggH7otDyIA7uGA6XnUMVSgeJwbR5X+w==", - "requires": { - "bowser": "2.9.0", - "camelize": "1.0.0", - "content-security-policy-builder": "2.1.0", - "dasherize": "2.0.0" - } - }, - "hide-powered-by": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/hide-powered-by/-/hide-powered-by-1.1.0.tgz", - "integrity": "sha512-Io1zA2yOA1YJslkr+AJlWSf2yWFkKjvkcL9Ni1XSUqnGLr/qRQe2UI3Cn/J9MsJht7yEVCe0SscY1HgVMujbgg==" - }, - "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" - } - }, - "hosted-git-info": { - "version": "2.8.8", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.8.tgz", - "integrity": "sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg==", - "dev": true - }, - "hpkp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/hpkp/-/hpkp-2.0.0.tgz", - "integrity": "sha1-EOFCJk52IVpdMMROxD3mTe5tFnI=" - }, - "hsts": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/hsts/-/hsts-2.2.0.tgz", - "integrity": "sha512-ToaTnQ2TbJkochoVcdXYm4HOCliNozlviNsg+X2XQLQvZNI/kCHR9rZxVYpJB3UPcHz80PgxRyWQ7PdU1r+VBQ==", - "requires": { - "depd": "2.0.0" - }, - "dependencies": { - "depd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==" - } - } - }, - "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-escaper": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", - "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", - "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==", - "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=" - } - } - }, - "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" - } - }, - "http2-client": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/http2-client/-/http2-client-1.3.3.tgz", - "integrity": "sha512-nUxLymWQ9pzkzTmir24p2RtsgruLmhje7lH3hLX1IpwvyTg77fW+1brenPPP3USAR+rQ36p5sTA/x7sjCJVkAA==", - "dev": true - }, - "https-browserify": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz", - "integrity": "sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=", - "dev": true - }, - "human-signals": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-1.1.1.tgz", - "integrity": "sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==", - "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==", - "requires": { - "safer-buffer": ">= 2.1.2 < 3" - } - }, - "ieee754": { - "version": "1.1.13", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz", - "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==", - "dev": true - }, - "ienoopen": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/ienoopen/-/ienoopen-1.1.0.tgz", - "integrity": "sha512-MFs36e/ca6ohEKtinTJ5VvAJ6oDRAYFdYXweUnGY9L9vcoqFOU4n2ZhmJ0C4z/cwGZ3YIQRSB3XZ1+ghZkY5NQ==" - }, - "ignore": { - "version": "5.1.4", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.4.tgz", - "integrity": "sha512-MzbUSahkTW1u7JpKKjY7LCARd1fU5W2rLdxlM4kdkayuCwZImjkpluF9CM1aLewYJguPDqewLam18Y6AU69A8A==" - }, - "import-local": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.0.2.tgz", - "integrity": "sha512-vjL3+w0oulAVZ0hBHnxa/Nm5TAurf9YLQJDhqRZyqb+VKGOB6LU8t9H1Nr5CIo16vh9XfJTOoHwU0B71S557gA==", - "dev": true, - "requires": { - "pkg-dir": "^4.2.0", - "resolve-cwd": "^3.0.0" - } - }, - "imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", - "dev": true - }, - "indent-string": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", - "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==" - }, - "inflection": { - "version": "1.12.0", - "resolved": "https://registry.npmjs.org/inflection/-/inflection-1.12.0.tgz", - "integrity": "sha1-ogCTVlbW9fa8TcdQLhrstwMihBY=" - }, - "inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" - }, - "ini": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", - "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==" - }, - "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-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.0", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.0.tgz", - "integrity": "sha512-M4Sjn6N/+O6/IXSJseKqHoFc+5FdGJ22sXqnjTpdZweHK64MzEPAyQZyEU3R/KRv2GLoa7nNtg/C2Ev6m7z+eA==" - }, - "is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", - "dev": true - }, - "is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "dev": true, - "requires": { - "binary-extensions": "^2.0.0" - } - }, - "is-bluebird": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-bluebird/-/is-bluebird-1.0.2.tgz", - "integrity": "sha1-CWQ5Bg9KpBGr7hkUOoTWpVNG1uI=" - }, - "is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", - "dev": true - }, - "is-ci": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz", - "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==", - "dev": true, - "requires": { - "ci-info": "^2.0.0" - } - }, - "is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" - }, - "dependencies": { - "kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", - "dev": true - } - } - }, - "is-extendable": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", - "dev": true - }, - "is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=" - }, - "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=" - }, - "is-generator-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", - "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", - "dev": true - }, - "is-glob": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", - "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", - "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==" - }, - "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==" - }, - "is-path-inside": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.2.tgz", - "integrity": "sha512-/2UGPSgmtqwo1ktx8NDHjuPwZWmHhO+gj0f93EkhLB5RgW9RZevWYYlIkS6zePc6U2WpOdQYIwHe9YC4DWEBVg==" - }, - "is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "requires": { - "isobject": "^3.0.1" - } - }, - "is-promise": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz", - "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=" - }, - "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-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", - "dev": true - }, - "is-what": { - "version": "3.7.1", - "resolved": "https://registry.npmjs.org/is-what/-/is-what-3.7.1.tgz", - "integrity": "sha512-IAoapxlqyLSqt0Zr/7ZMT/fjEw9nwxxmz/TlBH+TJjvcXxmmAdRvo41W74uw3XJMGFpbeft97cpkPmLK89lJWw==", - "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": "2.1.1", - "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.1.1.tgz", - "integrity": "sha512-umZHcSrwlDHo2TGMXv0DZ8dIUGunZ2Iv68YZnrmCiBPkZ4aaOhtv7pXJKeki9k3qJ3RJr0cDyitcl5wEH3AYog==", - "dev": true, - "optional": true - }, - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" - }, - "isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" - }, - "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 - }, - "istanbul-lib-coverage": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.0.0.tgz", - "integrity": "sha512-UiUIqxMgRDET6eR+o5HbfRYP1l0hqkWOs7vNxC/mggutCMUIhWMm8gAHb8tHlyfD3/l6rlgNA5cKdDzEAf6hEg==", - "dev": true - }, - "istanbul-lib-instrument": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.1.tgz", - "integrity": "sha512-imIchxnodll7pvQBYOqUu88EufLCU56LMeFPZZM/fJZ1irYcYdqroaV+ACK1Ila8ls09iEYArp+nqyC6lW1Vfg==", - "dev": true, - "requires": { - "@babel/core": "^7.7.5", - "@babel/parser": "^7.7.5", - "@babel/template": "^7.7.4", - "@babel/traverse": "^7.7.4", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-coverage": "^3.0.0", - "semver": "^6.3.0" - }, - "dependencies": { - "@babel/code-frame": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.8.3.tgz", - "integrity": "sha512-a9gxpmdXtZEInkCSHUJDLHZVBgb1QS0jhss4cPP93EW7s+uC5bikET2twEF3KV+7rDblJcmNvTR7VJejqd2C2g==", - "dev": true, - "requires": { - "@babel/highlight": "^7.8.3" - } - }, - "@babel/generator": { - "version": "7.9.5", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.9.5.tgz", - "integrity": "sha512-GbNIxVB3ZJe3tLeDm1HSn2AhuD/mVcyLDpgtLXa5tplmWrJdF/elxB56XNqCuD6szyNkDi6wuoKXln3QeBmCHQ==", - "dev": true, - "requires": { - "@babel/types": "^7.9.5", - "jsesc": "^2.5.1", - "lodash": "^4.17.13", - "source-map": "^0.5.0" - } - }, - "@babel/helper-function-name": { - "version": "7.9.5", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.9.5.tgz", - "integrity": "sha512-JVcQZeXM59Cd1qanDUxv9fgJpt3NeKUaqBqUEvfmQ+BCOKq2xUgaWZW2hr0dkbyJgezYuplEoh5knmrnS68efw==", - "dev": true, - "requires": { - "@babel/helper-get-function-arity": "^7.8.3", - "@babel/template": "^7.8.3", - "@babel/types": "^7.9.5" - } - }, - "@babel/helper-get-function-arity": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.8.3.tgz", - "integrity": "sha512-FVDR+Gd9iLjUMY1fzE2SR0IuaJToR4RkCDARVfsBBPSP53GEqSFjD8gNyxg246VUyc/ALRxFaAK8rVG7UT7xRA==", - "dev": true, - "requires": { - "@babel/types": "^7.8.3" - } - }, - "@babel/helper-split-export-declaration": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.8.3.tgz", - "integrity": "sha512-3x3yOeyBhW851hroze7ElzdkeRXQYQbFIb7gLK1WQYsw2GWDay5gAJNw1sWJ0VFP6z5J1whqeXH/WCdCjZv6dA==", - "dev": true, - "requires": { - "@babel/types": "^7.8.3" - } - }, - "@babel/highlight": { - "version": "7.9.0", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.9.0.tgz", - "integrity": "sha512-lJZPilxX7Op3Nv/2cvFdnlepPXDxi29wxteT57Q965oc5R9v86ztx0jfxVrTcBk8C2kcPkkDa2Z4T3ZsPPVWsQ==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.9.0", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - } - }, - "@babel/parser": { - "version": "7.9.4", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.9.4.tgz", - "integrity": "sha512-bC49otXX6N0/VYhgOMh4gnP26E9xnDZK3TmbNpxYzzz9BQLBosQwfyOe9/cXUU3txYhTzLCbcqd5c8y/OmCjHA==", - "dev": true - }, - "@babel/template": { - "version": "7.8.6", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.8.6.tgz", - "integrity": "sha512-zbMsPMy/v0PWFZEhQJ66bqjhH+z0JgMoBWuikXybgG3Gkd/3t5oQ1Rw2WQhnSrsOmsKXnZOx15tkC4qON/+JPg==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.8.3", - "@babel/parser": "^7.8.6", - "@babel/types": "^7.8.6" - } - }, - "@babel/traverse": { - "version": "7.9.5", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.9.5.tgz", - "integrity": "sha512-c4gH3jsvSuGUezlP6rzSJ6jf8fYjLj3hsMZRx/nX0h+fmHN0w+ekubRrHPqnMec0meycA2nwCsJ7dC8IPem2FQ==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.8.3", - "@babel/generator": "^7.9.5", - "@babel/helper-function-name": "^7.9.5", - "@babel/helper-split-export-declaration": "^7.8.3", - "@babel/parser": "^7.9.0", - "@babel/types": "^7.9.5", - "debug": "^4.1.0", - "globals": "^11.1.0", - "lodash": "^4.17.13" - } - }, - "@babel/types": { - "version": "7.9.5", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.9.5.tgz", - "integrity": "sha512-XjnvNqenk818r5zMaba+sLQjnbda31UfUURv3ei0qPQw4u+j2jMyJ5b11y8ZHYTRSI3NnInQkkkRT4fLqqPdHg==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.9.5", - "lodash": "^4.17.13", - "to-fast-properties": "^2.0.0" - }, - "dependencies": { - "@babel/helper-validator-identifier": { - "version": "7.9.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.9.5.tgz", - "integrity": "sha512-/8arLKUFq882w4tWGj9JYzRpAlZgiWUJ+dtteNTDqrRBz9Iguck9Rn3ykuBDoUwh2TO4tSAJlrxDUOXWklJe4g==", - "dev": true - } - } - }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - } - } - }, - "istanbul-lib-report": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", - "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==", - "dev": true, - "requires": { - "istanbul-lib-coverage": "^3.0.0", - "make-dir": "^3.0.0", - "supports-color": "^7.1.0" - }, - "dependencies": { - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", - "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "istanbul-lib-source-maps": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.0.tgz", - "integrity": "sha512-c16LpFRkR8vQXyHZ5nLpY35JZtzj1PQY1iZmesUbf1FZHbIupcWfjgOXBY9YHkLEQ6puz1u4Dgj6qmU/DisrZg==", - "dev": true, - "requires": { - "debug": "^4.1.1", - "istanbul-lib-coverage": "^3.0.0", - "source-map": "^0.6.1" - } - }, - "istanbul-reports": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.0.2.tgz", - "integrity": "sha512-9tZvz7AiR3PEDNGiV9vIouQ/EAcqMXFmkcA1CDFTwOB98OZVDL0PH9glHotf5Ugp6GCOTypfzGWI/OqjWNCRUw==", - "dev": true, - "requires": { - "html-escaper": "^2.0.0", - "istanbul-lib-report": "^3.0.0" - } - }, - "jest": { - "version": "25.4.0", - "resolved": "https://registry.npmjs.org/jest/-/jest-25.4.0.tgz", - "integrity": "sha512-XWipOheGB4wai5JfCYXd6vwsWNwM/dirjRoZgAa7H2wd8ODWbli2AiKjqG8AYhyx+8+5FBEdpO92VhGlBydzbw==", - "dev": true, - "requires": { - "@jest/core": "^25.4.0", - "import-local": "^3.0.2", - "jest-cli": "^25.4.0" - }, - "dependencies": { - "@jest/types": { - "version": "25.4.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-25.4.0.tgz", - "integrity": "sha512-XBeaWNzw2PPnGW5aXvZt3+VO60M+34RY3XDsCK5tW7kyj3RK0XClRutCfjqcBuaR2aBQTbluEDME9b5MB9UAPw==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^1.1.1", - "@types/yargs": "^15.0.0", - "chalk": "^3.0.0" - } - }, - "ansi-regex": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", - "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", - "dev": true - }, - "ansi-styles": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", - "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", - "dev": true, - "requires": { - "@types/color-name": "^1.1.1", - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", - "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "cliui": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", - "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", - "dev": true, - "requires": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^6.2.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, - "find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "requires": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - } - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true - }, - "jest-cli": { - "version": "25.4.0", - "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-25.4.0.tgz", - "integrity": "sha512-usyrj1lzCJZMRN1r3QEdnn8e6E6yCx/QN7+B1sLoA68V7f3WlsxSSQfy0+BAwRiF4Hz2eHauf11GZG3PIfWTXQ==", - "dev": true, - "requires": { - "@jest/core": "^25.4.0", - "@jest/test-result": "^25.4.0", - "@jest/types": "^25.4.0", - "chalk": "^3.0.0", - "exit": "^0.1.2", - "import-local": "^3.0.2", - "is-ci": "^2.0.0", - "jest-config": "^25.4.0", - "jest-util": "^25.4.0", - "jest-validate": "^25.4.0", - "prompts": "^2.0.1", - "realpath-native": "^2.0.0", - "yargs": "^15.3.1" - } - }, - "locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "requires": { - "p-locate": "^4.1.0" - } - }, - "p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "requires": { - "p-limit": "^2.2.0" - } - }, - "path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true - }, - "string-width": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", - "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", - "dev": true, - "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.0" - } - }, - "strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", - "dev": true, - "requires": { - "ansi-regex": "^5.0.0" - } - }, - "supports-color": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", - "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - }, - "wrap-ansi": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", - "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", - "dev": true, - "requires": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - } - }, - "yargs": { - "version": "15.3.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.3.1.tgz", - "integrity": "sha512-92O1HWEjw27sBfgmXiixJWT5hRBp2eobqXicLtPBIDBhYB+1HpwZlXmbW2luivBJHBzki+7VyCLRtAkScbTBQA==", - "dev": true, - "requires": { - "cliui": "^6.0.0", - "decamelize": "^1.2.0", - "find-up": "^4.1.0", - "get-caller-file": "^2.0.1", - "require-directory": "^2.1.1", - "require-main-filename": "^2.0.0", - "set-blocking": "^2.0.0", - "string-width": "^4.2.0", - "which-module": "^2.0.0", - "y18n": "^4.0.0", - "yargs-parser": "^18.1.1" - } - }, - "yargs-parser": { - "version": "18.1.3", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", - "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", - "dev": true, - "requires": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" - } - } - } - }, - "jest-changed-files": { - "version": "25.4.0", - "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-25.4.0.tgz", - "integrity": "sha512-VR/rfJsEs4BVMkwOTuStRyS630fidFVekdw/lBaBQjx9KK3VZFOZ2c0fsom2fRp8pMCrCTP6LGna00o/DXGlqA==", - "dev": true, - "requires": { - "@jest/types": "^25.4.0", - "execa": "^3.2.0", - "throat": "^5.0.0" - }, - "dependencies": { - "@jest/types": { - "version": "25.4.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-25.4.0.tgz", - "integrity": "sha512-XBeaWNzw2PPnGW5aXvZt3+VO60M+34RY3XDsCK5tW7kyj3RK0XClRutCfjqcBuaR2aBQTbluEDME9b5MB9UAPw==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^1.1.1", - "@types/yargs": "^15.0.0", - "chalk": "^3.0.0" - } - }, - "ansi-styles": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", - "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", - "dev": true, - "requires": { - "@types/color-name": "^1.1.1", - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", - "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "execa": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-3.4.0.tgz", - "integrity": "sha512-r9vdGQk4bmCuK1yKQu1KTwcT2zwfWdbdaXfCtAh+5nU/4fSX+JAb7vZGvI5naJrQlvONrEB20jeruESI69530g==", - "dev": true, - "requires": { - "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" - } - }, - "get-stream": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.1.0.tgz", - "integrity": "sha512-EXr1FOzrzTfGeL0gQdeFEvOMm2mzMOglyiOXSTpPC+iAjAKftbr3jpCMWynogwYnM+eSj9sHGc6wjIcDvYiygw==", - "dev": true, - "requires": { - "pump": "^3.0.0" - } - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "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": "4.0.1", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", - "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 - }, - "supports-color": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", - "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "jest-config": { - "version": "25.4.0", - "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-25.4.0.tgz", - "integrity": "sha512-egT9aKYxMyMSQV1aqTgam0SkI5/I2P9qrKexN5r2uuM2+68ypnc+zPGmfUxK7p1UhE7dYH9SLBS7yb+TtmT1AA==", - "dev": true, - "requires": { - "@babel/core": "^7.1.0", - "@jest/test-sequencer": "^25.4.0", - "@jest/types": "^25.4.0", - "babel-jest": "^25.4.0", - "chalk": "^3.0.0", - "deepmerge": "^4.2.2", - "glob": "^7.1.1", - "jest-environment-jsdom": "^25.4.0", - "jest-environment-node": "^25.4.0", - "jest-get-type": "^25.2.6", - "jest-jasmine2": "^25.4.0", - "jest-regex-util": "^25.2.6", - "jest-resolve": "^25.4.0", - "jest-util": "^25.4.0", - "jest-validate": "^25.4.0", - "micromatch": "^4.0.2", - "pretty-format": "^25.4.0", - "realpath-native": "^2.0.0" - }, - "dependencies": { - "@jest/types": { - "version": "25.4.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-25.4.0.tgz", - "integrity": "sha512-XBeaWNzw2PPnGW5aXvZt3+VO60M+34RY3XDsCK5tW7kyj3RK0XClRutCfjqcBuaR2aBQTbluEDME9b5MB9UAPw==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^1.1.1", - "@types/yargs": "^15.0.0", - "chalk": "^3.0.0" - } - }, - "ansi-regex": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", - "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", - "dev": true - }, - "ansi-styles": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", - "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", - "dev": true, - "requires": { - "@types/color-name": "^1.1.1", - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", - "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "jest-get-type": { - "version": "25.2.6", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-25.2.6.tgz", - "integrity": "sha512-DxjtyzOHjObRM+sM1knti6or+eOgcGU4xVSb2HNP1TqO4ahsT+rqZg+nyqHWJSvWgKC5cG3QjGFBqxLghiF/Ig==", - "dev": true - }, - "pretty-format": { - "version": "25.4.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-25.4.0.tgz", - "integrity": "sha512-PI/2dpGjXK5HyXexLPZU/jw5T9Q6S1YVXxxVxco+LIqzUFHXIbKZKdUVt7GcX7QUCr31+3fzhi4gN4/wUYPVxQ==", - "dev": true, - "requires": { - "@jest/types": "^25.4.0", - "ansi-regex": "^5.0.0", - "ansi-styles": "^4.0.0", - "react-is": "^16.12.0" - } - }, - "supports-color": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", - "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "jest-diff": { - "version": "25.4.0", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-25.4.0.tgz", - "integrity": "sha512-kklLbJVXW0y8UKOWOdYhI6TH5MG6QAxrWiBMgQaPIuhj3dNFGirKCd+/xfplBXICQ7fI+3QcqHm9p9lWu1N6ug==", - "dev": true, - "requires": { - "chalk": "^3.0.0", - "diff-sequences": "^25.2.6", - "jest-get-type": "^25.2.6", - "pretty-format": "^25.4.0" - }, - "dependencies": { - "ansi-styles": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", - "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", - "dev": true, - "requires": { - "@types/color-name": "^1.1.1", - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", - "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", - "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "jest-docblock": { - "version": "25.3.0", - "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-25.3.0.tgz", - "integrity": "sha512-aktF0kCar8+zxRHxQZwxMy70stc9R1mOmrLsT5VO3pIT0uzGRSDAXxSlz4NqQWpuLjPpuMhPRl7H+5FRsvIQAg==", - "dev": true, - "requires": { - "detect-newline": "^3.0.0" - } - }, - "jest-each": { - "version": "25.4.0", - "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-25.4.0.tgz", - "integrity": "sha512-lwRIJ8/vQU/6vq3nnSSUw1Y3nz5tkYSFIywGCZpUBd6WcRgpn8NmJoQICojbpZmsJOJNHm0BKdyuJ6Xdx+eDQQ==", - "dev": true, - "requires": { - "@jest/types": "^25.4.0", - "chalk": "^3.0.0", - "jest-get-type": "^25.2.6", - "jest-util": "^25.4.0", - "pretty-format": "^25.4.0" - }, - "dependencies": { - "@jest/types": { - "version": "25.4.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-25.4.0.tgz", - "integrity": "sha512-XBeaWNzw2PPnGW5aXvZt3+VO60M+34RY3XDsCK5tW7kyj3RK0XClRutCfjqcBuaR2aBQTbluEDME9b5MB9UAPw==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^1.1.1", - "@types/yargs": "^15.0.0", - "chalk": "^3.0.0" - } - }, - "ansi-regex": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", - "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", - "dev": true - }, - "ansi-styles": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", - "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", - "dev": true, - "requires": { - "@types/color-name": "^1.1.1", - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", - "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "jest-get-type": { - "version": "25.2.6", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-25.2.6.tgz", - "integrity": "sha512-DxjtyzOHjObRM+sM1knti6or+eOgcGU4xVSb2HNP1TqO4ahsT+rqZg+nyqHWJSvWgKC5cG3QjGFBqxLghiF/Ig==", - "dev": true - }, - "pretty-format": { - "version": "25.4.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-25.4.0.tgz", - "integrity": "sha512-PI/2dpGjXK5HyXexLPZU/jw5T9Q6S1YVXxxVxco+LIqzUFHXIbKZKdUVt7GcX7QUCr31+3fzhi4gN4/wUYPVxQ==", - "dev": true, - "requires": { - "@jest/types": "^25.4.0", - "ansi-regex": "^5.0.0", - "ansi-styles": "^4.0.0", - "react-is": "^16.12.0" - } - }, - "supports-color": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", - "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "jest-environment-jsdom": { - "version": "25.4.0", - "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-25.4.0.tgz", - "integrity": "sha512-KTitVGMDrn2+pt7aZ8/yUTuS333w3pWt1Mf88vMntw7ZSBNDkRS6/4XLbFpWXYfWfp1FjcjQTOKzbK20oIehWQ==", - "dev": true, - "requires": { - "@jest/environment": "^25.4.0", - "@jest/fake-timers": "^25.4.0", - "@jest/types": "^25.4.0", - "jest-mock": "^25.4.0", - "jest-util": "^25.4.0", - "jsdom": "^15.2.1" - }, - "dependencies": { - "@jest/types": { - "version": "25.4.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-25.4.0.tgz", - "integrity": "sha512-XBeaWNzw2PPnGW5aXvZt3+VO60M+34RY3XDsCK5tW7kyj3RK0XClRutCfjqcBuaR2aBQTbluEDME9b5MB9UAPw==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^1.1.1", - "@types/yargs": "^15.0.0", - "chalk": "^3.0.0" - } - }, - "ansi-styles": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", - "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", - "dev": true, - "requires": { - "@types/color-name": "^1.1.1", - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", - "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", - "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "jest-environment-node": { - "version": "25.4.0", - "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-25.4.0.tgz", - "integrity": "sha512-wryZ18vsxEAKFH7Z74zi/y/SyI1j6UkVZ6QsllBuT/bWlahNfQjLNwFsgh/5u7O957dYFoXj4yfma4n4X6kU9A==", - "dev": true, - "requires": { - "@jest/environment": "^25.4.0", - "@jest/fake-timers": "^25.4.0", - "@jest/types": "^25.4.0", - "jest-mock": "^25.4.0", - "jest-util": "^25.4.0", - "semver": "^6.3.0" - }, - "dependencies": { - "@jest/types": { - "version": "25.4.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-25.4.0.tgz", - "integrity": "sha512-XBeaWNzw2PPnGW5aXvZt3+VO60M+34RY3XDsCK5tW7kyj3RK0XClRutCfjqcBuaR2aBQTbluEDME9b5MB9UAPw==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^1.1.1", - "@types/yargs": "^15.0.0", - "chalk": "^3.0.0" - } - }, - "ansi-styles": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", - "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", - "dev": true, - "requires": { - "@types/color-name": "^1.1.1", - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", - "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", - "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "jest-get-type": { - "version": "25.2.6", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-25.2.6.tgz", - "integrity": "sha512-DxjtyzOHjObRM+sM1knti6or+eOgcGU4xVSb2HNP1TqO4ahsT+rqZg+nyqHWJSvWgKC5cG3QjGFBqxLghiF/Ig==", - "dev": true - }, - "jest-haste-map": { - "version": "25.4.0", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-25.4.0.tgz", - "integrity": "sha512-5EoCe1gXfGC7jmXbKzqxESrgRcaO3SzWXGCnvp9BcT0CFMyrB1Q6LIsjl9RmvmJGQgW297TCfrdgiy574Rl9HQ==", - "dev": true, - "requires": { - "@jest/types": "^25.4.0", - "anymatch": "^3.0.3", - "fb-watchman": "^2.0.0", - "fsevents": "^2.1.2", - "graceful-fs": "^4.2.3", - "jest-serializer": "^25.2.6", - "jest-util": "^25.4.0", - "jest-worker": "^25.4.0", - "micromatch": "^4.0.2", - "sane": "^4.0.3", - "walker": "^1.0.7", - "which": "^2.0.2" - }, - "dependencies": { - "@jest/types": { - "version": "25.4.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-25.4.0.tgz", - "integrity": "sha512-XBeaWNzw2PPnGW5aXvZt3+VO60M+34RY3XDsCK5tW7kyj3RK0XClRutCfjqcBuaR2aBQTbluEDME9b5MB9UAPw==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^1.1.1", - "@types/yargs": "^15.0.0", - "chalk": "^3.0.0" - } - }, - "ansi-styles": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", - "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", - "dev": true, - "requires": { - "@types/color-name": "^1.1.1", - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", - "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "graceful-fs": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz", - "integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", - "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "jest-jasmine2": { - "version": "25.4.0", - "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-25.4.0.tgz", - "integrity": "sha512-QccxnozujVKYNEhMQ1vREiz859fPN/XklOzfQjm2j9IGytAkUbSwjFRBtQbHaNZ88cItMpw02JnHGsIdfdpwxQ==", - "dev": true, - "requires": { - "@babel/traverse": "^7.1.0", - "@jest/environment": "^25.4.0", - "@jest/source-map": "^25.2.6", - "@jest/test-result": "^25.4.0", - "@jest/types": "^25.4.0", - "chalk": "^3.0.0", - "co": "^4.6.0", - "expect": "^25.4.0", - "is-generator-fn": "^2.0.0", - "jest-each": "^25.4.0", - "jest-matcher-utils": "^25.4.0", - "jest-message-util": "^25.4.0", - "jest-runtime": "^25.4.0", - "jest-snapshot": "^25.4.0", - "jest-util": "^25.4.0", - "pretty-format": "^25.4.0", - "throat": "^5.0.0" - }, - "dependencies": { - "@jest/types": { - "version": "25.4.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-25.4.0.tgz", - "integrity": "sha512-XBeaWNzw2PPnGW5aXvZt3+VO60M+34RY3XDsCK5tW7kyj3RK0XClRutCfjqcBuaR2aBQTbluEDME9b5MB9UAPw==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^1.1.1", - "@types/yargs": "^15.0.0", - "chalk": "^3.0.0" - } - }, - "ansi-regex": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", - "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", - "dev": true - }, - "ansi-styles": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", - "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", - "dev": true, - "requires": { - "@types/color-name": "^1.1.1", - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", - "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "pretty-format": { - "version": "25.4.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-25.4.0.tgz", - "integrity": "sha512-PI/2dpGjXK5HyXexLPZU/jw5T9Q6S1YVXxxVxco+LIqzUFHXIbKZKdUVt7GcX7QUCr31+3fzhi4gN4/wUYPVxQ==", - "dev": true, - "requires": { - "@jest/types": "^25.4.0", - "ansi-regex": "^5.0.0", - "ansi-styles": "^4.0.0", - "react-is": "^16.12.0" - } - }, - "supports-color": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", - "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "jest-leak-detector": { - "version": "25.4.0", - "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-25.4.0.tgz", - "integrity": "sha512-7Y6Bqfv2xWsB+7w44dvZuLs5SQ//fzhETgOGG7Gq3TTGFdYvAgXGwV8z159RFZ6fXiCPm/szQ90CyfVos9JIFQ==", - "dev": true, - "requires": { - "jest-get-type": "^25.2.6", - "pretty-format": "^25.4.0" - }, - "dependencies": { - "@jest/types": { - "version": "25.4.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-25.4.0.tgz", - "integrity": "sha512-XBeaWNzw2PPnGW5aXvZt3+VO60M+34RY3XDsCK5tW7kyj3RK0XClRutCfjqcBuaR2aBQTbluEDME9b5MB9UAPw==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^1.1.1", - "@types/yargs": "^15.0.0", - "chalk": "^3.0.0" - } - }, - "ansi-regex": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", - "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", - "dev": true - }, - "ansi-styles": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", - "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", - "dev": true, - "requires": { - "@types/color-name": "^1.1.1", - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", - "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "jest-get-type": { - "version": "25.2.6", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-25.2.6.tgz", - "integrity": "sha512-DxjtyzOHjObRM+sM1knti6or+eOgcGU4xVSb2HNP1TqO4ahsT+rqZg+nyqHWJSvWgKC5cG3QjGFBqxLghiF/Ig==", - "dev": true - }, - "pretty-format": { - "version": "25.4.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-25.4.0.tgz", - "integrity": "sha512-PI/2dpGjXK5HyXexLPZU/jw5T9Q6S1YVXxxVxco+LIqzUFHXIbKZKdUVt7GcX7QUCr31+3fzhi4gN4/wUYPVxQ==", - "dev": true, - "requires": { - "@jest/types": "^25.4.0", - "ansi-regex": "^5.0.0", - "ansi-styles": "^4.0.0", - "react-is": "^16.12.0" - } - }, - "supports-color": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", - "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "jest-matcher-utils": { - "version": "25.4.0", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-25.4.0.tgz", - "integrity": "sha512-yPMdtj7YDgXhnGbc66bowk8AkQ0YwClbbwk3Kzhn5GVDrciiCr27U4NJRbrqXbTdtxjImONITg2LiRIw650k5A==", - "dev": true, - "requires": { - "chalk": "^3.0.0", - "jest-diff": "^25.4.0", - "jest-get-type": "^25.2.6", - "pretty-format": "^25.4.0" - }, - "dependencies": { - "@jest/types": { - "version": "25.4.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-25.4.0.tgz", - "integrity": "sha512-XBeaWNzw2PPnGW5aXvZt3+VO60M+34RY3XDsCK5tW7kyj3RK0XClRutCfjqcBuaR2aBQTbluEDME9b5MB9UAPw==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^1.1.1", - "@types/yargs": "^15.0.0", - "chalk": "^3.0.0" - } - }, - "ansi-regex": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", - "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", - "dev": true - }, - "ansi-styles": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", - "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", - "dev": true, - "requires": { - "@types/color-name": "^1.1.1", - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", - "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "diff-sequences": { - "version": "25.2.6", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-25.2.6.tgz", - "integrity": "sha512-Hq8o7+6GaZeoFjtpgvRBUknSXNeJiCx7V9Fr94ZMljNiCr9n9L8H8aJqgWOQiDDGdyn29fRNcDdRVJ5fdyihfg==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "jest-diff": { - "version": "25.4.0", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-25.4.0.tgz", - "integrity": "sha512-kklLbJVXW0y8UKOWOdYhI6TH5MG6QAxrWiBMgQaPIuhj3dNFGirKCd+/xfplBXICQ7fI+3QcqHm9p9lWu1N6ug==", - "dev": true, - "requires": { - "chalk": "^3.0.0", - "diff-sequences": "^25.2.6", - "jest-get-type": "^25.2.6", - "pretty-format": "^25.4.0" - } - }, - "jest-get-type": { - "version": "25.2.6", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-25.2.6.tgz", - "integrity": "sha512-DxjtyzOHjObRM+sM1knti6or+eOgcGU4xVSb2HNP1TqO4ahsT+rqZg+nyqHWJSvWgKC5cG3QjGFBqxLghiF/Ig==", - "dev": true - }, - "pretty-format": { - "version": "25.4.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-25.4.0.tgz", - "integrity": "sha512-PI/2dpGjXK5HyXexLPZU/jw5T9Q6S1YVXxxVxco+LIqzUFHXIbKZKdUVt7GcX7QUCr31+3fzhi4gN4/wUYPVxQ==", - "dev": true, - "requires": { - "@jest/types": "^25.4.0", - "ansi-regex": "^5.0.0", - "ansi-styles": "^4.0.0", - "react-is": "^16.12.0" - } - }, - "supports-color": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", - "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "jest-message-util": { - "version": "25.4.0", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-25.4.0.tgz", - "integrity": "sha512-LYY9hRcVGgMeMwmdfh9tTjeux1OjZHMusq/E5f3tJN+dAoVVkJtq5ZUEPIcB7bpxDUt2zjUsrwg0EGgPQ+OhXQ==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.0.0", - "@jest/types": "^25.4.0", - "@types/stack-utils": "^1.0.1", - "chalk": "^3.0.0", - "micromatch": "^4.0.2", - "slash": "^3.0.0", - "stack-utils": "^1.0.1" - }, - "dependencies": { - "@jest/types": { - "version": "25.4.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-25.4.0.tgz", - "integrity": "sha512-XBeaWNzw2PPnGW5aXvZt3+VO60M+34RY3XDsCK5tW7kyj3RK0XClRutCfjqcBuaR2aBQTbluEDME9b5MB9UAPw==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^1.1.1", - "@types/yargs": "^15.0.0", - "chalk": "^3.0.0" - } - }, - "ansi-styles": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", - "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", - "dev": true, - "requires": { - "@types/color-name": "^1.1.1", - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", - "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", - "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "jest-mock": { - "version": "25.4.0", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-25.4.0.tgz", - "integrity": "sha512-MdazSfcYAUjJjuVTTnusLPzE0pE4VXpOUzWdj8sbM+q6abUjm3bATVPXFqTXrxSieR8ocpvQ9v/QaQCftioQFg==", - "dev": true, - "requires": { - "@jest/types": "^25.4.0" - }, - "dependencies": { - "@jest/types": { - "version": "25.4.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-25.4.0.tgz", - "integrity": "sha512-XBeaWNzw2PPnGW5aXvZt3+VO60M+34RY3XDsCK5tW7kyj3RK0XClRutCfjqcBuaR2aBQTbluEDME9b5MB9UAPw==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^1.1.1", - "@types/yargs": "^15.0.0", - "chalk": "^3.0.0" - } - }, - "ansi-styles": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", - "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", - "dev": true, - "requires": { - "@types/color-name": "^1.1.1", - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", - "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", - "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "jest-pnp-resolver": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.1.tgz", - "integrity": "sha512-pgFw2tm54fzgYvc/OHrnysABEObZCUNFnhjoRjaVOCN8NYc032/gVjPaHD4Aq6ApkSieWtfKAFQtmDKAmhupnQ==", - "dev": true - }, - "jest-regex-util": { - "version": "25.2.6", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-25.2.6.tgz", - "integrity": "sha512-KQqf7a0NrtCkYmZZzodPftn7fL1cq3GQAFVMn5Hg8uKx/fIenLEobNanUxb7abQ1sjADHBseG/2FGpsv/wr+Qw==", - "dev": true - }, - "jest-resolve": { - "version": "25.4.0", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-25.4.0.tgz", - "integrity": "sha512-wOsKqVDFWUiv8BtLMCC6uAJ/pHZkfFgoBTgPtmYlsprAjkxrr2U++ZnB3l5ykBMd2O24lXvf30SMAjJIW6k2aA==", - "dev": true, - "requires": { - "@jest/types": "^25.4.0", - "browser-resolve": "^1.11.3", - "chalk": "^3.0.0", - "jest-pnp-resolver": "^1.2.1", - "read-pkg-up": "^7.0.1", - "realpath-native": "^2.0.0", - "resolve": "^1.15.1", - "slash": "^3.0.0" - }, - "dependencies": { - "@jest/types": { - "version": "25.4.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-25.4.0.tgz", - "integrity": "sha512-XBeaWNzw2PPnGW5aXvZt3+VO60M+34RY3XDsCK5tW7kyj3RK0XClRutCfjqcBuaR2aBQTbluEDME9b5MB9UAPw==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^1.1.1", - "@types/yargs": "^15.0.0", - "chalk": "^3.0.0" - } - }, - "ansi-styles": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", - "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", - "dev": true, - "requires": { - "@types/color-name": "^1.1.1", - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", - "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "resolve": { - "version": "1.17.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz", - "integrity": "sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==", - "dev": true, - "requires": { - "path-parse": "^1.0.6" - } - }, - "supports-color": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", - "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "jest-resolve-dependencies": { - "version": "25.4.0", - "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-25.4.0.tgz", - "integrity": "sha512-A0eoZXx6kLiuG1Ui7wITQPl04HwjLErKIJTt8GR3c7UoDAtzW84JtCrgrJ6Tkw6c6MwHEyAaLk7dEPml5pf48A==", - "dev": true, - "requires": { - "@jest/types": "^25.4.0", - "jest-regex-util": "^25.2.6", - "jest-snapshot": "^25.4.0" - }, - "dependencies": { - "@jest/types": { - "version": "25.4.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-25.4.0.tgz", - "integrity": "sha512-XBeaWNzw2PPnGW5aXvZt3+VO60M+34RY3XDsCK5tW7kyj3RK0XClRutCfjqcBuaR2aBQTbluEDME9b5MB9UAPw==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^1.1.1", - "@types/yargs": "^15.0.0", - "chalk": "^3.0.0" - } - }, - "ansi-styles": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", - "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", - "dev": true, - "requires": { - "@types/color-name": "^1.1.1", - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", - "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", - "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "jest-runner": { - "version": "25.4.0", - "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-25.4.0.tgz", - "integrity": "sha512-wWQSbVgj2e/1chFdMRKZdvlmA6p1IPujhpLT7TKNtCSl1B0PGBGvJjCaiBal/twaU2yfk8VKezHWexM8IliBfA==", - "dev": true, - "requires": { - "@jest/console": "^25.4.0", - "@jest/environment": "^25.4.0", - "@jest/test-result": "^25.4.0", - "@jest/types": "^25.4.0", - "chalk": "^3.0.0", - "exit": "^0.1.2", - "graceful-fs": "^4.2.3", - "jest-config": "^25.4.0", - "jest-docblock": "^25.3.0", - "jest-haste-map": "^25.4.0", - "jest-jasmine2": "^25.4.0", - "jest-leak-detector": "^25.4.0", - "jest-message-util": "^25.4.0", - "jest-resolve": "^25.4.0", - "jest-runtime": "^25.4.0", - "jest-util": "^25.4.0", - "jest-worker": "^25.4.0", - "source-map-support": "^0.5.6", - "throat": "^5.0.0" - }, - "dependencies": { - "@jest/types": { - "version": "25.4.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-25.4.0.tgz", - "integrity": "sha512-XBeaWNzw2PPnGW5aXvZt3+VO60M+34RY3XDsCK5tW7kyj3RK0XClRutCfjqcBuaR2aBQTbluEDME9b5MB9UAPw==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^1.1.1", - "@types/yargs": "^15.0.0", - "chalk": "^3.0.0" - } - }, - "ansi-styles": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", - "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", - "dev": true, - "requires": { - "@types/color-name": "^1.1.1", - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", - "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "graceful-fs": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz", - "integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", - "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "jest-runtime": { - "version": "25.4.0", - "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-25.4.0.tgz", - "integrity": "sha512-lgNJlCDULtXu9FumnwCyWlOub8iytijwsPNa30BKrSNtgoT6NUMXOPrZvsH06U6v0wgD/Igwz13nKA2wEKU2VA==", - "dev": true, - "requires": { - "@jest/console": "^25.4.0", - "@jest/environment": "^25.4.0", - "@jest/source-map": "^25.2.6", - "@jest/test-result": "^25.4.0", - "@jest/transform": "^25.4.0", - "@jest/types": "^25.4.0", - "@types/yargs": "^15.0.0", - "chalk": "^3.0.0", - "collect-v8-coverage": "^1.0.0", - "exit": "^0.1.2", - "glob": "^7.1.3", - "graceful-fs": "^4.2.3", - "jest-config": "^25.4.0", - "jest-haste-map": "^25.4.0", - "jest-message-util": "^25.4.0", - "jest-mock": "^25.4.0", - "jest-regex-util": "^25.2.6", - "jest-resolve": "^25.4.0", - "jest-snapshot": "^25.4.0", - "jest-util": "^25.4.0", - "jest-validate": "^25.4.0", - "realpath-native": "^2.0.0", - "slash": "^3.0.0", - "strip-bom": "^4.0.0", - "yargs": "^15.3.1" - }, - "dependencies": { - "@jest/types": { - "version": "25.4.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-25.4.0.tgz", - "integrity": "sha512-XBeaWNzw2PPnGW5aXvZt3+VO60M+34RY3XDsCK5tW7kyj3RK0XClRutCfjqcBuaR2aBQTbluEDME9b5MB9UAPw==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^1.1.1", - "@types/yargs": "^15.0.0", - "chalk": "^3.0.0" - } - }, - "ansi-regex": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", - "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", - "dev": true - }, - "ansi-styles": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", - "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", - "dev": true, - "requires": { - "@types/color-name": "^1.1.1", - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", - "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "cliui": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", - "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", - "dev": true, - "requires": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^6.2.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, - "find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "requires": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - } - }, - "graceful-fs": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz", - "integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true - }, - "locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "requires": { - "p-locate": "^4.1.0" - } - }, - "p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "requires": { - "p-limit": "^2.2.0" - } - }, - "path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true - }, - "string-width": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", - "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", - "dev": true, - "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.0" - } - }, - "strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", - "dev": true, - "requires": { - "ansi-regex": "^5.0.0" - } - }, - "supports-color": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", - "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - }, - "wrap-ansi": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", - "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", - "dev": true, - "requires": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - } - }, - "yargs": { - "version": "15.3.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.3.1.tgz", - "integrity": "sha512-92O1HWEjw27sBfgmXiixJWT5hRBp2eobqXicLtPBIDBhYB+1HpwZlXmbW2luivBJHBzki+7VyCLRtAkScbTBQA==", - "dev": true, - "requires": { - "cliui": "^6.0.0", - "decamelize": "^1.2.0", - "find-up": "^4.1.0", - "get-caller-file": "^2.0.1", - "require-directory": "^2.1.1", - "require-main-filename": "^2.0.0", - "set-blocking": "^2.0.0", - "string-width": "^4.2.0", - "which-module": "^2.0.0", - "y18n": "^4.0.0", - "yargs-parser": "^18.1.1" - } - }, - "yargs-parser": { - "version": "18.1.3", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", - "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", - "dev": true, - "requires": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" - } - } - } - }, - "jest-serializer": { - "version": "25.2.6", - "resolved": "https://registry.npmjs.org/jest-serializer/-/jest-serializer-25.2.6.tgz", - "integrity": "sha512-RMVCfZsezQS2Ww4kB5HJTMaMJ0asmC0BHlnobQC6yEtxiFKIxohFA4QSXSabKwSggaNkqxn6Z2VwdFCjhUWuiQ==", - "dev": true - }, - "jest-snapshot": { - "version": "25.4.0", - "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-25.4.0.tgz", - "integrity": "sha512-J4CJ0X2SaGheYRZdLz9CRHn9jUknVmlks4UBeu270hPAvdsauFXOhx9SQP2JtRzhnR3cvro/9N9KP83/uvFfRg==", - "dev": true, - "requires": { - "@babel/types": "^7.0.0", - "@jest/types": "^25.4.0", - "@types/prettier": "^1.19.0", - "chalk": "^3.0.0", - "expect": "^25.4.0", - "jest-diff": "^25.4.0", - "jest-get-type": "^25.2.6", - "jest-matcher-utils": "^25.4.0", - "jest-message-util": "^25.4.0", - "jest-resolve": "^25.4.0", - "make-dir": "^3.0.0", - "natural-compare": "^1.4.0", - "pretty-format": "^25.4.0", - "semver": "^6.3.0" - }, - "dependencies": { - "@jest/types": { - "version": "25.4.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-25.4.0.tgz", - "integrity": "sha512-XBeaWNzw2PPnGW5aXvZt3+VO60M+34RY3XDsCK5tW7kyj3RK0XClRutCfjqcBuaR2aBQTbluEDME9b5MB9UAPw==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^1.1.1", - "@types/yargs": "^15.0.0", - "chalk": "^3.0.0" - } - }, - "ansi-regex": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", - "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", - "dev": true - }, - "ansi-styles": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", - "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", - "dev": true, - "requires": { - "@types/color-name": "^1.1.1", - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", - "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "diff-sequences": { - "version": "25.2.6", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-25.2.6.tgz", - "integrity": "sha512-Hq8o7+6GaZeoFjtpgvRBUknSXNeJiCx7V9Fr94ZMljNiCr9n9L8H8aJqgWOQiDDGdyn29fRNcDdRVJ5fdyihfg==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "jest-diff": { - "version": "25.4.0", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-25.4.0.tgz", - "integrity": "sha512-kklLbJVXW0y8UKOWOdYhI6TH5MG6QAxrWiBMgQaPIuhj3dNFGirKCd+/xfplBXICQ7fI+3QcqHm9p9lWu1N6ug==", - "dev": true, - "requires": { - "chalk": "^3.0.0", - "diff-sequences": "^25.2.6", - "jest-get-type": "^25.2.6", - "pretty-format": "^25.4.0" - } - }, - "jest-get-type": { - "version": "25.2.6", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-25.2.6.tgz", - "integrity": "sha512-DxjtyzOHjObRM+sM1knti6or+eOgcGU4xVSb2HNP1TqO4ahsT+rqZg+nyqHWJSvWgKC5cG3QjGFBqxLghiF/Ig==", - "dev": true - }, - "pretty-format": { - "version": "25.4.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-25.4.0.tgz", - "integrity": "sha512-PI/2dpGjXK5HyXexLPZU/jw5T9Q6S1YVXxxVxco+LIqzUFHXIbKZKdUVt7GcX7QUCr31+3fzhi4gN4/wUYPVxQ==", - "dev": true, - "requires": { - "@jest/types": "^25.4.0", - "ansi-regex": "^5.0.0", - "ansi-styles": "^4.0.0", - "react-is": "^16.12.0" - } - }, - "supports-color": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", - "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "jest-util": { - "version": "25.4.0", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-25.4.0.tgz", - "integrity": "sha512-WSZD59sBtAUjLv1hMeKbNZXmMcrLRWcYqpO8Dz8b4CeCTZpfNQw2q9uwrYAD+BbJoLJlu4ezVPwtAmM/9/SlZA==", - "dev": true, - "requires": { - "@jest/types": "^25.4.0", - "chalk": "^3.0.0", - "is-ci": "^2.0.0", - "make-dir": "^3.0.0" - }, - "dependencies": { - "@jest/types": { - "version": "25.4.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-25.4.0.tgz", - "integrity": "sha512-XBeaWNzw2PPnGW5aXvZt3+VO60M+34RY3XDsCK5tW7kyj3RK0XClRutCfjqcBuaR2aBQTbluEDME9b5MB9UAPw==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^1.1.1", - "@types/yargs": "^15.0.0", - "chalk": "^3.0.0" - } - }, - "ansi-styles": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", - "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", - "dev": true, - "requires": { - "@types/color-name": "^1.1.1", - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", - "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", - "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "jest-validate": { - "version": "25.4.0", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-25.4.0.tgz", - "integrity": "sha512-hvjmes/EFVJSoeP1yOl8qR8mAtMR3ToBkZeXrD/ZS9VxRyWDqQ/E1C5ucMTeSmEOGLipvdlyipiGbHJ+R1MQ0g==", - "dev": true, - "requires": { - "@jest/types": "^25.4.0", - "camelcase": "^5.3.1", - "chalk": "^3.0.0", - "jest-get-type": "^25.2.6", - "leven": "^3.1.0", - "pretty-format": "^25.4.0" - }, - "dependencies": { - "@jest/types": { - "version": "25.4.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-25.4.0.tgz", - "integrity": "sha512-XBeaWNzw2PPnGW5aXvZt3+VO60M+34RY3XDsCK5tW7kyj3RK0XClRutCfjqcBuaR2aBQTbluEDME9b5MB9UAPw==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^1.1.1", - "@types/yargs": "^15.0.0", - "chalk": "^3.0.0" - } - }, - "ansi-regex": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", - "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", - "dev": true - }, - "ansi-styles": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", - "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", - "dev": true, - "requires": { - "@types/color-name": "^1.1.1", - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", - "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "jest-get-type": { - "version": "25.2.6", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-25.2.6.tgz", - "integrity": "sha512-DxjtyzOHjObRM+sM1knti6or+eOgcGU4xVSb2HNP1TqO4ahsT+rqZg+nyqHWJSvWgKC5cG3QjGFBqxLghiF/Ig==", - "dev": true - }, - "pretty-format": { - "version": "25.4.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-25.4.0.tgz", - "integrity": "sha512-PI/2dpGjXK5HyXexLPZU/jw5T9Q6S1YVXxxVxco+LIqzUFHXIbKZKdUVt7GcX7QUCr31+3fzhi4gN4/wUYPVxQ==", - "dev": true, - "requires": { - "@jest/types": "^25.4.0", - "ansi-regex": "^5.0.0", - "ansi-styles": "^4.0.0", - "react-is": "^16.12.0" - } - }, - "supports-color": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", - "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "jest-watcher": { - "version": "25.4.0", - "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-25.4.0.tgz", - "integrity": "sha512-36IUfOSRELsKLB7k25j/wutx0aVuHFN6wO94gPNjQtQqFPa2rkOymmx9rM5EzbF3XBZZ2oqD9xbRVoYa2w86gw==", - "dev": true, - "requires": { - "@jest/test-result": "^25.4.0", - "@jest/types": "^25.4.0", - "ansi-escapes": "^4.2.1", - "chalk": "^3.0.0", - "jest-util": "^25.4.0", - "string-length": "^3.1.0" - }, - "dependencies": { - "@jest/types": { - "version": "25.4.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-25.4.0.tgz", - "integrity": "sha512-XBeaWNzw2PPnGW5aXvZt3+VO60M+34RY3XDsCK5tW7kyj3RK0XClRutCfjqcBuaR2aBQTbluEDME9b5MB9UAPw==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^1.1.1", - "@types/yargs": "^15.0.0", - "chalk": "^3.0.0" - } - }, - "ansi-styles": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", - "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", - "dev": true, - "requires": { - "@types/color-name": "^1.1.1", - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", - "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", - "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "jest-worker": { - "version": "25.4.0", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-25.4.0.tgz", - "integrity": "sha512-ghAs/1FtfYpMmYQ0AHqxV62XPvKdUDIBBApMZfly+E9JEmYh2K45G0R5dWxx986RN12pRCxsViwQVtGl+N4whw==", - "dev": true, - "requires": { - "merge-stream": "^2.0.0", - "supports-color": "^7.0.0" - }, - "dependencies": { - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", - "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "js-beautify": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/js-beautify/-/js-beautify-1.11.0.tgz", - "integrity": "sha512-a26B+Cx7USQGSWnz9YxgJNMmML/QG2nqIaL7VVYPCXbqiKz8PN0waSNvroMtvAK6tY7g/wPdNWGEP+JTNIBr6A==", - "requires": { - "config-chain": "^1.1.12", - "editorconfig": "^0.15.3", - "glob": "^7.1.3", - "mkdirp": "~1.0.3", - "nopt": "^4.0.3" - }, - "dependencies": { - "mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==" - } - } - }, - "js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true - }, - "js-yaml": { - "version": "3.13.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", - "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", - "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": "15.2.1", - "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-15.2.1.tgz", - "integrity": "sha512-fAl1W0/7T2G5vURSyxBzrJ1LSdQn6Tr5UX/xD4PXDx/PDgwygedfW6El/KIj3xJ7FU61TTYnc/l/B7P49Eqt6g==", - "dev": true, - "requires": { - "abab": "^2.0.0", - "acorn": "^7.1.0", - "acorn-globals": "^4.3.2", - "array-equal": "^1.0.0", - "cssom": "^0.4.1", - "cssstyle": "^2.0.0", - "data-urls": "^1.1.0", - "domexception": "^1.0.1", - "escodegen": "^1.11.1", - "html-encoding-sniffer": "^1.0.2", - "nwsapi": "^2.2.0", - "parse5": "5.1.0", - "pn": "^1.1.0", - "request": "^2.88.0", - "request-promise-native": "^1.0.7", - "saxes": "^3.1.9", - "symbol-tree": "^3.2.2", - "tough-cookie": "^3.0.1", - "w3c-hr-time": "^1.0.1", - "w3c-xmlserializer": "^1.1.2", - "webidl-conversions": "^4.0.2", - "whatwg-encoding": "^1.0.5", - "whatwg-mimetype": "^2.3.0", - "whatwg-url": "^7.0.0", - "ws": "^7.0.0", - "xml-name-validator": "^3.0.0" - } - }, - "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-pointer": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/json-pointer/-/json-pointer-0.6.0.tgz", - "integrity": "sha1-jlAFUKaqxUZKRzN32leqbMIoKNc=", - "dev": true, - "requires": { - "foreach": "^2.0.4" - } - }, - "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-ref-parser": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/json-schema-ref-parser/-/json-schema-ref-parser-6.1.0.tgz", - "integrity": "sha512-pXe9H1m6IgIpXmE5JSb8epilNTGsmTb2iPohAXpOdhqGFbQjNeHHsZxU+C8w6T81GZxSPFLeUoqDJmzxx5IGuw==", - "requires": { - "call-me-maybe": "^1.0.1", - "js-yaml": "^3.12.1", - "ono": "^4.0.11" - } - }, - "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-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 - }, - "json-to-ast": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/json-to-ast/-/json-to-ast-2.1.0.tgz", - "integrity": "sha512-W9Lq347r8tA1DfMvAGn9QNcgYm4Wm7Yc+k8e6vezpMnRT+NHbtlxgNBXRVjXe9YM6eTn6+p/MKOlV/aABJcSnQ==", - "dev": true, - "requires": { - "code-error-fragment": "0.0.230", - "grapheme-splitter": "^1.0.4" - } - }, - "json5": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.3.tgz", - "integrity": "sha512-KXPvOm8K9IJKFM0bmdn8QXh7udDh1g/giieX0NLCaMnb4hEiVFqnop2ImTXCc5e0/oHz3LTqmHGtExn5hfMkOA==", - "dev": true, - "requires": { - "minimist": "^1.2.5" - } - }, - "jsonfile": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", - "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", - "requires": { - "graceful-fs": "^4.1.6" - } - }, - "jsonpointer": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-4.0.1.tgz", - "integrity": "sha1-T9kss04OnbPInIYi7PUfm5eMbLk=", - "dev": true - }, - "jsonwebtoken": { - "version": "8.5.1", - "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz", - "integrity": "sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w==", - "requires": { - "jws": "^3.2.2", - "lodash.includes": "^4.3.0", - "lodash.isboolean": "^3.0.3", - "lodash.isinteger": "^4.0.4", - "lodash.isnumber": "^3.0.3", - "lodash.isplainobject": "^4.0.6", - "lodash.isstring": "^4.0.1", - "lodash.once": "^4.0.0", - "ms": "^2.1.1", - "semver": "^5.6.0" - }, - "dependencies": { - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" - } - } - }, - "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" - } - }, - "jwa": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", - "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==", - "requires": { - "buffer-equal-constant-time": "1.0.1", - "ecdsa-sig-formatter": "1.0.11", - "safe-buffer": "^5.0.1" - } - }, - "jws": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", - "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", - "requires": { - "jwa": "^1.4.1", - "safe-buffer": "^5.0.1" - } - }, - "kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "dev": true - }, - "kleur": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", - "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", - "dev": true - }, - "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" - } - }, - "leven": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", - "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", - "dev": true - }, - "levn": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", - "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", - "dev": true, - "requires": { - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2" - } - }, - "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 - }, - "locate-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", - "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", - "requires": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" - } - }, - "lodash": { - "version": "4.17.15", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", - "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==" - }, - "lodash.difference": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.difference/-/lodash.difference-4.5.0.tgz", - "integrity": "sha1-nMtOUF1Ia5FlE0V3KIWi3yf9AXw=" - }, - "lodash.groupby": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/lodash.groupby/-/lodash.groupby-4.6.0.tgz", - "integrity": "sha1-Cwih3PaDl8OXhVwyOXg4Mt90A9E=" - }, - "lodash.includes": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", - "integrity": "sha1-YLuYqHy5I8aMoeUTJUgzFISfVT8=" - }, - "lodash.isboolean": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", - "integrity": "sha1-bC4XHbKiV82WgC/UOwGyDV9YcPY=" - }, - "lodash.isequal": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", - "integrity": "sha1-QVxEePK8wwEgwizhDtMib30+GOA=" - }, - "lodash.isinteger": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", - "integrity": "sha1-YZwK89A/iwTDH1iChAt3sRzWg0M=" - }, - "lodash.isnumber": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", - "integrity": "sha1-POdoEMWSjQM1IwGsKHMX8RwLH/w=" - }, - "lodash.isplainobject": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", - "integrity": "sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs=" - }, - "lodash.isstring": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", - "integrity": "sha1-1SfftUVuynzJu5XV2ur4i6VKVFE=" - }, - "lodash.once": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", - "integrity": "sha1-DdOXEhPHxW34gJd9UEyI+0cal6w=" - }, - "lodash.partition": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/lodash.partition/-/lodash.partition-4.6.0.tgz", - "integrity": "sha1-o45GtzRp4EILDaEhLmbUFL42S6Q=" - }, - "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.uniqwith": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.uniqwith/-/lodash.uniqwith-4.5.0.tgz", - "integrity": "sha1-egy/ZfQ7WShiWp1NDcVLGMrcfvM=" - }, - "lolex": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/lolex/-/lolex-5.1.2.tgz", - "integrity": "sha512-h4hmjAvHTmd+25JSwrtTIuwbKdwg5NzZVRMLn9saij4SZaepCrTCxPr35H/3bjwfMJtN+t3CX8672UIkglz28A==", - "dev": true, - "requires": { - "@sinonjs/commons": "^1.7.0" - } - }, - "loose-envify": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", - "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", - "dev": true, - "requires": { - "js-tokens": "^3.0.0 || ^4.0.0" - } - }, - "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==", - "requires": { - "pseudomap": "^1.0.2", - "yallist": "^2.1.2" - } - }, - "lru-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/lru-queue/-/lru-queue-0.1.0.tgz", - "integrity": "sha1-Jzi9nw089PhEkMVzbEhpmsYyzaM=", - "requires": { - "es5-ext": "~0.10.2" - } - }, - "lunr": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/lunr/-/lunr-2.3.8.tgz", - "integrity": "sha512-oxMeX/Y35PNFuZoHp+jUj5OSEmLCaIH4KTFJh7a93cHBoFmpw2IoPs22VIz7vyO2YUnx2Tn9dzIwO2P/4quIRg==", - "dev": true - }, - "make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", - "dev": true, - "requires": { - "semver": "^6.0.0" - } - }, - "makeerror": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.11.tgz", - "integrity": "sha1-4BpckQnyr3lmDk6LlYd5AYT1qWw=", - "dev": true, - "requires": { - "tmpl": "1.0.x" - } - }, - "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" - } - }, - "mark.js": { - "version": "8.11.1", - "resolved": "https://registry.npmjs.org/mark.js/-/mark.js-8.11.1.tgz", - "integrity": "sha1-GA8fnr74sOY45BZq1S24eb6y/8U=", - "dev": true - }, - "marked": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/marked/-/marked-0.7.0.tgz", - "integrity": "sha512-c+yYdCZJQrsRjTPhUx7VKkApw9bwDkNbHUKo1ovgcfDjb2kc8rLuRbIFyXL5WOEUwzSSKo3IXpph2K6DqB/KZg==", - "dev": true - }, - "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" - } - }, - "media-typer": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", - "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" - }, - "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" - } - }, - "memoize-one": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-5.1.1.tgz", - "integrity": "sha512-HKeeBpWvqiVJD57ZUAsJNm71eHTykffzcLZVYWiVfQeI1rJtuEaS7hQiEpWfVVk18donPwJEcFKIkCmPJNOhHA==", - "dev": true - }, - "memoizee": { - "version": "0.4.14", - "resolved": "https://registry.npmjs.org/memoizee/-/memoizee-0.4.14.tgz", - "integrity": "sha512-/SWFvWegAIYAO4NQMpcX+gcra0yEZu4OntmUdrBaWrJncxOqAziGFlHxc7yjKVK2uu3lpPW27P27wkR82wA8mg==", - "requires": { - "d": "1", - "es5-ext": "^0.10.45", - "es6-weak-map": "^2.0.2", - "event-emitter": "^0.3.5", - "is-promise": "^2.1", - "lru-queue": "0.1", - "next-tick": "1", - "timers-ext": "^0.1.5" - } - }, - "merge-anything": { - "version": "2.4.4", - "resolved": "https://registry.npmjs.org/merge-anything/-/merge-anything-2.4.4.tgz", - "integrity": "sha512-l5XlriUDJKQT12bH+rVhAHjwIuXWdAIecGwsYjv2LJo+dA1AeRTmeQS+3QBpO6lEthBMDi2IUMpLC1yyRvGlwQ==", - "dev": true, - "requires": { - "is-what": "^3.3.1" - } - }, - "merge-descriptors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", - "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" - }, - "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.3.0", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.3.0.tgz", - "integrity": "sha512-2j4DAdlBOkiSZIsaXk4mTE3sRS02yBHAtfy127xRV3bQUFqXkjHCHLW6Scv7DwNRbIWNHH8zpnz9zMaKXIdvYw==" - }, - "methods": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", - "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" - }, - "micromatch": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz", - "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==", - "dev": true, - "requires": { - "braces": "^3.0.1", - "picomatch": "^2.0.5" - } - }, - "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" - } - }, - "mime": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" - }, - "mime-db": { - "version": "1.43.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.43.0.tgz", - "integrity": "sha512-+5dsGEEovYbT8UY9yD7eE4XTc4UwJ1jBYlgaQQF38ENsKR3wj/8q8RFZrF9WIZpB2V1ArTVFUva8sAul1NzRzQ==" - }, - "mime-types": { - "version": "2.1.26", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.26.tgz", - "integrity": "sha512-01paPWYgLrkqAyrlDorC1uDwl2p3qZT7yl806vW7DvDoxwXi46jsjFbg+WdwotBIk6/MbEhO/dh5aZ5sNj/dWQ==", - "requires": { - "mime-db": "1.43.0" - } - }, - "mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "dev": true - }, - "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==", - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "minimist": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", - "dev": true - }, - "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.5", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", - "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", - "requires": { - "minimist": "^1.2.5" - }, - "dependencies": { - "minimist": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" - } - } - }, - "mobx": { - "version": "4.15.4", - "resolved": "https://registry.npmjs.org/mobx/-/mobx-4.15.4.tgz", - "integrity": "sha512-nyuHPqmKnVOnbvkjR8OrijBtovxAHYC+JU8/qBqvBw4Dez/n+zzxqNHbZNFy7/07+wwc/Qz7JS9WSfy1LcYISA==", - "dev": true - }, - "mobx-react": { - "version": "6.1.5", - "resolved": "https://registry.npmjs.org/mobx-react/-/mobx-react-6.1.5.tgz", - "integrity": "sha512-EfWoXmGE2CfozH4Xirb65+il1ynHFCmxBSUabMSf+511YfjVs6QRcCrHkiVw+Il8iWp1gIyfa9qKkUgbDA9/2w==", - "dev": true, - "requires": { - "mobx-react-lite": "^1.4.2" - } - }, - "mobx-react-lite": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/mobx-react-lite/-/mobx-react-lite-1.5.2.tgz", - "integrity": "sha512-PyZmARqqWtpuQaAoHF5pKX7h6TKNLwq6vtovm4zZvG6sEbMRHHSqioGXSeQbpRmG8Kw8uln3q/W1yMO5IfL5Sg==", - "dev": true - }, - "moment": { - "version": "2.24.0", - "resolved": "https://registry.npmjs.org/moment/-/moment-2.24.0.tgz", - "integrity": "sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg==" - }, - "moment-timezone": { - "version": "0.5.28", - "resolved": "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.5.28.tgz", - "integrity": "sha512-TDJkZvAyKIVWg5EtVqRzU97w0Rb0YVbfpqyjgu6GwXCAohVRqwZjf4fOzDE6p1Ch98Sro/8hQQi65WDXW5STPw==", - "requires": { - "moment": ">= 2.9.0" - } - }, - "morgan": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.10.0.tgz", - "integrity": "sha512-AbegBVI4sh6El+1gNwvD5YIck7nSA36weD7xvIxG4in80j/UoK8AEGaWnnz8v1GxonMCltmlNs5ZKbGvl9b1XQ==", - "requires": { - "basic-auth": "~2.0.1", - "debug": "2.6.9", - "depd": "~2.0.0", - "on-finished": "~2.3.0", - "on-headers": "~1.0.2" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "requires": { - "ms": "2.0.0" - } - }, - "depd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==" - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - } - } - }, - "move-file": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/move-file/-/move-file-2.0.0.tgz", - "integrity": "sha512-cdkdhNCgbP5dvS4tlGxZbD+nloio9GIimP57EjqFhwLcMjnU+XJKAZzlmg/TN/AK1LuNAdTSvm3CPPP4Xkv0iQ==", - "requires": { - "path-exists": "^4.0.0" - }, - "dependencies": { - "path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==" - } - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - }, - "multer": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/multer/-/multer-1.4.2.tgz", - "integrity": "sha512-xY8pX7V+ybyUpbYMxtjM9KAiD9ixtg5/JkeKUTD6xilfDv0vzzOFcCp4Ljb1UU3tSOM3VTZtKo63OmzOrGi3Cg==", - "requires": { - "append-field": "^1.0.0", - "busboy": "^0.2.11", - "concat-stream": "^1.5.2", - "mkdirp": "^0.5.1", - "object-assign": "^4.1.1", - "on-finished": "^2.3.0", - "type-is": "^1.6.4", - "xtend": "^4.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==" - }, - "neo-async": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.1.tgz", - "integrity": "sha512-iyam8fBuCUpWeKPGpaNMetEocMt364qkCsfL9JuhjXX6dRnguRVOfk2GZaDpPjcOKiiXCPINZC1GczQ7iTq3Zw==", - "dev": true - }, - "next-tick": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz", - "integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw=" - }, - "nice-try": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", - "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", - "dev": true - }, - "nocache": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/nocache/-/nocache-2.1.0.tgz", - "integrity": "sha512-0L9FvHG3nfnnmaEQPjT9xhfN4ISk0A8/2j4M37Np4mcDesJjHgEUfgPhdCyZuFI954tjokaIj/A3NdpFNdEh4Q==" - }, - "node-fetch-h2": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/node-fetch-h2/-/node-fetch-h2-2.3.0.tgz", - "integrity": "sha512-ofRW94Ab0T4AOh5Fk8t0h8OBWrmjb0SSB20xh1H8YnPV9EJ+f5AMoYSUQ2zgJ4Iq2HAK0I2l5/Nequ8YzFS3Hg==", - "dev": true, - "requires": { - "http2-client": "^1.2.5" - } - }, - "node-int64": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", - "integrity": "sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs=", - "dev": true - }, - "node-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-modules-regexp": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/node-modules-regexp/-/node-modules-regexp-1.0.0.tgz", - "integrity": "sha1-jZ2+KJZKSsVxLpExZCEHxx6Q7EA=", - "dev": true - }, - "node-notifier": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/node-notifier/-/node-notifier-6.0.0.tgz", - "integrity": "sha512-SVfQ/wMw+DesunOm5cKqr6yDcvUTDl/yc97ybGHMrteNEY6oekXpNpS3lZwgLlwz0FLgHoiW28ZpmBHUDg37cw==", - "dev": true, - "optional": true, - "requires": { - "growly": "^1.3.0", - "is-wsl": "^2.1.1", - "semver": "^6.3.0", - "shellwords": "^0.1.1", - "which": "^1.3.1" - }, - "dependencies": { - "which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", - "dev": true, - "optional": true, - "requires": { - "isexe": "^2.0.0" - } - } - } - }, - "node-readfiles": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/node-readfiles/-/node-readfiles-0.2.0.tgz", - "integrity": "sha1-271K8SE04uY1wkXvk//Pb2BnOl0=", - "dev": true, - "requires": { - "es6-promise": "^3.2.1" - } - }, - "nopt": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.3.tgz", - "integrity": "sha512-CvaGwVMztSMJLOeXPrez7fyfObdZqNUK1cPAEzLHrTybIua9pMdmmPR5YwtfNftIOMv3DPUhFaxsZMNTQO20Kg==", - "requires": { - "abbrev": "1", - "osenv": "^0.1.4" - } - }, - "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" - }, - "dependencies": { - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "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 - }, - "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" - }, - "dependencies": { - "path-key": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", - "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", - "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 - }, - "oas-kit-common": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/oas-kit-common/-/oas-kit-common-1.0.8.tgz", - "integrity": "sha512-pJTS2+T0oGIwgjGpw7sIRU8RQMcUoKCDWFLdBqKB2BNmGpbBMH2sdqAaOXUg8OzonZHU0L7vfJu1mJFEiYDWOQ==", - "dev": true, - "requires": { - "fast-safe-stringify": "^2.0.7" - } - }, - "oas-linter": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/oas-linter/-/oas-linter-3.1.1.tgz", - "integrity": "sha512-bV20TrXYG0QUYL78LGByfyeJAkxIhZBkCXotH2SnnBGYvWvtxpp2DzvBvKIPbeAVItQL6WoxNzGGFecU/A6HRg==", - "dev": true, - "requires": { - "should": "^13.2.1", - "yaml": "^1.8.3" - } - }, - "oas-resolver": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/oas-resolver/-/oas-resolver-2.3.2.tgz", - "integrity": "sha512-toGCUv8wyZZmUAAsw4jn+511xNpUFW2ZLp4sAZ7xpERIeosrbxBxtkVxot9kXvdUHtPjRafi5+bkJ56TwQeYSQ==", - "dev": true, - "requires": { - "node-fetch-h2": "^2.3.0", - "oas-kit-common": "^1.0.8", - "reftools": "^1.1.1", - "yaml": "^1.8.3", - "yargs": "^15.3.1" - }, - "dependencies": { - "ansi-regex": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", - "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", - "dev": true - }, - "ansi-styles": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", - "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", - "dev": true, - "requires": { - "@types/color-name": "^1.1.1", - "color-convert": "^2.0.1" - } - }, - "cliui": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", - "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", - "dev": true, - "requires": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^6.2.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, - "find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "requires": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - } - }, - "is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true - }, - "locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "requires": { - "p-locate": "^4.1.0" - } - }, - "p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "requires": { - "p-limit": "^2.2.0" - } - }, - "path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true - }, - "string-width": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", - "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", - "dev": true, - "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.0" - } - }, - "strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", - "dev": true, - "requires": { - "ansi-regex": "^5.0.0" - } - }, - "wrap-ansi": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", - "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", - "dev": true, - "requires": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - } - }, - "yargs": { - "version": "15.3.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.3.1.tgz", - "integrity": "sha512-92O1HWEjw27sBfgmXiixJWT5hRBp2eobqXicLtPBIDBhYB+1HpwZlXmbW2luivBJHBzki+7VyCLRtAkScbTBQA==", - "dev": true, - "requires": { - "cliui": "^6.0.0", - "decamelize": "^1.2.0", - "find-up": "^4.1.0", - "get-caller-file": "^2.0.1", - "require-directory": "^2.1.1", - "require-main-filename": "^2.0.0", - "set-blocking": "^2.0.0", - "string-width": "^4.2.0", - "which-module": "^2.0.0", - "y18n": "^4.0.0", - "yargs-parser": "^18.1.1" - } - }, - "yargs-parser": { - "version": "18.1.2", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.2.tgz", - "integrity": "sha512-hlIPNR3IzC1YuL1c2UwwDKpXlNFBqD1Fswwh1khz5+d8Cq/8yc/Mn0i+rQXduu8hcrFKvO7Eryk+09NecTQAAQ==", - "dev": true, - "requires": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" - } - } - } - }, - "oas-schema-walker": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/oas-schema-walker/-/oas-schema-walker-1.1.4.tgz", - "integrity": "sha512-foVDDS0RJYMfhQEDh/WdBuCzydTcsCnGo9EeD8SpWq1uW10JXiz+8SfYVDA7LO87kjmlnTRZle/2gr5qxabaEA==", - "dev": true - }, - "oas-validator": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/oas-validator/-/oas-validator-3.4.0.tgz", - "integrity": "sha512-l/SxykuACi2U51osSsBXTxdsFc8Fw41xI7AsZkzgVgWJAzoEFaaNptt35WgY9C3757RUclsm6ye5GvSyYoozLQ==", - "dev": true, - "requires": { - "ajv": "^5.5.2", - "better-ajv-errors": "^0.6.7", - "call-me-maybe": "^1.0.1", - "oas-kit-common": "^1.0.7", - "oas-linter": "^3.1.0", - "oas-resolver": "^2.3.0", - "oas-schema-walker": "^1.1.3", - "reftools": "^1.1.0", - "should": "^13.2.1", - "yaml": "^1.8.3" - }, - "dependencies": { - "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" - } - }, - "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 - }, - "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 - } - } - }, - "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=" - }, - "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-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.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" - } - }, - "on-finished": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", - "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", - "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==" - }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "requires": { - "wrappy": "1" - } - }, - "onetime": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.0.tgz", - "integrity": "sha512-5NcSkPHhwTVFIQN+TUqXoS5+dlElHXdpAWu9I0HP20YOtIi+aZ0Ct82jdlILDxjLEAWwvm+qj1m6aEtsDVmm6Q==", - "dev": true, - "requires": { - "mimic-fn": "^2.1.0" - } - }, - "ono": { - "version": "4.0.11", - "resolved": "https://registry.npmjs.org/ono/-/ono-4.0.11.tgz", - "integrity": "sha512-jQ31cORBFE6td25deYeD80wxKBMj+zBmHTrVxnc6CKhx8gho6ipmWM5zj/oeoqioZ99yqBls9Z/9Nss7J26G2g==", - "requires": { - "format-util": "^1.0.3" - } - }, - "openapi-enforcer": { - "version": "1.10.3", - "resolved": "https://registry.npmjs.org/openapi-enforcer/-/openapi-enforcer-1.10.3.tgz", - "integrity": "sha512-2g2uzpAo1plTdFvDyU1Y0vOeOZhEvEoX+XLIGlMeSuu5YFwS47NwedgZMptIiRkFDij7Um2JW2FibmVFBgGiag==", - "requires": { - "axios": "^0.19.2", - "json-schema-ref-parser": "^6.0.1" - } - }, - "openapi-enforcer-middleware": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/openapi-enforcer-middleware/-/openapi-enforcer-middleware-1.2.2.tgz", - "integrity": "sha512-XO3S+k+EroeF48xpIC2zB8AaaU2YRuFlqF1QSRzQY8Ic2YvO9nQ2w8u1veqGE+AWDf++60JjCGiqrHAxTR5VHg==", - "requires": { - "debug": "^3.2.6" - }, - "dependencies": { - "debug": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", - "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", - "requires": { - "ms": "^2.1.1" - } - } - } - }, - "openapi-enforcer-multer": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/openapi-enforcer-multer/-/openapi-enforcer-multer-0.1.6.tgz", - "integrity": "sha512-vG7kLjLeA8pcJEzWgO7uUTg10L4wg5jbAMZxppikXUhN4uBGb6qQF6fUXnEi8JbwmMU67msMNO3IIuprAV0SMQ==" - }, - "openapi-sampler": { - "version": "1.0.0-beta.15", - "resolved": "https://registry.npmjs.org/openapi-sampler/-/openapi-sampler-1.0.0-beta.15.tgz", - "integrity": "sha512-wUD/vD3iBHKik/sME3uwUu4X3HFA53rDrPcVvLzgEELjHLbnTpSYfm4Jo9qZT1dPfBRowAnrF/VRQfOjL5QRAw==", - "dev": true, - "requires": { - "json-pointer": "^0.6.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" - } - }, - "os-browserify": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz", - "integrity": "sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc=", - "dev": true - }, - "os-homedir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", - "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=" - }, - "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=" - }, - "osenv": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz", - "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", - "requires": { - "os-homedir": "^1.0.0", - "os-tmpdir": "^1.0.0" - } - }, - "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-each-series": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/p-each-series/-/p-each-series-2.1.0.tgz", - "integrity": "sha512-ZuRs1miPT4HrjFa+9fRfOFXxGJfORgelKV9f9nNOWw2gl6gVsRaVDOQP0+MI0G0wGKns1Yacsu0GjOFbTK0JFQ==", - "dev": true - }, - "p-finally": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", - "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", - "dev": true - }, - "p-is-promise": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-2.1.0.tgz", - "integrity": "sha512-Y3W0wlRPK8ZMRbNq97l4M5otioeA5lm1z7bkNkxCka8HSPjR0xRWmpCmc9utiaLP9Jb1eD8BgeIxTW4AIF45Pg==", - "dev": true - }, - "p-limit": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.1.tgz", - "integrity": "sha512-85Tk+90UCVWvbDavCLKPOLC9vvY8OwEX/RtKF+/1OADJMVlFfEHOiMTPVyxg7mk/dKa+ipdHm0OUkTvCpMTuwg==", - "requires": { - "p-try": "^2.0.0" - } - }, - "p-locate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", - "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", - "requires": { - "p-limit": "^2.0.0" - } - }, - "p-map": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-3.0.0.tgz", - "integrity": "sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ==", - "requires": { - "aggregate-error": "^3.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==" - }, - "packet-reader": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/packet-reader/-/packet-reader-1.0.0.tgz", - "integrity": "sha512-HAKu/fG3HpHFO0AA8WE8q2g+gBJaZ9MG7fcKk+IJPLTGAD6Psw4443l+9DGRbOIh3/aXr7Phy0TjilYivJo5XQ==" - }, - "pako": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", - "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", - "dev": true - }, - "parse-asn1": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.5.tgz", - "integrity": "sha512-jkMYn1dcJqF6d5CpU689bq7w/b5ALS9ROVSpQDPrZsqqesUJii9qutvoT5ltGedNXMO2e16YUWIghG9KxaViTQ==", - "dev": true, - "requires": { - "asn1.js": "^4.0.0", - "browserify-aes": "^1.0.0", - "create-hash": "^1.1.0", - "evp_bytestokey": "^1.0.0", - "pbkdf2": "^3.0.3", - "safe-buffer": "^5.1.1" - } - }, - "parse-json": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.0.0.tgz", - "integrity": "sha512-OOY5b7PAEFV0E2Fir1KOkxchnZNCdowAJgQ5NuxjpBKTRP3pQhwkrkxqQjeoKJ+fO7bCpmIZaogI4eZGDMEGOw==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.0.0", - "error-ex": "^1.3.1", - "json-parse-better-errors": "^1.0.1", - "lines-and-columns": "^1.1.6" - } - }, - "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==" - }, - "pascalcase": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", - "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=", - "dev": true - }, - "passport": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/passport/-/passport-0.4.1.tgz", - "integrity": "sha512-IxXgZZs8d7uFSt3eqNjM9NQ3g3uQCW5avD8mRNoXV99Yig50vjuaez6dQK2qC0kVWPRTujxY0dWgGfT09adjYg==", - "requires": { - "passport-strategy": "1.x.x", - "pause": "0.0.1" - } - }, - "passport-json": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/passport-json/-/passport-json-1.2.0.tgz", - "integrity": "sha1-yXTzWkhvWkAN+LlaoAB/hxX0Z9Q=", - "requires": { - "passport-strategy": "^1.0.0" - } - }, - "passport-jwt": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/passport-jwt/-/passport-jwt-4.0.0.tgz", - "integrity": "sha512-BwC0n2GP/1hMVjR4QpnvqA61TxenUMlmfNjYNgK0ZAs0HK4SOQkHcSv4L328blNTLtHq7DbmvyNJiH+bn6C5Mg==", - "requires": { - "jsonwebtoken": "^8.2.0", - "passport-strategy": "^1.0.0" - } - }, - "passport-strategy": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/passport-strategy/-/passport-strategy-1.0.0.tgz", - "integrity": "sha1-tVOaqPwiWj0a0XlHbd8ja0QPUuQ=" - }, - "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-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=" - }, - "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=" - }, - "path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==" - }, - "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==" - }, - "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=" - }, - "pause": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/pause/-/pause-0.0.1.tgz", - "integrity": "sha1-HUCLP9t2kjuVQ9lvtMnf1TXZy10=" - }, - "pbkdf2": { - "version": "3.0.17", - "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.0.17.tgz", - "integrity": "sha512-U/il5MsrZp7mGg3mSQfn742na2T+1/vHDCG5/iTI3X9MKUuYUZVLQhyRsg06mCgDBTd57TxzgZt7P+fYfjRLtA==", - "dev": true, - "requires": { - "create-hash": "^1.1.2", - "create-hmac": "^1.1.4", - "ripemd160": "^2.0.1", - "safe-buffer": "^5.0.1", - "sha.js": "^2.4.8" - } - }, - "perfect-scrollbar": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/perfect-scrollbar/-/perfect-scrollbar-1.5.0.tgz", - "integrity": "sha512-NrNHJn5mUGupSiheBTy6x+6SXCFbLlm8fVZh9moIzw/LgqElN5q4ncR4pbCBCYuCJ8Kcl9mYM0NgDxvW+b4LxA==", - "dev": true - }, - "performance-now": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", - "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", - "dev": true - }, - "pg": { - "version": "8.0.3", - "resolved": "https://registry.npmjs.org/pg/-/pg-8.0.3.tgz", - "integrity": "sha512-fvcNXn4o/iq4jKq15Ix/e58q3jPSmzOp6/8C3CaHoSR/bsxdg+1FXfDRePdtE/zBb3++TytvOrS1hNef3WC/Kg==", - "requires": { - "buffer-writer": "2.0.0", - "packet-reader": "1.0.0", - "pg-connection-string": "0.1.3", - "pg-pool": "^3.1.1", - "pg-protocol": "^1.2.2", - "pg-types": "^2.1.0", - "pgpass": "1.x", - "semver": "4.3.2" - }, - "dependencies": { - "semver": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-4.3.2.tgz", - "integrity": "sha1-x6BxWKgL7dBSNVt3DYLWZA+AO+c=" - } - } - }, - "pg-connection-string": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-0.1.3.tgz", - "integrity": "sha1-2hhHsglA5C7hSSvq9l1J2RskXfc=" - }, - "pg-hstore": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/pg-hstore/-/pg-hstore-2.3.3.tgz", - "integrity": "sha512-qpeTpdkguFgfdoidtfeTho1Q1zPVPbtMHgs8eQ+Aan05iLmIs3Z3oo5DOZRclPGoQ4i68I1kCtQSJSa7i0ZVYg==", - "requires": { - "underscore": "^1.7.0" - } - }, - "pg-int8": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz", - "integrity": "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==" - }, - "pg-pool": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.1.1.tgz", - "integrity": "sha512-kYH6S0mcZF1TPg1F9boFee2JlCSm2oqnlR2Mz2Wgn1psQbEBNVeNTJCw2wCK48QsctwvGUzbxLMg/lYV6hL/3A==" - }, - "pg-protocol": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.2.2.tgz", - "integrity": "sha512-r8hGxHOk3ccMjjmhFJ/QOSVW5A+PP84TeRlEwB/cQ9Zu+bvtZg8Z59Cx3AMfVQc9S0Z+EG+HKhicF1W1GN5Eqg==" - }, - "pg-types": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-2.2.0.tgz", - "integrity": "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==", - "requires": { - "pg-int8": "1.0.1", - "postgres-array": "~2.0.0", - "postgres-bytea": "~1.0.0", - "postgres-date": "~1.0.4", - "postgres-interval": "^1.1.0" - } - }, - "pgpass": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/pgpass/-/pgpass-1.0.2.tgz", - "integrity": "sha1-Knu0G2BltnkH6R2hsHwYR8h3swY=", - "requires": { - "split": "^1.0.0" - } - }, - "picomatch": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.1.0.tgz", - "integrity": "sha512-uhnEDzAbrcJ8R3g2fANnSuXZMBtkpSjxTTgn2LeSiQlfmq72enQJWdQllXW24MBLYnA1SBD2vfvx2o0Zw3Ielw==" - }, - "pirates": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.1.tgz", - "integrity": "sha512-WuNqLTbMI3tmfef2TKxlQmAiLHKtFhlsCZnPIpuv2Ow0RDVO8lfy1Opf4NUzlMXLjPl+Men7AuVdX6TA+s+uGA==", - "dev": true, - "requires": { - "node-modules-regexp": "^1.0.0" - } - }, - "pkg-dir": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", - "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", - "dev": true, - "requires": { - "find-up": "^4.0.0" - }, - "dependencies": { - "find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "requires": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - } - }, - "locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "requires": { - "p-locate": "^4.1.0" - } - }, - "p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "requires": { - "p-limit": "^2.2.0" - } - }, - "path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true - } - } - }, - "pn": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/pn/-/pn-1.1.0.tgz", - "integrity": "sha512-2qHaIQr2VLRFoxe2nASzsV6ef4yOOH+Fi9FBOVH6cqeSgUnoyySPZkxzLuzd+RYOQTRpROA0ztTMqxROKSb/nA==", - "dev": true - }, - "polished": { - "version": "3.5.1", - "resolved": "https://registry.npmjs.org/polished/-/polished-3.5.1.tgz", - "integrity": "sha512-GVbvskpBiDV5TknurGL6OyFfLHsCknxbU8w5iMppT8rW0tLEoQHrIRfrPNPqGXNj3HGhkjRvhmg59Fy7HSnCAw==", - "dev": true, - "requires": { - "@babel/runtime": "^7.8.7" - } - }, - "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-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 - }, - "postgres-array": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz", - "integrity": "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==" - }, - "postgres-bytea": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.0.tgz", - "integrity": "sha1-AntTPAqokOJtFy1Hz5zOzFIazTU=" - }, - "postgres-date": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-1.0.5.tgz", - "integrity": "sha512-pdau6GRPERdAYUQwkBnGKxEfPyhVZXG/JiS44iZWiNdSOWE09N2lUgN6yshuq6fVSon4Pm0VMXd1srUUkLe9iA==" - }, - "postgres-interval": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-1.2.0.tgz", - "integrity": "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==", - "requires": { - "xtend": "^4.0.0" - } - }, - "prelude-ls": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", - "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", - "dev": true - }, - "pretty-format": { - "version": "25.4.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-25.4.0.tgz", - "integrity": "sha512-PI/2dpGjXK5HyXexLPZU/jw5T9Q6S1YVXxxVxco+LIqzUFHXIbKZKdUVt7GcX7QUCr31+3fzhi4gN4/wUYPVxQ==", - "dev": true, - "requires": { - "@jest/types": "^25.4.0", - "ansi-regex": "^5.0.0", - "ansi-styles": "^4.0.0", - "react-is": "^16.12.0" - }, - "dependencies": { - "ansi-regex": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", - "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", - "dev": true - }, - "ansi-styles": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", - "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", - "dev": true, - "requires": { - "@types/color-name": "^1.1.1", - "color-convert": "^2.0.1" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - } - } - }, - "prismjs": { - "version": "1.19.0", - "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.19.0.tgz", - "integrity": "sha512-IVFtbW9mCWm9eOIaEkNyo2Vl4NnEifis2GQ7/MLRG5TQe6t+4Sj9J5QWI9i3v+SS43uZBlCAOn+zYTVYQcPXJw==", - "dev": true, - "requires": { - "clipboard": "^2.0.0" - } - }, - "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==" - }, - "prompts": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.3.2.tgz", - "integrity": "sha512-Q06uKs2CkNYVID0VqwfAl9mipo99zkBv/n2JtWY89Yxa3ZabWSrs0e2KTudKVa3peLUvYXMefDqIleLPVUBZMA==", - "dev": true, - "requires": { - "kleur": "^3.0.3", - "sisteransi": "^1.0.4" - } - }, - "prop-types": { - "version": "15.7.2", - "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz", - "integrity": "sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==", - "dev": true, - "requires": { - "loose-envify": "^1.4.0", - "object-assign": "^4.1.1", - "react-is": "^16.8.1" - } - }, - "proto-list": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", - "integrity": "sha1-IS1b/hMYMGpCD2QCuOJv85ZHqEk=" - }, - "proxy-addr": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.5.tgz", - "integrity": "sha512-t/7RxHXPH6cJtP0pRG6smSr9QJidhB+3kXu0KgXnbGYMgzEnUxRQ4/LDdfOwZEMyIh3/xHb8PX3t+lfL9z+YVQ==", - "requires": { - "forwarded": "~0.1.2", - "ipaddr.js": "1.9.0" - } - }, - "pseudomap": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", - "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=" - }, - "psl": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", - "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==", - "dev": true - }, - "public-encrypt": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz", - "integrity": "sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==", - "dev": true, - "requires": { - "bn.js": "^4.1.0", - "browserify-rsa": "^4.0.0", - "create-hash": "^1.1.0", - "parse-asn1": "^5.0.0", - "randombytes": "^2.0.1", - "safe-buffer": "^5.1.2" - } - }, - "pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "dev": true, - "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, - "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 - }, - "qs": { - "version": "6.7.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", - "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==" - }, - "querystring": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", - "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=", - "dev": true - }, - "querystring-es3": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz", - "integrity": "sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM=", - "dev": true - }, - "randombytes": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", - "dev": true, - "requires": { - "safe-buffer": "^5.1.0" - } - }, - "randomfill": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz", - "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==", - "dev": true, - "requires": { - "randombytes": "^2.0.5", - "safe-buffer": "^5.1.0" - } - }, - "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==" - }, - "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==", - "requires": { - "bytes": "3.1.0", - "http-errors": "1.7.2", - "iconv-lite": "0.4.24", - "unpipe": "1.0.0" - } - }, - "react": { - "version": "16.13.1", - "resolved": "https://registry.npmjs.org/react/-/react-16.13.1.tgz", - "integrity": "sha512-YMZQQq32xHLX0bz5Mnibv1/LHb3Sqzngu7xstSM+vrkE5Kzr9xE0yMByK5kMoTK30YVJE61WfbxIFFvfeDKT1w==", - "dev": true, - "requires": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1", - "prop-types": "^15.6.2" - } - }, - "react-dom": { - "version": "16.13.1", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.13.1.tgz", - "integrity": "sha512-81PIMmVLnCNLO/fFOQxdQkvEq/+Hfpv24XNJfpyZhTRfO0QcmQIF/PgCa1zCOj2w1hrn12MFLyaJ/G0+Mxtfag==", - "dev": true, - "requires": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1", - "prop-types": "^15.6.2", - "scheduler": "^0.19.1" - } - }, - "react-dropdown": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/react-dropdown/-/react-dropdown-1.7.0.tgz", - "integrity": "sha512-zFZ73pgLA32hArpE4j/7DtOEhOMg240XG5QvbAb0/VinGekkHDVIakMyAFUKC5jDz8jqXEltgriqFW9R5iCtPQ==", - "dev": true, - "requires": { - "classnames": "^2.2.3" - } - }, - "react-is": { - "version": "16.13.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", - "dev": true - }, - "react-tabs": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/react-tabs/-/react-tabs-3.1.0.tgz", - "integrity": "sha512-9RKc77HCPsjQDVPyZEw37g3JPtg26oSQ9o4mtaVXjJuLedDX5+TQcE+MRNKR+4aO3GMAY4YslCePGG1//MQ3Jg==", - "dev": true, - "requires": { - "classnames": "^2.2.0", - "prop-types": "^15.5.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": { - "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 - } - } - }, - "read-pkg-up": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz", - "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==", - "dev": true, - "requires": { - "find-up": "^4.1.0", - "read-pkg": "^5.2.0", - "type-fest": "^0.8.1" - }, - "dependencies": { - "find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "requires": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - } - }, - "locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "requires": { - "p-locate": "^4.1.0" - } - }, - "p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "requires": { - "p-limit": "^2.2.0" - } - }, - "path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true - } - } - }, - "readable-stream": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", - "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", - "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" - } - }, - "readdirp": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.3.0.tgz", - "integrity": "sha512-zz0pAkSPOXXm1viEwygWIPSPkcBYjW1xU5j/JBh5t9bGCJwa6f9+BJa6VaB2g+b55yVrmXzqkyLf4xaWYM0IkQ==", - "dev": true, - "requires": { - "picomatch": "^2.0.7" - } - }, - "realpath-native": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/realpath-native/-/realpath-native-2.0.0.tgz", - "integrity": "sha512-v1SEYUOXXdbBZK8ZuNgO4TBjamPsiSgcFr0aP+tEKpQZK8vooEUqV6nm6Cv502mX4NF2EfsnVqtNAHG+/6Ur1Q==", - "dev": true - }, - "redoc": { - "version": "2.0.0-rc.24", - "resolved": "https://registry.npmjs.org/redoc/-/redoc-2.0.0-rc.24.tgz", - "integrity": "sha512-h82NZFDzTUgAEtd0st3D29EsrxO8bw+26xdX1Y0vtwlp6uiQUA44uZLpdBnOlcSWMipbZ75ra6uuBU2NHFNPGg==", - "dev": true, - "requires": { - "classnames": "^2.2.6", - "decko": "^1.2.0", - "dompurify": "^2.0.8", - "eventemitter3": "^4.0.0", - "json-pointer": "^0.6.0", - "json-schema-ref-parser": "^6.1.0", - "lunr": "2.3.8", - "mark.js": "^8.11.1", - "marked": "^0.7.0", - "memoize-one": "~5.1.1", - "mobx-react": "6.1.5", - "openapi-sampler": "1.0.0-beta.15", - "perfect-scrollbar": "^1.4.0", - "polished": "^3.4.4", - "prismjs": "^1.19.0", - "prop-types": "^15.7.2", - "react-dropdown": "^1.7.0", - "react-tabs": "^3.1.0", - "slugify": "^1.4.0", - "stickyfill": "^1.1.1", - "swagger2openapi": "^5.3.4", - "tslib": "^1.11.1", - "url-template": "^2.0.8" - } - }, - "redoc-cli": { - "version": "0.9.7", - "resolved": "https://registry.npmjs.org/redoc-cli/-/redoc-cli-0.9.7.tgz", - "integrity": "sha512-DSF89FotRZkxNXj77GRKJsgNRzvw9NqQMugw0Cr4wk3wgAMqf2RDRDX2AqnZCzXunJ10k7z++sG14dB0imMV/g==", - "dev": true, - "requires": { - "chokidar": "^3.0.2", - "handlebars": "^4.1.2", - "isarray": "^2.0.5", - "mkdirp": "^0.5.1", - "mobx": "^4.2.0", - "node-libs-browser": "^2.2.1", - "react": "^16.8.6", - "react-dom": "^16.8.6", - "redoc": "2.0.0-rc.24", - "styled-components": "^4.3.2", - "tslib": "^1.10.0", - "yargs": "^13.3.0" - }, - "dependencies": { - "isarray": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", - "dev": true - } - } - }, - "referrer-policy": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/referrer-policy/-/referrer-policy-1.2.0.tgz", - "integrity": "sha512-LgQJIuS6nAy1Jd88DCQRemyE3mS+ispwlqMk3b0yjZ257fI1v9c+/p6SD5gP5FGyXUIgrNOAfmyioHwZtYv2VA==" - }, - "reftools": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/reftools/-/reftools-1.1.1.tgz", - "integrity": "sha512-7ySkzK7YpUeJP16rzJqEXTZ7IrAq/AL/p+wWejD9wdKQOe+mYYVAOB3w5ZTs2eoHfmAidwr/6PcC+q+LzPF/DQ==", - "dev": true - }, - "regenerator-runtime": { - "version": "0.11.1", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", - "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==" - }, - "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" - } - }, - "remove-trailing-separator": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", - "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=", - "dev": true - }, - "repeat-element": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz", - "integrity": "sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==", - "dev": true - }, - "repeat-string": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", - "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", - "dev": true - }, - "request": { - "version": "2.88.2", - "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", - "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", - "dev": true, - "requires": { - "aws-sign2": "~0.7.0", - "aws4": "^1.8.0", - "caseless": "~0.12.0", - "combined-stream": "~1.0.6", - "extend": "~3.0.2", - "forever-agent": "~0.6.1", - "form-data": "~2.3.2", - "har-validator": "~5.1.3", - "http-signature": "~1.2.0", - "is-typedarray": "~1.0.0", - "isstream": "~0.1.2", - "json-stringify-safe": "~5.0.1", - "mime-types": "~2.1.19", - "oauth-sign": "~0.9.0", - "performance-now": "^2.1.0", - "qs": "~6.5.2", - "safe-buffer": "^5.1.2", - "tough-cookie": "~2.5.0", - "tunnel-agent": "^0.6.0", - "uuid": "^3.3.2" - }, - "dependencies": { - "qs": { - "version": "6.5.2", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", - "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==", - "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" - } - } - } - }, - "request-promise-core": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.3.tgz", - "integrity": "sha512-QIs2+ArIGQVp5ZYbWD5ZLCY29D5CfWizP8eWnm8FoGD1TX61veauETVQbrV60662V0oFBkrDOuaBI8XgtuyYAQ==", - "dev": true, - "requires": { - "lodash": "^4.17.15" - } - }, - "request-promise-native": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/request-promise-native/-/request-promise-native-1.0.8.tgz", - "integrity": "sha512-dapwLGqkHtwL5AEbfenuzjTYg35Jd6KPytsC2/TLkVMz8rm+tNt72MGUWT1RP/aYawMpN6HqbNGBQaRcBtjQMQ==", - "dev": true, - "requires": { - "request-promise-core": "1.1.3", - "stealthy-require": "^1.1.1", - "tough-cookie": "^2.3.3" - }, - "dependencies": { - "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" - } - } - } - }, - "require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=" - }, - "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==" - }, - "resolve": { - "version": "1.12.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.12.0.tgz", - "integrity": "sha512-B/dOmuoAik5bKcD6s6nXDCjzUKnaDvdkRyAk6rsmsKLipWj4797iothd7jmmUhWTfinVMU+wc56rYKsit2Qy4w==", - "requires": { - "path-parse": "^1.0.6" - } - }, - "resolve-cwd": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", - "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", - "dev": true, - "requires": { - "resolve-from": "^5.0.0" - } - }, - "resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "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 - }, - "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-as-promised": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/retry-as-promised/-/retry-as-promised-3.2.0.tgz", - "integrity": "sha512-CybGs60B7oYU/qSQ6kuaFmRd9sTZ6oXSc0toqePvV74Ac6/IFZSI1ReFQmtCN+uvW1Mtqdwpvt/LGOiCBAY2Mg==", - "requires": { - "any-promise": "^1.3.0" - } - }, - "reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==" - }, - "rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "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" - } - }, - "rsvp": { - "version": "4.8.5", - "resolved": "https://registry.npmjs.org/rsvp/-/rsvp-4.8.5.tgz", - "integrity": "sha512-nfMOlASu9OnRJo1mbEk2cz0D56a1MBNrJ7orjRZQG10XDyuvwksKbuXNp6qa+kbn839HwjwhBzhFmdsaEAfauA==", - "dev": true - }, - "run-parallel": { - "version": "1.1.9", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.1.9.tgz", - "integrity": "sha512-DEqnSRTDw/Tc3FXf49zedI638Z9onwUotBMiUFKmrO2sdFKIbXamXGQ3Axd4qgphxKB4kw/qP1w5kTxnfU1B9Q==" - }, - "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==" - }, - "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==" - }, - "sane": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/sane/-/sane-4.1.0.tgz", - "integrity": "sha512-hhbzAgTIX8O7SHfp2c8/kREfEn4qO/9q8C9beyY6+tvZ87EpoZ3i1RIEvp27YBswnNbY9mWd6paKVmKbAgLfZA==", - "dev": true, - "requires": { - "@cnakazawa/watch": "^1.0.3", - "anymatch": "^2.0.0", - "capture-exit": "^2.0.0", - "exec-sh": "^0.3.2", - "execa": "^1.0.0", - "fb-watchman": "^2.0.0", - "micromatch": "^3.1.4", - "minimist": "^1.1.1", - "walker": "~1.0.5" - }, - "dependencies": { - "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" - } - }, - "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" - } - } - } - }, - "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" - } - } - } - }, - "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" - } - } - } - }, - "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" - } - }, - "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" - } - }, - "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" - } - } - } - }, - "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" - } - }, - "scheduler": { - "version": "0.19.1", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.19.1.tgz", - "integrity": "sha512-n/zwRWRYSUj0/3g/otKDRPMh6qv2SYMWNq85IEa8iZyAv8od9zDYpGSnpBEjNgcMNq6Scbu5KfIPxNF72R/2EA==", - "dev": true, - "requires": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1" - } - }, - "select": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/select/-/select-1.1.2.tgz", - "integrity": "sha1-DnNQrN7ICxEIUoeG7B1EGNEbOW0=", - "dev": true, - "optional": true - }, - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" - }, - "send": { - "version": "0.17.1", - "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz", - "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==", - "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": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "requires": { - "ms": "2.0.0" - }, - "dependencies": { - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - } - } - }, - "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==" - } - } - }, - "sequelize": { - "version": "5.21.7", - "resolved": "https://registry.npmjs.org/sequelize/-/sequelize-5.21.7.tgz", - "integrity": "sha512-+JrS5Co7CN53cOFFFaUb+xqQP00wD1Ag9xGLBLoUko2KhRZxjm+UDkqAVPHTUp87McLwJaCPkKv61GPhBVloRQ==", - "requires": { - "bluebird": "^3.5.0", - "cls-bluebird": "^2.1.0", - "debug": "^4.1.1", - "dottie": "^2.0.0", - "inflection": "1.12.0", - "lodash": "^4.17.15", - "moment": "^2.24.0", - "moment-timezone": "^0.5.21", - "retry-as-promised": "^3.2.0", - "semver": "^6.3.0", - "sequelize-pool": "^2.3.0", - "toposort-class": "^1.0.1", - "uuid": "^3.3.3", - "validator": "^10.11.0", - "wkx": "^0.4.8" - } - }, - "sequelize-cli": { - "version": "5.5.1", - "resolved": "https://registry.npmjs.org/sequelize-cli/-/sequelize-cli-5.5.1.tgz", - "integrity": "sha512-ZM4kUZvY3y14y+Rq3cYxGH7YDJz11jWHcN2p2x7rhAIemouu4CEXr5ebw30lzTBtyXV4j2kTO+nUjZOqzG7k+Q==", - "requires": { - "bluebird": "^3.5.3", - "cli-color": "^1.4.0", - "fs-extra": "^7.0.1", - "js-beautify": "^1.8.8", - "lodash": "^4.17.5", - "resolve": "^1.5.0", - "umzug": "^2.1.0", - "yargs": "^13.1.0" - } - }, - "sequelize-pool": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/sequelize-pool/-/sequelize-pool-2.3.0.tgz", - "integrity": "sha512-Ibz08vnXvkZ8LJTiUOxRcj1Ckdn7qafNZ2t59jYHMX1VIebTAOYefWdRYFt6z6+hy52WGthAHAoLc9hvk3onqA==" - }, - "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==", - "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=" - }, - "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==" - }, - "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": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "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==" - }, - "shellwords": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/shellwords/-/shellwords-0.1.1.tgz", - "integrity": "sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww==", - "dev": true, - "optional": true - }, - "shimmer": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/shimmer/-/shimmer-1.2.1.tgz", - "integrity": "sha512-sQTKC1Re/rM6XyFM6fIAGHRPVGvyXfgzIDvzoq608vM+jeyVD0Tu1E6Np0Kc2zAIFWIj963V2800iF/9LPieQw==" - }, - "should": { - "version": "13.2.3", - "resolved": "https://registry.npmjs.org/should/-/should-13.2.3.tgz", - "integrity": "sha512-ggLesLtu2xp+ZxI+ysJTmNjh2U0TsC+rQ/pfED9bUZZ4DKefP27D+7YJVVTvKsmjLpIi9jAa7itwDGkDDmt1GQ==", - "dev": true, - "requires": { - "should-equal": "^2.0.0", - "should-format": "^3.0.3", - "should-type": "^1.4.0", - "should-type-adaptors": "^1.0.1", - "should-util": "^1.0.0" - } - }, - "should-equal": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/should-equal/-/should-equal-2.0.0.tgz", - "integrity": "sha512-ZP36TMrK9euEuWQYBig9W55WPC7uo37qzAEmbjHz4gfyuXrEUgF8cUvQVO+w+d3OMfPvSRQJ22lSm8MQJ43LTA==", - "dev": true, - "requires": { - "should-type": "^1.4.0" - } - }, - "should-format": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/should-format/-/should-format-3.0.3.tgz", - "integrity": "sha1-m/yPdPo5IFxT04w01xcwPidxJPE=", - "dev": true, - "requires": { - "should-type": "^1.3.0", - "should-type-adaptors": "^1.0.1" - } - }, - "should-type": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/should-type/-/should-type-1.4.0.tgz", - "integrity": "sha1-B1bYzoRt/QmEOmlHcZ36DUz/XPM=", - "dev": true - }, - "should-type-adaptors": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/should-type-adaptors/-/should-type-adaptors-1.1.0.tgz", - "integrity": "sha512-JA4hdoLnN+kebEp2Vs8eBe9g7uy0zbRo+RMcU0EsNy+R+k049Ki+N5tT5Jagst2g7EAja+euFuoXFCa8vIklfA==", - "dev": true, - "requires": { - "should-type": "^1.3.0", - "should-util": "^1.0.0" - } - }, - "should-util": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/should-util/-/should-util-1.0.1.tgz", - "integrity": "sha512-oXF8tfxx5cDk8r2kYqlkUJzZpDBqVY/II2WhvU0n9Y3XYvAYRmeaf1PvvIvTgPnv4KJ+ES5M0PyDq5Jp+Ygy2g==", - "dev": true - }, - "sigmund": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz", - "integrity": "sha1-P/IfGYytIXX587eBhT/ZTQ0ZtZA=" - }, - "signal-exit": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", - "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", - "dev": true - }, - "sisteransi": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", - "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", - "dev": true - }, - "slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true - }, - "slugify": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/slugify/-/slugify-1.4.0.tgz", - "integrity": "sha512-FtLNsMGBSRB/0JOE2A0fxlqjI6fJsgHGS13iTuVT28kViI4JjUiNqp/vyis0ZXYcMnpR3fzGNkv+6vRlI2GwdQ==", - "dev": true - }, - "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": { - "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" - } - }, - "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" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - } - } - }, - "snapdragon-node": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", - "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", - "dev": true, - "requires": { - "define-property": "^1.0.0", - "isobject": "^3.0.0", - "snapdragon-util": "^3.0.1" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - } - } - }, - "snapdragon-util": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", - "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", - "dev": true, - "requires": { - "kind-of": "^3.2.0" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "source-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.18", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.18.tgz", - "integrity": "sha512-9luZr/BZ2QeU6tO2uG8N2aZpVSli4TSAOAqFOyTO51AJcD9P99c0K1h6dD6r6qo5dyT44BR5exweOaLLeldTkQ==", - "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.0", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.0.tgz", - "integrity": "sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q==", - "dev": true, - "requires": { - "spdx-expression-parse": "^3.0.0", - "spdx-license-ids": "^3.0.0" - } - }, - "spdx-exceptions": { - "version": "2.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.0", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz", - "integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==", - "dev": true, - "requires": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" - } - }, - "spdx-license-ids": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.5.tgz", - "integrity": "sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q==", - "dev": true - }, - "split": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/split/-/split-1.0.1.tgz", - "integrity": "sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg==", - "requires": { - "through": "2" - } - }, - "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=" - }, - "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" - } - }, - "stack-utils": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-1.0.2.tgz", - "integrity": "sha512-MTX+MeG5U994cazkjd/9KNAapsHnibjMLnfXodlkXw76JEea0UiNzrqidzo1emMwk7w5Qhc9jd4Bn9TBb1MFwA==", - "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=" - }, - "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 - }, - "stickyfill": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/stickyfill/-/stickyfill-1.1.1.tgz", - "integrity": "sha1-OUE/7p0CXHSn5ZzuyyN4TMDxfwI=", - "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-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" - } - }, - "streamsearch": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-0.1.2.tgz", - "integrity": "sha1-gIudDlb8Jz2Am6VzOOkpkZoanxo=" - }, - "string-length": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-length/-/string-length-3.1.0.tgz", - "integrity": "sha512-Ttp5YvkGm5v9Ijagtaz1BnN+k9ObpvS0eIBblPMp2YWL8FBmi9qblQ9fexc2k/CXFgrTIteU3jAw3payCnwSTA==", - "dev": true, - "requires": { - "astral-regex": "^1.0.0", - "strip-ansi": "^5.2.0" - } - }, - "string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", - "requires": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - } - }, - "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "requires": { - "safe-buffer": "~5.1.0" - } - }, - "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "requires": { - "ansi-regex": "^4.1.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==" - } - } - }, - "strip-bom": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", - "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", - "dev": true - }, - "strip-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 - }, - "styled-components": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/styled-components/-/styled-components-4.4.1.tgz", - "integrity": "sha512-RNqj14kYzw++6Sr38n7197xG33ipEOktGElty4I70IKzQF1jzaD1U4xQ+Ny/i03UUhHlC5NWEO+d8olRCDji6g==", - "dev": true, - "requires": { - "@babel/helper-module-imports": "^7.0.0", - "@babel/traverse": "^7.0.0", - "@emotion/is-prop-valid": "^0.8.1", - "@emotion/unitless": "^0.7.0", - "babel-plugin-styled-components": ">= 1", - "css-to-react-native": "^2.2.2", - "memoize-one": "^5.0.0", - "merge-anything": "^2.2.4", - "prop-types": "^15.5.4", - "react-is": "^16.6.0", - "stylis": "^3.5.0", - "stylis-rule-sheet": "^0.0.10", - "supports-color": "^5.5.0" - } - }, - "stylis": { - "version": "3.5.4", - "resolved": "https://registry.npmjs.org/stylis/-/stylis-3.5.4.tgz", - "integrity": "sha512-8/3pSmthWM7lsPBKv7NXkzn2Uc9W7NotcwGNpJaa3k7WMM1XDCA4MgT5k/8BIexd5ydZdboXtU90XH9Ec4Bv/Q==", - "dev": true - }, - "stylis-rule-sheet": { - "version": "0.0.10", - "resolved": "https://registry.npmjs.org/stylis-rule-sheet/-/stylis-rule-sheet-0.0.10.tgz", - "integrity": "sha512-nTbZoaqoBnmK+ptANthb10ZRZOGC+EmTLLUxeYIuHNkEKcmKgXX1XWKkUBT2Ac4es3NybooPe0SmvKdhKJZAuw==", - "dev": true - }, - "superagent": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/superagent/-/superagent-5.1.0.tgz", - "integrity": "sha512-7V6JVx5N+eTL1MMqRBX0v0bG04UjrjAvvZJTF/VDH/SH2GjSLqlrcYepFlpTrXpm37aSY6h3GGVWGxXl/98TKA==", - "dev": true, - "requires": { - "component-emitter": "^1.3.0", - "cookiejar": "^2.1.2", - "debug": "^4.1.1", - "fast-safe-stringify": "^2.0.6", - "form-data": "^2.3.3", - "formidable": "^1.2.1", - "methods": "^1.1.2", - "mime": "^2.4.4", - "qs": "^6.7.0", - "readable-stream": "^3.4.0", - "semver": "^6.1.1" - }, - "dependencies": { - "mime": { - "version": "2.4.4", - "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.4.tgz", - "integrity": "sha512-LRxmNwziLPT828z+4YkNzloCFC2YM4wrB99k+AV5ZbEyfGNWfG8SO1FUXLmLDBSo89NrJZ4DIWeLjy1CHGhMGA==", - "dev": true - }, - "readable-stream": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.4.0.tgz", - "integrity": "sha512-jItXPLmrSR8jmTRmRWJXCnGJsfy85mB3Wd/uINMXA65yrnFo0cPClFIUWzo2najVNSl+mx7/4W8ttlLWJe99pQ==", - "dev": true, - "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - } - } - } - }, - "supertest": { - "version": "5.0.0-0", - "resolved": "https://registry.npmjs.org/supertest/-/supertest-5.0.0-0.tgz", - "integrity": "sha512-+XblQKVMblt7kf4BRtK1vezM+Xxq+CWlksy4kmLyqDsN1y89YrDIJ0j/H2CGLMMNk+8k1/bCcGUw8XLs1NYxpg==", - "dev": true, - "requires": { - "methods": "1.1.2", - "superagent": "5.1.0" - } - }, - "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" - } - }, - "supports-hyperlinks": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.1.0.tgz", - "integrity": "sha512-zoE5/e+dnEijk6ASB6/qrK+oYdm2do1hjoLWrqUC/8WEIW1gbxFcKuBof7sW8ArN6e+AYvsE8HBGiVRWL/F5CA==", - "dev": true, - "requires": { - "has-flag": "^4.0.0", - "supports-color": "^7.0.0" - }, - "dependencies": { - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", - "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "swagger2openapi": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/swagger2openapi/-/swagger2openapi-5.4.0.tgz", - "integrity": "sha512-f5QqfXawiVijhjMtYqWZ55ESHPZFqrPC8L9idhIiuSX8O2qsa1i4MVGtCM3TQF+Smzr/6WfT/7zBuzG3aTgPAA==", - "dev": true, - "requires": { - "better-ajv-errors": "^0.6.1", - "call-me-maybe": "^1.0.1", - "node-fetch-h2": "^2.3.0", - "node-readfiles": "^0.2.0", - "oas-kit-common": "^1.0.7", - "oas-resolver": "^2.3.0", - "oas-schema-walker": "^1.1.3", - "oas-validator": "^3.4.0", - "reftools": "^1.1.0", - "yaml": "^1.8.3", - "yargs": "^12.0.5" - }, - "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 - }, - "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" - } - }, - "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 - }, - "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 - }, - "string-width": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", - "dev": true, - "requires": { - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" - } - }, - "strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", - "dev": true, - "requires": { - "ansi-regex": "^3.0.0" - } - }, - "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": { - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "dev": true - }, - "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" - } - } - } - }, - "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" - } - } - } - }, - "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 - }, - "terminal-link": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/terminal-link/-/terminal-link-2.1.1.tgz", - "integrity": "sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ==", - "dev": true, - "requires": { - "ansi-escapes": "^4.2.1", - "supports-hyperlinks": "^2.0.0" - } - }, - "test-exclude": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", - "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", - "dev": true, - "requires": { - "@istanbuljs/schema": "^0.1.2", - "glob": "^7.1.4", - "minimatch": "^3.0.4" - } - }, - "throat": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/throat/-/throat-5.0.0.tgz", - "integrity": "sha512-fcwX4mndzpLQKBS1DVYhGAcYaYt7vsHNIvQV+WXMvnow5cgjPphq5CaayLaGsjRdSCKZFNGt7/GYAuXaNOiYCA==", - "dev": true - }, - "through": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=" - }, - "timers-browserify": { - "version": "2.0.11", - "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.11.tgz", - "integrity": "sha512-60aV6sgJ5YEbzUdn9c8kYGIqOubPoUdqQCul3SBAsRCZ40s6Y5cMcrW4dt3/k/EsbLVJNl9n6Vz3fTc+k2GeKQ==", - "dev": true, - "requires": { - "setimmediate": "^1.0.4" - } - }, - "timers-ext": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/timers-ext/-/timers-ext-0.1.7.tgz", - "integrity": "sha512-b85NUNzTSdodShTIbky6ZF02e8STtVVfD+fu4aXXShEELpozH+bCpJLYMPZbsABN2wDH7fJpqIoXxJpzbf0NqQ==", - "requires": { - "es5-ext": "~0.10.46", - "next-tick": "1" - } - }, - "tiny-emitter": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/tiny-emitter/-/tiny-emitter-2.1.0.tgz", - "integrity": "sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q==", - "dev": true, - "optional": true - }, - "tmpl": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.4.tgz", - "integrity": "sha1-I2QN17QtAEM5ERQIIOXPRA5SHdE=", - "dev": true - }, - "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": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "requires": { - "is-number": "^7.0.0" - } - }, - "toidentifier": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", - "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==" - }, - "toposort-class": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/toposort-class/-/toposort-class-1.0.1.tgz", - "integrity": "sha1-f/0feMi+KMO6Rc1OGj9e4ZO9mYg=" - }, - "tough-cookie": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-3.0.1.tgz", - "integrity": "sha512-yQyJ0u4pZsv9D4clxO69OEjLWYw+jbgspjTue4lTQZLfV0c5l1VmK2y1JK8E9ahdpltPOaAThPcp5nKPUgSnsg==", - "dev": true, - "requires": { - "ip-regex": "^2.1.0", - "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" - } - }, - "tslib": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.11.1.tgz", - "integrity": "sha512-aZW88SY8kQbU7gpV19lN24LtXh/yD4ZZg6qieAJDDg+YBsJcSmLGK9QpnUjAKVG/xefmvJGd1WUmfpT/g6AJGA==", - "dev": true - }, - "tty-browserify": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz", - "integrity": "sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY=", - "dev": true - }, - "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": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz", - "integrity": "sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==" - }, - "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.8.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", - "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", - "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==", - "requires": { - "media-typer": "0.3.0", - "mime-types": "~2.1.24" - } - }, - "typedarray": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", - "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=" - }, - "typedarray-to-buffer": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", - "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", - "dev": true, - "requires": { - "is-typedarray": "^1.0.0" - } - }, - "uglify-js": { - "version": "3.9.1", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.9.1.tgz", - "integrity": "sha512-JUPoL1jHsc9fOjVFHdQIhqEEJsQvfKDjlubcCilu8U26uZ73qOg8VsN8O1jbuei44ZPlwL7kmbAdM4tzaUvqnA==", - "dev": true, - "optional": true, - "requires": { - "commander": "~2.20.3" - } - }, - "umzug": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/umzug/-/umzug-2.2.0.tgz", - "integrity": "sha512-xZLW76ax70pND9bx3wqwb8zqkFGzZIK8dIHD9WdNy/CrNfjWcwQgQkGCuUqcuwEBvUm+g07z+qWvY+pxDmMEEw==", - "requires": { - "babel-runtime": "^6.23.0", - "bluebird": "^3.5.3" - } - }, - "underscore": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.1.tgz", - "integrity": "sha512-hzSoAVtJF+3ZtiFX0VgfFPHEDRm7Y/QPjGyNo4TVdnDTdft3tr8hEkD25a1jC+TjTuE7tkHGKkhwCgs9dgBB2g==" - }, - "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" - } - }, - "universalify": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", - "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==" - }, - "unpipe": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" - }, - "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 - } - } - }, - "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-template": { - "version": "2.0.8", - "resolved": "https://registry.npmjs.org/url-template/-/url-template-2.0.8.tgz", - "integrity": "sha1-/FZaPMy/93MMd19WQflVV5FDnyE=", - "dev": true - }, - "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=" - }, - "utils-merge": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", - "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" - }, - "uuid": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", - "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==" - }, - "v8-to-istanbul": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-4.1.3.tgz", - "integrity": "sha512-sAjOC+Kki6aJVbUOXJbcR0MnbfjvBzwKZazEJymA2IX49uoOdEdk+4fBq5cXgYgiyKtAyrrJNtBZdOeDIF+Fng==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.1", - "convert-source-map": "^1.6.0", - "source-map": "^0.7.3" - }, - "dependencies": { - "source-map": { - "version": "0.7.3", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", - "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", - "dev": true - } - } - }, - "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" - } - }, - "validator": { - "version": "10.11.0", - "resolved": "https://registry.npmjs.org/validator/-/validator-10.11.0.tgz", - "integrity": "sha512-X/p3UZerAIsbBfN/IwahhYaBbY68EN/UQBWHtsbXGT5bfrH/p4NQzUCG1kF/rtKaNpnJ7jAu6NGTdSNtyNIXMw==" - }, - "vary": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", - "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" - }, - "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 - }, - "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" - } - }, - "walker": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.7.tgz", - "integrity": "sha1-L3+bj9ENZ3JisYqITijRlhjgKPs=", - "dev": true, - "requires": { - "makeerror": "1.0.x" - } - }, - "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 - }, - "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": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "requires": { - "isexe": "^2.0.0" - } - }, - "which-module": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", - "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=" - }, - "wkx": { - "version": "0.4.8", - "resolved": "https://registry.npmjs.org/wkx/-/wkx-0.4.8.tgz", - "integrity": "sha512-ikPXMM9IR/gy/LwiOSqWlSL3X/J5uk9EO2hHNRXS41eTLXaUFEVw9fn/593jW/tE5tedNg8YjT5HkCa4FqQZyQ==", - "requires": { - "@types/node": "*" - } - }, - "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 - }, - "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==", - "requires": { - "ansi-styles": "^3.2.0", - "string-width": "^3.0.0", - "strip-ansi": "^5.0.0" - } - }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" - }, - "write-file-atomic": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", - "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", - "dev": true, - "requires": { - "imurmurhash": "^0.1.4", - "is-typedarray": "^1.0.0", - "signal-exit": "^3.0.2", - "typedarray-to-buffer": "^3.1.5" - } - }, - "ws": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.2.3.tgz", - "integrity": "sha512-HTDl9G9hbkNDk98naoR/cHDws7+EyYMOdL1BmjsZXRUjf7d+MficC4B7HLUPlSiho0vg+CWKrGIt/VJBd1xunQ==", - "dev": true - }, - "x-xss-protection": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/x-xss-protection/-/x-xss-protection-1.3.0.tgz", - "integrity": "sha512-kpyBI9TlVipZO4diReZMAHWtS0MMa/7Kgx8hwG/EuZLiA6sg4Ah/4TRdASHhRRN3boobzcYgFRUFSgHRge6Qhg==" - }, - "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.2", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", - "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==" - }, - "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==" - }, - "yallist": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", - "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=" - }, - "yaml": { - "version": "1.8.3", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.8.3.tgz", - "integrity": "sha512-X/v7VDnK+sxbQ2Imq4Jt2PRUsRsP7UcpSl3Llg6+NRRqWLIvxkMFYtH1FmvwNGYRKKPa+EPA4qDBlI9WVG1UKw==", - "dev": true, - "requires": { - "@babel/runtime": "^7.8.7" - } - }, - "yargs": { - "version": "13.3.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.0.tgz", - "integrity": "sha512-2eehun/8ALW8TLoIl7MVaRUrg+yCnenu8B4kBlRxj3GJGDKU1Og7sMXPNm1BYyM1DOJmTZ4YeN/Nwxv+8XJsUA==", - "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.1" - } - }, - "yargs-parser": { - "version": "13.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.1.tgz", - "integrity": "sha512-oVAVsHz6uFrg3XQheFII8ESO2ssAf9luWuAd6Wexsu4F3OtIW0o8IribPXYrD4WC24LWtPrJlGy87y5udK+dxQ==", - "requires": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" - } - } - } -} diff --git a/package.json b/package.json deleted file mode 100644 index 49faa97..0000000 --- a/package.json +++ /dev/null @@ -1,63 +0,0 @@ -{ - "name": "sourcecode-api", - "version": "1.0.0", - "description": "API for Source Code", - "repository": { - "type": "git", - "url": "https://github.com/SourceCodeOER/sourcecode_api.git" - }, - "scripts": { - "start": "node ./bin/www", - "createSchema": "node ./bin/create_schema", - "migrate": "npx sequelize-cli db:migrate", - "migrate:reset": "npx sequelize-cli db:migrate:undo:all && npm run migrate", - "setUp": "npm run createSchema && npm run migrate", - "test": "cross-env NODE_ENV=test jest --testTimeout=10000 --forceExit", - "pretest": "cross-env NODE_ENV=test npm run setUp" - }, - "author": "jy95", - "license": "GPL-3.0-or-later", - "dependencies": { - "bcryptjs": "^2.4.3", - "bluebird": "^3.7.2", - "body-parser": "latest", - "connect-chain-if": "^1.0.0", - "cookie-parser": "^1.4.5", - "cross-env": "^7.0.2", - "debug": "latest", - "del": "^5.1.0", - "express": "^4.17.1", - "helmet": "^3.22.0", - "jsonwebtoken": "^8.5.1", - "lodash.difference": "^4.5.0", - "lodash.groupby": "^4.6.0", - "lodash.isequal": "^4.5.0", - "lodash.partition": "^4.6.0", - "lodash.uniqwith": "^4.5.0", - "mime-types": "latest", - "morgan": "^1.10.0", - "move-file": "^2.0.0", - "multer": "^1.4.2", - "openapi-enforcer": "^1.10.3", - "openapi-enforcer-middleware": "^1.2.2", - "openapi-enforcer-multer": "^0.1.6", - "passport": "^0.4.1", - "passport-json": "^1.2.0", - "passport-jwt": "^4.0.0", - "pg": "^8.0.3", - "pg-hstore": "^2.3.3", - "sequelize": "^5.21.7", - "sequelize-cli": "^5.5.1", - "uuid": "^3.4.0" - }, - "devDependencies": { - "@openapitools/openapi-generator-cli": "^1.0.10-4.2.3", - "@types/express": "^4.17.6", - "@types/jest": "^25.2.1", - "@types/sequelize": "latest", - "@types/supertest": "latest", - "jest": "^25.4.0", - "redoc-cli": "^0.9.7", - "supertest": "^5.0.0-0" - } -} diff --git a/tests/endpoints.test.js b/tests/endpoints.test.js deleted file mode 100644 index 89e6150..0000000 --- a/tests/endpoints.test.js +++ /dev/null @@ -1,1463 +0,0 @@ -const supertest = require('supertest'); -const path = require("path"); -let request; -const example_zip_file = path.resolve(__dirname, "file.zip"); - -const user = { - email: "yolo24@uclouvain.be", - password: "API4LIFE" -}; -const userName = "Eric Cartman"; - -let JWT_TOKEN = ""; // The super admin user -let JWT_TOKEN_2 = ""; // A simple user -const tag_categories = ["keywords", "source", "institution", "auteur"]; -const tags = ["java", "UCLOUVAIN", "Jacques Y", "github.com"]; - - -// credits to https://stackoverflow.com/a/8511350/6149867 -const isObject = (obj) => typeof obj === 'object' && obj !== null; - -// For the basic set up : two user ( an admin and one that is not) -async function setUpBasic() { - - const app = await require('../app.js'); - request = supertest(app); - let result; - - // The admin user first - result = await request - .post("/auth/register") - .set('Content-Type', 'application/json') - .send(Object.assign({}, user, {fullName: userName})); - expect(result.status).toBe(200); - - const response = await request - .post("/auth/login") - .set('Content-Type', 'application/json') - .set('Accept', 'application/json') - .send(user); - expect(response.status).toBe(200); - - JWT_TOKEN = response.body.token; - expect(typeof JWT_TOKEN).toBe('string'); - - // We must be able to register other user ( a simple one) for other useful cases like voting - result = await request - .post("/auth/register") - .set('Content-Type', 'application/json') - .send(Object.assign({}, user, {fullName: "Super Voter", email: "yolo_voter24@uclouvain.be"})); - expect(result.status).toBe(200); - - let response2 = await request - .post("/auth/login") - .set('Content-Type', 'application/json') - .set('Accept', 'application/json') - .send(Object.assign({}, user, {email: "yolo_voter24@uclouvain.be"})); - expect(response2.status).toBe(200); - - // creates some tags categories - const response3 = await request - .post("/api/bulk/create_or_find_tag_categories") - .set('Authorization', 'bearer ' + JWT_TOKEN) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json') - .send(tag_categories); - expect(response3.status).toBe(200); - expect(response3.body).toHaveLength(tag_categories.length); - - // creates some validated tags and store them into the first categories - const response4 = await request - .post("/api/bulk/create_tags") - .set('Authorization', 'bearer ' + JWT_TOKEN) - .set('Content-Type', 'application/json') - .send( - tags.map(tag => ({ - text: tag, - category_id: 1, - state: "VALIDATED" - })) - ); - expect(response4.status).toBe(200); - - JWT_TOKEN_2 = response2.body.token; - expect(typeof JWT_TOKEN_2).toBe('string'); - - return "SET_UP_FINISHED" -} - -// Should be able to register and login -// if not, we cannot test so much things ... -beforeAll(() => { - // Yeah , I know it is stupid to wait but if not, Jest doesn't do its job correctly - return expect(setUpBasic()).resolves.toBe("SET_UP_FINISHED"); -}); - -describe("Simple case testing", () => { - - it("POST /auth/verify : Valid token", async () => { - await request - .post("/auth/verify") - .set('Content-Type', 'application/json') - .send({ - token: JWT_TOKEN - }) - .expect(200); - }); - - it("POST /api/bulk/create_or_find_tag_categories", async () => { - const response = await request - .post("/api/bulk/create_or_find_tag_categories") - .set('Authorization', 'bearer ' + JWT_TOKEN) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json') - .send(tag_categories); - expect(response.status).toBe(200); - expect(response.body).toHaveLength(tag_categories.length); - }); - - it("POST /api/tags", async () => { - const responses = await Promise.all(tags.map(tag => { - request - .post("/api/tags") - .set('Authorization', 'bearer ' + JWT_TOKEN) - .set('Content-Type', 'application/json') - .send({text: tag, category_id: 1}) - })); - expect(responses).toHaveLength(tags.length); - }); - - it("GET /api/tags", async () => { - const response = await request - .get("/api/tags") - .set('Accept', 'application/json'); - expect(response.status).toBe(200); - expect(Array.isArray(response.body)).toBeTruthy(); - }); - - it("GET /api/tags_by_categories", async () => { - const response = await request - .get("/api/tags_by_categories") - .set('Accept', 'application/json'); - expect(response.status).toBe(200); - expect(Array.isArray(response.body)).toBeTruthy(); - }); - - it("GET /api/tags_categories", async () => { - const response = await request - .get("/api/tags_categories") - .set('Accept', 'application/json'); - expect(response.status).toBe(200); - expect(Array.isArray(response.body)).toBeTruthy(); - }); - - it("GET /api/exercises/{id} : 404 error", async () => { - await request - .get("/api/exercises/" + 42) - .set('Accept', 'application/json') - .expect(404); - }); - - it("POST /api/search with no exercise", async () => { - const criteria = { - "data": { - "title": "HELLO WORLD", - "tags": [ - 1, - [2, -3, 4], - 37, - -42 - ], - "user_ids": [1, 2, 3], - "exercise_ids": [1, 2, 3], - "vote": { - "operator": "<=", - "value": 5.0 - } - }, - "filterOptions": { - "state": ["DRAFT", "PENDING", "VALIDATED", "NOT_VALIDATED", "ARCHIVED"], - }, - "includeOptions": { - "includeCreator": false, - "includeMetrics": false, - "includeDescription": false, - "includeTags": false - }, - "orderBy": [ - // When my issue in Sequelize is fixed, it will restore my tags length sorting : - // https://github.com/sequelize/sequelize/issues/11845 - //{"field": "tags_count", "value": "DESC"}, - {"field": "id", "value": "ASC"}, - {"field": "state", "value": "DESC"}, - {"field": "avg_score", "value": "ASC"}, - {"field": "date", "value": "DESC"}, - {"field": "title", "value": "ASC"}, - {"field": "vote_count", "value": "DESC"} - ] - }; - await search_exercise(0, criteria); - }); - - it("POST /api/search with no parameters", async () => { - await search_exercise(-1, {}); - }); - - it("GET /api/configurations", async () => { - let response = await request - .get("/api/configurations") - .set('Authorization', 'bearer ' + JWT_TOKEN) - .set('Accept', 'application/json') - .send(); - expect(response.status).toBe(200); - }); - - it("GET /api/configurations with settings", async () => { - let response = await request - .get("/api/configurations") - .query('ids=1') - .set('Authorization', 'bearer ' + JWT_TOKEN) - .set('Accept', 'application/json') - .send(); - expect(response.status).toBe(200); - }); - - it("PUT /api/configurations without a valid configuration", async () => { - await request - .put("/api/configurations") - .set('Authorization', 'bearer ' + JWT_TOKEN) - .set('Accept', 'application/json') - .send({ - title: "YOLO", - tags: [1, 2, 3], - name: "YOLO", - id: 42 - }) - .expect(404); - }); - - it("POST /api/configurations with no tags", async () => { - await request - .post("/api/configurations") - .set('Authorization', 'bearer ' + JWT_TOKEN_2) - .set('Content-Type', 'application/json') - .send({ - name: "UCLouvain exercises in Java", - }) - .expect(200); - }); - - it("GET /api/tags with all settings used", async () => { - const response = await request - .get("/api/tags") - .query('state=NOT_VALIDATED') - .query('tags_ids=1') - .query('tags_ids=2') - .query('categories_ids=' + 1) - .query('title=hero') - .set('Accept', 'application/json'); - expect(response.status).toBe(200); - expect(Array.isArray(response.body)).toBe(true); - }); - - it("GET /api/tags_by_categories with all settings used", async () => { - const response = await request - .get("/api/tags_by_categories") - .query('state=VALIDATED') - .query('onlySelected=1') - .query('countStates=VALIDATED') - .query('countStates=PENDING') - .set('Accept', 'application/json'); - expect(response.status).toBe(200); - expect(Array.isArray(response.body)).toBe(true); - }); - - it("GET /auth/me", async () => { - const response = await request - .get("/auth/me") - .set('Accept', 'application/json') - .set('Authorization', 'bearer ' + JWT_TOKEN); - - expect(response.status).toBe(200); - expect(isObject(response.body)).toBeTruthy(); - expect(response.body.hasOwnProperty("email")).toBeTruthy(); - expect(response.body.hasOwnProperty("fullName")).toBeTruthy(); - expect(response.body.hasOwnProperty("role")).toBeTruthy(); - expect(response.body.hasOwnProperty("password")).toBeFalsy(); - expect(response.body.fullName).toBe(userName); - expect(response.body.email).toBe(user.email); - expect(response.body.role).toBe("super_admin"); - }); - - it("PUT /auth/update", async () => { - let response = await request - .put("/auth/update") - .set('Content-Type', 'application/json') - .set('Authorization', 'bearer ' + JWT_TOKEN) - .send({ - "fullName": "SUPERMAN", - "password": user.password, - "role": "super_admin" - }); - expect(response.status).toBe(200); - }); - - it("GET /api/users", async () => { - const response = await request - .get("/api/users") - .set('Accept', 'application/json') - .set('Authorization', 'bearer ' + JWT_TOKEN); - - expect(response.status).toBe(200); - expect(response.body.hasOwnProperty("metadata")).toBeTruthy(); - expect(response.body.hasOwnProperty("data")).toBeTruthy(); - expect(response.body.data).toHaveLength(response.body.metadata.totalItems); - }); - - it("GET /api/users with all settings", async () => { - const response = await request - .get("/api/users") - .query('metadata%5Bsize%5D=10') - .query('metadata%5Bpage%5D=1') - .query('roles=user') - .query('roles=admin') - .query('fullName=Bot') - .query('email=jy95@bot.net') - .set('Accept', 'application/json') - .set('Authorization', 'bearer ' + JWT_TOKEN); - - expect(response.status).toBe(200); - expect(response.body.hasOwnProperty("metadata")).toBeTruthy(); - expect(response.body.hasOwnProperty("data")).toBeTruthy(); - expect(response.body.data).toHaveLength(response.body.metadata.totalItems); - }); - - it("GET /api/tags_categories", async () => { - let response = await request - .get("/api/tags_categories"); - expect(response.status).toBe(200); - expect(Array.isArray(response.body)).toBeTruthy(); - }); - - it("GET /api/tags_categories with count properties", async () => { - let response = await request - .get("/api/tags_categories") - .query("fetchStats=1") - .query("category_ids=1") - .query("category_ids=2") - .query("category_ids=3"); - expect(response.status).toBe(200); - // check that the count is correct ( for example if someone creates a better version that mine with errors ^^) - expect(Array.isArray(response.body)).toBeTruthy(); - expect(response.body.every(t => t.hasOwnProperty("total"))).toBeTruthy(); - expect(response.body.every(t => t.hasOwnProperty("total_validated"))).toBeTruthy(); - expect(response.body.every(t => t.hasOwnProperty("total_unvalidated"))).toBeTruthy(); - expect(response.body.every(t => t.hasOwnProperty("total_deprecated"))).toBeTruthy(); - expect(response.body.every(t => t.hasOwnProperty("total_pending"))).toBeTruthy(); - // to check if total is still correct/coherent - const otherFields = ["total_validated", "total_unvalidated", "total_deprecated", "total_pending"]; - expect( - response.body.every( - t => - t.total - === - otherFields.reduce( (sum, field) => sum + t[field], 0) - ) - ).toBeTruthy(); - }); - - it("POST /api/bulk/create_tags", async () => { - // creates some tags categories - let response = await request - .post("/api/bulk/create_or_find_tag_categories") - .set('Authorization', 'bearer ' + JWT_TOKEN) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json') - .send(tag_categories); - expect(response.status).toBe(200); - - const aTagCategory = response.body[0].id; - const someTags = [ - { - text: "MASTER_TAG_1", - category_id: aTagCategory, - state: "VALIDATED", - }, - { - text: "MASTER_TAG_2", - category_id: aTagCategory, - } - ]; - - // insert two tags by admin - let response2 = await request - .post("/api/bulk/create_tags") - .set('Authorization', 'bearer ' + JWT_TOKEN) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json') - .send(someTags); - expect(response2.status).toBe(200); - - // Retrieve the tags and check it works as expected - response2 = await request - .get("/api/tags") - .query('title=MASTER_TAG_') - .set('Accept', 'application/json'); - expect(response2.status).toBe(200); - expect(Array.isArray(response2.body)).toBeTruthy(); - expect(response2.body).toHaveLength(2); - - // check if given properties are satisfied - expect(someTags - .every(tag => - response2.body - .some(tag2 => - (tag.text === tag2.tag_text) - && (tag2.category_id === aTagCategory) - && (tag2.state === (tag.state || "NOT_VALIDATED")) - ) - ) - ); - }); - - it("Export all exercises without settings", async () => { - // Try to use at least one combination of everything possible - const response = await request - .post("/api/export") - .set('Authorization', 'bearer ' + JWT_TOKEN) - .send(); - expect(response.status).toBe(200); - expect(response.body.hasOwnProperty("categories")); - expect(response.body.hasOwnProperty("exercises")); - }); -}); - -describe("Complex scenarios", () => { - it("Scenario n°1 : Creates a exercise / Find it / Update it 2 times and then update its status several times", async () => { - // retrieve some tag categories - let response = await request - .post("/api/bulk/create_or_find_tag_categories") - .set('Authorization', 'bearer ' + JWT_TOKEN) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json') - .send(tag_categories); - expect(response.status).toBe(200); - expect(response.body).toHaveLength(tag_categories.length); - - const tag_categories_ids = response.body.map(category => category.id); - // create some tags - response = await request - .post("/api/bulk/create_tags") - .set('Authorization', 'bearer ' + JWT_TOKEN) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json') - .send(tags.map(tag => ({ - text: tag, - category_id: tag_categories_ids[0] - }))); - expect(response.status).toBe(200); - - // take some tags - response = await request - .get("/api/tags") - .set('Accept', 'application/json'); - expect(response.status).toBe(200); - const some_tags_ids = response.body - .map(tag => tag.tag_id); - - // creates one exercise - const title = "HELLO WORLD"; - const some_exercise_data = { - "title": title, - "description": "Some verrrrrrrrrry long description here", - // try to use both existent tags and not - tags: some_tags_ids.concat( - ["SOME_TAG1", "SOME_TAG2", "SOME_TAG3", "some_Tag3"].map(tag => ({ - text: tag, - category_id: tag_categories_ids[0], - state: "PENDING" - })) - ), - "state": "DRAFT" - }; - let responseTemp = await request - .post("/api/bulk/create_exercises") - .set('Authorization', 'bearer ' + JWT_TOKEN) - .set('Content-Type', 'application/json') - .send([ - some_exercise_data - ]); - expect(responseTemp.status).toBe(200); - - // research this exercise - const criteria = { - data: { - title: title, - tags: some_tags_ids - } - }; - response = await search_exercise(1, criteria); - - let data = response.data[0]; - expect(data.version).toBe(0); - expect(data.state).toBe("DRAFT"); - expect(data.tags.some(tag => tag.state === "PENDING")).toBe(true); - - // A simple user should not be able to delete exercises - response = await request - .delete("/api/bulk/delete_exercises") - .set('Accept', 'application/json') - .set('Authorization', 'bearer ' + JWT_TOKEN_2) - .send([ - data.id - ]); - expect(response.status).toBe(403); - - // A simple user should not be able to modify a exercise that doesn't belong to him - let newExerciseVersion = { - title: data.title, - version: data.version, - description: data.description + "API4FUN", - tags: data.tags.map(tag => tag.tag_id), - removePreviousFile: true, - state: "PENDING", - }; - - response = await request - .put("/api/exercises/" + data.id) - .set('Authorization', 'bearer ' + JWT_TOKEN_2) - .set('Content-Type', 'application/json') - .send(newExerciseVersion); - - expect(response.status).toBe(403); - - - // test most updates cases : keep tags / add & remove - // 1. Only changed description - response = await request - .put("/api/exercises/" + data.id) - .set('Authorization', 'bearer ' + JWT_TOKEN) - .set('Content-Type', 'application/json') - .send(newExerciseVersion); - - expect(response.status).toBe(200); - - response = await request - .get("/api/exercises/" + data.id) - .set('Accept', 'application/json'); - - expect(response.status).toBe(200); - - expect(isObject(response.body)).toBeTruthy(); - expect(response.body.version).toBe(1); - expect(response.body.id).toBe(data.id); - expect(response.body.state).toBe("PENDING"); - - // 2. Add / remove some tags ( difficult case ) - response = await request - .put("/api/exercises/" + data.id) - .set('Authorization', 'bearer ' + JWT_TOKEN) - .set('Content-Type', 'application/json') - .send({ - title: data.title, - version: 1, - description: data.description + "API4FUN", - tags: data.tags.splice(0, 3).map(tag => tag.tag_id).concat([ - {text: "TRY 1", category_id: tag_categories_ids[0]}, - {text: "TRY 2", category_id: tag_categories_ids[0]}, - ]) - }); - - expect(response.status).toBe(200); - - // 3. Finally validate the exercise - response = await request - .put("/api/bulk/modify_exercises_status") - .set('Authorization', 'bearer ' + JWT_TOKEN) - .set('Content-Type', 'application/json') - .send({ - exercises: [data.id], - state: "VALIDATED" - }); - - expect(response.status).toBe(200); - - // 4. Archive this exercise - response = await request - .put("/api/bulk/modify_exercises_status") - .set('Authorization', 'bearer ' + JWT_TOKEN) - .set('Content-Type', 'application/json') - .send({ - exercises: [data.id], - state: "ARCHIVED" - }); - - expect(response.status).toBe(200); - - // Other user should not be able to fetch that - response = await request - .get("/api/exercises/" + data.id) - .set('Authorization', 'bearer ' + JWT_TOKEN_2) - .set('Accept', 'application/json'); - expect(response.status).toBe(410); - - // but its creator / admin should - response = await request - .get("/api/exercises/" + data.id) - .set('Authorization', 'bearer ' + JWT_TOKEN) - .set('Accept', 'application/json'); - expect(response.status).toBe(200); - - }); - - it("Scenario n°2 : Creates a single exercise with (no) existent tag(s) and add tags later", async () => { - // retrieve some tag categories - let response = await request - .post("/api/bulk/create_or_find_tag_categories") - .set('Authorization', 'bearer ' + JWT_TOKEN) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json') - .send(tag_categories); - expect(response.status).toBe(200); - expect(response.body).toHaveLength(tag_categories.length); - - // create some tags - response = await Promise.all(tags.map(tag => { - request - .post("/api/tags") - .set('Authorization', 'bearer ' + JWT_TOKEN) - .set('Content-Type', 'application/json') - .send({text: tag, category_id: 1}) - })); - expect(response).toHaveLength(tags.length); - - const title = "MEAN_OF_LIFE_42"; - // creates a single exercise - const exerciseData = { - "title": title, - "description": "Random exercise", - "tags": [1, 2, 3, { - "text": "JDG", - "category_id": 1 - }, { - "text": tags[2], - "category_id": 1 - }], - "url": "https://inginious.info.ucl.ac.be/mycourses" - }; - - response = await request - .post("/api/create_exercise") - .set('Authorization', 'bearer ' + JWT_TOKEN) - .set('Content-Type', 'application/json') - .send(exerciseData); - - expect(response.status).toBe(200); - - const criteria = { - data: { - title: title - }, - metadata: { - size: 1 - } - }; - response = await search_exercise(1, criteria); - const data = response.data[0]; - expect(data.version).toBe(0); - expect(data.file).toBe(null); - expect(data.url).not.toBe(null); - - // Only additions of tags - response = await request - .put("/api/exercises/" + data.id) - .set('Authorization', 'bearer ' + JWT_TOKEN) - .set('Content-Type', 'application/json') - .send({ - title: data.title, - version: data.version, - description: data.description, - tags: data.tags.map(tag => tag.tag_id).concat([ - {text: "TRY 42-42", category_id: 1} - ]), - "url": null, - "file": null - }); - - expect(response.status).toBe(200); - - }); - - it("Scenario n°3 : Creates a tag proposal / update it and try to recreate one similar", async () => { - // creates a tag proposal - let responseTmp = await request - .post("/api/tags") - .set('Authorization', 'bearer ' + JWT_TOKEN) - .set('Content-Type', 'application/json') - .send({text: "UNVALIDATED_TAG", category_id: 1}); - expect(responseTmp.status).toBe(200); - - // should be able to retrieve it - const response = await request - .get("/api/tags") - .set('Accept', 'application/json'); - expect(response.status).toBe(200); - const created_tag = response - .body - .filter(tag => tag.tag_text === "UNVALIDATED_TAG" && tag.category_id === 1) - .reduce((_prev, curr) => curr, undefined); - - expect(created_tag).not.toBe(undefined); - expect(created_tag.version).toBe(0); - expect(created_tag.state).toBe("PENDING"); - - // modify it to validate it - responseTmp = await request - .put("/api/tags") - .set('Authorization', 'bearer ' + JWT_TOKEN) - .set('Content-Type', 'application/json') - .send({ - tag_id: created_tag.tag_id, - tag_text: created_tag.tag_text, - category_id: created_tag.category_id, - version: created_tag.version, - state: "VALIDATED" - }); - expect(responseTmp.status).toBe(200); - - // try to recreate it (for example if someone doesn't see the tag proposal) - responseTmp = await request - .post("/api/tags") - .set('Authorization', 'bearer ' + JWT_TOKEN) - .set('Content-Type', 'application/json') - .send({text: "UNVALIDATED_TAG", category_id: 1}); - expect(responseTmp.status).toBe(200); - }); - - it("Scenario n°4 : Evaluates an exercise : multiple variation", async () => { - const title = "SOME_EXERCISE_WITH_VOTES"; - // creates a single exercise - let responseTmp = await request - .post("/api/create_exercise") - .set('Authorization', 'bearer ' + JWT_TOKEN) - .set('Content-Type', 'application/json') - .send({ - "title": title, - "description": "Random exercise", - "tags": [1, 2, 3] - .concat( - ["JDG", "JDG-2", "JDG-3"] - .map(text => ({ - "text": text, - "category_id": 1 - })) - ) - }); - expect(responseTmp.status).toBe(200); - - const criteria = { - data: { - title: title - }, - metadata: { - size: 1 - } - }; - - // retrieve it and send first vote on it - let response = await search_exercise(1, criteria); - let data = response.data[0]; - - // we must check that metrics are correct - expect(data).toHaveProperty("metrics"); - expect(isObject(data.metrics)).toBeTruthy(); - expect(data.metrics).toHaveProperty("votes"); - expect(data.metrics).toHaveProperty("avg_score"); - expect(data.metrics.votes).toBe(0); - expect(data.metrics.avg_score).toBe(0); - - // User 1 votes for this exercise - responseTmp = await request - .post("/api/vote_for_exercise") - .set('Authorization', 'bearer ' + JWT_TOKEN) - .set('Content-Type', 'application/json') - .send({ - exercise_id: data.id, - score: 3 - }); - expect(responseTmp.status).toBe(200); - - // We should see the change in this exercise data - response = await search_exercise(1, criteria); - expect(response.data[0].metrics.votes).toBe(1); - expect(response.data[0].metrics.avg_score).toBe(3); - - // User 2 votes for this exercise - response = await request - .post("/api/vote_for_exercise") - .set('Authorization', 'bearer ' + JWT_TOKEN_2) - .set('Content-Type', 'application/json') - .send({ - exercise_id: data.id, - score: 2 - }); - expect(response.status).toBe(200); - - // We should see the change in this exercise data - response = await search_exercise(1, criteria); - expect(response.data[0].metrics.votes).toBe(2); - expect(response.data[0].metrics.avg_score).toBe(2.5); - - // User 1 wants to change his vote for this exercise - responseTmp = await request - .post("/api/vote_for_exercise") - .set('Authorization', 'bearer ' + JWT_TOKEN) - .set('Content-Type', 'application/json') - .send({ - exercise_id: data.id, - score: 5.0 - }); - expect(responseTmp.status).toBe(200); - - // We should see the change in this exercise data - response = await search_exercise(1, criteria); - expect(response.data[0].metrics.votes).toBe(2); - expect(response.data[0].metrics.avg_score).toBe(3.5); - - const check = await request - .get("/api/exercises/" + data.id) - .set('Authorization', 'bearer ' + JWT_TOKEN) - .query('includeOptions%5BincludeCreator%5D=true') - .query('includeOptions%5BincludeMetrics%5D=false') - .query('includeOptions%5BincludeDescription%5D=false') - .query('includeOptions%5BincludeTags%5D=false') - .send(); - - expect(check.status).toBe(200); - expect(check.body.hasOwnProperty("metrics")).toBeFalsy(); - expect(check.body.hasOwnProperty("description")).toBeFalsy(); - expect(check.body.hasOwnProperty("tags")).toBeFalsy(); - expect(check.body.hasOwnProperty("creator")).toBeTruthy(); - expect(check.body.hasOwnProperty("vote")).toBeTruthy(); - expect(check.body.vote).toBe(5.0); - }); - - it("Scenario n°5 : Creates a configuration / update it then delete it", async () => { - // creates some tags ( it is not important if validated or not ) - const responses = await Promise.all(tags.map(tag => { - request - .post("/api/tags") - .set('Authorization', 'bearer ' + JWT_TOKEN) - .set('Content-Type', 'application/json') - .send({text: tag, category_id: 1}) - .expect(200) - })); - expect(responses).toHaveLength(tags.length); - let responseTmp; - // creates a configuration - responseTmp = await request - .post("/api/configurations") - .set('Authorization', 'bearer ' + JWT_TOKEN) - .set('Content-Type', 'application/json') - .send({ - name: "UCLouvain exercises in Java", - title: "CS1-Java", - tags: [1] - }); - expect(responseTmp.status).toBe(200); - - // should be able to find it in my configurations list - const response = await request - .get("/api/configurations") - .set('Authorization', 'bearer ' + JWT_TOKEN) - .set('Accept', 'application/json') - .send(); - - expect(response.status).toBe(200); - expect(response.body).toHaveLength(1); - expect(response.body[0].tags).toHaveLength(1); - expect(response.body[0].name).toBe("UCLouvain exercises in Java"); - expect(response.body[0].title).toBe("CS1-Java"); - - // should be able to to update it - responseTmp = await request - .put("/api/configurations") - .set('Authorization', 'bearer ' + JWT_TOKEN) - .set('Content-Type', 'application/json') - .send({ - name: "UCLouvain 4 FUN", - title: "CS1-Java", - tags: [2], - id: response.body[0].id - }); - expect(responseTmp.status).toBe(200); - - // changes should be visible - const response2 = await request - .get("/api/configurations") - .set('Authorization', 'bearer ' + JWT_TOKEN) - .set('Accept', 'application/json') - .send(); - - expect(response2.status).toBe(200); - expect(response2.body[0].tags).not.toBe(response.body[0].tags); - expect(response2.body[0].name).not.toBe(response.body[0].name); - expect(response2.body[0].id).toBe(response.body[0].id); - expect(response2.body[0].title).toBe(response.body[0].title); - - // should be able to delete it - responseTmp = await request - .delete("/api/configurations") - .set('Authorization', 'bearer ' + JWT_TOKEN) - .set('Content-Type', 'application/json') - .send({ - id: response2.body[0].id - }); - expect(responseTmp.status).toBe(200); - }); - - it("Scenario n°6 : Change a Tag Category", async () => { - - // Retrieve created tag category - const response = await request - .get("/api/tags_categories") - .set('Content-Type', 'application/json') - .set('Accept', 'application/json') - .send(); - expect(response.status).toBe(200); - - // Takes the first one - expect(Array.isArray(response.body)).toBe(true); - expect(response.body.length).toBeGreaterThanOrEqual(1); - - let responseTmp = await request - .put("/api/tags_categories") - .set('Content-Type', 'application/json') - .set('Authorization', 'bearer ' + JWT_TOKEN) - .send({ - id: response.body[0].id, - category: response.body[0].category - }); - expect(responseTmp.status).toBe(200); - }); - - it("Scenario n°7 : Creates a single exercise with two tags and deletes one tag", async () => { - - // creates a tag category just for that purpose - const response = await request - .post("/api/bulk/create_or_find_tag_categories") - .set('Authorization', 'bearer ' + JWT_TOKEN) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json') - .send(["TEMP_category"]); - expect(response.status).toBe(200); - expect(Array.isArray(response.body)).toBeTruthy(); - const categoryId = response.body[0].id; - - // creates an exercise with two tags - const some_exercise_data = { - "title": "Exercise for delete scenario", - tags: ["TEMP_TAG-0", "TEMP_TAG-1", "TEMP_TAG-2"] - .map(tag => ({ - text: tag, - category_id: categoryId - })) - }; - let responseTmp = await request - .post("/api/bulk/create_exercises") - .set('Authorization', 'bearer ' + JWT_TOKEN) - .set('Content-Type', 'application/json') - .send([ - some_exercise_data - ]); - expect(responseTmp.status).toBe(200); - - // fetch the tags linked to this exercise - let searchCriteria = { - includeOptions: { - includeTags: true, - includeMetrics: true - }, - filterOptions: { - "tags": ["PENDING", "NOT_VALIDATED", "DEPRECATED"] - }, - data: { - title: "Exercise for delete scenario" - } - }; - let result = await search_exercise(1, searchCriteria); - const tags = result.data[0].tags.map(tag => tag.tag_id); - - // delete multiple tags but keep one ( the first one ) - let test = await request - .delete("/api/bulk/delete_tags") - .set('Authorization', 'bearer ' + JWT_TOKEN) - .set('Content-Type', 'application/json') - .send(tags.slice(1)); - expect(test.status).toBe(200); - - // check that there is only a single tag now - result = await search_exercise(1, searchCriteria); - expect(result.data[0].tags).toHaveLength(1); - - // delete the temp tags category to provoke the destruction of the last tags - responseTmp = await request - .delete("/api/bulk/delete_tags_categories") - .set('Authorization', 'bearer ' + JWT_TOKEN) - .set('Content-Type', 'application/json') - .send([ - categoryId - ]); - expect(responseTmp.status).toBe(200); - - // check that there is no tag left - result = await search_exercise(1, searchCriteria); - expect(result.data[0].tags).toHaveLength(0); - }); - - it("Scenario n°8 : Export all exercises with all settings", async () => { - // Try to use at least one combination of everything possible - const response = await request - .post("/api/export") - .set('Authorization', 'bearer ' + JWT_TOKEN) - .send({ - filterOptions: { - state: ["VALIDATED", "ARCHIVED"], - tags: ["VALIDATED", "NOT_VALIDATED" ,"DEPRECATED"] - }, - "orderBy": [ - // When my issue in Sequelize is fixed, it will restore my tags length sorting : - // https://github.com/sequelize/sequelize/issues/11845 - //{"field": "tags_count", "value": "DESC"}, - {"field": "id", "value": "ASC"}, - {"field": "state", "value": "DESC"}, - {"field": "avg_score", "value": "ASC"}, - {"field": "date", "value": "DESC"}, - {"field": "title", "value": "ASC"}, - {"field": "vote_count", "value": "DESC"} - ] - }); - expect(response.status).toBe(200); - expect(response.body.hasOwnProperty("categories")); - expect(response.body.hasOwnProperty("exercises")); - }); -}); - -describe("Using multipart/form-data (instead of JSON)", () => { - it("Should be able to create an exercise with a file and update it (new file and new url)", async () => { - const title = "MULTIPART FORM TESTING 1"; - const exercise_data = { - "title": title, - "description": "HELLO WORLD", - "url": "https://inginious.info.ucl.ac.be/" - }; - - const search_criteria = { - data: { - title: title - }, - metadata: { - size: 1 - } - }; - - let responseTmp = await request - .post("/api/create_exercise") - .set('Authorization', 'bearer ' + JWT_TOKEN) - //.set('Content-Type', "multipart/form-data") - .attach("exerciseFile", example_zip_file) - .field(exercise_data) - .field("tags[0][text]", "MULTI PART exercise") - .field("tags[0][category_id]", 1) - .field("tags[1][text]", "MULTI PART exercise 2") - .field("tags[1][category_id]", 1) - .field("tags[2][text]", "MULTI PART exercise 3") - .field("tags[2][category_id]", 1) - .field("tags[2][state]", "DEPRECATED") - .field("tags[3]", 1) - .field("tags[4]", 2) - .field("tags[5]", 3); - expect(responseTmp.status).toBe(200); - - const exercise = await search_exercise(1, search_criteria); - expect(exercise.data[0].file).not.toBe(null); - expect(exercise.data[0].url).not.toBe(null); - // See if we can find the deprecated tag - expect(exercise.data[0].tags - .some(tag => tag["tag_text"] === "MULTI PART exercise 3" && tag.state === "DEPRECATED") - ).toBe(true); - - responseTmp = await request - .put("/api/exercises/" + exercise.data[0].id) - .set('Authorization', 'bearer ' + JWT_TOKEN) - .attach("exerciseFile", example_zip_file) - .field({ - "title": title, - "description": "Something changes ...", - "version": 0 - }) - .field("tags[0][text]", "MULTI PART exercise") - .field("tags[0][category_id]", 1) - .field("tags[1][text]", "MULTI PART exercise 2") - .field("tags[1][category_id]", 1) - // This time, let's see if the system had recognized the similar tags (including the one with no state set) - .field("tags[2][text]", "MULTI PART exercise 3") - .field("tags[2][category_id]", 1) - .field("tags[3]", 1) - .field("tags[4]", 2) - .field("tags[5]", 3) - // Add a new tag with state ( to trigger validation & testing ) - .field("tags[6][text]", "MULTI PART exercise 42") - .field("tags[6][category_id]", 1) - .field("tags[6][state]", "NOT_VALIDATED"); - expect(responseTmp.status).toBe(200); - - const exercise2 = await search_exercise(1, search_criteria); - expect(exercise2.data[0].file).not.toBe(exercise.data[0].file); - expect(exercise2.data[0].url).toBe(exercise2.data[0].url); - expect(exercise2.data[0].title).toBe(title); - expect(exercise2.data[0].description).toBe("Something changes ..."); - expect(exercise2.data[0].tags).toHaveLength(exercise.data[0].tags.length + 1); - // This time, let's see if the system had recognized the similar tags (including the one with no state set) - expect(exercise2.data[0].tags - .some(tag => tag["tag_text"] === "MULTI PART exercise 3" && tag.state === "DEPRECATED") - ).toBe(true); - // And also find the NOT_VALIDATED tag - expect(exercise2.data[0].tags - .some(tag => tag["tag_text"] === "MULTI PART exercise 42" && tag.state === "NOT_VALIDATED") - ).toBe(true); - }); - it("Should be able to upload multiple exercises with their linked files then delete one of them", async () => { - - // retrieve some tag categories - let response = await request - .post("/api/bulk/create_or_find_tag_categories") - .set('Authorization', 'bearer ' + JWT_TOKEN) - .set('Content-Type', 'application/json') - .set('Accept', 'application/json') - .send(tag_categories); - expect(response.status).toBe(200); - expect(response.body).toHaveLength(tag_categories.length); - - // files linked to exercises - const files = ["file.zip", "file2.zip"].map((filename, index) => ({ - "filename": filename, - "path": path.resolve(__dirname, "./" + filename), - "exercise": index - })); - - // an array of exercises - const exercises = [...Array(3).keys()].map((number) => ({ - "description": "HELLO WORLD", - "url": "https://inginious.info.ucl.ac.be/", - "title": "SOME MULTIPLE UPLOAD WITH FILE " + (number + 1), - "tags": ["java", "Java", "JaVA"].map(tag => ({ - "category_id": response.body[0].id, - "text": tag - })) - })); - - let result = await multiple_upload_with_files_request(exercises, files); - expect(result.status).toBe(200); - - const criteria = { - data: { - title: "SOME MULTIPLE UPLOAD WITH FILE" - } - }; - - result = await search_exercise(3, criteria); - - // Take the first one to be deleted - let responseTmp = await request - .delete("/api/bulk/delete_exercises") - .set('Authorization', 'bearer ' + JWT_TOKEN) - .set('Content-Type', 'application/json') - .send([ - result.data[0].id - ]); - expect(responseTmp.status).toBe(200); - - // Only one should be removed after that - await search_exercise(2, criteria); - - }); - it("A guest should not be allowed to create an exercise with(out) a file", async () => { - const title = "MULTIPART FORM TESTING 1"; - const exercise_data = { - "title": title, - "description": "HELLO WORLD", - "url": "https://inginious.info.ucl.ac.be/" - }; - - const test = await request - .post("/api/create_exercise") - .set('Authorization', 'bearer ' + "NOT_A_TOKEN") - //.set('Content-Type', "multipart/form-data") - .attach("exerciseFile", example_zip_file) - .field(exercise_data) - .field("tags[0]", 42) - .field("tags[1]", 43) - .field("tags[2]", 44); - expect(test.status).toBe(401); - }); -}); - -describe("Validations testing", () => { - - it("POST /login : Wrong content type", async () => { - await request - .post("/auth/login") - .set('Content-Type', 'application/xml') - .send() - .expect(400); - }); - - it("POST /login : Bad request", async () => { - await request - .post("/auth/login") - .set('Content-Type', 'application/json') - .send() - .expect(400); - }); - - it("POST /login : Wrong password", async () => { - await request - .post("/auth/login") - .set('Content-Type', 'application/json') - .send( - Object.assign({}, user, {password: "HACKERMAN"}) - ) - .expect(401); - }); - - it("POST /login : Unknown user", async () => { - await request - .post("/auth/login") - .set('Content-Type', 'application/json') - .send( - Object.assign({}, user, {email: "hackerman@perdu.com"}) - ) - .expect(401); - }); - - it("POST /register : Cannot register same user twice (or more)", async () => { - await request - .post("/auth/register") - .set('Content-Type', 'application/json') - .send(Object.assign({}, user, {fullName: userName})) - .expect(409); - }); - - it("POST /auth/verify : Expired token", async () => { - // this JWT token is at least expired from 23/04/2020 (fetched from my browser) - const tokenParts = [ - "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9", - "eyJpZCI6MSwiaWF0IjoxNTg3NDk3NjI3LCJleHAiOjE1ODc1MDEyMjd9", - "3bbBZwSlxRbJ4tFAcv3viae43nnSaKDm40kzXcQmY0M" - ]; - const tokenExpired = tokenParts.join("."); - let response = await request - .post("/auth/verify") - .set('Content-Type', 'application/json') - .send({ - token: tokenExpired - }); - expect(response.status).not.toBe(200); - }); - - it("PUT /api/tags : A simple user cannot modify a tag", async () => { - await request - .put("/api/tags") - .set('Content-Type', 'application/json') - .set('Authorization', 'bearer ' + JWT_TOKEN_2) - .send({ - "tag_id": 0, - "tag_text": "SomeTest", - "category_id": 0, - "state": "NOT_VALIDATED", - "version": 0 - }) - .expect(403); - }); - - it("PUT /api/tags_categories : A simple user cannot modify a tag category", async () => { - await request - .put("/api/tags_categories") - .set('Content-Type', 'application/json') - .set('Authorization', 'bearer ' + JWT_TOKEN_2) - .send({ - id: 42, - category: "HACKERMAN" - }) - .expect(403); - }); - - it("PUT /api/exercises/{id} : Required an account", async () => { - await request - .put("/api/exercises/42") - .set('Content-Type', 'application/json') - .send({ - "title": "A Super Exercise", - "description": "...", - "tags": [ - 0, 1, 2 - ], - "url": "https://inginious.info.ucl.ac.be/course/LEPL1402/Streams", - "version": 42 - }) - .expect(401); - }); - - it("PUT /auth/update : An simple user cannot become an admin", async () => { - await request - .put("/auth/update") - .set('Content-Type', 'application/json') - .set('Authorization', 'bearer ' + JWT_TOKEN_2) - .send({ - "fullName": "HACKERMAN", - "password": "42", - "role": "admin", - }) - .expect(403); - }); - - it("POST /api/create_exercise : An simple user cannot insert a exercise with forbidden state", async () => { - // creates one exercise - const some_exercise_data = { - "title": "HELLO WORLD", - "description": "Some verrrrrrrrrry long description here", - tags: ["SOME_TAG1", "SOME_TAG2", "SOME_TAG3"].map(text => ({ - text: text, - category_id: 42 - })), - "state": "VALIDATED" - }; - let responseTemp = await request - .post("/api/create_exercise") - .set('Authorization', 'bearer ' + JWT_TOKEN_2) - .set('Content-Type', 'application/json') - .send(some_exercise_data); - expect(responseTemp.status).toBe(403); - }); - - it("POST /api/create_exercise : An simple user cannot insert a exercise with tags state", async () => { - // creates one exercise - const some_exercise_data = { - "title": "HELLO WORLD", - "description": "Some verrrrrrrrrry long description here", - tags: ["SOME_TAG1", "SOME_TAG2", "SOME_TAG3"].map(text => ({ - text: text, - category_id: 42, - state: "VALIDATED" - })) - }; - let responseTemp = await request - .post("/api/create_exercise") - .set('Authorization', 'bearer ' + JWT_TOKEN_2) - .set('Content-Type', 'application/json') - .send(some_exercise_data); - expect(responseTemp.status).toBe(403); - }); - - it("POST /api/ : Cannot create/update an exercise with not expected validated tag count", async () => { - // creates one exercise with 2 - const title = "HELLO WORLD"; - const some_exercise_data = { - "title": title, - "description": "Some verrrrrrrrrry long description here", - tags: [1, 2, {"text": "lol", "category_id": 1}] - }; - let responseTemp = await request - .post("/api/create_exercise") - .set('Authorization', 'bearer ' + JWT_TOKEN) - .set('Content-Type', 'application/json') - .send(some_exercise_data); - expect(responseTemp.status).toBe(400); - }); - - it("POST /api/bulk/create_tags : Simple user cannot create a validated tag", async () => { - // creates some tags categories - let response = await request - .post("/api/bulk/create_tags") - .set('Authorization', 'bearer ' + JWT_TOKEN_2) - .set('Content-Type', 'application/json') - .send( - ["TROLL"].map(tag => ({ - text: tag, - category_id: 1, - state: "VALIDATED" - })) - ); - expect(response.status).toBe(403); - }); -}); - -// utilities functions -// to fetch exercise(s) -// if expected_count is equal to -1, we should skip a test -async function search_exercise(expected_count, search_criteria) { - const response = await request - .post("/api/search") - .set('Content-Type', 'application/json') - .set('Accept', 'application/json') - .send(search_criteria); - - expect(response.status).toBe(200); - - expect(isObject(response.body)).toBeTruthy(); - expect(Array.isArray(response.body.data)).toBeTruthy(); - if (expected_count !== -1) { - expect(response.body.metadata.totalItems).toBe(expected_count); - } - expect(response.body.data).toHaveLength(response.body.metadata.totalItems); - return response.body; -} - -// to prepare a supertest instance with -function multiple_upload_with_files_request(exercises, files) { - - // build the request now - let requestInstance = request - .post("/api/bulk/create_exercises") - .set('Authorization', 'bearer ' + JWT_TOKEN); - - // Add all given files - for (const file of files) { - requestInstance.attach("files", file.path) - } - - // Add the mapping between exercises and files - files.forEach((file, index) => { - const sub_field = "filesMapping[" + index + "]"; - requestInstance.field(sub_field + "[filename]", file.filename); - requestInstance.field(sub_field + "[exercise]", file.exercise); - }); - - // Add the exercises metadata - exercises.forEach((exercise, index) => { - - // since tags are more complicated to deal with, I must handle them separately - const exercise_tags = exercise.tags; - delete exercise.tags; - - const sub_field = "exercisesData[" + index + "]"; - - // for other properties of exercise, it is pretty easy to handle them - Object.entries(exercise).forEach(([key, value]) => { - requestInstance.field(sub_field + "[" + key + "]", value); - }); - - // for tags, we have to use this ugly way because of supertest - const sub_tag_field = sub_field + "[tags]"; - - exercise_tags.forEach((tag, index) => { - const sub_tag_field_index = sub_tag_field + "[" + index + "]"; - Object.entries(tag).forEach(([key, value]) => { - requestInstance.field(sub_tag_field_index + "[" + key + "]", value); - }); - }); - }); - - return requestInstance; -} diff --git a/tests/file.zip b/tests/file.zip deleted file mode 100644 index fb3b614..0000000 Binary files a/tests/file.zip and /dev/null differ diff --git a/tests/file2.zip b/tests/file2.zip deleted file mode 100644 index fb3b614..0000000 Binary files a/tests/file2.zip and /dev/null differ