diff --git a/.dockerignore b/.dockerignore index 57189ad6..fe1fa8c9 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1 +1,2 @@ -datasets/* \ No newline at end of file +datasets/* +models/* \ No newline at end of file diff --git a/.gitignore b/.gitignore index 4598ae83..bb5431d3 100644 --- a/.gitignore +++ b/.gitignore @@ -9,4 +9,5 @@ __pycache__ dist/* !dist/.gitkeep -docs/.vuepress/dist/* \ No newline at end of file +docs/.vuepress/dist/* +models/*.h5 \ No newline at end of file diff --git a/.travis.yml b/.travis.yml index 4f436e95..4196ba16 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,21 +12,19 @@ matrix: - TESTING=true - LOGIN_DISABLED=true before_script: + - pip install -r backend/requirements.txt - pip install pycocotools - docker run -d -p 27017:27017 mongo - docker ps -a script: pytest - - - language: node_js - node_js: - - 8 - - node - cache: npm - before_install: - - npm install -g npm@latest - - cd client - install: - - npm i - script: npm test - - + # - language: node_js + # node_js: + # - 8 + # - node + # cache: npm + # before_install: + # - npm install -g npm@latest + # - cd client + # install: + # - npm i + # script: npm test diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 00000000..45fc542d --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,146 @@ +# Contributing to HTML5 Boilerplate + +Love [COCO Annotator](/jsbroks/coco-annotator) and want to get involved? +Thanks! We're actively looking for folks interested in helping out and there +are plenty of ways you can help! + +Please take a moment to review this document in order to make the contribution +process easy and effective for everyone involved. + +Following these guidelines helps to communicate that you respect the time of +the developers managing and developing this open source project. In return, +they should reciprocate that respect in addressing your issue or assessing +patches and features. + + +## Using the issue tracker + +The [issue tracker](/jsbroks/coco-annotator/issues) is +the preferred channel for [bug reports](#bugs), [features requests](#features) +and [submitting pull requests](#pull-requests), but please respect the following +restrictions: + +* Please **do not** use the issue tracker for personal support requests (use + [Stack Overflow](https://stackoverflow.com/questions/tagged/coco-annotator)). + +* Please **do not** derail or troll issues. Keep the discussion on topic and + respect the opinions of others. + + +## Bug reports + +A bug is a _demonstrable problem_ that is caused by the code in the repository. +Good bug reports are extremely helpful - thank you! + +Guidelines for bug reports: + +1. **Use the GitHub issue search** — check if the issue has already been + reported. + +2. **Check if the issue has been fixed** — try to reproduce it using the + latest `master` or development branch in the repository. + +3. **Isolate the problem** — ideally create a [reduced test + case](https://css-tricks.com/reduced-test-cases/) and a live example. + +A good bug report shouldn't leave others needing to chase you up for more +information. Please try to be as detailed as possible in your report. What is +your environment? What steps will reproduce the issue? What browser(s) and OS +experience the problem? What would you expect to be the outcome? All these +details will help people to fix any potential bugs. + +Example: + +> Short and descriptive example bug report title +> +> A summary of the issue and the browser/OS environment in which it occurs. If +> suitable, include the steps required to reproduce the bug. +> +> 1. This is the first step +> 2. This is the second step +> 3. Further steps, etc. +> +> `` - a link to the reduced test case +> +> Any other information you want to share that is relevant to the issue being +> reported. This might include the lines of code that you have identified as +> causing the bug, and potential solutions (and your opinions on their +> merits). + + + +## Feature requests + +Feature requests are welcome. But take a moment to find out whether your idea +fits with the scope and aims of the project. It's up to *you* to make a strong +case to convince the project's developers of the merits of this feature. Please +provide as much detail and context as possible. + + + +## Pull requests + +Good pull requests - patches, improvements, new features - are a fantastic +help. They should remain focused in scope and avoid containing unrelated +commits. + +**Please ask first** before embarking on any significant pull request (e.g. +implementing features, refactoring code, porting to a different language), +otherwise you risk spending a lot of time working on something that the +project's developers might not want to merge into the project. + +Please adhere to the coding conventions used throughout a project (indentation, +accurate comments, etc.) and any other requirements (such as test coverage). + +Adhering to the following process is the best way to get your work +included in the project: + +1. [Fork](https://help.github.com/articles/fork-a-repo/) the project, clone your + fork, and configure the remotes: + + ```bash + # Clone your fork of the repo into the current directory + git clone https://github.com//html5-boilerplate.git + # Navigate to the newly cloned directory + cd html5-boilerplate + # Assign the original repo to a remote called "upstream" + git remote add upstream https://github.com/h5bp/html5-boilerplate.git + ``` + +2. If you cloned a while ago, get the latest changes from upstream: + + ```bash + git checkout master + git pull upstream master + ``` + +3. Create a new topic branch (off the main project development branch) to + contain your feature, change, or fix: + + ```bash + git checkout -b + ``` + +4. Commit your changes in logical chunks. Please adhere to these [git commit + message guidelines](https://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html) + or your code is unlikely be merged into the main project. Use Git's + [interactive rebase](https://help.github.com/articles/about-git-rebase/) + feature to tidy up your commits before making them public. + +5. Locally merge (or rebase) the upstream development branch into your topic branch: + + ```bash + git pull [--rebase] upstream master + ``` + +6. Push your topic branch up to your fork: + + ```bash + git push origin + ``` + +7. [Open a Pull Request](https://help.github.com/articles/using-pull-requests/) + with a clear title and description. + +**IMPORTANT**: By submitting a patch, you agree to allow the project +owners to license your work under the terms of the [MIT License](LICENSE.txt). diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 00000000..325ee79b --- /dev/null +++ b/Dockerfile @@ -0,0 +1,30 @@ +FROM node:10 as build-stage + +WORKDIR /workspace/ +COPY ./client /workspace/client + +RUN npm install -g @vue/cli@3.3.0 +RUN npm install -g @vue/cli-service@3.3.0 + +COPY ./client/package* /workspace/ + +RUN npm install +ENV NODE_PATH=/workspace/node_modules + +WORKDIR /workspace/client +RUN npm run build + +FROM jsbroks/coco-annotator:python-env + +WORKDIR /workspace/ +COPY ./backend/ /workspace/ +COPY ./.git /workspace/.git +RUN python set_path.py + +COPY --from=build-stage /workspace/client/dist /workspace/dist + +ENV FLASK_ENV=production +ENV DEBUG=false + +EXPOSE 5000 +CMD gunicorn -c webserver/gunicorn_config.py webserver:app --no-sendfile --timeout 180 diff --git a/README.md b/README.md index cb847f4d..4c43c887 100644 --- a/README.md +++ b/README.md @@ -3,67 +3,140 @@

FeaturesWiki • - Getting Stated • + Getting StartedIssuesLicense

- --- +

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

+ +COCO Annotator is a web-based image annotation tool designed for versatility and efficiently label images to create training data for image localization and object detection. It provides many distinct features including the ability to label an image segment (or part of a segment), track object instances, labeling objects with disconnected visible parts, efficiently storing and export annotations in the well-known [COCO format](http://cocodataset.org/#format-data). The annotation process is delivered through an intuitive and customizable interface and provides many tools for creating accurate datasets. -[![GitHub Stars](https://img.shields.io/github/stars/jsbroks/coco-annotator.svg)](https://github.com/jsbroks/coco-annotator/stargazers) -[![GitHub Issues](https://img.shields.io/github/issues/jsbroks/coco-annotator.svg)](https://github.com/jsbroks/coco-annotator/issues) -![GitHub](https://img.shields.io/github/license/mashape/apistatus.svg) -[![Code Quality](https://img.shields.io/lgtm/grade/javascript/g/jsbroks/coco-annotator.svg?label=code%20quality)](https://lgtm.com/projects/g/jsbroks/coco-annotator/context:javascript) -[![Demo](https://img.shields.io/badge/demo-online-green.svg)](https://annotator.justinbrooks.ca/) -[![Build Status](https://travis-ci.org/jsbroks/coco-annotator.svg?branch=master)](https://travis-ci.org/jsbroks/coco-annotator) -[![Docker Pulls](https://img.shields.io/docker/pulls/jsbroks/coco-annotator.svg)](https://hub.docker.com/r/jsbroks/coco-annotator) -COCO Annotator is a web-based image annotation tool designed for versatility and efficiently label images to create training data for image localization and object detection. It provides many distinct features including the ability to label an image segment (or part of a segment), track object instances, labeling objects with disconnected visible parts, efficiently storing and export annotations in the well-know [COCO format](http://cocodataset.org/#format-data). The annotation process is delivered though an intuitive and customizable interface and provides many tools for creating accurate datasets. +
+ +

Join our growing discord community of ML practitioner

+

+ + + +

+ +
+ +

+

Checkout the video for a basic guide on installing and using COCO Annotator.

+ +

Note: This video is from v0.1.0 and many new features have been added.

+ +
+ +

If you enjoy my work please consider supporting me

+

+ + + +

+
+ # Features Several annotation tools are currently available, with most applications as a desktop installation. Once installed, users can manually define regions in an image and creating a textual description. Generally, objects can be marked by a bounding box, either directly, through a masking tool, or by marking points to define the containing area. _COCO Annotator_ allows users to annotate images using free-form curves or polygons and provides many additional features were other annotations tool fall short. - - Directly export to COCO format - - Segmentation of objects - - Useful API endpoints to analyze data - - Import datasets already annotated in COCO format - - Annotated disconnected objects as a single instance - - Labeling image segments with any number of labels simultaneously - - Allow custom metadata for each instance or object - - Magic wand/select tool - - Generate datasets using google images - - User authenication system +- Directly export to COCO format +- Segmentation of objects +- Ability to add key points +- Useful API endpoints to analyze data +- Import datasets already annotated in COCO format +- Annotate disconnect objects as a single instance +- Labeling image segments with any number of labels simultaneously +- Allow custom metadata for each instance or object +- Advanced selection tools such as, [DEXTR](https://github.com/jsbroks/dextr-keras), [MaskRCNN](https://github.com/matterport/Mask_RCNN) and Magic Wand +- Annotate images with semi-trained models +- Generate datasets using google images +- User authentication system For examples and more information check out the [wiki](https://github.com/jsbroks/coco-annotator/wiki). # Demo -| Login Information | -| ----------------- | -| __Username:__ admin | -| __Password:__ password | +| Login Information | +| ---------------------- | +| **Username:** admin | +| **Password:** password | https://annotator.justinbrooks.ca/ # Backers -

-

Backed by the The Robotics Institute @ Guelph (GitHub)

+If you enjoy the development of coco-annotator or are looking for an enterprise annotation tool, consider checking out DataTorch. + +

+ + + +

+ https://datatorch.io · support@datatorch.io · Next generation of coco-annotator +

+

# Built With Thanks to all these wonderful libaries/frameworks: - - [Flask](http://flask.pocoo.org/) - Python web microframework - - [Vue](https://vuejs.org/) - Frontend javascript framework - - [Axios](https://github.com/axios/axios) - Promise based HTTP client - - [PaperJS](http://paperjs.org/) - Canvas editor library - - [Bootstrap](https://getbootstrap.com/) - Frontend component library + +### Backend + +- [Flask](http://flask.pocoo.org/) - Python web microframework +- [MongoDB](https://www.mongodb.com/) - Cross-platform document-oriented database +- [MongoEngine](http://mongoengine.org/) - Python object data mapper for MongoDB + +### Frontend + +- [Vue](https://vuejs.org/) - JavaScript framework for building user interfaces +- [Axios](https://github.com/axios/axios) - Promise based HTTP client +- [PaperJS](http://paperjs.org/) - HTML canvas vector graphics library +- [Bootstrap](https://getbootstrap.com/) - Frontend component library # License + [MIT](https://tldrlegal.com/license/mit-license) + +# Citation + +``` + @MISC{cocoannotator, + author = {Justin Brooks}, + title = {{COCO Annotator}}, + howpublished = "\url{https://github.com/jsbroks/coco-annotator/}", + year = {2019}, + } +``` diff --git a/app/api/annotations.py b/app/api/annotations.py deleted file mode 100644 index 8b7cde36..00000000 --- a/app/api/annotations.py +++ /dev/null @@ -1,77 +0,0 @@ -from flask_restplus import Namespace, Resource, reqparse -from flask_login import login_required, current_user - -from ..models import AnnotationModel -from ..util import query_util, color_util - -import datetime - -api = Namespace('annotation', description='Annotation related operations') - -create_annotation = reqparse.RequestParser() -create_annotation.add_argument('image_id', type=int, required=True, location='json') -create_annotation.add_argument('category_id', type=int, location='json') -create_annotation.add_argument('metadata', type=dict, location='json') -create_annotation.add_argument('color', location='json') - - -@api.route('/') -class Annotation(Resource): - - @login_required - def get(self): - """ Returns all annotations """ - return query_util.fix_ids(current_user.annotations.exclude("paper_object").all()) - - @api.expect(create_annotation) - @login_required - def post(self): - """ Creates an annotation """ - args = create_annotation.parse_args() - image_id = args.get('image_id') - category_id = args.get('category_id') - metadata = args.get('metadata', {}) - color = args.get('color') - - try: - annotation = AnnotationModel(image_id=image_id, category_id=category_id, metadata=metadata) - annotation.color = color_util.random_color_hex() if color is None else color - annotation.save() - except (ValueError, TypeError) as e: - return {'message': str(e)}, 400 - - return query_util.fix_ids(annotation) - - -@api.route('/') -class AnnotationId(Resource): - - @login_required - def get(self, annotation_id): - """ Returns annotation by ID """ - annotation = current_user.annotations.filter(id=annotation_id).first() - - if annotation is None: - return {"message": "Invalid annotation id"}, 400 - - return query_util.fix_ids(annotation) - - @login_required - def delete(self, annotation_id): - """ Deletes an annotation by ID """ - annotation = current_user.annotations.filter(id=annotation_id).first() - - if annotation is None: - return {"message": "Invalid annotation id"}, 400 - - annotation.update(set__deleted=True, set__deleted_date=datetime.datetime.now()) - return {'success': True} - - -# @api.route('//mask') -# class AnnotationMask(Resource): -# def get(self, annotation_id): -# """ Returns the binary mask of an annotation """ -# return query_util.fix_ids(AnnotationModel.objects(id=annotation_id).first()) - - diff --git a/app/api/categories.py b/app/api/categories.py deleted file mode 100644 index 56c54142..00000000 --- a/app/api/categories.py +++ /dev/null @@ -1,102 +0,0 @@ -from flask_restplus import Namespace, Resource, reqparse -from flask_login import login_required, current_user - -from ..util.pagination_util import Pagination -from ..util import query_util, color_util -from ..models import CategoryModel, AnnotationModel - -import datetime - -api = Namespace('category', description='Category related operations') - -create_category = reqparse.RequestParser() -create_category.add_argument('name', required=True, location='json') -create_category.add_argument('supercategory', location='json') -create_category.add_argument('color', location='json') -create_category.add_argument('metadata', type=dict, location='json') - -page_data = reqparse.RequestParser() -page_data.add_argument('page', default=1, type=int) -page_data.add_argument('limit', default=20, type=int) - - -@api.route('/') -class Category(Resource): - - @login_required - def get(self): - """ Returns all categories """ - return query_util.fix_ids(current_user.categories.all()) - - @api.expect(create_category) - @login_required - def post(self): - """ Creates a category """ - args = create_category.parse_args() - name = args.get('name') - supercategory = args.get('supercategory') - metadata = args.get('metadata', {}) - color = args.get('color') - - try: - category = CategoryModel( - name=name, - supercategory=supercategory, - color=color, - metadata=metadata - ) - category.save() - except (ValueError, TypeError) as e: - return {'message': str(e)}, 400 - - return query_util.fix_ids(category) - - -@api.route('/') -class Category(Resource): - - @login_required - def get(self, category_id): - """ Returns a category by ID """ - category = current_user.categories.filter(id=category_id).first() - - if category is None: - return {'success': False}, 400 - - return query_util.fix_ids(category) - - @login_required - def delete(self, category_id): - """ Deletes a category by ID """ - category = current_user.categories.filter(id=category_id).first() - if category is None: - return {"message": "Invalid image id"}, 400 - - category.update(set__deleted=True, set__deleted_date=datetime.datetime.now()) - return {'success': True} - - -@api.route('/data') -class CategoriesData(Resource): - - @api.expect(page_data) - @login_required - def get(self): - """ Endpoint called by category viewer client """ - args = page_data.parse_args() - limit = args['limit'] - page = args['page'] - - categories = current_user.categories.filter(deleted=False) - - pagination = Pagination(categories.count(), limit, page) - categories = query_util.fix_ids(categories[pagination.start:pagination.end]) - - for category in categories: - category['numberAnnotations'] = AnnotationModel.objects(deleted=False, category_id=category.get('id')).count() - - return { - "pagination": pagination.export(), - "page": page, - "categories": categories - } diff --git a/app/api/datasets.py b/app/api/datasets.py deleted file mode 100644 index fc65f833..00000000 --- a/app/api/datasets.py +++ /dev/null @@ -1,393 +0,0 @@ -from flask_restplus import Namespace, Resource, reqparse -from flask_login import login_required, current_user -from werkzeug.datastructures import FileStorage -from mongoengine.errors import NotUniqueError -from threading import Thread - -from google_images_download import google_images_download as gid - -from ..util.pagination_util import Pagination -from ..util import query_util, coco_util -from ..models import * - - -import datetime -import json -import os - -api = Namespace('dataset', description='Dataset related operations') - - -dataset_create = reqparse.RequestParser() -dataset_create.add_argument('name', required=True) -dataset_create.add_argument('categories', type=list, required=False, location='json', - help="List of default categories for sub images") - -page_data = reqparse.RequestParser() -page_data.add_argument('page', default=1, type=int) -page_data.add_argument('limit', default=20, type=int) -page_data.add_argument('folder', required=False, default='', help='Folder for data') - -delete_data = reqparse.RequestParser() -delete_data.add_argument('fully', default=False, type=bool, - help="Fully delete dataset (no undo)") - -coco_upload = reqparse.RequestParser() -coco_upload.add_argument('coco', location='files', type=FileStorage, required=True, help='Json coco') - - -update_dataset = reqparse.RequestParser() -update_dataset.add_argument('categories', location='json', type=list, help="New list of categories") -update_dataset.add_argument('default_annotation_metadata', location='json', type=dict, - help="Default annotation metadata") - -dataset_generate = reqparse.RequestParser() -dataset_generate.add_argument('keywords', location='json', type=list, default=[], - help="Keywords associated with images") -dataset_generate.add_argument('limit', location='json', type=int, default=100, help="Number of images per keyword") - -share = reqparse.RequestParser() -share.add_argument('users', location='json', type=list, default=[], help="List of users") - - -@api.route('/') -class Dataset(Resource): - @login_required - def get(self): - """ Returns all datasets """ - return query_util.fix_ids(current_user.datasets.filter(deleted=False).all()) - - @api.expect(dataset_create) - @login_required - def post(self): - """ Creates a dataset """ - args = dataset_create.parse_args() - name = args['name'] - categories = args.get('categories', []) - - category_ids = CategoryModel.bulk_create(categories) - - try: - dataset = DatasetModel(name=name, categories=category_ids) - dataset.save() - except NotUniqueError: - return {'message': 'Dataset already exists. Check the undo tab to fully delete the dataset.'}, 400 - - return query_util.fix_ids(dataset) - - -def download_images(output_dir, args): - for keyword in args['keywords']: - response = gid.googleimagesdownload() - response.download({ - "keywords": keyword, - "limit": args['limit'], - "output_directory": output_dir, - "no_numbering": True, - "format": "jpg", - "type": "photo", - "print_urls": False, - "print_paths": False, - "print_size": False - }) - - -@api.route('//generate') -class DatasetGenerate(Resource): - @api.expect(dataset_generate) - @login_required - def post(self, dataset_id): - """ Adds images found on google to the dataset """ - args = dataset_generate.parse_args() - - dataset = current_user.datasets.filter(id=dataset_id, deleted=False).first() - if dataset is None: - return {"message": "Invalid dataset id"}, 400 - - thread = Thread(target=download_images, args=(dataset.directory, args)) - thread.start() - - return {"success": True} - - -@api.route('/') -class DatasetId(Resource): - @login_required - def delete(self, dataset_id): - """ Deletes dataset by ID (only owners of datasets can delete them)""" - - datasets = DatasetModel.objects(id=dataset_id, deleted=False) - if not current_user.is_admin: - datasets = datasets.filter(owner=current_user.username) - - dataset = datasets.first() - - if dataset is None: - return {"message": "Invalid dataset id"}, 400 - - dataset.update(set__deleted=True, set__deleted_date=datetime.datetime.now()) - return {"success": True} - - @api.expect(update_dataset) - def post(self, dataset_id): - """ Updates dataset by ID """ - dataset = current_user.datasets.filter(id=dataset_id, deleted=False).first() - if dataset is None: - return {"message": "Invalid dataset id"}, 400 - - args = update_dataset.parse_args() - categories = args.get('categories') - default_annotation_metadata = args.get('default_annotation_metadata') - - if categories is not None: - dataset.categories = CategoryModel.bulk_create(categories) - - if default_annotation_metadata is not None: - dataset.default_annotation_metadata = default_annotation_metadata - - dataset.update( - categories=dataset.categories, - default_annotation_metadata=dataset.default_annotation_metadata - ) - - return {"success": True} - - -@api.route('//share') -class DatasetIdShare(Resource): - @api.expect(share) - @login_required - def post(self, dataset_id): - args = share.parse_args() - - dataset = current_user.datasets.filter(id=dataset_id, deleted=False).first() - if dataset is None: - return {"message": "Invalid dataset id"}, 400 - - dataset.update(users=args.get('users')) - - return {"success": True} - - -@api.route('/data') -class Dataset(Resource): - @api.expect(page_data) - @login_required - def get(self): - """ Endpoint called by dataset viewer client """ - - args = page_data.parse_args() - limit = args['limit'] - page = args['page'] - folder = args['folder'] - - datasets = current_user.datasets.filter(deleted=False) - pagination = Pagination(datasets.count(), limit, page) - datasets = query_util.fix_ids(datasets[pagination.start:pagination.end]) - - for dataset in datasets: - images = ImageModel.objects(dataset_id=dataset.get('id'), deleted=False) - - dataset['numberImages'] = images.count() - dataset['numberAnnotated'] = images.filter(annotated=True).count() - - first = images.first() - if first is not None: - dataset['first_image_id'] = images.first().id - - return { - "pagination": pagination.export(), - "folder": folder, - "datasets": datasets, - "categories": query_util.fix_ids(current_user.categories.filter(deleted=False).all()) - } - - -@api.route('//data') -class DatasetDataId(Resource): - - @api.expect(page_data) - @login_required - def get(self, dataset_id): - """ Endpoint called by image viewer client """ - - exec_start = datetime.datetime.now() - args = page_data.parse_args() - limit = args['limit'] - page = args['page'] - folder = args['folder'] - - # Check if dataset exists - dataset = current_user.datasets.filter(id=dataset_id, deleted=False).first() - if dataset is None: - return {'message', 'Invalid dataset id'}, 400 - - # Make sure folder starts with is in proper format - if len(folder) > 0: - folder = folder[0].strip('/') + folder[1:] - if folder[-1] != '/': - folder = folder + '/' - - # Get directory - directory = os.path.join(dataset.directory, folder) - if not os.path.exists(directory): - return {'message': 'Directory does not exist.'}, 400 - - images = ImageModel.objects(dataset_id=dataset_id, path__startswith=directory, deleted=False) \ - .order_by('file_name').only('id', 'file_name') - - pagination = Pagination(images.count(), limit, page) - images = query_util.fix_ids(images[pagination.start:pagination.end]) - - for image in images: - image_id = image.get('id') - image['annotations'] = AnnotationModel.objects(image_id=image_id, deleted=False).count() - - subdirectories = [f for f in sorted(os.listdir(directory)) - if os.path.isdir(directory + f)] - - delta = datetime.datetime.now() - exec_start - return { - "time_ms": int(delta.total_seconds() * 1000), - "pagination": pagination.export(), - "images": images, - "folder": folder, - "directory": directory, - "dataset": query_util.fix_ids(dataset), - "subdirectories": subdirectories - } - - -@api.route('//coco') -class ImageCoco(Resource): - - @login_required - def get(self, dataset_id): - """ Returns coco of images and annotations in the dataset """ - - dataset = current_user.datasets.filter(id=dataset_id).first() - - if dataset is None: - return {"message": "Invalid dataset ID"}, 400 - - return coco_util.get_dataset_coco(dataset) - - @api.expect(coco_upload) - @login_required - def post(self, dataset_id): - """ Adds coco formatted annotations to the dataset """ - args = coco_upload.parse_args() - coco = args['coco'] - - dataset = current_user.datasets.filter(id=dataset_id).first() - images = ImageModel.objects(dataset_id=dataset_id) - categories = CategoryModel.objects - - if dataset is None: - return {'message': 'Invalid dataset ID'}, 400 - - coco_json = json.load(coco) - coco_images = coco_json.get('images') - coco_annotations = coco_json.get('annotations') - coco_categories = coco_json.get('categories') - - errors = [] - - categories_id = {} - images_id = {} - - # Create any missing categories - for category in coco_categories: - category_name = category.get('name') - print("Loading category {}".format(category_name), flush=True) - - category_id = category.get('id') - category_model = categories.filter(name__exact=category_name).all() - - if len(category_model) == 0: - errors.append({'category': category_name, - 'message': 'Creating category ' + category_name + '.'}) - - new_category = CategoryModel(name=category_name, color=color_util.random_color_hex()) - new_category.save() - categories_id[category_id] = new_category.id - print("Category not found! (Creating new one)", flush=True) - continue - - if len(category_model) > 1: - errors.append({'category': category_name, - 'message': 'To many categories found with file name.'}) - continue - - category_model = category_model[0] - categories_id[category_id] = category_model.id - - # Add any new categories to dataset - for key, value in categories_id.items(): - if value not in dataset.categories: - dataset.categories.append(value) - - dataset.update(set__categories=dataset.categories) - - # Find all images - for image in coco_images: - image_id = image.get('id') - image_filename = image.get('file_name') - - print("Loading image {}".format(image_filename), flush=True) - image_model = images.filter(file_name__exact=image_filename).all() - - if len(image_model) == 0: - errors.append({'file_name': image_filename, - 'message': 'Could not find image.'}) - continue - - if len(image_model) > 1: - errors.append({'file_name': image_filename, - 'message': 'To many images found with the same file name.'}) - continue - - image_model = image_model[0] - print("Image found", flush=True) - images_id[image_id] = image_model - - # Generate annotations - for annotation in coco_annotations: - image_id = annotation.get('image_id') - category_id = annotation.get('category_id') - segmentation = annotation.get('segmentation', []) - is_crowd = annotation.get('iscrowed', False) - - if len(segmentation) == 0: - continue - - print("Loading annotation data (image:{} category:{})".format(image_id, category_id), flush=True) - - try: - image_model = images_id[image_id] - category_model_id = categories_id[category_id] - except KeyError: - continue - - # Check if annotation already exists - annotation = AnnotationModel.objects(image_id=image_model.id, - category_id=category_model_id, - segmentation=segmentation, delete=False).first() - # Create annotation - if annotation is None: - print("Creating annotation", flush=True) - annotation = AnnotationModel(image_id=image_model.id) - annotation.category_id = category_model_id - # annotation.iscrowd = is_crowd - annotation.segmentation = segmentation - annotation.color = color_util.random_color_hex() - annotation.save() - - image_model.update(set__annotated=True) - else: - print("Annotation already exists", flush=True) - - return { - 'errors': errors - } - diff --git a/app/config.py b/app/config.py deleted file mode 100644 index aceaf763..00000000 --- a/app/config.py +++ /dev/null @@ -1,28 +0,0 @@ -import os - -from .util.version_util import get_tag - - -class Config: - - NAME = "COCO Annotator" - VERSION = get_tag() - - # Flask instance - SWAGGER_UI_JSONEDITOR = True - MAX_CONTENT_LENGTH = 1 * 1024 * 1024 * 1024 # 1GB - MONGODB_HOST = os.getenv("MONGODB_HOST", "mongodb://database/flask") - SECRET_KEY = os.getenv('SECRET_KEY', '<--- YOUR_SECRET_FORM_KEY --->') - - TESTING = os.getenv("TESTING", False) - - # Dataset Options - DATASET_DIRECTORY = os.getenv("DATASET_DIRECTORY", "/datasets/") - INITIALIZE_FROM_FILE = os.getenv("INITIALIZE_FROM_FILE") - LOAD_IMAGES_ON_START = os.getenv("LOAD_IMAGES_ON_START", False) - - # User Options - LOGIN_DISABLED = os.getenv('LOGIN_DISABLED', False) - ALLOW_REGISTRATION = True - - diff --git a/app/gunicorn_config.py b/app/gunicorn_config.py deleted file mode 100644 index b2a64ad5..00000000 --- a/app/gunicorn_config.py +++ /dev/null @@ -1,53 +0,0 @@ -import os - - -def on_starting(server): - """ - Attach a set of IDs that can be temporarily re-used. - Used on reloads when each worker exists twice. - """ - server._worker_id_overload = set() - - -def nworkers_changed(server, new_value, old_value): - """ - Gets called on startup too. - Set the current number of workers. Required if we raise the worker count - temporarily using TTIN because server.cfg.workers won't be updated and if - one of those workers dies, we wouldn't know the ids go that far. - """ - server._worker_id_current_workers = new_value - - -def _next_worker_id(server): - """ - If there are IDs open for re-use, take one. Else look for a free one. - """ - if server._worker_id_overload: - return server._worker_id_overload.pop() - - in_use = set(w._worker_id for w in server.WORKERS.values() if w.alive) - free = set(range(1, server._worker_id_current_workers + 1)) - in_use - - return free.pop() - - -def on_reload(server): - """ - Add a full set of ids into overload so it can be re-used once. - """ - server._worker_id_overload = set(range(1, server.cfg.workers + 1)) - - -def pre_fork(server, worker): - """ - Attach the next free worker_id before forking off. - """ - worker._worker_id = _next_worker_id(server) - - -def post_fork(server, worker): - """ - Put the worker_id into an env variable for further use within the app. - """ - os.environ["APP_WORKER_ID"] = str(worker._worker_id) \ No newline at end of file diff --git a/app/image_folder.py b/app/image_folder.py deleted file mode 100644 index f38c54e8..00000000 --- a/app/image_folder.py +++ /dev/null @@ -1,35 +0,0 @@ -from watchdog.events import FileSystemEventHandler - -from .models import ImageModel - - -class ImageFolderHandler(FileSystemEventHandler): - - def __init__(self, pattern=None): - self.pattern = pattern or (".gif", ".png", ".jpg", ".jpeg", ".bmp") - - def on_any_event(self, event): - - path = event.dest_path if event.event_type == "moved" else event.src_path - - # Check if thumbnails directory - folders = path.split('/') - i = folders.index("datasets") - if i+1 < len(folders) and folders[i+1] == "_thumbnails": - return - - if not event.is_directory and path.endswith(self.pattern): - - image = ImageModel.objects(path=event.src_path).first() - - if image is None and event.event_type != 'deleted': - print("Adding new file to database: {}".format(path), flush=True) - ImageModel.create_from_path(path).save() - - elif event.event_type == 'moved': - print("Moving image from {} to {}".format(event.src_path, path), flush=True) - image.update(path=path) - - elif event.event_type == 'deleted': - print("Deleting image from database: {}".format(path), flush=True) - ImageModel.objects(path=path).delete() diff --git a/app/models.py b/app/models.py deleted file mode 100644 index e0b0c3de..00000000 --- a/app/models.py +++ /dev/null @@ -1,375 +0,0 @@ -import os -import cv2 -import json -import datetime -import numpy as np - -from flask_mongoengine import MongoEngine -from mongoengine.queryset.visitor import Q -from flask_login import UserMixin, current_user - - -from .util import color_util -from .config import Config -from PIL import Image - - -db = MongoEngine() - - -class DatasetModel(db.DynamicDocument): - - id = db.SequenceField(primary_key=True) - name = db.StringField(required=True, unique=True) - directory = db.StringField() - categories = db.ListField(default=[]) - - owner = db.StringField(required=True) - users = db.ListField(default=[]) - - default_annotation_metadata = db.DictField(default={}) - - deleted = db.BooleanField(default=False) - deleted_date = db.DateTimeField() - - def save(self, *args, **kwargs): - - directory = os.path.join(Config.DATASET_DIRECTORY, self.name + '/') - - if not os.path.exists(directory): - os.makedirs(directory) - else: - ImageModel.load_images(directory, self.id) - - self.directory = directory - self.owner = current_user.username - - return super(DatasetModel, self).save(*args, **kwargs) - - -class ImageModel(db.DynamicDocument): - - PATTERN = (".gif", ".png", ".jpg", ".jpeg", ".bmp") - - id = db.SequenceField(primary_key=True) - path = db.StringField(required=True, unique=True) - - dataset_id = db.IntField() - - width = db.IntField(required=True) - height = db.IntField(required=True) - file_name = db.StringField() - - annotated = db.BooleanField(default=False) - - image_url = db.StringField() - thumbnail_url = db.StringField() - - category_ids = db.ListField(default=[]) - - metadata = db.DictField() - - license = db.IntField() - coco_url = db.StringField() - - deleted = db.BooleanField(default=False) - deleted_date = db.DateTimeField() - - @classmethod - def create_from_path(cls, path, dataset_id=None): - - pil_image = Image.open(path) - - image = cls() - image.file_name = os.path.basename(path) - image.path = path - image.width = pil_image.size[0] - image.height = pil_image.size[1] - - if dataset_id is not None: - image.dataset_id = dataset_id - else: - # Get dataset name from path - folders = path.split('/') - i = folders.index("datasets") - dataset_name = folders[i+1] - - dataset = DatasetModel.objects(name=dataset_name).first() - if dataset is not None: - image.dataset_id = dataset.id - - pil_image.close() - - return image - - @classmethod - def load_images(cls, directory, dataset_id=None): - print("Checking all images in dataset directory (may take a few minutes)") - for root, dirs, files in os.walk(directory): - for file in files: - path = os.path.join(root, file) - - if path.endswith(cls.PATTERN): - db_image = cls.objects(path=path).first() - - if db_image is None: - print("New file found: {}".format(path)) - cls.create_from_path(path, dataset_id).save() - - def thumbnail_path(self): - folders = self.path.split('/') - i = folders.index("datasets") - folders.insert(i+1, "_thumbnails") - - directory = '/'.join(folders[:-1]) - if not os.path.exists(directory): - os.makedirs(directory) - - return '/'.join(folders) - - def copy_annotations(self, annotations): - """ - Creates a copy of the annotations for this image - :param annotations: QuerySet of annotation models - :return: number of annotations - """ - annotations = annotations.filter(width=self.width, height=self.height, area__gt=0) - - for annotation in annotations: - clone = annotation.clone() - - clone.dataset_id = self.dataset_id - clone.image_id = self.id - - clone.save(copy=True) - - return annotations.count() - - -class AnnotationModel(db.DynamicDocument): - - id = db.SequenceField(primary_key=True) - image_id = db.IntField(required=True) - category_id = db.IntField(required=True) - dataset_id = db.IntField() - - segmentation = db.ListField(default=[]) - area = db.IntField(default=0) - bbox = db.ListField() - iscrowd = db.BooleanField(default=False) - - creator = db.StringField(required=True) - width = db.IntField() - height = db.IntField() - - color = db.StringField() - - metadata = db.DictField(default={}) - paper_object = db.ListField(default=[]) - - deleted = db.BooleanField(default=False) - deleted_date = db.DateTimeField() - - def __init__(self, image_id=None, **data): - - image = ImageModel.objects(id=image_id).first() - - if image is not None: - data['image_id'] = image_id - data['width'] = image.width - data['height'] = image.height - data['dataset_id'] = image.dataset_id - else: - raise ValueError("Invalid image id.") - - super(AnnotationModel, self).__init__(**data) - - def save(self, copy=False, *args, **kwargs): - - if not self.dataset_id and not copy: - dataset = DatasetModel.objects(id=self.dataset_id).first() - - if dataset is not None: - self.metadata = dataset.default_annotation_metadata.copy() - - if self.color is None: - self.color = color_util.random_color_hex() - - self.creator = current_user.username - return super(AnnotationModel, self).save(*args, **kwargs) - - def is_empty(self): - return len(self.segmentation) == 0 or self.area == 0 - - def mask(self): - """ Returns binary mask of annotation """ - mask = np.zeros((self.height, self.width)) - pts = [ - np.array(anno).reshape(-1, 2).round().astype(int) - for anno in self.segmentation - ] - mask = cv2.fillPoly(mask, pts, 1) - return mask - - def clone(self): - """ Creates a clone """ - create = json.loads(self.to_json()) - del create['_id'] - - return AnnotationModel(**create) - - -class CategoryModel(db.DynamicDocument): - - id = db.SequenceField(primary_key=True) - name = db.StringField(required=True, unique_with=['creator']) - supercategory = db.StringField(default="") - color = db.StringField(default=None) - metadata = db.DictField(default={}) - - creator = db.StringField(default="unknown") - deleted = db.BooleanField(default=False) - deleted_date = db.DateTimeField() - - @classmethod - def bulk_create(cls, categories): - - if not categories: - return [] - - category_ids = [] - for category in categories: - category_model = CategoryModel.objects(name=category).first() - - if category_model is None: - new_category = CategoryModel(name=category) - new_category.save() - category_ids.append(new_category.id) - else: - category_ids.append(category_model.id) - - return category_ids - - def save(self, *args, **kwargs): - - if not self.color: - self.color = color_util.random_color_hex() - - if current_user: - self.creator = current_user.username - - return super(CategoryModel, self).save(*args, **kwargs) - - -class LicenseModel(db.DynamicDocument): - id = db.SequenceField(primary_key=True) - name = db.StringField() - url = db.StringField() - - -class UserModel(db.DynamicDocument, UserMixin): - password = db.StringField(required=True) - username = db.StringField(max_length=25, required=True, unique=True) - email = db.StringField(max_length=30) - - name = db.StringField() - last_seen = db.DateTimeField() - - is_admin = db.BooleanField(default=False) - - preferences = db.DictField(default={}) - - def save(self, *args, **kwargs): - - self.last_seen = datetime.datetime.now() - - return super(UserModel, self).save(*args, **kwargs) - - @property - def datasets(self): - self._update_last_seen() - - if self.is_admin: - return DatasetModel.objects - - return DatasetModel.objects(Q(owner=self.username) | Q(users__contains=self.username)) - - @property - def categories(self): - self._update_last_seen() - - if self.is_admin: - return CategoryModel.objects - - dataset_ids = self.datasets.distinct('categories') - return CategoryModel.objects(Q(id__in=dataset_ids) | Q(creator=self.username)) - - @property - def images(self): - self._update_last_seen() - - if self.is_admin: - return ImageModel.objects - - dataset_ids = self.datasets.distinct('id') - return ImageModel.objects(dataset_id__in=dataset_ids) - - @property - def annotations(self): - self._update_last_seen() - - if self.is_admin: - return AnnotationModel.objects - - image_ids = self.images.distinct('id') - return AnnotationModel.objects(image_id__in=image_ids) - - def _update_last_seen(self): - self.update(last_seen=datetime.datetime.now()) - - -# https://github.com/MongoEngine/mongoengine/issues/1171 -# Use this methods until a solution is found -def upsert(model, query=None, update=None): - - if not update: - update = query - - if not query: - return None - - found = model.objects(**query) - - if found.first(): - return found.modify(new=True, **update) - - new_model = model(**update) - new_model.save() - - return new_model - - -def create_from_json(json_file): - - with open(json_file) as file: - - data_json = json.load(file) - for category in data_json.get('categories', []): - name = category.get('name') - if name is not None: - upsert(CategoryModel, query={"name": name}, update=category) - - for dataset_json in data_json.get('datasets', []): - name = dataset_json.get('name') - if name: - # map category names to ids; create as needed - category_ids = [] - for category in dataset_json.get('categories', []): - category_obj = {"name": category} - - category_model = upsert(CategoryModel, query=category_obj) - category_ids.append(category_model.id) - - dataset_json['categories'] = category_ids - upsert(DatasetModel, query={ "name": name}, update=dataset_json) - diff --git a/app/routes.py b/app/routes.py deleted file mode 100644 index 0ec48266..00000000 --- a/app/routes.py +++ /dev/null @@ -1,40 +0,0 @@ -# from flask import Blueprint, render_template - - -# client = Blueprint('client', __name__, static_folder='client') -# client = Blueprint('client', __name__, static_folder="../dist", template_folder="../dist") - - -# @client.route('/') -# def index(): -# return render_template('index.html') - - -# @client.route('/images/') -# @client.route('/datasets/') -# def index(dataset_id): -# return render_template('images.html') -# -# -# @client.route('/annotate/') -# @client.route('/editor/') -# def annotate(image_id): -# return render_template('annotator.html') -# -# -# @client.route('/datasets/') -# def datasets(): -# return render_template('datasets.html') -# -# -# @client.route('/categories/') -# def categories(): -# return render_template('categories.html') -# -# -# @client.route('/undo/') -# def undo(): -# return render_template('undo.html') - - - diff --git a/app/util/coco_util.py b/app/util/coco_util.py deleted file mode 100644 index 62e480eb..00000000 --- a/app/util/coco_util.py +++ /dev/null @@ -1,185 +0,0 @@ -import pycocotools.mask as mask - -from .query_util import fix_ids -from ..models import * - - -def paperjs_to_coco(image_width, image_height, paperjs): - """ - Given a paperjs CompoundPath, converts path into coco segmentation format based on children paths - - :param image_width: Width of Image - :param image_height: Height of Image - :param paperjs: paperjs CompoundPath in dict format - :return: segmentation, area, bbox - """ - assert image_width > 0 - assert image_height > 0 - assert len(paperjs) == 2 - - # Compute segmentation - # paperjs points are relative to the center, so we must shift them relative to the top left. - segments = [] - center = [image_width/2, image_height/2] - - if paperjs[0] == "Path": - compound_path = {"children": [paperjs]} - else: - compound_path = paperjs[1] - - children = compound_path.get('children', []) - - for child in children: - - child_segments = child[1].get('segments', []) - segments_to_add = [] - - for point in child_segments: - if len(point) != 2: - continue - - x = _fit(round(center[0] + point[0], 2), image_width, 0) - y = _fit(round(center[1] + point[1], 2), image_height, 0) - - segments_to_add.extend([x, y]) - - # Make sure shape is not all outside the image - if sum(segments_to_add) == 0: - continue - - num_widths = segments_to_add.count(image_width) - num_heights = segments_to_add.count(image_height) - if num_widths + num_heights == len(segments_to_add): - continue - - segments.append(segments_to_add) - - if len(segments) < 1: - return [], 0, [0, 0, 0, 0] - - # Convert into rle - rles = mask.frPyObjects(segments, image_height, image_width) - rle = mask.merge(rles) - - return segments, mask.area(rle), mask.toBbox(rle) - - -def get_annotations_iou(annotation_a, annotation_b): - """ - Computes the IOU between two annotation objects - """ - seg_a = list([list(part) for part in annotation_a.segmentation]) - seg_b = list([list(part) for part in annotation_b.segmentation]) - - rles_a = mask.frPyObjects( - seg_a, annotation_a.height, annotation_a.width) - - rles_b = mask.frPyObjects( - seg_b, annotation_b.height, annotation_b.width) - - ious = mask.iou(rles_a, rles_b, [0]) - return ious[0][0] - - -def get_image_coco(image): - """ - Generates coco for an image - - :param image: ImageModel - :return: Coco in dictionary format - """ - dataset = DatasetModel.objects(id=image.dataset_id).first() - image = fix_ids(image) - - bulk_categories = CategoryModel.objects(deleted=False) \ - .exclude('deleted_date').in_bulk(dataset.categories).items() - - categories = [] - annotations = [] - - for category in bulk_categories: - - category_annotations = AnnotationModel.objects( - deleted=False, category_id=category[1].id, image_id=image.get('id') - ).exclude('paper_object', 'deleted_date').all() - - if len(category_annotations) == 0: - continue - - for annotation in category_annotations: - annotation = fix_ids(annotation) - - if len(annotation.get('segmentation')) != 0: - del annotation['deleted'] - del annotation['paper_object'] - annotations.append(annotation) - - category = fix_ids(category[1]) - del category['deleted'] - categories.append(category) - - del image['deleted'] - - coco = { - "images": [image], - "categories": categories, - "annotations": annotations - } - - return coco - - -def get_dataset_coco(dataset): - """ - Generates coco for all images in dataset - - :param dataset: DatasetModel - :return: Coco in dictionary format - """ - - categories = CategoryModel.objects(deleted=False) \ - .exclude('deleted_date').in_bulk(dataset.categories).items() - - dataset = fix_ids(dataset) - - images = ImageModel.objects(deleted=False, dataset_id=dataset.get('id')).exclude('deleted_date') - all_annotations = AnnotationModel.objects(deleted=False).exclude('deleted_date', 'paper_object') - - coco = { - 'images': [], - 'categories': [], - 'annotations': [] - } - - for category in categories: - category = fix_ids(category[1]) - del category['deleted'] - coco.get('categories').append(category) - - for image in images: - annotations = all_annotations.filter(image_id=image.id) - if annotations.count() == 0: - continue - - annotations = fix_ids(annotations.all()) - - for annotation in annotations: - del annotation['deleted'] - coco.get('annotations').append(annotation) - - image = fix_ids(image) - del image['deleted'] - coco.get('images').append(image) - - return coco - - -def _fit(value, max_value, min_value): - - if value > max_value: - return max_value - - if value < min_value: - return min_value - - return value diff --git a/app/util/color_util.py b/app/util/color_util.py deleted file mode 100644 index 17ffe1bc..00000000 --- a/app/util/color_util.py +++ /dev/null @@ -1,29 +0,0 @@ -import random -import colorsys - - -def random_color_hls(hue=[0, 1], lightness=[0.35, 0.70], saturation=[0.60, 1]): - h = random.uniform(hue[0], hue[1]) - l = random.uniform(lightness[0], lightness[1]) - s = random.uniform(saturation[0], saturation[1]) - return h, l, s - - -def random_color_rgb(): - h, l, s = random_color_hls() - return [int(256*i) for i in colorsys.hls_to_rgb(h, l, s)] - - -def random_color_hex(): - rgb = random_color_rgb() - return '#%02x%02x%02x' % (rgb[0], rgb[1], rgb[2]) - - -def hex_to_rgb(h): - h = h.lstrip('#') - return tuple(int(h[i:i + 2], 16) for i in (0, 2, 4)) - - -def rgb_to_hsl(): - pass - diff --git a/app/util/query_util.py b/app/util/query_util.py deleted file mode 100644 index a88e5a46..00000000 --- a/app/util/query_util.py +++ /dev/null @@ -1,7 +0,0 @@ -import json - - -def fix_ids(objs): - objects_list = json.loads(objs.to_json().replace('\"_id\"', '\"id\"')) - return objects_list - diff --git a/app/util/thumbnail_util.py b/app/util/thumbnail_util.py deleted file mode 100644 index 60dc926b..00000000 --- a/app/util/thumbnail_util.py +++ /dev/null @@ -1,46 +0,0 @@ -import numpy as np - -from ..models import AnnotationModel -from .color_util import hex_to_rgb - -from PIL import Image - - -def apply_mask(image, mask, color, alpha=0.5): - """Apply the given mask to the image. - """ - for c in range(3): - image[:, :, c] = np.where(mask == 1, - image[:, :, c] * - (1 - alpha) + alpha * color[c] * 255, - image[:, :, c]) - return image - - -def generate_thumbnail(image_model, save=True): - - image = Image.open(image_model.path) - binary_image = np.array(image) - binary_image.setflags(write=True) - - annotations = AnnotationModel.objects(image_id=image_model.id, deleted=False).all() - - for annotation in annotations: - - if len(annotation.segmentation) == 0: - continue - - color = np.array(hex_to_rgb(annotation.color))/255 - binary_image = apply_mask(binary_image, annotation.mask(), color) - - image = Image.fromarray(binary_image) - - if save: - image.save(image_model.thumbnail_path()) - - return image - - - - - diff --git a/backend/Dockerfile b/backend/Dockerfile new file mode 100644 index 00000000..a30d67d4 --- /dev/null +++ b/backend/Dockerfile @@ -0,0 +1,27 @@ +# Backend environment docker image +FROM tensorflow/tensorflow:1.14.0-gpu-py3 + +RUN apt-get update +RUN apt-get install -y git + +WORKDIR /workspace/ + +# Copy backend +COPY ./backend/requirements.txt /workspace/ + +# Install python package dependices +RUN pip install -r requirements.txt && \ + pip install gunicorn[eventlet]==19.9.0 && \ + pip install pycocotools + +# Install maskrcnn +RUN git clone --single-branch --depth 1 https://github.com/matterport/Mask_RCNN.git /tmp/maskrcnn +#RUN cd /tmp/maskrcnn && pip install -r requirements.txt +RUN cd /tmp/maskrcnn && python3 setup.py install + +# Install DEXTR +RUN git clone --single --depth 1 https://github.com/jsbroks/dextr-keras.git /tmp/dextr && \ + cd /tmp/dextr && \ + python setup.py install + +RUN apt-get -y -o Dpkg::Options::="--force-confmiss" install --reinstall netbase diff --git a/backend/README.md b/backend/README.md new file mode 100644 index 00000000..1aad7b09 --- /dev/null +++ b/backend/README.md @@ -0,0 +1,9 @@ +# COCO Annotator Backend + +## Web Server + +## Workers + +## Database + +## Config diff --git a/backend/config/__init__.py b/backend/config/__init__.py new file mode 100644 index 00000000..d085c3a9 --- /dev/null +++ b/backend/config/__init__.py @@ -0,0 +1 @@ +from .config import * \ No newline at end of file diff --git a/backend/config/config.py b/backend/config/config.py new file mode 100644 index 00000000..8d27a2cc --- /dev/null +++ b/backend/config/config.py @@ -0,0 +1,73 @@ +import os +import subprocess + + +def get_tag(): + result = subprocess.run(["git", "describe", "--abbrev=0", "--tags"], stdout=subprocess.PIPE) + return str(result.stdout.decode("utf-8")).strip() + +def _get_bool(key, default_value): + if key in os.environ: + value = os.environ[key] + if value == 'True' or value == 'true' or value == '1': + return True + return False + return default_value + +class Config: + + NAME = os.getenv("NAME", "COCO Annotator") + VERSION = get_tag() + + ### File Watcher + FILE_WATCHER = os.getenv("FILE_WATCHER", False) + IGNORE_DIRECTORIES = ["_thumbnail", "_settings"] + + # Flask/Gunicorn + # + # LOG_LEVEL - The granularity of log output + # + # A string of "debug", "info", "warning", "error", "critical" + # + # WORKER_CONNECTIONS - limits the maximum number of simultaneous + # clients that a single process can handle. + # + # A positive integer generally set to around 1000. + # + # WORKER_TIMEOUT - If a worker does not notify the master process + # in this number of seconds it is killed and a new worker is + # spawned to replace it. + # + SWAGGER_UI_JSONEDITOR = True + DEBUG = os.getenv("DEBUG", 'false').lower() == 'true' + PRELOAD = False + + MAX_CONTENT_LENGTH = os.getenv("MAX_CONTENT_LENGTH", 1 * 1024 * 1024 * 1024) # 1GB + MONGODB_HOST = os.getenv("MONGODB_HOST", "mongodb://database/flask") + SECRET_KEY = os.getenv("SECRET_KEY", "<--- CHANGE THIS KEY --->") + + LOG_LEVEL = 'debug' + WORKER_CONNECTIONS = 1000 + + TESTING = os.getenv("TESTING", False) + + ### Workers + CELERY_BROKER_URL = os.getenv("CELERY_BROKER_URL", "amqp://user:password@messageq:5672//") + CELERY_RESULT_BACKEND = os.getenv("CELERY_RESULT_BACKEND", "mongodb://database/flask") + + ### Dataset Options + DATASET_DIRECTORY = os.getenv("DATASET_DIRECTORY", "/datasets/") + INITIALIZE_FROM_FILE = os.getenv("INITIALIZE_FROM_FILE") + + ### User Options + LOGIN_DISABLED = _get_bool("LOGIN_DISABLED", False) + ALLOW_REGISTRATION = _get_bool('ALLOW_REGISTRATION', True) + + ### Models + MASK_RCNN_FILE = os.getenv("MASK_RCNN_FILE", "") + MASK_RCNN_CLASSES = os.getenv("MASK_RCNN_CLASSES", "BG") + + DEXTR_FILE = os.getenv("DEXTR_FILE", "/models/dextr_pascal-sbd.h5") + + +__all__ = ["Config"] diff --git a/backend/database/__init__.py b/backend/database/__init__.py new file mode 100644 index 00000000..7bf07a43 --- /dev/null +++ b/backend/database/__init__.py @@ -0,0 +1,73 @@ +from mongoengine import connect +from config import Config + +from .annotations import * +from .categories import * +from .datasets import * +from .lisence import * +from .exports import * +from .images import * +from .events import * +from .users import * +from .tasks import * + +import json + + +def connect_mongo(name, host=None): + if host is None: + host = Config.MONGODB_HOST + connect(name, host=host) + + +# https://github.com/MongoEngine/mongoengine/issues/1171 +# Use this methods until a solution is found +def upsert(model, query=None, update=None): + + if not update: + update = query + + if not query: + return None + + found = model.objects(**query) + + if found.first(): + return found.modify(new=True, **update) + + new_model = model(**update) + new_model.save() + + return new_model + + +def fix_ids(q): + json_obj = json.loads(q.to_json().replace('\"_id\"', '\"id\"')) + return json_obj + + +def create_from_json(json_file): + + with open(json_file) as file: + + data_json = json.load(file) + for category in data_json.get('categories', []): + name = category.get('name') + if name is not None: + upsert(CategoryModel, query={"name": name}, update=category) + + for dataset_json in data_json.get('datasets', []): + name = dataset_json.get('name') + if name: + # map category names to ids; create as needed + category_ids = [] + for category in dataset_json.get('categories', []): + category_obj = {"name": category} + + category_model = upsert(CategoryModel, query=category_obj) + category_ids.append(category_model.id) + + dataset_json['categories'] = category_ids + upsert(DatasetModel, query={ "name": name}, update=dataset_json) + + diff --git a/backend/database/annotations.py b/backend/database/annotations.py new file mode 100644 index 00000000..1b9d3737 --- /dev/null +++ b/backend/database/annotations.py @@ -0,0 +1,121 @@ +import imantics as im +import json + +from mongoengine import * + +from .datasets import DatasetModel +from .categories import CategoryModel +from .events import Event +from flask_login import current_user + + +class AnnotationModel(DynamicDocument): + + COCO_PROPERTIES = ["id", "image_id", "category_id", "segmentation", + "iscrowd", "color", "area", "bbox", "metadata", + "keypoints", "isbbox"] + + id = SequenceField(primary_key=True) + image_id = IntField(required=True) + category_id = IntField(required=True) + dataset_id = IntField() + + segmentation = ListField(default=[]) + area = IntField(default=0) + bbox = ListField(default=[0, 0, 0, 0]) + iscrowd = BooleanField(default=False) + isbbox = BooleanField(default=False) + + creator = StringField(required=True) + width = IntField() + height = IntField() + + color = StringField() + + keypoints = ListField(default=[]) + + metadata = DictField(default={}) + paper_object = ListField(default=[]) + + deleted = BooleanField(default=False) + deleted_date = DateTimeField() + + milliseconds = IntField(default=0) + events = EmbeddedDocumentListField(Event) + + def __init__(self, image_id=None, **data): + + from .images import ImageModel + + if image_id is not None: + image = ImageModel.objects(id=image_id).first() + + if image is not None: + data['image_id'] = image_id + data['width'] = image.width + data['height'] = image.height + data['dataset_id'] = image.dataset_id + + super(AnnotationModel, self).__init__(**data) + + def save(self, copy=False, *args, **kwargs): + + if self.dataset_id and not copy: + dataset = DatasetModel.objects(id=self.dataset_id).first() + + if dataset is not None: + self.metadata = dataset.default_annotation_metadata.copy() + + if self.color is None: + self.color = im.Color.random().hex + + if current_user: + self.creator = current_user.username + else: + self.creator = 'system' + + return super(AnnotationModel, self).save(*args, **kwargs) + + def is_empty(self): + return len(self.segmentation) == 0 or self.area == 0 + + def mask(self): + """ Returns binary mask of annotation """ + mask = np.zeros((self.height, self.width)) + pts = [ + np.array(anno).reshape(-1, 2).round().astype(int) + for anno in self.segmentation + ] + mask = cv2.fillPoly(mask, pts, 1) + return mask + + def clone(self): + """ Creates a clone """ + create = json.loads(self.to_json()) + del create['_id'] + + return AnnotationModel(**create) + + def __call__(self): + + category = CategoryModel.objects(id=self.category_id).first() + if category: + category = category() + + data = { + 'image': None, + 'category': category, + 'color': self.color, + 'polygons': self.segmentation, + 'width': self.width, + 'height': self.height, + 'metadata': self.metadata + } + + return im.Annotation(**data) + + def add_event(self, e): + self.update(push__events=e) + + +__all__ = ["AnnotationModel"] diff --git a/backend/database/categories.py b/backend/database/categories.py new file mode 100644 index 00000000..0910ef7f --- /dev/null +++ b/backend/database/categories.py @@ -0,0 +1,83 @@ + +from flask_login import current_user +from mongoengine import * + +import imantics as im + + +class CategoryModel(DynamicDocument): + + COCO_PROPERTIES = ["id", "name", "supercategory", "color", "metadata",\ + "keypoint_edges", "keypoint_labels", "keypoint_colors"] + + id = SequenceField(primary_key=True) + name = StringField(required=True, unique_with=['creator']) + supercategory = StringField(default='') + color = StringField(default=None) + metadata = DictField(default={}) + + creator = StringField(default='unknown') + deleted = BooleanField(default=False) + deleted_date = DateTimeField() + + keypoint_edges = ListField(default=[]) + keypoint_labels = ListField(default=[]) + keypoint_colors = ListField(default=[]) + + @classmethod + def bulk_create(cls, categories): + + if not categories: + return [] + + category_ids = [] + for category in categories: + category_model = CategoryModel.objects(name=category).first() + + if category_model is None: + new_category = CategoryModel(name=category) + new_category.save() + category_ids.append(new_category.id) + else: + category_ids.append(category_model.id) + + return category_ids + + def save(self, *args, **kwargs): + + if not self.color: + self.color = im.Color.random().hex + + if current_user: + self.creator = current_user.username + else: + self.creator = 'system' + + return super(CategoryModel, self).save(*args, **kwargs) + + def __call__(self): + """ Generates imantics category object """ + data = { + 'name': self.name, + 'color': self.color, + 'parent': self.supercategory, + 'metadata': self.metadata, + 'id': self.id + } + return im.Category(**data) + + def is_owner(self, user): + + if user.is_admin: + return True + + return user.username.lower() == self.creator.lower() + + def can_edit(self, user): + return self.is_owner(user) + + def can_delete(self, user): + return self.is_owner(user) + + +__all__ = ["CategoryModel"] \ No newline at end of file diff --git a/backend/database/datasets.py b/backend/database/datasets.py new file mode 100644 index 00000000..32eabf41 --- /dev/null +++ b/backend/database/datasets.py @@ -0,0 +1,141 @@ + +from flask_login import current_user +from mongoengine import * +from config import Config + +from .tasks import TaskModel + +import os + + +class DatasetModel(DynamicDocument): + + id = SequenceField(primary_key=True) + name = StringField(required=True, unique=True) + directory = StringField() + thumbnails = StringField() + categories = ListField(default=[]) + + owner = StringField(required=True) + users = ListField(default=[]) + + annotate_url = StringField(default="") + + default_annotation_metadata = DictField(default={}) + + deleted = BooleanField(default=False) + deleted_date = DateTimeField() + + def save(self, *args, **kwargs): + + directory = os.path.join(Config.DATASET_DIRECTORY, self.name + '/') + os.makedirs(directory, mode=0o777, exist_ok=True) + + self.directory = directory + self.owner = current_user.username if current_user else 'system' + + return super(DatasetModel, self).save(*args, **kwargs) + + def get_users(self): + from .users import UserModel + + members = self.users + members.append(self.owner) + + return UserModel.objects(username__in=members)\ + .exclude('password', 'id', 'preferences') + + def import_coco(self, coco_json): + + from workers.tasks import import_annotations + + task = TaskModel( + name="Import COCO format into {}".format(self.name), + dataset_id=self.id, + group="Annotation Import" + ) + task.save() + + cel_task = import_annotations.delay(task.id, self.id, coco_json) + + return { + "celery_id": cel_task.id, + "id": task.id, + "name": task.name + } + + def export_coco(self, categories=None, style="COCO", with_empty_images=False): + + from workers.tasks import export_annotations + + if categories is None or len(categories) == 0: + categories = self.categories + + task = TaskModel( + name=f"Exporting {self.name} into {style} format", + dataset_id=self.id, + group="Annotation Export" + ) + task.save() + + cel_task = export_annotations.delay(task.id, self.id, categories, with_empty_images) + + return { + "celery_id": cel_task.id, + "id": task.id, + "name": task.name + } + + def scan(self): + + from workers.tasks import scan_dataset + + task = TaskModel( + name=f"Scanning {self.name} for new images", + dataset_id=self.id, + group="Directory Image Scan" + ) + task.save() + + cel_task = scan_dataset.delay(task.id, self.id) + + return { + "celery_id": cel_task.id, + "id": task.id, + "name": task.name + } + + def is_owner(self, user): + + if user.is_admin: + return True + + return user.username.lower() == self.owner.lower() + + def can_download(self, user): + return self.is_owner(user) + + def can_delete(self, user): + return self.is_owner(user) + + def can_share(self, user): + return self.is_owner(user) + + def can_generate(self, user): + return self.is_owner(user) + + def can_edit(self, user): + return user.username in self.users or self.is_owner(user) + + def permissions(self, user): + return { + 'owner': self.is_owner(user), + 'edit': self.can_edit(user), + 'share': self.can_share(user), + 'generate': self.can_generate(user), + 'delete': self.can_delete(user), + 'download': self.can_download(user) + } + + +__all__ = ["DatasetModel"] diff --git a/backend/database/events.py b/backend/database/events.py new file mode 100644 index 00000000..92e8de01 --- /dev/null +++ b/backend/database/events.py @@ -0,0 +1,36 @@ +from mongoengine import * + +import datetime +import time + + +class Event(EmbeddedDocument): + + name = StringField() + created_at = DateTimeField() + + meta = {'allow_inheritance': True} + + def now(self, event): + self.created_at = datetime.datetime.now() + + +class SessionEvent(Event): + + user = StringField(required=True) + milliseconds = IntField(default=0, min_value=0) + tools_used = ListField(default=[]) + + @classmethod + def create(self, start, user, end=None, tools=[]): + + if end is None: + end = time.time() + + return SessionEvent( + user=user.username, + milliseconds=int((end-start)*1000) + ) + + +__all__ = ["Event", "SessionEvent"] \ No newline at end of file diff --git a/backend/database/exports.py b/backend/database/exports.py new file mode 100644 index 00000000..65170fa7 --- /dev/null +++ b/backend/database/exports.py @@ -0,0 +1,20 @@ +from mongoengine import * + +import datetime +import time + + +class ExportModel(DynamicDocument): + + id = SequenceField(primary_key=True) + dataset_id = IntField(required=True) + path = StringField(required=True) + tags = ListField(default=[]) + categories = ListField(default=[]) + created_at = DateTimeField(default=datetime.datetime.utcnow) + + def get_file(self): + return + + +__all__ = ["ExportModel"] \ No newline at end of file diff --git a/backend/database/images.py b/backend/database/images.py new file mode 100644 index 00000000..b5b0fade --- /dev/null +++ b/backend/database/images.py @@ -0,0 +1,211 @@ +import os +import imantics as im + + +from PIL import Image, ImageFile +from mongoengine import * + +from .events import Event, SessionEvent +from .datasets import DatasetModel +from .annotations import AnnotationModel + + +ImageFile.LOAD_TRUNCATED_IMAGES = True + + +class ImageModel(DynamicDocument): + + COCO_PROPERTIES = ["id", "width", "height", "file_name", "path", "license",\ + "flickr_url", "coco_url", "date_captured", "dataset_id"] + + # -- Contants + THUMBNAIL_DIRECTORY = '.thumbnail' + PATTERN = (".gif", ".png", ".jpg", ".jpeg", ".bmp", ".tif", ".tiff", ".GIF", ".PNG", ".JPG", ".JPEG", ".BMP", ".TIF", ".TIFF") + + # Set maximum thumbnail size (h x w) to use on dataset page + MAX_THUMBNAIL_DIM = (1024, 1024) + + # -- Private + _dataset = None + + # -- Database + id = SequenceField(primary_key=True) + dataset_id = IntField(required=True) + category_ids = ListField(default=[]) + + # Absolute path to image file + path = StringField(required=True, unique=True) + width = IntField(required=True) + height = IntField(required=True) + file_name = StringField() + + # True if the image is annotated + annotated = BooleanField(default=False) + # Poeple currently annotation the image + annotating = ListField(default=[]) + num_annotations = IntField(default=0) + + thumbnail_url = StringField() + image_url = StringField() + coco_url = StringField() + date_captured = DateTimeField() + + metadata = DictField() + license = IntField() + + deleted = BooleanField(default=False) + deleted_date = DateTimeField() + + milliseconds = IntField(default=0) + events = EmbeddedDocumentListField(Event) + regenerate_thumbnail = BooleanField(default=False) + + @classmethod + def create_from_path(cls, path, dataset_id=None): + + pil_image = Image.open(path) + + image = cls() + image.file_name = os.path.basename(path) + image.path = path + image.width = pil_image.size[0] + image.height = pil_image.size[1] + image.regenerate_thumbnail = True + + if dataset_id is not None: + image.dataset_id = dataset_id + else: + # Get dataset name from path + folders = path.split('/') + i = folders.index("datasets") + dataset_name = folders[i+1] + + dataset = DatasetModel.objects(name=dataset_name).first() + if dataset is not None: + image.dataset_id = dataset.id + + pil_image.close() + + return image + + def delete(self, *args, **kwargs): + self.thumbnail_delete() + AnnotationModel.objects(image_id=self.id).delete() + return super(ImageModel, self).delete(*args, **kwargs) + + def thumbnail(self): + """ + Generates (if required) thumbnail + """ + + thumbnail_path = self.thumbnail_path() + + if self.regenerate_thumbnail: + + pil_image = self.generate_thumbnail() + pil_image = pil_image.convert("RGB") + + # Resize image to fit in MAX_THUMBNAIL_DIM envelope as necessary + pil_image.thumbnail((self.MAX_THUMBNAIL_DIM[1], self.MAX_THUMBNAIL_DIM[0])) + + # Save as a jpeg to improve loading time + # (note file extension will not match but allows for backwards compatibility) + pil_image.save(thumbnail_path, "JPEG", quality=80, optimize=True, progressive=True) + + self.update(is_modified=False) + return pil_image + + def open_thumbnail(self): + """ + Return thumbnail + """ + thumbnail_path = self.thumbnail_path() + return Image.open(thumbnail_path) + + def thumbnail_path(self): + folders = self.path.split('/') + folders.insert(len(folders)-1, self.THUMBNAIL_DIRECTORY) + + path = '/' + os.path.join(*folders) + directory = os.path.dirname(path) + + if not os.path.exists(directory): + os.makedirs(directory) + + return path + + def thumbnail_delete(self): + path = self.thumbnail_path() + if os.path.isfile(path): + os.remove(path) + + def generate_thumbnail(self): + image = self().draw(color_by_category=True, bbox=False) + return Image.fromarray(image) + + def flag_thumbnail(self, flag=True): + """ + Toggles values to regenerate thumbnail on next thumbnail request + """ + if self.regenerate_thumbnail != flag: + self.update(regenerate_thumbnail=flag) + + def copy_annotations(self, annotations): + """ + Creates a copy of the annotations for this image + :param annotations: QuerySet of annotation models + :return: number of annotations + """ + annotations = annotations.filter( + width=self.width, height=self.height).exclude('events') + + for annotation in annotations: + if annotation.area > 0 or len(annotation.keypoints) > 0: + clone = annotation.clone() + + clone.dataset_id = self.dataset_id + clone.image_id = self.id + + clone.save(copy=True) + + return annotations.count() + + @property + def dataset(self): + if self._dataset is None: + self._dataset = DatasetModel.objects(id=self.dataset_id).first() + return self._dataset + + def __call__(self): + + image = im.Image.from_path(self.path) + for annotation in AnnotationModel.objects(image_id=self.id, deleted=False).all(): + if not annotation.is_empty(): + image.add(annotation()) + + return image + + def can_delete(self, user): + return user.can_delete(self.dataset) + + def can_download(self, user): + return user.can_download(self.dataset) + + # TODO: Fix why using the functions throws an error + def permissions(self, user): + return { + 'delete': True, + 'download': True + } + + def add_event(self, e): + u = { + 'push__events': e, + } + if isinstance(e, SessionEvent): + u['inc__milliseconds'] = e.milliseconds + + self.update(**u) + + +__all__ = ["ImageModel"] diff --git a/backend/database/lisence.py b/backend/database/lisence.py new file mode 100644 index 00000000..d5d35997 --- /dev/null +++ b/backend/database/lisence.py @@ -0,0 +1,10 @@ +from mongoengine import * + + +class LicenseModel(DynamicDocument): + id = SequenceField(primary_key=True) + name = StringField() + url = StringField() + + +__all__ = ["LicenseModel"] \ No newline at end of file diff --git a/backend/database/tasks.py b/backend/database/tasks.py new file mode 100644 index 00000000..7a9e622a --- /dev/null +++ b/backend/database/tasks.py @@ -0,0 +1,99 @@ +from mongoengine import * + +import datetime + + +class TaskModel(DynamicDocument): + id = SequenceField(primary_key=True) + + # Type of task: Importer, Exporter, Scanner, etc. + group = StringField(required=True) + name = StringField(required=True) + desciption = StringField() + status = StringField(default="PENDING") + creator = StringField() + + #: Start date of the executor + start_date = DateTimeField() + #: End date of the executor + end_date = DateTimeField() + completed = BooleanField(default=False) + failed = BooleanField(default=False) + has_download = BooleanField(default=False) + + # If any of the information is relevant to the task + # it should be added + dataset_id = IntField() + image_id = IntField() + category_id = IntField() + + progress = FloatField(default=0, min_value=0, max_value=100) + + logs = ListField(default=[]) + errors = IntField(default=0) + warnings = IntField(default=0) + + priority = IntField() + + metadata = DictField(default={}) + + _update_every = 10 + _progress_update = 0 + + def error(self, string): + self._log(string, level="ERROR") + + def warning(self, string): + self._log(string, level="WARNING") + + def info(self, string): + self._log(string, level="INFO") + + def _log(self, string, level): + + level = level.upper() + date = datetime.datetime.now().strftime("%d-%m-%Y %H:%M:%S") + + message = f"[{date}] [{level}] {string}" + + statment = { + 'push__logs': message + } + + if level == "ERROR": + statment['inc__errors'] = 1 + self.errors += 1 + + if level == "WARNING": + statment['inc__warnings'] = 1 + self.warnings += 1 + + self.update(**statment) + + def set_progress(self, percent, socket=None): + + self.update(progress=int(percent), completed=(percent >= 100)) + + # Send socket update every 10% + if self._progress_update < percent or percent >= 100: + + if socket is not None: + # logger.debug(f"Emitting {percent} progress update for task {self.id}") + + socket.emit('taskProgress', { + 'id': self.id, + 'progress': percent, + 'errors': self.errors, + 'warnings': self.warnings + }, broadcast=True) + + self._progress_update += self._update_every + + def api_json(self): + return { + "id": self.id, + "name": self.name + } + + +__all__ = ["TaskModel"] \ No newline at end of file diff --git a/backend/database/users.py b/backend/database/users.py new file mode 100644 index 00000000..d154ab4d --- /dev/null +++ b/backend/database/users.py @@ -0,0 +1,96 @@ +import datetime + +from mongoengine import * +from flask_login import UserMixin + +from .annotations import AnnotationModel +from .categories import CategoryModel +from .datasets import DatasetModel +from .images import ImageModel + + +class UserModel(DynamicDocument, UserMixin): + + password = StringField(required=True) + username = StringField(max_length=25, required=True, unique=True) + email = StringField(max_length=30) + + name = StringField() + online = BooleanField(default=False) + last_seen = DateTimeField() + + is_admin = BooleanField(default=False) + + preferences = DictField(default={}) + permissions = ListField(defualt=[]) + + # meta = {'allow_inheritance': True} + + @property + def datasets(self): + self._update_last_seen() + + if self.is_admin: + return DatasetModel.objects + + return DatasetModel.objects(Q(owner=self.username) | Q(users__contains=self.username)) + + @property + def categories(self): + self._update_last_seen() + + if self.is_admin: + return CategoryModel.objects + + dataset_ids = self.datasets.distinct('categories') + return CategoryModel.objects(Q(id__in=dataset_ids) | Q(creator=self.username)) + + @property + def images(self): + self._update_last_seen() + + if self.is_admin: + return ImageModel.objects + + dataset_ids = self.datasets.distinct('id') + return ImageModel.objects(dataset_id__in=dataset_ids) + + @property + def annotations(self): + self._update_last_seen() + + if self.is_admin: + return AnnotationModel.objects + + image_ids = self.images.distinct('id') + return AnnotationModel.objects(image_id__in=image_ids) + + def can_view(self, model): + if model is None: + return False + + return model.can_view(self) + + def can_download(self, model): + if model is None: + return False + + return model.can_download(self) + + def can_delete(self, model): + if model is None: + return False + return model.can_delete(self) + + def can_edit(self, model): + if model is None: + return False + + return model.can_edit(self) + + def _update_last_seen(self): + self.update(last_seen=datetime.datetime.utcnow()) + + + +__all__ = ["UserModel"] \ No newline at end of file diff --git a/backend/requirements.txt b/backend/requirements.txt new file mode 100644 index 00000000..2066a636 --- /dev/null +++ b/backend/requirements.txt @@ -0,0 +1,27 @@ +eventlet==0.24.1 +opencv-python==4.0.0.21 +flask==1.0.2 +flask-cors==3.0.7 +flask-login==0.4.1 +flask-restplus==0.12.1 +flask-mongoengine==0.9.5 +numpy +cython +scikit-image +requests +google_images_download==2.5.0 +watchdog==0.8.3 +pytest==3.9.3 +pytest-ordering==0.6 +imantics==0.1.9 +flask-socketio==3.3.2 +celery==4.2.2 +Shapely==1.7.0 +scipy +Pillow +matplotlib +keras==2.1.1 +h5py +imgaug +IPython[all] +jupyter diff --git a/backend/set_path.py b/backend/set_path.py new file mode 100644 index 00000000..252cddbc --- /dev/null +++ b/backend/set_path.py @@ -0,0 +1,10 @@ + +import sys + +paths = [ + '/workspace/' +] + +for path in paths: + if path not in sys.path: + sys.path.append(path) diff --git a/backend/tests/Dockerfile b/backend/tests/Dockerfile new file mode 100644 index 00000000..69d3ffa7 --- /dev/null +++ b/backend/tests/Dockerfile @@ -0,0 +1,13 @@ +FROM python:3.6 + +WORKDIR /workspace/ + +# Install python package dependices +COPY ./backend/ /workspace/ +COPY ./.git /workspace/.git + +RUN pip install -r requirements.txt &&\ + pip install pycocotools + +ENV LOGIN_DISABLED=true +CMD pytest diff --git a/app/util/__init__.py b/backend/tests/__init__.py similarity index 100% rename from app/util/__init__.py rename to backend/tests/__init__.py diff --git a/tests/api/test_category.py b/backend/tests/api/test_category.py similarity index 64% rename from tests/api/test_category.py rename to backend/tests/api/test_category.py index 1ad52e58..acd82d25 100644 --- a/tests/api/test_category.py +++ b/backend/tests/api/test_category.py @@ -1,7 +1,7 @@ import json import pytest -from app.models import CategoryModel +from database import CategoryModel category1_id = 0 category2_id = 0 @@ -51,7 +51,6 @@ def test_post_categories(self, client): response = client.post("/api/category/", json=data) r = json.loads(response.data) - print(data) assert response.status_code == 200 assert r.get("name") == data.get("name") assert r.get("color") == data.get("color") @@ -104,6 +103,54 @@ def test_get(self, client): response = client.delete("/api/category/{}".format(category3_id)) assert response.status_code == 200 + @pytest.mark.run(after='test_post_categories') + def test_put_equal(self, client): + """ Test response when the name to update is the same as already stored """ + data = { + "name": "test1" + } + response = client.put("/api/category/{}".format(category1_id), json=data) + assert response.status_code == 200 + + def test_put_invalid_id(self, client): + """ Test response when id does not exit """ + response = client.put("/api/category/1000") + assert response.status_code == 400 + + def test_put_not_unique(self, client): + """ Test response when the name already exits """ + data = { + "name": "test2" + } + response = client.put("/api/category/{}".format(category1_id), json=data) + assert response.status_code == 400 + + def test_put_empty(self, client): + """ Test response when category name is empty""" + data = { + "name": "" + } + response = client.put("/api/category/{}".format(category1_id), json=data) + assert response.status_code == 400 + + @pytest.mark.run(after='test_put_not_unique') + def test_put(self, client): + """ Test response when update is correct""" + data = { + "name": "test1_updated" + } + response = client.put("/api/category/{}".format(category1_id), json=data) + assert response.status_code == 200 + + @pytest.mark.run(after='test_put') + def test_put_reset(self, client): + """ Reset test after a correct update """ + data = { + "name": "test1" + } + response = client.put("/api/category/{}".format(category1_id), json=data) + assert response.status_code == 200 + class TestCategoryData: diff --git a/tests/api/test_image.py b/backend/tests/api/test_image.py similarity index 84% rename from tests/api/test_image.py rename to backend/tests/api/test_image.py index 62771257..8e628322 100644 --- a/tests/api/test_image.py +++ b/backend/tests/api/test_image.py @@ -37,9 +37,4 @@ def test_get_invalid_id(self, client): assert response.status_code == 400 -class TestImageThumbnail: - def test_invalid_id(self, client): - response = client.get("/api/image/1000/thumbnail") - assert response.status_code == 400 - diff --git a/tests/api/test_info.py b/backend/tests/api/test_info.py similarity index 100% rename from tests/api/test_info.py rename to backend/tests/api/test_info.py diff --git a/tests/api/test_user.py b/backend/tests/api/test_user.py similarity index 93% rename from tests/api/test_user.py rename to backend/tests/api/test_user.py index 0e9dea05..06e4a7ab 100644 --- a/tests/api/test_user.py +++ b/backend/tests/api/test_user.py @@ -1,7 +1,7 @@ import json import pytest -from app.models import UserModel +from database import UserModel @pytest.mark.second diff --git a/tests/conftest.py b/backend/tests/conftest.py similarity index 80% rename from tests/conftest.py rename to backend/tests/conftest.py index 7b7fc41f..0875e78b 100644 --- a/tests/conftest.py +++ b/backend/tests/conftest.py @@ -1,5 +1,5 @@ import pytest -from app import app +from webserver import app @pytest.fixture diff --git a/tests/models/test_upsert.py b/backend/tests/models/test_upsert.py similarity index 94% rename from tests/models/test_upsert.py rename to backend/tests/models/test_upsert.py index efb9d67d..c37b52e4 100644 --- a/tests/models/test_upsert.py +++ b/backend/tests/models/test_upsert.py @@ -1,4 +1,4 @@ -from app.models import CategoryModel, upsert +from database import CategoryModel, upsert category1 = { "name": "Upsert Category", diff --git a/tests/test_app.py b/backend/tests/test_app.py similarity index 100% rename from tests/test_app.py rename to backend/tests/test_app.py diff --git a/backend/webserver/Dockerfile b/backend/webserver/Dockerfile new file mode 100644 index 00000000..cb8fe628 --- /dev/null +++ b/backend/webserver/Dockerfile @@ -0,0 +1,16 @@ +FROM jsbroks/coco-annotator:python-env + +WORKDIR /workspace/ + +# Install python package dependices +COPY ./backend/ /workspace/ +COPY ./.git /workspace/.git +RUN python set_path.py + +ENV FLASK_ENV=development +ENV DEBUG=true + +EXPOSE 5000 +CMD gunicorn -c webserver/gunicorn_config.py webserver:app --no-sendfile + + diff --git a/app/__init__.py b/backend/webserver/__init__.py similarity index 52% rename from app/__init__.py rename to backend/webserver/__init__.py index d830f09c..6bf29388 100644 --- a/app/__init__.py +++ b/backend/webserver/__init__.py @@ -1,41 +1,43 @@ +import eventlet +eventlet.monkey_patch(thread=False) + +import sys +import workers + +from config import Config +from database import ( + connect_mongo, + ImageModel, + create_from_json +) + from flask import Flask -from werkzeug.contrib.fixers import ProxyFix from flask_cors import CORS -from watchdog.observers import Observer +from flask_socketio import SocketIO +from werkzeug.contrib.fixers import ProxyFix + +from celery import Celery -from .image_folder import ImageFolderHandler +from .watcher import run_watcher from .api import blueprint as api -from .config import Config -from .models import * +from .util import query_util, thumbnails from .authentication import login_manager -from .util import query_util, color_util +from .sockets import socketio import threading import requests +import logging import time import os -def run_watcher(): - observer = Observer() - observer.schedule(ImageFolderHandler(), Config.DATASET_DIRECTORY, recursive=True) - observer.start() - - try: - while True: - time.sleep(1) - except KeyboardInterrupt: - observer.stop() - - observer.join() +connect_mongo('webserver') def create_app(): - if os.environ.get("APP_WORKER_ID", "1") == "1" and not Config.TESTING: - print("Creating file watcher on PID: {}".format(os.getpid()), flush=True) - watcher_thread = threading.Thread(target=run_watcher) - watcher_thread.start() + if Config.FILE_WATCHER: + run_watcher() flask = Flask(__name__, static_url_path='', @@ -48,29 +50,32 @@ def create_app(): flask.wsgi_app = ProxyFix(flask.wsgi_app) flask.register_blueprint(api) - db.init_app(flask) login_manager.init_app(flask) + socketio.init_app(flask, message_queue=Config.CELERY_BROKER_URL) + # Remove all poeple who were annotating when + # the server shutdown + ImageModel.objects.update(annotating=[]) + thumbnails.generate_thumbnails() return flask app = create_app() +logger = logging.getLogger('gunicorn.error') +app.logger.handlers = logger.handlers +app.logger.setLevel(logger.level) + if Config.INITIALIZE_FROM_FILE: create_from_json(Config.INITIALIZE_FROM_FILE) -if Config.LOAD_IMAGES_ON_START: - ImageModel.load_images(Config.DATASET_DIRECTORY) - @app.route('/', defaults={'path': ''}) @app.route('/') def index(path): - + if app.debug: return requests.get('http://frontend:8080/{}'.format(path)).text return app.send_static_file('index.html') - - diff --git a/app/api/__init__.py b/backend/webserver/api/__init__.py similarity index 80% rename from app/api/__init__.py rename to backend/webserver/api/__init__.py index 36420bc1..280028d2 100644 --- a/app/api/__init__.py +++ b/backend/webserver/api/__init__.py @@ -5,13 +5,16 @@ from .categories import api as ns_categories from .annotator import api as ns_annotator from .datasets import api as ns_datasets +from .exports import api as ns_exports from .images import api as ns_images +from .models import api as ns_models from .users import api as ns_users from .admin import api as ns_admin +from .tasks import api as ns_tasks from .undo import api as ns_undo from .info import api as ns_info -from ..config import Config +from config import Config # Create /api/ space blueprint = Blueprint('api', __name__, url_prefix='/api') @@ -31,8 +34,11 @@ api.add_namespace(ns_images) api.add_namespace(ns_annotations) api.add_namespace(ns_categories) -api.add_namespace(ns_annotator) api.add_namespace(ns_datasets) +api.add_namespace(ns_exports) +api.add_namespace(ns_tasks) api.add_namespace(ns_undo) +api.add_namespace(ns_models) api.add_namespace(ns_admin) +api.add_namespace(ns_annotator) diff --git a/app/api/admin.py b/backend/webserver/api/admin.py similarity index 98% rename from app/api/admin.py rename to backend/webserver/api/admin.py index db21d383..c7575b24 100644 --- a/app/api/admin.py +++ b/backend/webserver/api/admin.py @@ -2,7 +2,7 @@ from flask_restplus import Namespace, Resource, reqparse from werkzeug.security import generate_password_hash -from ..models import UserModel +from database import UserModel from ..util.query_util import fix_ids api = Namespace('admin', description='Admin related operations') @@ -42,7 +42,7 @@ def get(self): total = user_model.count() pages = int(total/per_page) + 1 - user_model = user_model.skip(page*per_page).limit(per_page).exclude("preferences") + user_model = user_model.skip(page*per_page).limit(per_page).exclude("preferences", "password") return { "total": total, diff --git a/backend/webserver/api/annotations.py b/backend/webserver/api/annotations.py new file mode 100644 index 00000000..d33ecd02 --- /dev/null +++ b/backend/webserver/api/annotations.py @@ -0,0 +1,123 @@ +from flask_restplus import Namespace, Resource, reqparse +from flask_login import login_required, current_user + +from database import AnnotationModel +from ..util import query_util + +import datetime +import logging +logger = logging.getLogger('gunicorn.error') + +api = Namespace('annotation', description='Annotation related operations') + +create_annotation = reqparse.RequestParser() +create_annotation.add_argument( + 'image_id', type=int, required=True, location='json') +create_annotation.add_argument('category_id', type=int, location='json') +create_annotation.add_argument('isbbox', type=bool, location='json') +create_annotation.add_argument('metadata', type=dict, location='json') +create_annotation.add_argument('segmentation', type=list, location='json') +create_annotation.add_argument('keypoints', type=list, location='json') +create_annotation.add_argument('color', location='json') + +update_annotation = reqparse.RequestParser() +update_annotation.add_argument('category_id', type=int, location='json') + +@api.route('/') +class Annotation(Resource): + + @login_required + def get(self): + """ Returns all annotations """ + return query_util.fix_ids(current_user.annotations.exclude("paper_object").all()) + + @api.expect(create_annotation) + @login_required + def post(self): + """ Creates an annotation """ + args = create_annotation.parse_args() + image_id = args.get('image_id') + category_id = args.get('category_id') + isbbox = args.get('isbbox') + metadata = args.get('metadata', {}) + segmentation = args.get('segmentation', []) + keypoints = args.get('keypoints', []) + + image = current_user.images.filter(id=image_id, deleted=False).first() + if image is None: + return {"message": "Invalid image id"}, 400 + + logger.info( + f'{current_user.username} has created an annotation for image {image_id} with {isbbox}') + logger.info( + f'{current_user.username} has created an annotation for image {image_id}') + + try: + annotation = AnnotationModel( + image_id=image_id, + category_id=category_id, + metadata=metadata, + segmentation=segmentation, + keypoints=keypoints, + isbbox=isbbox + ) + annotation.save() + except (ValueError, TypeError) as e: + return {'message': str(e)}, 400 + + return query_util.fix_ids(annotation) + + +@api.route('/') +class AnnotationId(Resource): + + @login_required + def get(self, annotation_id): + """ Returns annotation by ID """ + annotation = current_user.annotations.filter(id=annotation_id).first() + + if annotation is None: + return {"message": "Invalid annotation id"}, 400 + + return query_util.fix_ids(annotation) + + @login_required + def delete(self, annotation_id): + """ Deletes an annotation by ID """ + annotation = current_user.annotations.filter(id=annotation_id).first() + + if annotation is None: + return {"message": "Invalid annotation id"}, 400 + + image = current_user.images.filter( + id=annotation.image_id, deleted=False).first() + image.flag_thumbnail() + + annotation.update(set__deleted=True, + set__deleted_date=datetime.datetime.now()) + return {'success': True} + + @api.expect(update_annotation) + @login_required + def put(self, annotation_id): + """ Updates an annotation by ID """ + annotation = current_user.annotations.filter(id=annotation_id).first() + + if annotation is None: + return { "message": "Invalid annotation id" }, 400 + + args = update_annotation.parse_args() + + new_category_id = args.get('category_id') + annotation.update(category_id=new_category_id) + logger.info( + f'{current_user.username} has updated category for annotation (id: {annotation.id})' + ) + newAnnotation = current_user.annotations.filter(id=annotation_id).first() + return query_util.fix_ids(newAnnotation) + +# @api.route('//mask') +# class AnnotationMask(Resource): +# def get(self, annotation_id): +# """ Returns the binary mask of an annotation """ +# return query_util.fix_ids(AnnotationModel.objects(id=annotation_id).first()) diff --git a/app/api/annotator.py b/backend/webserver/api/annotator.py similarity index 52% rename from app/api/annotator.py rename to backend/webserver/api/annotator.py index a772cd30..3f737cb4 100644 --- a/app/api/annotator.py +++ b/backend/webserver/api/annotator.py @@ -1,11 +1,18 @@ +import datetime + from flask_restplus import Namespace, Resource from flask_login import login_required, current_user from flask import request -from ..util import query_util -from ..util import coco_util -from ..models import * +from ..util import query_util, coco_util, profile, thumbnails +from config import Config +from database import ( + ImageModel, + CategoryModel, + AnnotationModel, + SessionEvent +) api = Namespace('annotator', description='Annotator related operations') @@ -13,6 +20,7 @@ @api.route('/data') class AnnotatorData(Resource): + @profile @login_required def post(self): """ @@ -20,23 +28,28 @@ def post(self): """ data = request.get_json(force=True) image = data.get('image') + dataset = data.get('dataset') image_id = image.get('id') - + image_model = ImageModel.objects(id=image_id).first() - # Check if current user can access dataset - if current_user.datasets.filter(id=image_model.dataset_id).first() is None: - return {'success': False, 'message': 'Could not find associated dataset'} - if image_model is None: return {'success': False, 'message': 'Image does not exist'}, 400 + # Check if current user can access dataset + db_dataset = current_user.datasets.filter(id=image_model.dataset_id).first() + if dataset is None: + return {'success': False, 'message': 'Could not find associated dataset'} + + db_dataset.update(annotate_url=dataset.get('annotate_url', '')) + categories = CategoryModel.objects.all() annotations = AnnotationModel.objects(image_id=image_id) current_user.update(preferences=data.get('user', {})) annotated = False + num_annotations = 0 # Iterate every category passed in the data for category in data.get('categories', []): category_id = category.get('id') @@ -46,11 +59,17 @@ def post(self): if db_category is None: continue - db_category.update(set__color=category.get('color')) + category_update = {'color': category.get('color')} + if current_user.can_edit(db_category): + category_update['keypoint_edges'] = category.get('keypoint_edges', []) + category_update['keypoint_labels'] = category.get('keypoint_labels', []) + category_update['keypoint_colors'] = category.get('keypoint_colors', []) + + db_category.update(**category_update) # Iterate every annotation from the data annotations for annotation in category.get('annotations', []): - + counted = False # Find corresponding annotation object in database annotation_id = annotation.get('id') db_annotation = annotations.filter(id=annotation_id).first() @@ -62,7 +81,28 @@ def post(self): # the annotation twice, checking if the paperjs exists. # Update annotation in database + sessions = [] + total_time = 0 + for session in annotation.get('sessions', []): + date = datetime.datetime.fromtimestamp(int(session.get('start')) / 1e3) + model = SessionEvent( + user=current_user.username, + created_at=date, + milliseconds=session.get('milliseconds'), + tools_used=session.get('tools') + ) + total_time += session.get('milliseconds') + sessions.append(model) + + keypoints = annotation.get('keypoints', []) + if keypoints: + counted = True + db_annotation.update( + add_to_set__events=sessions, + inc__milliseconds=total_time, + set__isbbox=annotation.get('isbbox', False), + set__keypoints=keypoints, set__metadata=annotation.get('metadata'), set__color=annotation.get('color') ) @@ -82,29 +122,39 @@ def post(self): db_annotation.update( set__segmentation=segmentation, set__area=area, + set__isbbox=annotation.get('isbbox', False), set__bbox=bbox, set__paper_object=paperjs_object, ) if area > 0: - annotated = True + counted = True + + if counted: + num_annotations += 1 image_model.update( set__metadata=image.get('metadata', {}), - set__annotated=annotated, - set__category_ids=image.get('category_ids', []) + set__annotated=(num_annotations > 0), + set__category_ids=image.get('category_ids', []), + set__regenerate_thumbnail=True, + set__num_annotations=num_annotations ) - return data + thumbnails.generate_thumbnail(image_model) + + return {"success": True} @api.route('/data/') class AnnotatorId(Resource): + @profile @login_required def get(self, image_id): """ Called when loading from the annotator client """ - image = ImageModel.objects(id=image_id).first() + image = ImageModel.objects(id=image_id)\ + .exclude('events').first() if image is None: return {'success': False, 'message': 'Could not load image'}, 400 @@ -113,36 +163,48 @@ def get(self, image_id): if dataset is None: return {'success': False, 'message': 'Could not find associated dataset'}, 400 - categories = CategoryModel.objects(deleted=False).in_bulk(dataset.categories).items() + categories = CategoryModel.objects(deleted=False)\ + .in_bulk(dataset.categories).items() # Get next and previous image - images = list(ImageModel.objects(dataset_id=dataset.id, deleted=False).order_by('file_name').all()) - image_index = images.index(image) - image_previous = None if image_index - 1 < 0 else images[image_index - 1].id - image_next = None if image_index + 1 == len(images) else images[image_index + 1].id + images = ImageModel.objects(dataset_id=dataset.id, deleted=False) + pre = images.filter(file_name__lt=image.file_name).order_by('-file_name').first() + nex = images.filter(file_name__gt=image.file_name).order_by('file_name').first() + + preferences = {} + if not Config.LOGIN_DISABLED: + preferences = current_user.preferences # Generate data about the image to return to client data = { 'image': query_util.fix_ids(image), 'categories': [], 'dataset': query_util.fix_ids(dataset), - 'settings': [] + 'preferences': preferences, + 'permissions': { + 'dataset': dataset.permissions(current_user), + 'image': image.permissions(current_user) + } } - data['image']['previous'] = image_previous - data['image']['next'] = image_next + data['image']['previous'] = pre.id if pre else None + data['image']['next'] = nex.id if nex else None + + # Optimize query: query all annotation of specific image, and then categorize them according to the categories. + all_annotations = AnnotationModel.objects(image_id=image_id, deleted=False).exclude('events').all() for category in categories: category = query_util.fix_ids(category[1]) - category_id = category.get('id') - annotations = AnnotationModel.objects(image_id=image_id, category_id=category_id, deleted=False).all() + + annotations = [] + for annotation in all_annotations: + if annotation['category_id'] == category_id: + annotations.append(query_util.fix_ids(annotation)) category['show'] = True category['visualize'] = False - category['annotations'] = [] if annotations is None else query_util.fix_ids(annotations) + category['annotations'] = [] if annotations is None else annotations data.get('categories').append(category) return data - - diff --git a/backend/webserver/api/categories.py b/backend/webserver/api/categories.py new file mode 100644 index 00000000..33d391da --- /dev/null +++ b/backend/webserver/api/categories.py @@ -0,0 +1,189 @@ +from flask_restplus import Namespace, Resource, reqparse +from flask_login import login_required, current_user +from mongoengine.errors import NotUniqueError + +from ..util.pagination_util import Pagination +from ..util import query_util +from database import CategoryModel, AnnotationModel + +import datetime + +api = Namespace('category', description='Category related operations') + +create_category = reqparse.RequestParser() +create_category.add_argument('name', required=True, location='json') +create_category.add_argument('supercategory', location='json') +create_category.add_argument('color', location='json') +create_category.add_argument('metadata', type=dict, location='json') +create_category.add_argument( + 'keypoint_edges', type=list, default=[], location='json') +create_category.add_argument( + 'keypoint_labels', type=list, default=[], location='json') +create_category.add_argument( + 'keypoint_colors', type=list, default=[], location='json') + +update_category = reqparse.RequestParser() +update_category.add_argument('name', required=True, location='json') +update_category.add_argument('supercategory', location='json') +update_category.add_argument('color', location='json') +update_category.add_argument('metadata', type=dict, location='json') +update_category.add_argument('keypoint_edges', type=list, location='json') +update_category.add_argument('keypoint_labels', type=list, location='json') +update_category.add_argument('keypoint_colors', type=list, location='json') + +page_data = reqparse.RequestParser() +page_data.add_argument('page', default=1, type=int) +page_data.add_argument('limit', default=20, type=int) + + +@api.route('/') +class Category(Resource): + + @login_required + def get(self): + """ Returns all categories """ + return query_util.fix_ids(current_user.categories.all()) + + @api.expect(create_category) + @login_required + def post(self): + """ Creates a category """ + args = create_category.parse_args() + name = args.get('name') + supercategory = args.get('supercategory') + metadata = args.get('metadata', {}) + color = args.get('color') + keypoint_edges = args.get('keypoint_edges') + keypoint_labels = args.get('keypoint_labels') + keypoint_colors = args.get('keypoint_colors') + + try: + category = CategoryModel( + name=name, + supercategory=supercategory, + color=color, + metadata=metadata, + keypoint_edges=keypoint_edges, + keypoint_labels=keypoint_labels, + keypoint_colors=keypoint_colors, + ) + category.save() + except NotUniqueError as e: + return {'message': 'Category already exists. Check the undo tab to fully delete the category.'}, 400 + + return query_util.fix_ids(category) + + +@api.route('/') +class Category(Resource): + + @login_required + def get(self, category_id): + """ Returns a category by ID """ + category = current_user.categories.filter(id=category_id).first() + + if category is None: + return {'success': False}, 400 + + return query_util.fix_ids(category) + + @login_required + def delete(self, category_id): + """ Deletes a category by ID """ + category = current_user.categories.filter(id=category_id).first() + if category is None: + return {"message": "Invalid image id"}, 400 + + if not current_user.can_delete(category): + return {"message": "You do not have permission to delete this category"}, 403 + + category.update(set__deleted=True, + set__deleted_date=datetime.datetime.now()) + return {'success': True} + + @api.expect(update_category) + @login_required + def put(self, category_id): + """ Updates a category name by ID """ + + category = current_user.categories.filter(id=category_id).first() + + # check if the id exits + if category is None: + return {"message": "Invalid category id"}, 400 + + args = update_category.parse_args() + name = args.get('name') + supercategory = args.get('supercategory', category.supercategory) + color = args.get('color', category.color) + metadata = args.get('metadata', category.metadata) + keypoint_edges = args.get('keypoint_edges', category.keypoint_edges) + keypoint_labels = args.get('keypoint_labels', category.keypoint_labels) + keypoint_colors = args.get('keypoint_colors', category.keypoint_colors) + + # check if there is anything to update + if category.name == name \ + and category.supercategory == supercategory \ + and category.color == color \ + and category.keypoint_edges == keypoint_edges \ + and category.keypoint_labels == keypoint_labels \ + and category.keypoint_colors == keypoint_colors: + return {"message": "Nothing to update"}, 200 + + # check if the name is empty + if not name: + return {"message": "Invalid category name to update"}, 400 + + # update name of the category + # check if the name to update exits already in db + # @ToDo: Is it necessary to allow equal category names among different creators? + category.name = name + category.supercategory = supercategory + category.color = color + category.keypoint_edges = keypoint_edges + category.keypoint_labels = keypoint_labels + category.keypoint_colors = keypoint_colors + + try: + category.update( + name=category.name, + supercategory=category.supercategory, + color=category.color, + metadata=category.metadata, + keypoint_edges=category.keypoint_edges, + keypoint_labels=category.keypoint_labels, + keypoint_colors=category.keypoint_colors, + ) + except NotUniqueError: + # it is only triggered when the name already exists and the creator is the same + return {"message": "Category '" + name_to_update + "' already exits"}, 400 + + return {"success": True} + + +@api.route('/data') +class CategoriesData(Resource): + + @api.expect(page_data) + @login_required + def get(self): + """ Endpoint called by category viewer client """ + args = page_data.parse_args() + limit = args['limit'] + page = args['page'] + + categories = current_user.categories.filter(deleted=False) + + pagination = Pagination(categories.count(), limit, page) + categories = query_util.fix_ids( + categories[pagination.start:pagination.end]) + + for category in categories: + category['numberAnnotations'] = AnnotationModel.objects( + deleted=False, category_id=category.get('id')).count() + + return { + "pagination": pagination.export(), + "page": page, + "categories": categories + } diff --git a/backend/webserver/api/datasets.py b/backend/webserver/api/datasets.py new file mode 100644 index 00000000..916fd88f --- /dev/null +++ b/backend/webserver/api/datasets.py @@ -0,0 +1,608 @@ +from flask import request +from flask_restplus import Namespace, Resource, reqparse, inputs +from flask_login import login_required, current_user +from werkzeug.datastructures import FileStorage +from mongoengine.errors import NotUniqueError +from mongoengine.queryset.visitor import Q +from threading import Thread + +from google_images_download import google_images_download as gid + +from ..util.pagination_util import Pagination +from ..util import query_util, coco_util, profile + +from database import ( + ImageModel, + DatasetModel, + CategoryModel, + AnnotationModel, + ExportModel +) + +import datetime +import json +import os + +api = Namespace('dataset', description='Dataset related operations') + + +dataset_create = reqparse.RequestParser() +dataset_create.add_argument('name', required=True) +dataset_create.add_argument('categories', type=list, required=False, location='json', + help="List of default categories for sub images") + +page_data = reqparse.RequestParser() +page_data.add_argument('page', default=1, type=int) +page_data.add_argument('limit', default=20, type=int) +page_data.add_argument('folder', default='', help='Folder for data') +page_data.add_argument('order', default='file_name', help='Order to display images') + +delete_data = reqparse.RequestParser() +delete_data.add_argument('fully', default=False, type=bool, + help="Fully delete dataset (no undo)") + +coco_upload = reqparse.RequestParser() +coco_upload.add_argument('coco', location='files', type=FileStorage, required=True, help='Json coco') + +export = reqparse.RequestParser() +export.add_argument('categories', type=str, default=None, required=False, help='Ids of categories to export') +export.add_argument('with_empty_images', type=inputs.boolean, default=False, required=False, help='Export with un-annotated images') + +update_dataset = reqparse.RequestParser() +update_dataset.add_argument('categories', location='json', type=list, help="New list of categories") +update_dataset.add_argument('default_annotation_metadata', location='json', type=dict, + help="Default annotation metadata") + +dataset_generate = reqparse.RequestParser() +dataset_generate.add_argument('keywords', location='json', type=list, default=[], + help="Keywords associated with images") +dataset_generate.add_argument('limit', location='json', type=int, default=100, help="Number of images per keyword") + +share = reqparse.RequestParser() +share.add_argument('users', location='json', type=list, default=[], help="List of users") + + +@api.route('/') +class Dataset(Resource): + @login_required + def get(self): + """ Returns all datasets """ + return query_util.fix_ids(current_user.datasets.filter(deleted=False).all()) + + @api.expect(dataset_create) + @login_required + def post(self): + """ Creates a dataset """ + args = dataset_create.parse_args() + name = args['name'] + categories = args.get('categories', []) + + category_ids = CategoryModel.bulk_create(categories) + + try: + dataset = DatasetModel(name=name, categories=category_ids) + dataset.save() + except NotUniqueError: + return {'message': 'Dataset already exists. Check the undo tab to fully delete the dataset.'}, 400 + + return query_util.fix_ids(dataset) + + +def download_images(output_dir, args): + for keyword in args['keywords']: + response = gid.googleimagesdownload() + response.download({ + "keywords": keyword, + "limit": args['limit'], + "output_directory": output_dir, + "no_numbering": True, + "format": "jpg", + "type": "photo", + "print_urls": False, + "print_paths": False, + "print_size": False + }) + + +@api.route('//generate') +class DatasetGenerate(Resource): + @api.expect(dataset_generate) + @login_required + def post(self, dataset_id): + """ Adds images found on google to the dataset """ + args = dataset_generate.parse_args() + + dataset = current_user.datasets.filter(id=dataset_id, deleted=False).first() + if dataset is None: + return {"message": "Invalid dataset id"}, 400 + + if not dataset.is_owner(current_user): + return {"message": "You do not have permission to download the dataset's annotations"}, 403 + + thread = Thread(target=download_images, args=(dataset.directory, args)) + thread.start() + + return {"success": True} + + +@api.route('//users') +class DatasetMembers(Resource): + + @login_required + def get(self, dataset_id): + """ All users in the dataset """ + args = dataset_generate.parse_args() + + dataset = current_user.datasets.filter(id=dataset_id, deleted=False).first() + if dataset is None: + return {"message": "Invalid dataset id"}, 400 + + users = dataset.get_users() + return query_util.fix_ids(users) + + +@api.route('//reset/metadata') +class DatasetCleanMeta(Resource): + + @login_required + def get(self, dataset_id): + """ All users in the dataset """ + args = dataset_generate.parse_args() + + dataset = current_user.datasets.filter(id=dataset_id, deleted=False).first() + if dataset is None: + return {"message": "Invalid dataset id"}, 400 + + AnnotationModel.objects(dataset_id=dataset.id)\ + .update(metadata=dataset.default_annotation_metadata) + ImageModel.objects(dataset_id=dataset.id)\ + .update(metadata={}) + + return {'success': True} + + +@api.route('//stats') +class DatasetStats(Resource): + + @login_required + def get(self, dataset_id): + """ All users in the dataset """ + args = dataset_generate.parse_args() + + dataset = current_user.datasets.filter(id=dataset_id, deleted=False).first() + if dataset is None: + return {"message": "Invalid dataset id"}, 400 + + images = ImageModel.objects(dataset_id=dataset.id, deleted=False) + annotated_images = images.filter(annotated=True) + annotations = AnnotationModel.objects(dataset_id=dataset_id, deleted=False) + + # Calculate annotation counts by category in this dataset + category_count = dict() + image_category_count = dict() + + + + user_stats = dict() + + for user in dataset.get_users(): + user_annots = AnnotationModel.objects(dataset_id=dataset_id, deleted=False, creator=user.username) + image_count = dict() + for annot in user_annots: + image_count[annot.image_id] = image_count.get(annot.image_id, 0) + 1 + + user_stats[user.username] = { + "annotations": len(user_annots), + "images": len(image_count) + } + + + for category in dataset.categories: + + # Calculate the annotation count in the current category in this dataset + cat_name = CategoryModel.objects(id=category).first()['name'] + cat_count = AnnotationModel.objects(dataset_id=dataset_id, category_id=category, deleted=False).count() + category_count.update({str(cat_name): cat_count}) + + # Calculate the annotated images count in the current category in this dataset + image_count = len(AnnotationModel.objects(dataset_id=dataset_id, category_id=category, deleted=False).distinct('image_id')) + image_category_count.update({str(cat_name): image_count}) + + stats = { + 'total': { + 'Users': dataset.get_users().count(), + 'Images': images.count(), + 'Annotated Images': annotated_images.count(), + 'Annotations': annotations.count(), + 'Categories': len(dataset.categories), + 'Time Annotating (s)': (images.sum('milliseconds') or 0) / 1000 + }, + 'average': { + 'Image Size (px)': images.average('width'), + 'Image Height (px)': images.average('height'), + 'Annotation Area (px)': annotations.average('area'), + 'Time (ms) per Image': images.average('milliseconds') or 0, + 'Time (ms) per Annotation': annotations.average('milliseconds') or 0 + }, + 'categories': category_count, + 'images_per_category': image_category_count, + 'users': user_stats + } + return stats + + +@api.route('/') +class DatasetId(Resource): + + @login_required + def delete(self, dataset_id): + """ Deletes dataset by ID (only owners)""" + + dataset = DatasetModel.objects(id=dataset_id, deleted=False).first() + + if dataset is None: + return {"message": "Invalid dataset id"}, 400 + + if not current_user.can_delete(dataset): + return {"message": "You do not have permission to delete the dataset"}, 403 + + dataset.update(set__deleted=True, set__deleted_date=datetime.datetime.now()) + return {"success": True} + + @api.expect(update_dataset) + def post(self, dataset_id): + + """ Updates dataset by ID """ + + dataset = current_user.datasets.filter(id=dataset_id, deleted=False).first() + if dataset is None: + return {"message": "Invalid dataset id"}, 400 + + args = update_dataset.parse_args() + categories = args.get('categories') + default_annotation_metadata = args.get('default_annotation_metadata') + set_default_annotation_metadata = args.get('set_default_annotation_metadata') + + if categories is not None: + dataset.categories = CategoryModel.bulk_create(categories) + + if default_annotation_metadata is not None: + + update = {} + for key, value in default_annotation_metadata.items(): + if key not in dataset.default_annotation_metadata: + update[f'set__metadata__{key}'] = value + + dataset.default_annotation_metadata = default_annotation_metadata + + if len(update.keys()) > 0: + AnnotationModel.objects(dataset_id=dataset.id, deleted=False)\ + .update(**update) + + dataset.update( + categories=dataset.categories, + default_annotation_metadata=dataset.default_annotation_metadata + ) + + return {"success": True} + + +@api.route('//share') +class DatasetIdShare(Resource): + @api.expect(share) + @login_required + def post(self, dataset_id): + args = share.parse_args() + + dataset = current_user.datasets.filter(id=dataset_id, deleted=False).first() + if dataset is None: + return {"message": "Invalid dataset id"}, 400 + + if not dataset.is_owner(current_user): + return {"message": "You do not have permission to share this dataset"}, 403 + + dataset.update(users=args.get('users')) + + return {"success": True} + + +@api.route('/data') +class DatasetData(Resource): + @api.expect(page_data) + @login_required + def get(self): + """ Endpoint called by dataset viewer client """ + + args = page_data.parse_args() + limit = args['limit'] + page = args['page'] + folder = args['folder'] + + datasets = current_user.datasets.filter(deleted=False) + pagination = Pagination(datasets.count(), limit, page) + datasets = datasets[pagination.start:pagination.end] + + datasets_json = [] + for dataset in datasets: + dataset_json = query_util.fix_ids(dataset) + images = ImageModel.objects(dataset_id=dataset.id, deleted=False) + + dataset_json['numberImages'] = images.count() + dataset_json['numberAnnotated'] = images.filter(annotated=True).count() + dataset_json['permissions'] = dataset.permissions(current_user) + + first = images.first() + if first is not None: + dataset_json['first_image_id'] = images.first().id + datasets_json.append(dataset_json) + + return { + "pagination": pagination.export(), + "folder": folder, + "datasets": datasets_json, + "categories": query_util.fix_ids(current_user.categories.filter(deleted=False).all()) + } + +@api.route('//data') +class DatasetDataId(Resource): + + @profile + @api.expect(page_data) + @login_required + def get(self, dataset_id): + """ Endpoint called by image viewer client """ + + parsed_args = page_data.parse_args() + per_page = parsed_args.get('limit') + page = parsed_args.get('page') - 1 + folder = parsed_args.get('folder') + order = parsed_args.get('order') + + args = dict(request.args) + + # Check if dataset exists + dataset = current_user.datasets.filter(id=dataset_id, deleted=False).first() + if dataset is None: + return {'message', 'Invalid dataset id'}, 400 + + # Make sure folder starts with is in proper format + if len(folder) > 0: + folder = folder[0].strip('/') + folder[1:] + if folder[-1] != '/': + folder = folder + '/' + + # Get directory + directory = os.path.join(dataset.directory, folder) + if not os.path.exists(directory): + return {'message': 'Directory does not exist.'}, 400 + + # Remove parsed arguments + for key in parsed_args: + args.pop(key, None) + + # Generate query from remaining arugments + query = {} + for key, value in args.items(): + lower = value.lower() + if lower in ["true", "false"]: + value = json.loads(lower) + + if len(lower) != 0: + query[key] = value + + # Change category_ids__in to list + if 'category_ids__in' in query.keys(): + query['category_ids__in'] = [int(x) for x in query['category_ids__in'].split(',')] + + # Initialize mongo query with required elements: + query_build = Q(dataset_id=dataset_id) + query_build &= Q(path__startswith=directory) + query_build &= Q(deleted=False) + + # Define query names that should use complex logic: + complex_query = ['annotated', 'category_ids__in'] + + # Add additional 'and' arguments to mongo query that do not require complex_query logic + for key in query.keys(): + if key not in complex_query: + query_dict = {} + query_dict[key] = query[key] + query_build &= Q(**query_dict) + + # Add additional arguments to mongo query that require more complex logic to construct + if 'annotated' in query.keys(): + + if 'category_ids__in' in query.keys() and query['annotated']: + + # Only show annotated images with selected category_ids + query_dict = {} + query_dict['category_ids__in'] = query['category_ids__in'] + query_build &= Q(**query_dict) + + else: + + # Only show non-annotated images + query_dict = {} + query_dict['annotated'] = query['annotated'] + query_build &= Q(**query_dict) + + elif 'category_ids__in' in query.keys(): + + # Ahow annotated images with selected category_ids or non-annotated images + query_dict_1 = {} + query_dict_1['category_ids__in'] = query['category_ids__in'] + + query_dict_2 = {} + query_dict_2['annotated'] = False + query_build &= (Q(**query_dict_1) | Q(**query_dict_2)) + + # Perform mongodb query + images = current_user.images \ + .filter(query_build) \ + .order_by(order).only('id', 'file_name', 'annotating', 'annotated', 'num_annotations') + + total = images.count() + pages = int(total/per_page) + 1 + + images = images.skip(page*per_page).limit(per_page) + images_json = query_util.fix_ids(images) + # for image in images: + # image_json = query_util.fix_ids(image) + + # query = AnnotationModel.objects(image_id=image.id, deleted=False) + # category_ids = query.distinct('category_id') + # categories = CategoryModel.objects(id__in=category_ids).only('name', 'color') + + # image_json['annotations'] = query.count() + # image_json['categories'] = query_util.fix_ids(categories) + + # images_json.append(image_json) + + + subdirectories = [f for f in sorted(os.listdir(directory)) + if os.path.isdir(directory + f) and not f.startswith('.')] + + categories = CategoryModel.objects(id__in=dataset.categories).only('id', 'name') + + return { + "total": total, + "per_page": per_page, + "pages": pages, + "page": page, + "images": images_json, + "folder": folder, + "directory": directory, + "dataset": query_util.fix_ids(dataset), + "categories": query_util.fix_ids(categories), + "subdirectories": subdirectories + } + + +@api.route('//exports') +class DatasetExports(Resource): + + @login_required + def get(self, dataset_id): + """ Returns exports of images and annotations in the dataset (only owners) """ + dataset = current_user.datasets.filter(id=dataset_id).first() + + if dataset is None: + return {"message": "Invalid dataset ID"}, 400 + + if not current_user.can_download(dataset): + return {"message": "You do not have permission to download the dataset's annotations"}, 403 + + exports = ExportModel.objects(dataset_id=dataset.id).order_by('-created_at').limit(50) + + dict_export = [] + for export in exports: + + time_delta = datetime.datetime.utcnow() - export.created_at + dict_export.append({ + 'id': export.id, + 'ago': query_util.td_format(time_delta), + 'tags': export.tags + }) + + return dict_export + + +@api.route('//export') +class DatasetExport(Resource): + + @api.expect(export) + @login_required + def get(self, dataset_id): + + args = export.parse_args() + categories = args.get('categories') + with_empty_images = args.get('with_empty_images', False) + + if len(categories) == 0: + categories = [] + + if len(categories) > 0 or isinstance(categories, str): + categories = [int(c) for c in categories.split(',')] + + dataset = DatasetModel.objects(id=dataset_id).first() + + if not dataset: + return {'message': 'Invalid dataset ID'}, 400 + + return dataset.export_coco(categories=categories, with_empty_images=with_empty_images) + + @api.expect(coco_upload) + @login_required + def post(self, dataset_id): + """ Adds coco formatted annotations to the dataset """ + args = coco_upload.parse_args() + coco = args['coco'] + + dataset = current_user.datasets.filter(id=dataset_id).first() + if dataset is None: + return {'message': 'Invalid dataset ID'}, 400 + + return dataset.import_coco(json.load(coco)) + + +@api.route('//coco') +class DatasetCoco(Resource): + + @login_required + def get(self, dataset_id): + """ Returns coco of images and annotations in the dataset (only owners) """ + dataset = current_user.datasets.filter(id=dataset_id).first() + + if dataset is None: + return {"message": "Invalid dataset ID"}, 400 + + if not current_user.can_download(dataset): + return {"message": "You do not have permission to download the dataset's annotations"}, 403 + + return coco_util.get_dataset_coco(dataset) + + @api.expect(coco_upload) + @login_required + def post(self, dataset_id): + """ Adds coco formatted annotations to the dataset """ + args = coco_upload.parse_args() + coco = args['coco'] + + dataset = current_user.datasets.filter(id=dataset_id).first() + if dataset is None: + return {'message': 'Invalid dataset ID'}, 400 + + return dataset.import_coco(json.load(coco)) + + +@api.route('/coco/') +class DatasetCocoId(Resource): + + @login_required + def get(self, import_id): + """ Returns current progress and errors of a coco import """ + coco_import = CocoImportModel.objects( + id=import_id, creator=current_user.username).first() + + if not coco_import: + return {'message': 'No such coco import'}, 400 + + return { + "progress": coco_import.progress, + "errors": coco_import.errors + } + + +@api.route('//scan') +class DatasetScan(Resource): + + @login_required + def get(self, dataset_id): + + dataset = DatasetModel.objects(id=dataset_id).first() + + if not dataset: + return {'message': 'Invalid dataset ID'}, 400 + + return dataset.scan() + diff --git a/backend/webserver/api/exports.py b/backend/webserver/api/exports.py new file mode 100644 index 00000000..f168bb35 --- /dev/null +++ b/backend/webserver/api/exports.py @@ -0,0 +1,71 @@ +from flask import send_file +from flask_restplus import Namespace, Resource, reqparse +from flask_login import login_required, current_user + +import datetime +from ..util import query_util + +from database import ( + ExportModel, + DatasetModel, + fix_ids +) + + +api = Namespace('export', description='Export related operations') + + +@api.route('/') +class DatasetExports(Resource): + + @login_required + def get(self, export_id): + """ Returns exports """ + export = ExportModel.objects(id=export_id).first() + if export is None: + return {"message": "Invalid export ID"}, 400 + + dataset = current_user.datasets.filter(id=export.dataset_id).first() + if dataset is None: + return {"message": "Invalid dataset ID"}, 400 + + time_delta = datetime.datetime.utcnow() - export.created_at + d = fix_ids(export) + d['ago'] = query_util.td_format(time_delta) + return d + + @login_required + def delete(self, export_id): + """ Returns exports """ + export = ExportModel.objects(id=export_id).first() + if export is None: + return {"message": "Invalid export ID"}, 400 + + dataset = current_user.datasets.filter(id=export.dataset_id).first() + if dataset is None: + return {"message": "Invalid dataset ID"}, 400 + + export.delete() + return {'success': True} + + +@api.route('//download') +class DatasetExports(Resource): + + @login_required + def get(self, export_id): + """ Returns exports """ + + export = ExportModel.objects(id=export_id).first() + if export is None: + return {"message": "Invalid export ID"}, 400 + + dataset = current_user.datasets.filter(id=export.dataset_id).first() + if dataset is None: + return {"message": "Invalid dataset ID"}, 400 + + if not current_user.can_download(dataset): + return {"message": "You do not have permission to download the dataset's annotations"}, 403 + + return send_file(export.path, attachment_filename=f"{dataset.name.encode('utf-8')}-{'-'.join(export.tags).encode('utf-8')}.json", as_attachment=True) + diff --git a/app/api/images.py b/backend/webserver/api/images.py similarity index 65% rename from app/api/images.py rename to backend/webserver/api/images.py index 961d3525..408ab36e 100644 --- a/app/api/images.py +++ b/backend/webserver/api/images.py @@ -2,10 +2,16 @@ from flask_login import login_required, current_user from werkzeug.datastructures import FileStorage from flask import send_file +from mongoengine.errors import NotUniqueError -from ..util import query_util, coco_util, thumbnail_util -from ..models import * +from ..util import query_util, coco_util +from database import ( + ImageModel, + DatasetModel, + AnnotationModel +) +from PIL import Image import datetime import os import io @@ -17,20 +23,21 @@ image_all = reqparse.RequestParser() image_all.add_argument('fields', required=False, type=str) image_all.add_argument('page', default=1, type=int) -image_all.add_argument('perPage', default=50, type=int, required=False) - +image_all.add_argument('per_page', default=50, type=int, required=False) image_upload = reqparse.RequestParser() image_upload.add_argument('image', location='files', type=FileStorage, required=True, help='PNG or JPG file') -image_upload.add_argument('folder', required=False, default='', - help='Folder to insert photo into') +image_upload.add_argument('dataset_id', required=True, type=int, + help='Id of dataset to insert image into') image_download = reqparse.RequestParser() -image_download.add_argument('asAttachment', type=bool, required=False, default=False) -image_download.add_argument('width', type=int, required=False, default=0) -image_download.add_argument('height', type=int, required=False, default=0) +image_download.add_argument('asAttachment', type=bool, default=False) +image_download.add_argument('thumbnail', type=bool, default=False) +image_download.add_argument('width', type=int) +image_download.add_argument('height', type=int) +image_download.add_argument('original', type=bool, default=False) copy_annotations = reqparse.RequestParser() copy_annotations.add_argument('category_ids', location='json', type=list, @@ -45,9 +52,9 @@ class Images(Resource): def get(self): """ Returns all images """ args = image_all.parse_args() - per_page = args['perPage'] + per_page = args['per_page'] page = args['page']-1 - fields = args.get('fields', "") + fields = args.get('fields', '') images = current_user.images.filter(deleted=False) total = images.count() @@ -73,34 +80,28 @@ def post(self): args = image_upload.parse_args() image = args['image'] - folder = args['folder'] - if len(folder) > 0: - folder = folder[0].strip('/') + folder[1:] - - directory = os.path.join(Config.DATASET_DIRECTORY, folder) + dataset_id = args['dataset_id'] + try: + dataset = DatasetModel.objects.get(id=dataset_id) + except: + return {'message': 'dataset does not exist'}, 400 + directory = dataset.directory path = os.path.join(directory, image.filename) if os.path.exists(path): return {'message': 'file already exists'}, 400 - if not os.path.exists(directory): - os.makedirs(directory) - pil_image = Image.open(io.BytesIO(image.read())) - image_model = ImageModel( - file_name=image.filename, - width=pil_image.size[0], - height=pil_image.size[1], - path=path - ) - - image_model.save() pil_image.save(path) image.close() pil_image.close() - return query_util.fix_ids(image_model) + try: + db_image = ImageModel.create_from_path(path, dataset_id).save() + except NotUniqueError: + db_image = ImageModel.objects.get(path=path) + return db_image.id @api.route('/') @@ -111,25 +112,26 @@ class ImageId(Resource): def get(self, image_id): """ Returns category by ID """ args = image_download.parse_args() - as_attachment = args['asAttachment'] - width = args['width'] - height = args['height'] + as_attachment = args.get('asAttachment') + thumbnail = args.get('thumbnail') + original = args.get('original') image = current_user.images.filter(id=image_id, deleted=False).first() if image is None: return {'success': False}, 400 + if original: + return send_file(image.path, attachment_filename=image.file_name, as_attachment=as_attachment) - if width < 1: + width = args.get('width') + height = args.get('height') + + if not width: width = image.width - - if height < 1: + if not height: height = image.height - - try: - pil_image = Image.open(image.path) - except Exception as e: - return {'message': str(e)}, 400 + + pil_image = image.open_thumbnail() if thumbnail else Image.open(image.path) pil_image.thumbnail((width, height), Image.ANTIALIAS) image_io = io.BytesIO() @@ -146,6 +148,9 @@ def delete(self, image_id): if image is None: return {"message": "Invalid image id"}, 400 + if not current_user.can_delete(image): + return {"message": "You do not have permission to download the image"}, 403 + image.update(set__deleted=True, set__deleted_date=datetime.datetime.now()) return {"success": True} @@ -183,40 +188,6 @@ def post(self, from_id, to_id): return {'annotations_created': image_to.copy_annotations(query)} -@api.route('//thumbnail') -class ImageCoco(Resource): - - @api.expect(image_download) - @login_required - def get(self, image_id): - """ Returns coco of image and annotations """ - args = image_download.parse_args() - as_attachment = args['asAttachment'] - width = args['width'] - height = args['height'] - - image = current_user.images.filter(id=image_id, deleted=False).first() - - if image is None: - return {'success': False}, 400 - - if width < 1: - width = image.width - - if height < 1: - height = image.height - - pil_image = thumbnail_util.generate_thumbnail(image, save=False) - pil_image.thumbnail((width, height), Image.ANTIALIAS) - - image_io = io.BytesIO() - pil_image = pil_image.convert("RGB") - pil_image.save(image_io, "JPEG", quality=90) - image_io.seek(0) - - return send_file(image_io, attachment_filename=image.file_name, as_attachment=as_attachment) - - @api.route('//coco') class ImageCoco(Resource): @@ -224,9 +195,12 @@ class ImageCoco(Resource): def get(self, image_id): """ Returns coco of image and annotations """ image = current_user.images.filter(id=image_id).exclude('deleted_date').first() - + if image is None: return {"message": "Invalid image ID"}, 400 - return coco_util.get_image_coco(image) + if not current_user.can_download(image): + return {"message": "You do not have permission to download the images's annotations"}, 403 + + return coco_util.get_image_coco(image_id) diff --git a/app/api/info.py b/backend/webserver/api/info.py similarity index 54% rename from app/api/info.py rename to backend/webserver/api/info.py index 81450347..5a933507 100644 --- a/app/api/info.py +++ b/backend/webserver/api/info.py @@ -1,8 +1,8 @@ -from flask_restplus import Namespace, Resource, reqparse +from flask_restplus import Namespace, Resource -from ..config import Config -from ..util.version_util import get_tag -from ..models import UserModel +from workers.tasks import long_task +from config import Config +from database import UserModel, TaskModel api = Namespace('info', description='Software related operations') @@ -19,10 +19,20 @@ def get(self): "demo": "https://annotator.justinbrooks.ca/", "repo": "https://github.com/jsbroks/coco-annotator", "git": { - "tag": get_tag() + "tag": Config.VERSION }, "login_enabled": not Config.LOGIN_DISABLED, "total_users": UserModel.objects.count(), "allow_registration": Config.ALLOW_REGISTRATION } + +@api.route('/long_task') +class TaskTest(Resource): + def get(self): + """ Returns information about current version """ + task_model = TaskModel(group="test", name="Testing Celery") + task_model.save() + + task = long_task.delay(20, task_model.id) + return {'id': task.id, 'state': task.state} \ No newline at end of file diff --git a/backend/webserver/api/models.py b/backend/webserver/api/models.py new file mode 100644 index 00000000..9fa22dad --- /dev/null +++ b/backend/webserver/api/models.py @@ -0,0 +1,81 @@ +from flask_restplus import Namespace, Resource, reqparse +from werkzeug.datastructures import FileStorage +from imantics import Mask +from flask_login import login_required +from config import Config +from PIL import Image +from database import ImageModel + +import os +import logging + +logger = logging.getLogger('gunicorn.error') + + +MASKRCNN_LOADED = os.path.isfile(Config.MASK_RCNN_FILE) +if MASKRCNN_LOADED: + from ..util.mask_rcnn import model as maskrcnn +else: + logger.warning("MaskRCNN model is disabled.") + +DEXTR_LOADED = os.path.isfile(Config.DEXTR_FILE) +if DEXTR_LOADED: + from ..util.dextr import model as dextr +else: + logger.warning("DEXTR model is disabled.") + +api = Namespace('model', description='Model related operations') + + +image_upload = reqparse.RequestParser() +image_upload.add_argument('image', location='files', type=FileStorage, required=True, help='Image') + +dextr_args = reqparse.RequestParser() +dextr_args.add_argument('points', location='json', type=list, required=True) +dextr_args.add_argument('padding', location='json', type=int, default=50) +dextr_args.add_argument('threshold', location='json', type=int, default=80) + + +@api.route('/dextr/') +class MaskRCNN(Resource): + + @login_required + @api.expect(dextr_args) + def post(self, image_id): + """ COCO data test """ + + if not DEXTR_LOADED: + return {"disabled": True, "message": "DEXTR is disabled"}, 400 + + args = dextr_args.parse_args() + points = args.get('points') + # padding = args.get('padding') + # threshold = args.get('threshold') + + if len(points) != 4: + return {"message": "Invalid points entered"}, 400 + + image_model = ImageModel.objects(id=image_id).first() + if not image_model: + return {"message": "Invalid image ID"}, 400 + + image = Image.open(image_model.path) + result = dextr.predict_mask(image, points) + + return { "segmentaiton": Mask(result).polygons().segmentation } + + +@api.route('/maskrcnn') +class MaskRCNN(Resource): + + @login_required + @api.expect(image_upload) + def post(self): + """ COCO data test """ + if not MASKRCNN_LOADED: + return {"disabled": True, "coco": {}} + + args = image_upload.parse_args() + im = Image.open(args.get('image')) + coco = maskrcnn.detect(im) + return {"coco": coco} \ No newline at end of file diff --git a/backend/webserver/api/tasks.py b/backend/webserver/api/tasks.py new file mode 100644 index 00000000..5be4a4fb --- /dev/null +++ b/backend/webserver/api/tasks.py @@ -0,0 +1,50 @@ +from flask_restplus import Namespace, Resource +from flask_login import login_required + +from ..util import query_util +from database import TaskModel + + +api = Namespace('tasks', description='Task related operations') + + +@api.route('/') +class Task(Resource): + @login_required + def get(self): + """ Returns all tasks """ + query = TaskModel.objects.only( + 'group', 'id', 'name', 'completed', 'progress', + 'priority', 'creator', 'desciption', 'errors', + 'warnings' + ).all() + return query_util.fix_ids(query) + + +@api.route('/') +class TaskId(Resource): + @login_required + def delete(self, task_id): + """ Deletes task """ + task = TaskModel.objects(id=task_id).first() + + if task is None: + return {"message": "Invalid task id"}, 400 + + if not task.completed: + return {"message": "Task is not completed"}, 400 + + task.delete() + return {"success": True} + + +@api.route('//logs') +class TaskId(Resource): + @login_required + def get(self, task_id): + """ Deletes task """ + task = TaskModel.objects(id=task_id).first() + if task is None: + return {"message": "Invalid task id"}, 400 + + return {'logs': task.logs} diff --git a/app/api/undo.py b/backend/webserver/api/undo.py similarity index 89% rename from app/api/undo.py rename to backend/webserver/api/undo.py index 0cd6354b..561961c3 100644 --- a/app/api/undo.py +++ b/backend/webserver/api/undo.py @@ -1,8 +1,15 @@ from flask_restplus import Namespace, Resource, reqparse -from flask_login import login_required, current_user +from flask_login import login_required +import os +import shutil import datetime -from ..models import * +from database import ( + ImageModel, + DatasetModel, + CategoryModel, + AnnotationModel +) api = Namespace('undo', description='Undo related operations') @@ -100,6 +107,14 @@ def delete(self): if model_object is None: return {"message": "Invalid id"}, 400 + if isinstance(model_object, ImageModel): + if os.path.isfile(model_object.path): + os.remove(model_object.path) + + if isinstance(model_object, DatasetModel): + if os.path.isdir(model_object.directory): + shutil.rmtree(model_object.directory) + model_object.delete() return {"success": True} diff --git a/app/api/users.py b/backend/webserver/api/users.py similarity index 93% rename from app/api/users.py rename to backend/webserver/api/users.py index c2d82591..cf84ca34 100644 --- a/app/api/users.py +++ b/backend/webserver/api/users.py @@ -2,10 +2,13 @@ from werkzeug.security import generate_password_hash, check_password_hash from flask_restplus import Namespace, Resource, reqparse -from ..models import UserModel -from ..config import Config +from database import UserModel +from config import Config from ..util.query_util import fix_ids +import logging +logger = logging.getLogger('gunicorn.error') + api = Namespace('user', description='User related operations') register = reqparse.RequestParser() @@ -104,6 +107,8 @@ def post(self): user_json = fix_ids(current_user) del user_json['password'] + + logger.info(f'User {current_user.username} has LOGIN') return {'success': True, 'user': user_json} @@ -115,6 +120,7 @@ class UserLogout(Resource): @login_required def get(self): """ Logs user out """ + logger.info(f'User {current_user.username} has LOGOUT') logout_user() return {'success': True} diff --git a/app/authentication.py b/backend/webserver/authentication.py similarity index 59% rename from app/authentication.py rename to backend/webserver/authentication.py index d1172d1f..4d9d4174 100644 --- a/app/authentication.py +++ b/backend/webserver/authentication.py @@ -1,6 +1,12 @@ -from flask_login import LoginManager, login_user, login_required, logout_user, current_user, AnonymousUserMixin -from .models import * -from .config import Config +from flask_login import LoginManager, AnonymousUserMixin +from werkzeug.security import check_password_hash +from database import ( + UserModel, + DatasetModel, + CategoryModel, + AnnotationModel, + ImageModel +) login_manager = LoginManager() @@ -46,6 +52,18 @@ def to_json(self): "anonymous": True } + def can_edit(self, model): + return True + + def can_view(self, model): + return True + + def can_download(self, model): + return True + + def can_delete(self, model): + return True + login_manager.anonymous_user = AnonymousUser @@ -59,3 +77,14 @@ def load_user(user_id): def unauthorized(): return {'success': False, 'message': 'Authorization required'}, 401 + +@login_manager.request_loader +def load_user_from_request(request): + auth = request.authorization + if not auth: + return None + user = UserModel.objects(username__iexact=auth.username).first() + if user and check_password_hash(user.password, auth.password): + # login_user(user) + return user + return None diff --git a/backend/webserver/gunicorn_config.py b/backend/webserver/gunicorn_config.py new file mode 100644 index 00000000..b3b734cf --- /dev/null +++ b/backend/webserver/gunicorn_config.py @@ -0,0 +1,19 @@ + +from config import Config + + +bind = '0.0.0.0:5000' +backlog = 2048 + +workers = 1 +worker_class = 'eventlet' +worker_connections = 1000 +timeout = 30 +keepalive = 2 + +reload = Config.DEBUG +preload = Config.PRELOAD + +errorlog = '-' +loglevel = Config.LOG_LEVEL +accesslog = None \ No newline at end of file diff --git a/backend/webserver/sockets.py b/backend/webserver/sockets.py new file mode 100644 index 00000000..fcb5ceca --- /dev/null +++ b/backend/webserver/sockets.py @@ -0,0 +1,131 @@ +import functools +import time + +from flask import session +from flask_socketio import ( + SocketIO, + disconnect, + join_room, + leave_room, + emit +) +from flask_login import current_user + +from database import ImageModel, SessionEvent +from config import Config + +import logging +logger = logging.getLogger('gunicorn.error') + + +socketio = SocketIO() + + +def authenticated_only(f): + @functools.wraps(f) + def wrapped(*args, **kwargs): + if current_user.is_authenticated or Config.LOGIN_DISABLED: + return f(*args, **kwargs) + else: + disconnect() + return wrapped + + +@socketio.on('annotation') +@authenticated_only +def annotation(data): + emit('annotation', data, broadcast=True) + + +@socketio.on('annotating') +@authenticated_only +def annotating(data): + """ + Socket for handling image locking and time logging + """ + + image_id = data.get('image_id') + active = data.get('active') + + image = ImageModel.objects(id=image_id).first() + if image is None: + # invalid image ID + return + + emit('annotating', { + 'image_id': image_id, + 'active': active, + 'username': current_user.username + }, broadcast=True, include_self=False) + + if active: + logger.info(f'{current_user.username} has started annotating image {image_id}') + # Remove user from pervious room + previous = session.get('annotating') + if previous is not None: + leave_room(previous) + previous_image = ImageModel.objects(id=previous).first() + + if previous_image is not None: + + start = session.get('annotating_time', time.time()) + event = SessionEvent.create(start, current_user) + + previous_image.add_event(event) + previous_image.update( + pull__annotating=current_user.username + ) + + emit('annotating', { + 'image_id': previous, + 'active': False, + 'username': current_user.username + }, broadcast=True, include_self=False) + + join_room(image_id) + session['annotating'] = image_id + session['annotating_time'] = time.time() + image.update(add_to_set__annotating=current_user.username) + else: + leave_room(image_id) + + start = session.get('annotating_time', time.time()) + event = SessionEvent.create(start, current_user) + + image.add_event(event) + image.update( + pull__annotating=current_user.username + ) + + session['annotating'] = None + session['time'] = None + + +@socketio.on('connect') +def connect(): + logger.info(f'Socket connection created with {current_user.username}') + + +@socketio.on('disconnect') +def disconnect(): + if current_user.is_authenticated: + logger.info(f'Socket connection has been disconnected with {current_user.username}') + image_id = session.get('annotating') + + # Remove user from room + if image_id is not None: + image = ImageModel.objects(id=image_id).first() + if image is not None: + start = session.get('annotating_time', time.time()) + event = SessionEvent.create(start, current_user) + + image.add_event(event) + image.update( + pull__annotating=current_user.username + ) + emit('annotating', { + 'image_id': image_id, + 'active': False, + 'username': current_user.username + }, broadcast=True, include_self=False) + diff --git a/backend/webserver/util/__init__.py b/backend/webserver/util/__init__.py new file mode 100644 index 00000000..431976bd --- /dev/null +++ b/backend/webserver/util/__init__.py @@ -0,0 +1,16 @@ + + +import time +import logging + + +def profile(func): + def wrap(*args, **kwargs): + started_at = time.time() + result = func(*args, **kwargs) + diff = time.time() - started_at + if isinstance(result, dict): + result['time_ms'] = int(diff * 1000) + return result + + return wrap \ No newline at end of file diff --git a/backend/webserver/util/coco_util.py b/backend/webserver/util/coco_util.py new file mode 100644 index 00000000..5540deb3 --- /dev/null +++ b/backend/webserver/util/coco_util.py @@ -0,0 +1,346 @@ +import pycocotools.mask as mask +import numpy as np +import shapely +from shapely.geometry import LineString, Point + +from database import ( + fix_ids, + ImageModel, + DatasetModel, + CategoryModel, + AnnotationModel +) + + +def paperjs_to_coco(image_width, image_height, paperjs): + """ + Given a paperjs CompoundPath, converts path into coco segmentation format based on children paths + + :param image_width: Width of Image + :param image_height: Height of Image + :param paperjs: paperjs CompoundPath in dict format + :return: segmentation, area, bbox + """ + assert image_width > 0 + assert image_height > 0 + assert len(paperjs) == 2 + + # Compute segmentation + # paperjs points are relative to the center, so we must shift them relative to the top left. + segments = [] + center = [image_width/2, image_height/2] + + if paperjs[0] == "Path": + compound_path = {"children": [paperjs]} + else: + compound_path = paperjs[1] + + children = compound_path.get('children', []) + + for child in children: + + child_segments = child[1].get('segments', []) + segments_to_add = [] + + for point in child_segments: + + # Cruve + if len(point) == 4: + point = point[0] + + # Point + if len(point) == 2: + x = round(center[0] + point[0], 2) + y = round(center[1] + point[1], 2) + segments_to_add.extend([x, y]) + + # Make sure shape is not all outside the image + if sum(segments_to_add) == 0: + continue + + if len(segments_to_add) == 4: + # len 4 means this is a line with no width; it contributes + # no area to the mask, and if we include it, coco will treat + # it instead as a bbox (and throw an error) + continue + + num_widths = segments_to_add.count(image_width) + num_heights = segments_to_add.count(image_height) + if num_widths + num_heights == len(segments_to_add): + continue + + segments.append(segments_to_add) + + if len(segments) < 1: + return [], 0, [0, 0, 0, 0] + + area, bbox = get_segmentation_area_and_bbox( + segments, image_height, image_width) + + return segments, area, bbox + + +def paperjs_to_coco_cliptobounds(image_width, image_height, paperjs): # todo: there's lots of edge cases to this. It needs a different solution or many many if statements :P + """ + Given a paperjs CompoundPath, converts path into coco segmentation format based on children paths + + :param image_width: Width of Image + :param image_height: Height of Image + :param paperjs: paperjs CompoundPath in dict format + :return: segmentation, area, bbox + """ + assert image_width > 0 + assert image_height > 0 + assert len(paperjs) == 2 + + # Compute segmentation + # paperjs points are relative to the center, so we must shift them relative to the top left. + segments = [] + center = [image_width/2, image_height/2] + + if paperjs[0] == "Path": + compound_path = {"children": [paperjs]} + else: + compound_path = paperjs[1] + + children = compound_path.get('children', []) + + for child in children: + + child_segments = child[1].get('segments', []) + segments_to_add = [] + + + i_start = 0 + inside = False + # find a point that's inside the canvas + while(i_start < len(child_segments)): + point = child_segments[i_start] + if len(point) == 4: point = point[0] # curve + if len(point) == 2: # point + if (abs(point[0]) > image_width/2 or point[1] > image_height/2): + i_start += 1 + continue + inside = True + break + i_start += 1 + + if inside: # if point is inside the canvas. Otherwise ignore it + edges = { + 'w_0': np.array([[0,0],[image_width, 0]], np.float), + 'w_1': np.array([[0,image_height],[image_width, image_height]], np.float), + 'h_0': np.array([[0,0],[0, image_height]], np.float), + 'h_1': np.array([[image_width,0],[image_width, image_height]], np.float), + } + prev_point = None + for i in range(i_start, i_start + len(child_segments)): + p = i % len(child_segments) + point = child_segments[p] + + # print('point:', point, flush=True) + # Cruve + if len(point) == 4: + point = point[0] + + # Point + if len(point) == 2: + x = round(center[0] + point[0], 2) + y = round(center[1] + point[1], 2) + x_orig, y_orig = x,y + point_outside = x > image_width or x < 0 or y > image_height or y < 0 + # prev_point_outside = prev_point[0] > image_width or prev_point[0] < 0 or prev_point[1] > image_height or prev_point[1] < 0 + if point_outside: # outside canvas + line = LineString([[x,y], prev_point]) + for _, edge in edges.items(): + intersect = line.intersection(LineString(edge)) + if not intersect.is_empty: + if intersect.type == 'LineString': intersect = intersect.xy[0] + else: intersect = [intersect.x, intersect.y] + print(x,y, prev_point) + print(intersect, flush=True) + x,y = intersect + break + segments_to_add.extend([x, y]) + prev_point = [x_orig,y_orig] + # Make sure shape is not all outside the image + if sum(segments_to_add) == 0: + continue + + if len(segments_to_add) == 4: + # len 4 means this is a line with no width; it contributes + # no area to the mask, and if we include it, coco will treat + # it instead as a bbox (and throw an error) + continue + + num_widths = segments_to_add.count(image_width) + num_heights = segments_to_add.count(image_height) + if num_widths + num_heights == len(segments_to_add): + continue + + segments.append(segments_to_add) + + if len(segments) < 1: + return [], 0, [0, 0, 0, 0] + + area, bbox = get_segmentation_area_and_bbox( + segments, image_height, image_width) + + return segments, area, bbox + +def get_segmentation_area_and_bbox(segmentation, image_height, image_width): + # Convert into rle + rles = mask.frPyObjects(segmentation, image_height, image_width) + rle = mask.merge(rles) + + return mask.area(rle), mask.toBbox(rle) + + +def get_annotations_iou(annotation_a, annotation_b): + """ + Computes the IOU between two annotation objects + """ + seg_a = list([list(part) for part in annotation_a.segmentation]) + seg_b = list([list(part) for part in annotation_b.segmentation]) + + rles_a = mask.frPyObjects( + seg_a, annotation_a.height, annotation_a.width) + + rles_b = mask.frPyObjects( + seg_b, annotation_b.height, annotation_b.width) + + ious = mask.iou(rles_a, rles_b, [0]) + return ious[0][0] + + +def get_image_coco(image_id): + """ + Generates coco for an image + + :param image: ImageModel + :return: Coco in dictionary format + """ + image = ImageModel.objects(id=image_id)\ + .only(*ImageModel.COCO_PROPERTIES) + + image = fix_ids(image)[0] + dataset = DatasetModel.objects(id=image.get('dataset_id')).first() + + bulk_categories = CategoryModel.objects(id__in=dataset.categories, deleted=False) \ + .only(*CategoryModel.COCO_PROPERTIES) + + print(bulk_categories) + + db_annotations = AnnotationModel.objects(deleted=False, image_id=image_id) + categories = [] + annotations = [] + + for category in fix_ids(bulk_categories): + + category_annotations = db_annotations\ + .filter(category_id=category.get('id'))\ + .only(*AnnotationModel.COCO_PROPERTIES) + + if category_annotations.count() == 0: + continue + + category_annotations = fix_ids(category_annotations) + for annotation in category_annotations: + + has_segmentation = len(annotation.get('segmentation', [])) > 0 + has_keypoints = len(annotation.get('keypoints', [])) > 0 + + if has_segmentation or has_keypoints: + + if has_keypoints: + arr = np.array(annotation.get('keypoints', [])) + arr = arr[2::3] + annotation['num_keypoints'] = len(arr[arr > 0]) + + annotations.append(annotation) + + if len(category.get('keypoint_labels')) > 0: + category['keypoints'] = category.pop('keypoint_labels') + category['skeleton'] = category.pop('keypoint_edges') + else: + del category['keypoint_edges'] + del category['keypoint_labels'] + + categories.append(category) + + coco = { + "images": [image], + "categories": categories, + "annotations": annotations + } + + return coco + + +def get_dataset_coco(dataset): + """ + Generates coco for all images in dataset + + :param dataset: DatasetModel + :return: Coco in dictionary format + """ + + categories = CategoryModel.objects(deleted=False) \ + .exclude('deleted_date').in_bulk(dataset.categories).items() + + dataset = fix_ids(dataset) + + images = ImageModel.objects(deleted=False, dataset_id=dataset.get('id')).exclude('deleted_date') + all_annotations = AnnotationModel.objects(deleted=False).exclude('deleted_date', 'paper_object') + + coco = { + 'images': [], + 'categories': [], + 'annotations': [] + } + + for category in categories: + category = fix_ids(category[1]) + + del category['deleted'] + if len(category.get('keypoint_labels', [])) > 0: + category['keypoints'] = category.pop('keypoint_labels') + category['skeleton'] = category.pop('keypoint_edges') + else: + del category['keypoint_edges'] + del category['keypoint_labels'] + + coco.get('categories').append(category) + + for image in images: + annotations = all_annotations.filter(image_id=image.id) + if annotations.count() == 0: + continue + + annotations = fix_ids(annotations.all()) + + for annotation in annotations: + + has_keypoints = len(annotation.get('keypoints', [])) > 0 + has_segmentation = len(annotation.get('segmentation', [])) > 0 + + if has_keypoints or has_segmentation: + del annotation['deleted'] + + if not has_keypoints: + del annotation['keypoints'] + else: + arr = np.array(annotation.get('keypoints', [])) + arr = arr[2::3] + annotation['num_keypoints'] = len(arr[arr > 0]) + + coco.get('annotations').append(annotation) + + image = fix_ids(image) + del image['deleted'] + coco.get('images').append(image) + + return coco + + +def _fit(value, max_value, min_value): + return max(min(value, max_value), min_value) diff --git a/backend/webserver/util/dextr.py b/backend/webserver/util/dextr.py new file mode 100644 index 00000000..5f1f03e4 --- /dev/null +++ b/backend/webserver/util/dextr.py @@ -0,0 +1,6 @@ +from dextr import DEXTR +from config import Config + + +model = DEXTR(nb_classes=1, resnet_layers=101, input_shape=(512, 512), weights_path=Config.DEXTR_FILE, + num_input_channels=4, classifier='psp', sigmoid=True) diff --git a/backend/webserver/util/mask_rcnn.py b/backend/webserver/util/mask_rcnn.py new file mode 100644 index 00000000..593ce072 --- /dev/null +++ b/backend/webserver/util/mask_rcnn.py @@ -0,0 +1,73 @@ +from config import Config as AnnotatorConfig +from skimage.transform import resize +import imantics as im + +from keras.preprocessing.image import img_to_array +from mrcnn.config import Config +import mrcnn.model as modellib +import logging +logger = logging.getLogger('gunicorn.error') + + +MODEL_DIR = "/workspace/models" +COCO_MODEL_PATH = AnnotatorConfig.MASK_RCNN_FILE +CLASS_NAMES = AnnotatorConfig.MASK_RCNN_CLASSES.split(',') + +class CocoConfig(Config): + """ + Configuration for COCO Dataset. + """ + NAME = "coco" + GPU_COUNT = 1 + IMAGES_PER_GPU = 1 + NUM_CLASSES = len(CLASS_NAMES) + + +class MaskRCNN(): + + def __init__(self): + + self.config = CocoConfig() + self.model = modellib.MaskRCNN( + mode="inference", + model_dir=MODEL_DIR, + config=self.config + ) + try: + self.model.load_weights(COCO_MODEL_PATH, by_name=True) + self.model.keras_model._make_predict_function() + logger.info(f"Loaded MaskRCNN model: {COCO_MODEL_PATH}") + except: + logger.error(f"Could not load MaskRCNN model (place 'mask_rcnn_coco.h5' in the models directory)") + self.model = None + + + def detect(self, image): + + if self.model is None: + return {} + + image = image.convert('RGB') + width, height = image.size + image.thumbnail((1024, 1024)) + + image = img_to_array(image) + result = self.model.detect([image])[0] + + masks = result.get('masks') + class_ids = result.get('class_ids') + + coco_image = im.Image(width=width, height=height) + + for i in range(masks.shape[-1]): + mask = resize(masks[..., i], (height, width)) + mask = im.Mask(mask) + class_id = class_ids[i] + class_name = CLASS_NAMES[class_id] + category = im.Category(class_name) + coco_image.add(mask, category=category) + + return coco_image.coco() + + +model = MaskRCNN() diff --git a/app/util/pagination_util.py b/backend/webserver/util/pagination_util.py similarity index 100% rename from app/util/pagination_util.py rename to backend/webserver/util/pagination_util.py diff --git a/backend/webserver/util/query_util.py b/backend/webserver/util/query_util.py new file mode 100644 index 00000000..5a09b9c5 --- /dev/null +++ b/backend/webserver/util/query_util.py @@ -0,0 +1,28 @@ +import json + + +def fix_ids(objs): + objects_list = json.loads(objs.to_json().replace('\"_id\"', '\"id\"')) + return objects_list + + +def td_format(td_object): + seconds = int(td_object.total_seconds()) + periods = [ + ('year', 60*60*24*365), + ('month', 60*60*24*30), + ('day', 60*60*24), + ('hour', 60*60), + ('minute', 60), + ('second', 1) + ] + + strings = [] + for period_name, period_seconds in periods: + if seconds > period_seconds: + period_value, seconds = divmod(seconds, period_seconds) + has_s = 's' if period_value > 1 else '' + strings.append("%s %s%s" % (period_value, period_name, has_s)) + break + + return ", ".join(strings) diff --git a/backend/webserver/util/thumbnails.py b/backend/webserver/util/thumbnails.py new file mode 100644 index 00000000..3690365e --- /dev/null +++ b/backend/webserver/util/thumbnails.py @@ -0,0 +1,12 @@ +from database import ImageModel + + +def generate_thumbnails(): + PREFIX = "[Thumbnails]" + print(f'{PREFIX} Sending request for regenerating images with non actual thumbnails', flush=True) + [generate_thumbnail(image) for image in ImageModel.objects(regenerate_thumbnail=True).all()] + + +def generate_thumbnail(image): + from workers.tasks import thumbnail_generate_single_image + thumbnail_generate_single_image.delay(image.id) diff --git a/app/util/version_util.py b/backend/webserver/util/version_util.py similarity index 95% rename from app/util/version_util.py rename to backend/webserver/util/version_util.py index 8e72c00d..e6d58c1c 100644 --- a/app/util/version_util.py +++ b/backend/webserver/util/version_util.py @@ -46,7 +46,6 @@ def get_latest(self): r = requests.get(COMMITS.format(self.branch)) if r.status_code != requests.codes.ok: - print(r.json(), flush=True) self.valid = False return "" @@ -60,7 +59,6 @@ def get_commits_behind(self): r = requests.get(COMPARE.format(self.latest_version, self.current_version)) if r.status_code != requests.codes.ok: - print(r.json(), flush=True) self.valid = False return 0 diff --git a/backend/webserver/watcher.py b/backend/webserver/watcher.py new file mode 100644 index 00000000..610ecec7 --- /dev/null +++ b/backend/webserver/watcher.py @@ -0,0 +1,62 @@ +from watchdog.events import FileSystemEventHandler +from watchdog.observers import Observer + +from config import Config +from database import ImageModel +from .util.thumbnails import generate_thumbnail + +import re + + +class ImageFolderHandler(FileSystemEventHandler): + + PREFIX = "[File Watcher]" + + def __init__(self, pattern=None): + self.pattern = pattern or ImageModel.PATTERN + + def on_any_event(self, event): + + path = event.dest_path if event.event_type == "moved" else event.src_path + + if event.is_directory: + # Listen to directory events as some file systems don't generate + # per-file `deleted` events when moving/deleting directories + if event.event_type == 'deleted': + self._log(f'Deleting images from database {path}') + ImageModel.objects(path=re.compile('^' + re.escape(path))).delete() + return + + if ( + # check if its a hidden file + bool(re.search(r'\/\..*?\/', path)) + or not path.lower().endswith(self.pattern) + ): + return + + self._log(f'File {path} for {event.event_type}') + + image = ImageModel.objects(path=event.src_path).first() + + if image is None and event.event_type != 'deleted': + self._log(f'Adding new file to database: {path}') + image = ImageModel.create_from_path(path).save() + generate_thumbnail(image) + + elif event.event_type == 'moved': + self._log(f'Moving image from {event.src_path} to {path}') + image.update(path=path) + generate_thumbnail(image) + + elif event.event_type == 'deleted': + self._log(f'Deleting image from database {path}') + ImageModel.objects(path=path).delete() + + def _log(self, message): + print(f'{self.PREFIX} {message}', flush=True) + + +def run_watcher(): + observer = Observer() + observer.schedule(ImageFolderHandler(), Config.DATASET_DIRECTORY, recursive=True) + observer.start() diff --git a/backend/workers/Dockerfile b/backend/workers/Dockerfile new file mode 100644 index 00000000..81626d31 --- /dev/null +++ b/backend/workers/Dockerfile @@ -0,0 +1,9 @@ +FROM jsbroks/coco-annotator:python-env + +WORKDIR /workspace/ + +# Install python package dependices +COPY ./backend/ /workspace/ + +EXPOSE 5555 +CMD celery -A workers worker -l info diff --git a/backend/workers/__init__.py b/backend/workers/__init__.py new file mode 100644 index 00000000..817fe9ac --- /dev/null +++ b/backend/workers/__init__.py @@ -0,0 +1,16 @@ +from celery import Celery +from config import Config +from database import connect_mongo + +connect_mongo('Celery_Worker') + +celery = Celery( + Config.NAME, + backend=Config.CELERY_RESULT_BACKEND, + broker=Config.CELERY_BROKER_URL +) +celery.autodiscover_tasks(['workers.tasks']) + + +if __name__ == '__main__': + celery.start() diff --git a/backend/workers/socket.py b/backend/workers/socket.py new file mode 100644 index 00000000..391b112f --- /dev/null +++ b/backend/workers/socket.py @@ -0,0 +1,6 @@ +from config import Config +from flask_socketio import SocketIO + + +def create_socket(): + return SocketIO(message_queue=Config.CELERY_BROKER_URL) diff --git a/backend/workers/tasks/__init__.py b/backend/workers/tasks/__init__.py new file mode 100644 index 00000000..b00d7307 --- /dev/null +++ b/backend/workers/tasks/__init__.py @@ -0,0 +1,5 @@ + +from .data import * +from .test import * +from .scan import * +from .thumbnails import * \ No newline at end of file diff --git a/backend/workers/tasks/data.py b/backend/workers/tasks/data.py new file mode 100644 index 00000000..4c9817a2 --- /dev/null +++ b/backend/workers/tasks/data.py @@ -0,0 +1,313 @@ + +from database import ( + fix_ids, + ImageModel, + CategoryModel, + AnnotationModel, + DatasetModel, + TaskModel, + ExportModel +) + +# import pycocotools.mask as mask +import numpy as np +import time +import json +import os + +from celery import shared_task +from ..socket import create_socket +from mongoengine import Q + + +@shared_task +def export_annotations(task_id, dataset_id, categories, with_empty_images=False): + + task = TaskModel.objects.get(id=task_id) + dataset = DatasetModel.objects.get(id=dataset_id) + + task.update(status="PROGRESS") + socket = create_socket() + + task.info("Beginning Export (COCO Format)") + + db_categories = CategoryModel.objects(id__in=categories, deleted=False) \ + .only(*CategoryModel.COCO_PROPERTIES) + db_images = ImageModel.objects( + deleted=False, dataset_id=dataset.id).only( + *ImageModel.COCO_PROPERTIES) + db_annotations = AnnotationModel.objects( + deleted=False, category_id__in=categories) + + total_items = db_categories.count() + + coco = { + 'images': [], + 'categories': [], + 'annotations': [] + } + + total_items += db_images.count() + progress = 0 + + # iterate though all categoires and upsert + category_names = [] + for category in fix_ids(db_categories): + + if len(category.get('keypoint_labels', [])) > 0: + category['keypoints'] = category.pop('keypoint_labels', []) + category['skeleton'] = category.pop('keypoint_edges', []) + else: + if 'keypoint_edges' in category: + del category['keypoint_edges'] + if 'keypoint_labels' in category: + del category['keypoint_labels'] + + task.info(f"Adding category: {category.get('name')}") + coco.get('categories').append(category) + category_names.append(category.get('name')) + + progress += 1 + task.set_progress((progress / total_items) * 100, socket=socket) + + total_annotations = db_annotations.count() + total_images = db_images.count() + for image in db_images: + image = fix_ids(image) + + progress += 1 + task.set_progress((progress / total_items) * 100, socket=socket) + + annotations = db_annotations.filter(image_id=image.get('id'))\ + .only(*AnnotationModel.COCO_PROPERTIES) + annotations = fix_ids(annotations) + + if len(annotations) == 0: + if with_empty_images: + coco.get('images').append(image) + continue + + num_annotations = 0 + for annotation in annotations: + + has_keypoints = len(annotation.get('keypoints', [])) > 0 + has_segmentation = len(annotation.get('segmentation', [])) > 0 + + if has_keypoints or has_segmentation: + + if not has_keypoints: + if 'keypoints' in annotation: + del annotation['keypoints'] + else: + arr = np.array(annotation.get('keypoints', [])) + arr = arr[2::3] + annotation['num_keypoints'] = len(arr[arr > 0]) + + num_annotations += 1 + coco.get('annotations').append(annotation) + + task.info( + f"Exporting {num_annotations} annotations for image {image.get('id')}") + coco.get('images').append(image) + + task.info( + f"Done export {total_annotations} annotations and {total_images} images from {dataset.name}") + + timestamp = time.time() + directory = f"{dataset.directory}.exports/" + file_path = f"{directory}coco-{timestamp}.json" + + if not os.path.exists(directory): + os.makedirs(directory) + + task.info(f"Writing export to file {file_path}") + with open(file_path, 'w') as fp: + json.dump(coco, fp) + + task.info("Creating export object") + export = ExportModel(dataset_id=dataset.id, path=file_path, tags=[ + "COCO", *category_names]) + export.save() + + task.set_progress(100, socket=socket) + + +@shared_task +def import_annotations(task_id, dataset_id, coco_json): + + task = TaskModel.objects.get(id=task_id) + dataset = DatasetModel.objects.get(id=dataset_id) + + task.update(status="PROGRESS") + socket = create_socket() + + task.info("Beginning Import") + + images = ImageModel.objects(dataset_id=dataset.id) + categories = CategoryModel.objects + + coco_images = coco_json.get('images', []) + coco_annotations = coco_json.get('annotations', []) + coco_categories = coco_json.get('categories', []) + + task.info(f"Importing {len(coco_categories)} categories, " + f"{len(coco_images)} images, and " + f"{len(coco_annotations)} annotations") + + total_items = sum([ + len(coco_categories), + len(coco_annotations), + len(coco_images) + ]) + progress = 0 + + task.info("===== Importing Categories =====") + # category id mapping ( file : database ) + categories_id = {} + + # Create any missing categories + for category in coco_categories: + + category_name = category.get('name') + category_id = category.get('id') + category_model = categories.filter(name__iexact=category_name).first() + + if category_model is None: + task.warning( + f"{category_name} category not found (creating a new one)") + + new_category = CategoryModel( + name=category_name, + keypoint_edges=category.get('skeleton', []), + keypoint_labels=category.get('keypoints', []) + ) + new_category.save() + + category_model = new_category + dataset.categories.append(new_category.id) + + task.info(f"{category_name} category found") + # map category ids + categories_id[category_id] = category_model.id + + # update progress + progress += 1 + task.set_progress((progress / total_items) * 100, socket=socket) + + dataset.update(set__categories=dataset.categories) + + task.info("===== Loading Images =====") + # image id mapping ( file: database ) + images_id = {} + categories_by_image = {} + + # Find all images + for image in coco_images: + image_id = image.get('id') + image_filename = image.get('file_name') + + # update progress + progress += 1 + task.set_progress((progress / total_items) * 100, socket=socket) + + image_model = images.filter(file_name__exact=image_filename).all() + + if len(image_model) == 0: + task.warning(f"Could not find image {image_filename}") + continue + + if len(image_model) > 1: + task.error( + f"Too many images found with the same file name: {image_filename}") + continue + + task.info(f"Image {image_filename} found") + image_model = image_model[0] + images_id[image_id] = image_model + categories_by_image[image_id] = list() + + task.info("===== Import Annotations =====") + for annotation in coco_annotations: + + image_id = annotation.get('image_id') + category_id = annotation.get('category_id') + segmentation = annotation.get('segmentation', []) + keypoints = annotation.get('keypoints', []) + # is_crowd = annotation.get('iscrowed', False) + area = annotation.get('area', 0) + bbox = annotation.get('bbox', [0, 0, 0, 0]) + isbbox = annotation.get('isbbox', False) + + progress += 1 + task.set_progress((progress / total_items) * 100, socket=socket) + + has_segmentation = len(segmentation) > 0 + has_keypoints = len(keypoints) > 0 + if not has_segmentation and not has_keypoints: + task.warning( + f"Annotation {annotation.get('id')} has no segmentation or keypoints") + continue + + try: + image_model = images_id[image_id] + category_model_id = categories_id[category_id] + image_categories = categories_by_image[image_id] + except KeyError: + task.warning( + f"Could not find image assoicated with annotation {annotation.get('id')}") + continue + + annotation_model = AnnotationModel.objects( + image_id=image_model.id, + category_id=category_model_id, + segmentation=segmentation, + keypoints=keypoints + ).first() + + if annotation_model is None: + task.info(f"Creating annotation data ({image_id}, {category_id})") + + annotation_model = AnnotationModel(image_id=image_model.id) + annotation_model.category_id = category_model_id + + annotation_model.color = annotation.get('color') + annotation_model.metadata = annotation.get('metadata', {}) + + if has_segmentation: + annotation_model.segmentation = segmentation + annotation_model.area = area + annotation_model.bbox = bbox + + if has_keypoints: + annotation_model.keypoints = keypoints + + annotation_model.isbbox = isbbox + annotation_model.save() + + image_categories.append(category_id) + else: + annotation_model.update(deleted=False, isbbox=isbbox) + task.info( + f"Annotation already exists (i:{image_id}, c:{category_id})") + + for image_id in images_id: + image_model = images_id[image_id] + category_ids = categories_by_image[image_id] + all_category_ids = list(image_model.category_ids) + all_category_ids += category_ids + + num_annotations = AnnotationModel.objects( + Q(image_id=image_id) & Q(deleted=False) & + (Q(area__gt=0) | Q(keypoints__size__gt=0)) + ).count() + + image_model.update( + set__annotated=True, + set__category_ids=list(set(all_category_ids)), + set__num_annotations=num_annotations + ) + + task.set_progress(100, socket=socket) + + +__all__ = ["export_annotations", "import_annotations"] diff --git a/backend/workers/tasks/scan.py b/backend/workers/tasks/scan.py new file mode 100644 index 00000000..df6efd7c --- /dev/null +++ b/backend/workers/tasks/scan.py @@ -0,0 +1,62 @@ +from database import ( + ImageModel, + TaskModel, + DatasetModel +) + +from celery import shared_task +from ..socket import create_socket +from .thumbnails import thumbnail_generate_single_image + +import os + + +@shared_task +def scan_dataset(task_id, dataset_id): + + task = TaskModel.objects.get(id=task_id) + dataset = DatasetModel.objects.get(id=dataset_id) + + task.update(status="PROGRESS") + socket = create_socket() + + directory = dataset.directory + toplevel = list(os.listdir(directory)) + task.info(f"Scanning {directory}") + + count = 0 + for root, dirs, files in os.walk(directory): + + try: + youarehere = toplevel.index(root.split('/')[-1]) + progress = int(((youarehere)/len(toplevel))*100) + task.set_progress(progress, socket=socket) + except: + pass + + if root.split('/')[-1].startswith('.'): + continue + + for file in files: + path = os.path.join(root, file) + + if path.endswith(ImageModel.PATTERN): + db_image = ImageModel.objects(path=path).first() + + if db_image is not None: + continue + + try: + ImageModel.create_from_path(path, dataset.id).save() + count += 1 + task.info(f"New file found: {path}") + except: + task.warning(f"Could not read {path}") + + [thumbnail_generate_single_image.delay(image.id) for image in ImageModel.objects(regenerate_thumbnail=True).all()] + + task.info(f"Created {count} new image(s)") + task.set_progress(100, socket=socket) + + +__all__ = ["scan_dataset"] \ No newline at end of file diff --git a/backend/workers/tasks/test.py b/backend/workers/tasks/test.py new file mode 100644 index 00000000..fe5ad144 --- /dev/null +++ b/backend/workers/tasks/test.py @@ -0,0 +1,27 @@ + +from celery import shared_task +from database import TaskModel + +from ..socket import create_socket + + +@shared_task +def long_task(n, task_id): + + task = TaskModel.objects.get(id=task_id) + task.update(status="PROGRESS") + + socketio = create_socket() + + print(f"This task will take {n} seconds") + import time + + for i in range(n): + print(i) + time.sleep(1) + socketio.emit('test', i) + + return n + + +__all__ = ["long_task"] \ No newline at end of file diff --git a/backend/workers/tasks/thumbnails.py b/backend/workers/tasks/thumbnails.py new file mode 100644 index 00000000..259a980c --- /dev/null +++ b/backend/workers/tasks/thumbnails.py @@ -0,0 +1,12 @@ +from database import ImageModel +from celery import task + + +@task +def thumbnail_generate_single_image(image_id): + image = ImageModel.objects(id=image_id).first() + image.thumbnail() + image.flag_thumbnail(flag=False) + + +__all__ = ["thumbnail_generate_single_image"] \ No newline at end of file diff --git a/build_gpu.sh b/build_gpu.sh new file mode 100755 index 00000000..587389b3 --- /dev/null +++ b/build_gpu.sh @@ -0,0 +1,3 @@ +docker build -f ./backend/Dockerfile . -t jsbroks/coco-annotator:python-env --no-cache +docker build . -t annotator_webclient_gpu --no-cache +docker build -f ./backend/workers/Dockerfile . -t annotator_workers_gpu --no-cache diff --git a/docker/client/Dockerfile b/client/Dockerfile similarity index 78% rename from docker/client/Dockerfile rename to client/Dockerfile index 140e3c1f..c2cf2e96 100644 --- a/docker/client/Dockerfile +++ b/client/Dockerfile @@ -1,8 +1,5 @@ FROM node:10 -RUN apt-get -y update \ - && apt-get install -y git - RUN npm install -g --quiet \ @vue/cli@3.3.0 \ @vue/cli-service@3.3.0 @@ -13,7 +10,7 @@ COPY ./client/package.json /workspace/package.json RUN npm install ENV NODE_PATH=/workspace/node_modules -WORKDIR client/ +WORKDIR /workspace/client/ EXPOSE 8080 CMD npm run serve \ No newline at end of file diff --git a/client/package-lock.json b/client/package-lock.json index 8dc252ef..8c5c46ae 100755 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -10,7 +10,7 @@ "integrity": "sha1-BuKrGb21NThVWaq7W6WXKUgoAPg=", "dev": true, "requires": { - "@babel/highlight": "7.0.0" + "@babel/highlight": "^7.0.0" } }, "@babel/core": { @@ -19,20 +19,20 @@ "integrity": "sha512-Hz6PJT6e44iUNpAn8AoyAs6B3bl60g7MJQaI0rZEar6ECzh6+srYO1xlIdssio34mPaUtAb1y+XlkkSJzok3yw==", "dev": true, "requires": { - "@babel/code-frame": "7.0.0", - "@babel/generator": "7.1.6", - "@babel/helpers": "7.1.5", - "@babel/parser": "7.1.6", - "@babel/template": "7.1.2", - "@babel/traverse": "7.1.6", - "@babel/types": "7.1.6", - "convert-source-map": "1.6.0", - "debug": "4.1.0", - "json5": "2.1.0", - "lodash": "4.17.11", - "resolve": "1.8.1", - "semver": "5.6.0", - "source-map": "0.5.7" + "@babel/code-frame": "^7.0.0", + "@babel/generator": "^7.1.6", + "@babel/helpers": "^7.1.5", + "@babel/parser": "^7.1.6", + "@babel/template": "^7.1.2", + "@babel/traverse": "^7.1.6", + "@babel/types": "^7.1.6", + "convert-source-map": "^1.1.0", + "debug": "^4.1.0", + "json5": "^2.1.0", + "lodash": "^4.17.10", + "resolve": "^1.3.2", + "semver": "^5.4.1", + "source-map": "^0.5.0" }, "dependencies": { "debug": { @@ -41,7 +41,7 @@ "integrity": "sha512-heNPJUJIqC+xB6ayLAMHaIrmN9HKa7aQO8MGqKpvCA+uJYVcvR6l5kgdrhRuwPFHU7P5/A1w0BjByPHwpfTDKg==", "dev": true, "requires": { - "ms": "2.1.1" + "ms": "^2.1.1" } }, "ms": { @@ -58,11 +58,11 @@ "integrity": "sha512-brwPBtVvdYdGxtenbQgfCdDPmtkmUBZPjUoK5SXJEBuHaA5BCubh9ly65fzXz7R6o5rA76Rs22ES8Z+HCc0YIQ==", "dev": true, "requires": { - "@babel/types": "7.1.6", - "jsesc": "2.5.2", - "lodash": "4.17.11", - "source-map": "0.5.7", - "trim-right": "1.0.1" + "@babel/types": "^7.1.6", + "jsesc": "^2.5.1", + "lodash": "^4.17.10", + "source-map": "^0.5.0", + "trim-right": "^1.0.1" } }, "@babel/helper-annotate-as-pure": { @@ -71,7 +71,7 @@ "integrity": "sha512-3UYcJUj9kvSLbLbUIfQTqzcy5VX7GRZ/CCDrnOaZorFFM01aXp1+GJwuFGV4NDDoAS+mOUyHcO6UD/RfqOks3Q==", "dev": true, "requires": { - "@babel/types": "7.1.6" + "@babel/types": "^7.0.0" } }, "@babel/helper-builder-binary-assignment-operator-visitor": { @@ -80,8 +80,8 @@ "integrity": "sha512-qNSR4jrmJ8M1VMM9tibvyRAHXQs2PmaksQF7c1CGJNipfe3D8p+wgNwgso/P2A2r2mdgBWAXljNWR0QRZAMW8w==", "dev": true, "requires": { - "@babel/helper-explode-assignable-expression": "7.1.0", - "@babel/types": "7.1.6" + "@babel/helper-explode-assignable-expression": "^7.1.0", + "@babel/types": "^7.0.0" } }, "@babel/helper-call-delegate": { @@ -90,9 +90,9 @@ "integrity": "sha512-YEtYZrw3GUK6emQHKthltKNZwszBcHK58Ygcis+gVUrF4/FmTVr5CCqQNSfmvg2y+YDEANyYoaLz/SHsnusCwQ==", "dev": true, "requires": { - "@babel/helper-hoist-variables": "7.0.0", - "@babel/traverse": "7.1.6", - "@babel/types": "7.1.6" + "@babel/helper-hoist-variables": "^7.0.0", + "@babel/traverse": "^7.1.0", + "@babel/types": "^7.0.0" } }, "@babel/helper-define-map": { @@ -101,9 +101,9 @@ "integrity": "sha512-yPPcW8dc3gZLN+U1mhYV91QU3n5uTbx7DUdf8NnPbjS0RMwBuHi9Xt2MUgppmNz7CJxTBWsGczTiEp1CSOTPRg==", "dev": true, "requires": { - "@babel/helper-function-name": "7.1.0", - "@babel/types": "7.1.6", - "lodash": "4.17.11" + "@babel/helper-function-name": "^7.1.0", + "@babel/types": "^7.0.0", + "lodash": "^4.17.10" } }, "@babel/helper-explode-assignable-expression": { @@ -112,8 +112,8 @@ "integrity": "sha512-NRQpfHrJ1msCHtKjbzs9YcMmJZOg6mQMmGRB+hbamEdG5PNpaSm95275VD92DvJKuyl0s2sFiDmMZ+EnnvufqA==", "dev": true, "requires": { - "@babel/traverse": "7.1.6", - "@babel/types": "7.1.6" + "@babel/traverse": "^7.1.0", + "@babel/types": "^7.0.0" } }, "@babel/helper-function-name": { @@ -122,9 +122,9 @@ "integrity": "sha1-oM6wFoX3M1XUNgwSR/WCv6/I/1M=", "dev": true, "requires": { - "@babel/helper-get-function-arity": "7.0.0", - "@babel/template": "7.1.2", - "@babel/types": "7.1.6" + "@babel/helper-get-function-arity": "^7.0.0", + "@babel/template": "^7.1.0", + "@babel/types": "^7.0.0" } }, "@babel/helper-get-function-arity": { @@ -133,7 +133,7 @@ "integrity": "sha1-g1ctQyDipGVyY3NBE8QoaLZOScM=", "dev": true, "requires": { - "@babel/types": "7.1.6" + "@babel/types": "^7.0.0" } }, "@babel/helper-hoist-variables": { @@ -142,7 +142,7 @@ "integrity": "sha512-Ggv5sldXUeSKsuzLkddtyhyHe2YantsxWKNi7A+7LeD12ExRDWTRk29JCXpaHPAbMaIPZSil7n+lq78WY2VY7w==", "dev": true, "requires": { - "@babel/types": "7.1.6" + "@babel/types": "^7.0.0" } }, "@babel/helper-member-expression-to-functions": { @@ -151,7 +151,7 @@ "integrity": "sha512-avo+lm/QmZlv27Zsi0xEor2fKcqWG56D5ae9dzklpIaY7cQMK5N8VSpaNVPPagiqmy7LrEjK1IWdGMOqPu5csg==", "dev": true, "requires": { - "@babel/types": "7.1.6" + "@babel/types": "^7.0.0" } }, "@babel/helper-module-imports": { @@ -160,7 +160,7 @@ "integrity": "sha512-aP/hlLq01DWNEiDg4Jn23i+CXxW/owM4WpDLFUbpjxe4NS3BhLVZQ5i7E0ZrxuQ/vwekIeciyamgB1UIYxxM6A==", "dev": true, "requires": { - "@babel/types": "7.1.6" + "@babel/types": "^7.0.0" } }, "@babel/helper-module-transforms": { @@ -169,12 +169,12 @@ "integrity": "sha1-Rw1PlnbZ+tULMkzczl+6u8PaV4c=", "dev": true, "requires": { - "@babel/helper-module-imports": "7.0.0", - "@babel/helper-simple-access": "7.1.0", - "@babel/helper-split-export-declaration": "7.0.0", - "@babel/template": "7.1.2", - "@babel/types": "7.1.6", - "lodash": "4.17.11" + "@babel/helper-module-imports": "^7.0.0", + "@babel/helper-simple-access": "^7.1.0", + "@babel/helper-split-export-declaration": "^7.0.0", + "@babel/template": "^7.1.0", + "@babel/types": "^7.0.0", + "lodash": "^4.17.10" } }, "@babel/helper-optimise-call-expression": { @@ -183,7 +183,7 @@ "integrity": "sha512-u8nd9NQePYNQV8iPWu/pLLYBqZBa4ZaY1YWRFMuxrid94wKI1QNt67NEZ7GAe5Kc/0LLScbim05xZFWkAdrj9g==", "dev": true, "requires": { - "@babel/types": "7.1.6" + "@babel/types": "^7.0.0" } }, "@babel/helper-plugin-utils": { @@ -198,7 +198,7 @@ "integrity": "sha512-TR0/N0NDCcUIUEbqV6dCO+LptmmSQFQ7q70lfcEB4URsjD0E1HzicrwUH+ap6BAQ2jhCX9Q4UqZy4wilujWlkg==", "dev": true, "requires": { - "lodash": "4.17.11" + "lodash": "^4.17.10" } }, "@babel/helper-remap-async-to-generator": { @@ -207,11 +207,11 @@ "integrity": "sha512-3fOK0L+Fdlg8S5al8u/hWE6vhufGSn0bN09xm2LXMy//REAF8kDCrYoOBKYmA8m5Nom+sV9LyLCwrFynA8/slg==", "dev": true, "requires": { - "@babel/helper-annotate-as-pure": "7.0.0", - "@babel/helper-wrap-function": "7.1.0", - "@babel/template": "7.1.2", - "@babel/traverse": "7.1.6", - "@babel/types": "7.1.6" + "@babel/helper-annotate-as-pure": "^7.0.0", + "@babel/helper-wrap-function": "^7.1.0", + "@babel/template": "^7.1.0", + "@babel/traverse": "^7.1.0", + "@babel/types": "^7.0.0" } }, "@babel/helper-replace-supers": { @@ -220,10 +220,10 @@ "integrity": "sha1-X8Md5SLsDvCJncmz589qXdZV82I=", "dev": true, "requires": { - "@babel/helper-member-expression-to-functions": "7.0.0", - "@babel/helper-optimise-call-expression": "7.0.0", - "@babel/traverse": "7.1.6", - "@babel/types": "7.1.6" + "@babel/helper-member-expression-to-functions": "^7.0.0", + "@babel/helper-optimise-call-expression": "^7.0.0", + "@babel/traverse": "^7.1.0", + "@babel/types": "^7.0.0" } }, "@babel/helper-simple-access": { @@ -232,8 +232,8 @@ "integrity": "sha512-Vk+78hNjRbsiu49zAPALxTb+JUQCz1aolpd8osOF16BGnLtseD21nbHgLPGUwrXEurZgiCOUmvs3ExTu4F5x6w==", "dev": true, "requires": { - "@babel/template": "7.1.2", - "@babel/types": "7.1.6" + "@babel/template": "^7.1.0", + "@babel/types": "^7.0.0" } }, "@babel/helper-split-export-declaration": { @@ -242,7 +242,7 @@ "integrity": "sha1-Oq4oXAMRwqsJXZl7jJqUytVH2BM=", "dev": true, "requires": { - "@babel/types": "7.1.6" + "@babel/types": "^7.0.0" } }, "@babel/helper-wrap-function": { @@ -251,10 +251,10 @@ "integrity": "sha1-jPVOkZBwYGfwFq+Pdcs9+CnMjGY=", "dev": true, "requires": { - "@babel/helper-function-name": "7.1.0", - "@babel/template": "7.1.2", - "@babel/traverse": "7.1.6", - "@babel/types": "7.1.6" + "@babel/helper-function-name": "^7.1.0", + "@babel/template": "^7.1.0", + "@babel/traverse": "^7.1.0", + "@babel/types": "^7.0.0" } }, "@babel/helpers": { @@ -263,9 +263,9 @@ "integrity": "sha512-2jkcdL02ywNBry1YNFAH/fViq4fXG0vdckHqeJk+75fpQ2OH+Az6076tX/M0835zA45E0Cqa6pV5Kiv9YOqjEg==", "dev": true, "requires": { - "@babel/template": "7.1.2", - "@babel/traverse": "7.1.6", - "@babel/types": "7.1.6" + "@babel/template": "^7.1.2", + "@babel/traverse": "^7.1.5", + "@babel/types": "^7.1.5" } }, "@babel/highlight": { @@ -274,9 +274,9 @@ "integrity": "sha1-9xDDjI1Fjm3ZogGvtjf8t4HOmeQ=", "dev": true, "requires": { - "chalk": "2.4.1", - "esutils": "2.0.2", - "js-tokens": "4.0.0" + "chalk": "^2.0.0", + "esutils": "^2.0.2", + "js-tokens": "^4.0.0" } }, "@babel/parser": { @@ -291,9 +291,9 @@ "integrity": "sha1-QcGnAuEAgUVuI6e3TYkZIt0bts4=", "dev": true, "requires": { - "@babel/helper-plugin-utils": "7.0.0", - "@babel/helper-remap-async-to-generator": "7.1.0", - "@babel/plugin-syntax-async-generators": "7.0.0" + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-remap-async-to-generator": "^7.1.0", + "@babel/plugin-syntax-async-generators": "^7.0.0" } }, "@babel/plugin-proposal-class-properties": { @@ -302,12 +302,12 @@ "integrity": "sha1-mvAYVrEkHbYOyIONhGkaoL0ejfQ=", "dev": true, "requires": { - "@babel/helper-function-name": "7.1.0", - "@babel/helper-member-expression-to-functions": "7.0.0", - "@babel/helper-optimise-call-expression": "7.0.0", - "@babel/helper-plugin-utils": "7.0.0", - "@babel/helper-replace-supers": "7.1.0", - "@babel/plugin-syntax-class-properties": "7.0.0" + "@babel/helper-function-name": "^7.1.0", + "@babel/helper-member-expression-to-functions": "^7.0.0", + "@babel/helper-optimise-call-expression": "^7.0.0", + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-replace-supers": "^7.1.0", + "@babel/plugin-syntax-class-properties": "^7.0.0" } }, "@babel/plugin-proposal-decorators": { @@ -316,10 +316,10 @@ "integrity": "sha512-U42f8KhUbtlhUDyV/wK4Rq/wWh8vWyttYABckG/v0vVnMPvayOewZC/83CbVdmyP+UhEqI368FEQ7hHMfhBpQA==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "7.0.0", - "@babel/helper-replace-supers": "7.1.0", - "@babel/helper-split-export-declaration": "7.0.0", - "@babel/plugin-syntax-decorators": "7.1.0" + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-replace-supers": "^7.1.0", + "@babel/helper-split-export-declaration": "^7.0.0", + "@babel/plugin-syntax-decorators": "^7.1.0" } }, "@babel/plugin-proposal-json-strings": { @@ -328,8 +328,8 @@ "integrity": "sha1-O017XPUeHy5w9SNR0o1E/Clw0B4=", "dev": true, "requires": { - "@babel/helper-plugin-utils": "7.0.0", - "@babel/plugin-syntax-json-strings": "7.0.0" + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-syntax-json-strings": "^7.0.0" } }, "@babel/plugin-proposal-object-rest-spread": { @@ -338,8 +338,8 @@ "integrity": "sha1-mhe1R/ZNBna2yc7NTt90qCq4Xn4=", "dev": true, "requires": { - "@babel/helper-plugin-utils": "7.0.0", - "@babel/plugin-syntax-object-rest-spread": "7.0.0" + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-syntax-object-rest-spread": "^7.0.0" } }, "@babel/plugin-proposal-optional-catch-binding": { @@ -348,8 +348,8 @@ "integrity": "sha1-thDZKP5VH/cRfULIu0EO7DEqZCU=", "dev": true, "requires": { - "@babel/helper-plugin-utils": "7.0.0", - "@babel/plugin-syntax-optional-catch-binding": "7.0.0" + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-syntax-optional-catch-binding": "^7.0.0" } }, "@babel/plugin-proposal-unicode-property-regex": { @@ -358,9 +358,9 @@ "integrity": "sha1-SYs5zXJTbNfEsmF30DAibroIzTM=", "dev": true, "requires": { - "@babel/helper-plugin-utils": "7.0.0", - "@babel/helper-regex": "7.0.0", - "regexpu-core": "4.2.0" + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-regex": "^7.0.0", + "regexpu-core": "^4.2.0" } }, "@babel/plugin-syntax-async-generators": { @@ -369,7 +369,7 @@ "integrity": "sha1-vwiR3Nv1lVg1nQxib9yUkOILwTw=", "dev": true, "requires": { - "@babel/helper-plugin-utils": "7.0.0" + "@babel/helper-plugin-utils": "^7.0.0" } }, "@babel/plugin-syntax-class-properties": { @@ -378,7 +378,7 @@ "integrity": "sha1-4FGvXTAMv7zsSnR243qANImIFjQ=", "dev": true, "requires": { - "@babel/helper-plugin-utils": "7.0.0" + "@babel/helper-plugin-utils": "^7.0.0" } }, "@babel/plugin-syntax-decorators": { @@ -387,7 +387,7 @@ "integrity": "sha1-L6fBp5BaKZyYU+vO80AwZnX5y9w=", "dev": true, "requires": { - "@babel/helper-plugin-utils": "7.0.0" + "@babel/helper-plugin-utils": "^7.0.0" } }, "@babel/plugin-syntax-dynamic-import": { @@ -396,7 +396,7 @@ "integrity": "sha1-bft9i2w74UzpUpYvZY87frVMM+4=", "dev": true, "requires": { - "@babel/helper-plugin-utils": "7.0.0" + "@babel/helper-plugin-utils": "^7.0.0" } }, "@babel/plugin-syntax-json-strings": { @@ -405,7 +405,7 @@ "integrity": "sha1-DSWaaAkOFbODzjcQ4B1bI/N3DL0=", "dev": true, "requires": { - "@babel/helper-plugin-utils": "7.0.0" + "@babel/helper-plugin-utils": "^7.0.0" } }, "@babel/plugin-syntax-jsx": { @@ -414,7 +414,7 @@ "integrity": "sha1-A01eK04UzK6i5ME3r35K+zk3X/0=", "dev": true, "requires": { - "@babel/helper-plugin-utils": "7.0.0" + "@babel/helper-plugin-utils": "^7.0.0" } }, "@babel/plugin-syntax-object-rest-spread": { @@ -423,7 +423,7 @@ "integrity": "sha1-N9j7yvIWvWWOoa6764t16I68VJs=", "dev": true, "requires": { - "@babel/helper-plugin-utils": "7.0.0" + "@babel/helper-plugin-utils": "^7.0.0" } }, "@babel/plugin-syntax-optional-catch-binding": { @@ -432,7 +432,7 @@ "integrity": "sha1-iG9yAIs6ixhZd/fLcHE7ReUe5HU=", "dev": true, "requires": { - "@babel/helper-plugin-utils": "7.0.0" + "@babel/helper-plugin-utils": "^7.0.0" } }, "@babel/plugin-transform-arrow-functions": { @@ -441,7 +441,7 @@ "integrity": "sha1-psFIdYSMaKO0sxY6SGU17yXH50k=", "dev": true, "requires": { - "@babel/helper-plugin-utils": "7.0.0" + "@babel/helper-plugin-utils": "^7.0.0" } }, "@babel/plugin-transform-async-to-generator": { @@ -450,9 +450,9 @@ "integrity": "sha1-EJ4DZJbFHdZYV+FqyrO6/fPFeBE=", "dev": true, "requires": { - "@babel/helper-module-imports": "7.0.0", - "@babel/helper-plugin-utils": "7.0.0", - "@babel/helper-remap-async-to-generator": "7.1.0" + "@babel/helper-module-imports": "^7.0.0", + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-remap-async-to-generator": "^7.1.0" } }, "@babel/plugin-transform-block-scoped-functions": { @@ -461,7 +461,7 @@ "integrity": "sha1-SCs/dRA5J+NyiLO2e2X4SOKqDQc=", "dev": true, "requires": { - "@babel/helper-plugin-utils": "7.0.0" + "@babel/helper-plugin-utils": "^7.0.0" } }, "@babel/plugin-transform-block-scoping": { @@ -470,8 +470,8 @@ "integrity": "sha512-jlYcDrz+5ayWC7mxgpn1Wj8zj0mmjCT2w0mPIMSwO926eXBRxpEgoN/uQVRBfjtr8ayjcmS+xk2G1jaP8JjMJQ==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "7.0.0", - "lodash": "4.17.11" + "@babel/helper-plugin-utils": "^7.0.0", + "lodash": "^4.17.10" } }, "@babel/plugin-transform-classes": { @@ -480,14 +480,14 @@ "integrity": "sha1-qz+KVkNhgAy8irHKbyEQgDhDIkk=", "dev": true, "requires": { - "@babel/helper-annotate-as-pure": "7.0.0", - "@babel/helper-define-map": "7.1.0", - "@babel/helper-function-name": "7.1.0", - "@babel/helper-optimise-call-expression": "7.0.0", - "@babel/helper-plugin-utils": "7.0.0", - "@babel/helper-replace-supers": "7.1.0", - "@babel/helper-split-export-declaration": "7.0.0", - "globals": "11.9.0" + "@babel/helper-annotate-as-pure": "^7.0.0", + "@babel/helper-define-map": "^7.1.0", + "@babel/helper-function-name": "^7.1.0", + "@babel/helper-optimise-call-expression": "^7.0.0", + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-replace-supers": "^7.1.0", + "@babel/helper-split-export-declaration": "^7.0.0", + "globals": "^11.1.0" } }, "@babel/plugin-transform-computed-properties": { @@ -496,7 +496,7 @@ "integrity": "sha1-L7uJAM0+gljyou3pCbkOdVYYXjE=", "dev": true, "requires": { - "@babel/helper-plugin-utils": "7.0.0" + "@babel/helper-plugin-utils": "^7.0.0" } }, "@babel/plugin-transform-destructuring": { @@ -505,7 +505,7 @@ "integrity": "sha1-5p/1DKAfrGy3KGPFROUWwrGTAS8=", "dev": true, "requires": { - "@babel/helper-plugin-utils": "7.0.0" + "@babel/helper-plugin-utils": "^7.0.0" } }, "@babel/plugin-transform-dotall-regex": { @@ -514,9 +514,9 @@ "integrity": "sha1-c6JNppvDw3AlH0Oj0EgZhUYRXlg=", "dev": true, "requires": { - "@babel/helper-plugin-utils": "7.0.0", - "@babel/helper-regex": "7.0.0", - "regexpu-core": "4.2.0" + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-regex": "^7.0.0", + "regexpu-core": "^4.1.3" } }, "@babel/plugin-transform-duplicate-keys": { @@ -525,7 +525,7 @@ "integrity": "sha1-oGAeWAmR58rOCA5M+RnP1Y2nToY=", "dev": true, "requires": { - "@babel/helper-plugin-utils": "7.0.0" + "@babel/helper-plugin-utils": "^7.0.0" } }, "@babel/plugin-transform-exponentiation-operator": { @@ -534,8 +534,8 @@ "integrity": "sha1-nDTC7n/XfgJ3nPo35AOi4QA8zHM=", "dev": true, "requires": { - "@babel/helper-builder-binary-assignment-operator-visitor": "7.1.0", - "@babel/helper-plugin-utils": "7.0.0" + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.1.0", + "@babel/helper-plugin-utils": "^7.0.0" } }, "@babel/plugin-transform-for-of": { @@ -544,7 +544,7 @@ "integrity": "sha1-8rpOrbg70X3Dx+mzD0cHNl4cPjk=", "dev": true, "requires": { - "@babel/helper-plugin-utils": "7.0.0" + "@babel/helper-plugin-utils": "^7.0.0" } }, "@babel/plugin-transform-function-name": { @@ -553,8 +553,8 @@ "integrity": "sha1-KcVVDVxGII5/cwUW1B7t3Ur/rbs=", "dev": true, "requires": { - "@babel/helper-function-name": "7.1.0", - "@babel/helper-plugin-utils": "7.0.0" + "@babel/helper-function-name": "^7.1.0", + "@babel/helper-plugin-utils": "^7.0.0" } }, "@babel/plugin-transform-literals": { @@ -563,7 +563,7 @@ "integrity": "sha1-KuwdKc3STEBzWckwzdiekU7o/4Y=", "dev": true, "requires": { - "@babel/helper-plugin-utils": "7.0.0" + "@babel/helper-plugin-utils": "^7.0.0" } }, "@babel/plugin-transform-modules-amd": { @@ -572,8 +572,8 @@ "integrity": "sha1-+eCnBywS4pYHm1pZ9Aj/W5e/hqg=", "dev": true, "requires": { - "@babel/helper-module-transforms": "7.1.0", - "@babel/helper-plugin-utils": "7.0.0" + "@babel/helper-module-transforms": "^7.1.0", + "@babel/helper-plugin-utils": "^7.0.0" } }, "@babel/plugin-transform-modules-commonjs": { @@ -582,9 +582,9 @@ "integrity": "sha1-Cp2GRRy7+ym9FRhjBol8Z/b5oFw=", "dev": true, "requires": { - "@babel/helper-module-transforms": "7.1.0", - "@babel/helper-plugin-utils": "7.0.0", - "@babel/helper-simple-access": "7.1.0" + "@babel/helper-module-transforms": "^7.1.0", + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-simple-access": "^7.1.0" } }, "@babel/plugin-transform-modules-systemjs": { @@ -593,8 +593,8 @@ "integrity": "sha1-IRmj49thL9dKGdiGUu+/6WE6XbA=", "dev": true, "requires": { - "@babel/helper-hoist-variables": "7.0.0", - "@babel/helper-plugin-utils": "7.0.0" + "@babel/helper-hoist-variables": "^7.0.0", + "@babel/helper-plugin-utils": "^7.0.0" } }, "@babel/plugin-transform-modules-umd": { @@ -603,8 +603,8 @@ "integrity": "sha1-opp9hdbyjDVhwzlkRCJXzGoh8qg=", "dev": true, "requires": { - "@babel/helper-module-transforms": "7.1.0", - "@babel/helper-plugin-utils": "7.0.0" + "@babel/helper-module-transforms": "^7.1.0", + "@babel/helper-plugin-utils": "^7.0.0" } }, "@babel/plugin-transform-new-target": { @@ -613,7 +613,7 @@ "integrity": "sha512-yin069FYjah+LbqfGeTfzIBODex/e++Yfa0rH0fpfam9uTbuEeEOx5GLGr210ggOV77mVRNoeqSYqeuaqSzVSw==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "7.0.0" + "@babel/helper-plugin-utils": "^7.0.0" } }, "@babel/plugin-transform-object-super": { @@ -622,8 +622,8 @@ "integrity": "sha1-sa4ZSgVLgm2NS6fKkUhtStoPkbs=", "dev": true, "requires": { - "@babel/helper-plugin-utils": "7.0.0", - "@babel/helper-replace-supers": "7.1.0" + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-replace-supers": "^7.1.0" } }, "@babel/plugin-transform-parameters": { @@ -632,9 +632,9 @@ "integrity": "sha1-RPSS+dYYyRJAJuYjAcKWv2Bqeu0=", "dev": true, "requires": { - "@babel/helper-call-delegate": "7.1.0", - "@babel/helper-get-function-arity": "7.0.0", - "@babel/helper-plugin-utils": "7.0.0" + "@babel/helper-call-delegate": "^7.1.0", + "@babel/helper-get-function-arity": "^7.0.0", + "@babel/helper-plugin-utils": "^7.0.0" } }, "@babel/plugin-transform-regenerator": { @@ -643,7 +643,7 @@ "integrity": "sha512-sj2qzsEx8KDVv1QuJc/dEfilkg3RRPvPYx/VnKLtItVQRWt1Wqf5eVCOLZm29CiGFfYYsA3VPjfizTCV0S0Dlw==", "dev": true, "requires": { - "regenerator-transform": "0.13.3" + "regenerator-transform": "^0.13.3" } }, "@babel/plugin-transform-runtime": { @@ -652,10 +652,10 @@ "integrity": "sha1-n3aSDUJVG7V34txZTfIptfdiS2M=", "dev": true, "requires": { - "@babel/helper-module-imports": "7.0.0", - "@babel/helper-plugin-utils": "7.0.0", - "resolve": "1.8.1", - "semver": "5.6.0" + "@babel/helper-module-imports": "^7.0.0", + "@babel/helper-plugin-utils": "^7.0.0", + "resolve": "^1.8.1", + "semver": "^5.5.1" } }, "@babel/plugin-transform-shorthand-properties": { @@ -664,7 +664,7 @@ "integrity": "sha1-hfivWS3MB2R1QaA1DoyVx79BnRU=", "dev": true, "requires": { - "@babel/helper-plugin-utils": "7.0.0" + "@babel/helper-plugin-utils": "^7.0.0" } }, "@babel/plugin-transform-spread": { @@ -673,7 +673,7 @@ "integrity": "sha1-k1g85I3YyF5T86RgVshW5K8wtJs=", "dev": true, "requires": { - "@babel/helper-plugin-utils": "7.0.0" + "@babel/helper-plugin-utils": "^7.0.0" } }, "@babel/plugin-transform-sticky-regex": { @@ -682,8 +682,8 @@ "integrity": "sha1-MKnWSsKrRu7Ah7hTBTW+zZDnM2Y=", "dev": true, "requires": { - "@babel/helper-plugin-utils": "7.0.0", - "@babel/helper-regex": "7.0.0" + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-regex": "^7.0.0" } }, "@babel/plugin-transform-template-literals": { @@ -692,8 +692,8 @@ "integrity": "sha1-CE8ZUu/lsVPdrmnriUX4gsepfGU=", "dev": true, "requires": { - "@babel/helper-annotate-as-pure": "7.0.0", - "@babel/helper-plugin-utils": "7.0.0" + "@babel/helper-annotate-as-pure": "^7.0.0", + "@babel/helper-plugin-utils": "^7.0.0" } }, "@babel/plugin-transform-typeof-symbol": { @@ -702,7 +702,7 @@ "integrity": "sha1-Tc8eUulD5SZ7cxO/80f9vg+Bzsk=", "dev": true, "requires": { - "@babel/helper-plugin-utils": "7.0.0" + "@babel/helper-plugin-utils": "^7.0.0" } }, "@babel/plugin-transform-unicode-regex": { @@ -711,9 +711,9 @@ "integrity": "sha1-xngOWxhjp2/nktkO3tn81bUdaPw=", "dev": true, "requires": { - "@babel/helper-plugin-utils": "7.0.0", - "@babel/helper-regex": "7.0.0", - "regexpu-core": "4.2.0" + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-regex": "^7.0.0", + "regexpu-core": "^4.1.3" } }, "@babel/preset-env": { @@ -722,47 +722,47 @@ "integrity": "sha512-YIBfpJNQMBkb6MCkjz/A9J76SNCSuGVamOVBgoUkLzpJD/z8ghHi9I42LQ4pulVX68N/MmImz6ZTixt7Azgexw==", "dev": true, "requires": { - "@babel/helper-module-imports": "7.0.0", - "@babel/helper-plugin-utils": "7.0.0", - "@babel/plugin-proposal-async-generator-functions": "7.1.0", - "@babel/plugin-proposal-json-strings": "7.0.0", - "@babel/plugin-proposal-object-rest-spread": "7.0.0", - "@babel/plugin-proposal-optional-catch-binding": "7.0.0", - "@babel/plugin-proposal-unicode-property-regex": "7.0.0", - "@babel/plugin-syntax-async-generators": "7.0.0", - "@babel/plugin-syntax-object-rest-spread": "7.0.0", - "@babel/plugin-syntax-optional-catch-binding": "7.0.0", - "@babel/plugin-transform-arrow-functions": "7.0.0", - "@babel/plugin-transform-async-to-generator": "7.1.0", - "@babel/plugin-transform-block-scoped-functions": "7.0.0", - "@babel/plugin-transform-block-scoping": "7.1.5", - "@babel/plugin-transform-classes": "7.1.0", - "@babel/plugin-transform-computed-properties": "7.0.0", - "@babel/plugin-transform-destructuring": "7.1.3", - "@babel/plugin-transform-dotall-regex": "7.0.0", - "@babel/plugin-transform-duplicate-keys": "7.0.0", - "@babel/plugin-transform-exponentiation-operator": "7.1.0", - "@babel/plugin-transform-for-of": "7.0.0", - "@babel/plugin-transform-function-name": "7.1.0", - "@babel/plugin-transform-literals": "7.0.0", - "@babel/plugin-transform-modules-amd": "7.1.0", - "@babel/plugin-transform-modules-commonjs": "7.1.0", - "@babel/plugin-transform-modules-systemjs": "7.1.3", - "@babel/plugin-transform-modules-umd": "7.1.0", - "@babel/plugin-transform-new-target": "7.0.0", - "@babel/plugin-transform-object-super": "7.1.0", - "@babel/plugin-transform-parameters": "7.1.0", - "@babel/plugin-transform-regenerator": "7.0.0", - "@babel/plugin-transform-shorthand-properties": "7.0.0", - "@babel/plugin-transform-spread": "7.0.0", - "@babel/plugin-transform-sticky-regex": "7.0.0", - "@babel/plugin-transform-template-literals": "7.0.0", - "@babel/plugin-transform-typeof-symbol": "7.0.0", - "@babel/plugin-transform-unicode-regex": "7.0.0", - "browserslist": "4.3.4", - "invariant": "2.2.4", - "js-levenshtein": "1.1.4", - "semver": "5.6.0" + "@babel/helper-module-imports": "^7.0.0", + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-proposal-async-generator-functions": "^7.1.0", + "@babel/plugin-proposal-json-strings": "^7.0.0", + "@babel/plugin-proposal-object-rest-spread": "^7.0.0", + "@babel/plugin-proposal-optional-catch-binding": "^7.0.0", + "@babel/plugin-proposal-unicode-property-regex": "^7.0.0", + "@babel/plugin-syntax-async-generators": "^7.0.0", + "@babel/plugin-syntax-object-rest-spread": "^7.0.0", + "@babel/plugin-syntax-optional-catch-binding": "^7.0.0", + "@babel/plugin-transform-arrow-functions": "^7.0.0", + "@babel/plugin-transform-async-to-generator": "^7.1.0", + "@babel/plugin-transform-block-scoped-functions": "^7.0.0", + "@babel/plugin-transform-block-scoping": "^7.1.5", + "@babel/plugin-transform-classes": "^7.1.0", + "@babel/plugin-transform-computed-properties": "^7.0.0", + "@babel/plugin-transform-destructuring": "^7.0.0", + "@babel/plugin-transform-dotall-regex": "^7.0.0", + "@babel/plugin-transform-duplicate-keys": "^7.0.0", + "@babel/plugin-transform-exponentiation-operator": "^7.1.0", + "@babel/plugin-transform-for-of": "^7.0.0", + "@babel/plugin-transform-function-name": "^7.1.0", + "@babel/plugin-transform-literals": "^7.0.0", + "@babel/plugin-transform-modules-amd": "^7.1.0", + "@babel/plugin-transform-modules-commonjs": "^7.1.0", + "@babel/plugin-transform-modules-systemjs": "^7.0.0", + "@babel/plugin-transform-modules-umd": "^7.1.0", + "@babel/plugin-transform-new-target": "^7.0.0", + "@babel/plugin-transform-object-super": "^7.1.0", + "@babel/plugin-transform-parameters": "^7.1.0", + "@babel/plugin-transform-regenerator": "^7.0.0", + "@babel/plugin-transform-shorthand-properties": "^7.0.0", + "@babel/plugin-transform-spread": "^7.0.0", + "@babel/plugin-transform-sticky-regex": "^7.0.0", + "@babel/plugin-transform-template-literals": "^7.0.0", + "@babel/plugin-transform-typeof-symbol": "^7.0.0", + "@babel/plugin-transform-unicode-regex": "^7.0.0", + "browserslist": "^4.1.0", + "invariant": "^2.2.2", + "js-levenshtein": "^1.1.3", + "semver": "^5.3.0" } }, "@babel/runtime": { @@ -771,7 +771,7 @@ "integrity": "sha512-xKnPpXG/pvK1B90JkwwxSGii90rQGKtzcMt2gI5G6+M0REXaq6rOHsGC2ay6/d0Uje7zzvSzjEzfR3ENhFlrfA==", "dev": true, "requires": { - "regenerator-runtime": "0.12.1" + "regenerator-runtime": "^0.12.0" } }, "@babel/template": { @@ -780,9 +780,9 @@ "integrity": "sha1-CQSEpXT+9aLS13JqZ07O2lxbVkQ=", "dev": true, "requires": { - "@babel/code-frame": "7.0.0", - "@babel/parser": "7.1.6", - "@babel/types": "7.1.6" + "@babel/code-frame": "^7.0.0", + "@babel/parser": "^7.1.2", + "@babel/types": "^7.1.2" } }, "@babel/traverse": { @@ -791,15 +791,15 @@ "integrity": "sha512-CXedit6GpISz3sC2k2FsGCUpOhUqKdyL0lqNrImQojagnUMXf8hex4AxYFRuMkNGcvJX5QAFGzB5WJQmSv8SiQ==", "dev": true, "requires": { - "@babel/code-frame": "7.0.0", - "@babel/generator": "7.1.6", - "@babel/helper-function-name": "7.1.0", - "@babel/helper-split-export-declaration": "7.0.0", - "@babel/parser": "7.1.6", - "@babel/types": "7.1.6", - "debug": "4.1.0", - "globals": "11.9.0", - "lodash": "4.17.11" + "@babel/code-frame": "^7.0.0", + "@babel/generator": "^7.1.6", + "@babel/helper-function-name": "^7.1.0", + "@babel/helper-split-export-declaration": "^7.0.0", + "@babel/parser": "^7.1.6", + "@babel/types": "^7.1.6", + "debug": "^4.1.0", + "globals": "^11.1.0", + "lodash": "^4.17.10" }, "dependencies": { "debug": { @@ -808,7 +808,7 @@ "integrity": "sha512-heNPJUJIqC+xB6ayLAMHaIrmN9HKa7aQO8MGqKpvCA+uJYVcvR6l5kgdrhRuwPFHU7P5/A1w0BjByPHwpfTDKg==", "dev": true, "requires": { - "ms": "2.1.1" + "ms": "^2.1.1" } }, "ms": { @@ -825,9 +825,9 @@ "integrity": "sha512-DMiUzlY9DSjVsOylJssxLHSgj6tWM9PRFJOGW/RaOglVOK9nzTxoOMfTfRQXGUCUQ/HmlG2efwC+XqUEJ5ay4w==", "dev": true, "requires": { - "esutils": "2.0.2", - "lodash": "4.17.11", - "to-fast-properties": "2.0.0" + "esutils": "^2.0.2", + "lodash": "^4.17.10", + "to-fast-properties": "^2.0.0" } }, "@intervolga/optimize-cssnano-plugin": { @@ -836,9 +836,9 @@ "integrity": "sha512-zN69TnSr0viRSU6cEDIcuPcP67QcpQ6uHACg58FiN9PDrU6SLyGW3MR4tiISbYxy1kDWAVPwD+XwQTWE5cigAA==", "dev": true, "requires": { - "cssnano": "4.1.7", - "cssnano-preset-default": "4.0.5", - "postcss": "7.0.5" + "cssnano": "^4.0.0", + "cssnano-preset-default": "^4.0.0", + "postcss": "^7.0.0" } }, "@mrmlnc/readdir-enhanced": { @@ -847,8 +847,8 @@ "integrity": "sha512-bPHp6Ji8b41szTOcaP63VlnbbO5Ny6dwAATtY6JTjh5N2OLrb5Qk/Th5cRkRQhkWCt+EJsYrNB0MiL+Gpn6e3g==", "dev": true, "requires": { - "call-me-maybe": "1.0.1", - "glob-to-regexp": "0.3.0" + "call-me-maybe": "^1.0.1", + "glob-to-regexp": "^0.3.0" } }, "@nodelib/fs.stat": { @@ -858,9 +858,9 @@ "dev": true }, "@types/node": { - "version": "10.12.18", - "resolved": "https://registry.npmjs.org/@types/node/-/node-10.12.18.tgz", - "integrity": "sha512-fh+pAqt4xRzPfqA6eh3Z2y6fyZavRIumvjhaCL753+TVkGKGhpPeyrJG2JftD0T9q4GF00KjefsQ+PQNDdWQaQ==", + "version": "10.12.26", + "resolved": "https://registry.npmjs.org/@types/node/-/node-10.12.26.tgz", + "integrity": "sha512-nMRqS+mL1TOnIJrL6LKJcNZPB8V3eTfRo9FQA2b5gDvrHurC8XbSA86KNe0dShlEL7ReWJv/OU9NL7Z0dnqWTg==", "dev": true }, "@types/semver": { @@ -887,17 +887,17 @@ "integrity": "sha1-G7Y5XF3chLyOmTrORxUbDZXTgqc=", "dev": true, "requires": { - "@babel/plugin-proposal-class-properties": "7.1.0", - "@babel/plugin-proposal-decorators": "7.1.6", - "@babel/plugin-syntax-dynamic-import": "7.0.0", - "@babel/plugin-syntax-jsx": "7.0.0", - "@babel/plugin-transform-runtime": "7.1.0", - "@babel/preset-env": "7.1.6", - "@babel/runtime": "7.1.5", - "babel-helper-vue-jsx-merge-props": "2.0.3", - "babel-plugin-dynamic-import-node": "2.2.0", - "babel-plugin-transform-vue-jsx": "4.0.1", - "core-js": "2.5.7" + "@babel/plugin-proposal-class-properties": "^7.0.0", + "@babel/plugin-proposal-decorators": "^7.0.0", + "@babel/plugin-syntax-dynamic-import": "^7.0.0", + "@babel/plugin-syntax-jsx": "^7.0.0", + "@babel/plugin-transform-runtime": "^7.0.0", + "@babel/preset-env": "^7.0.0", + "@babel/runtime": "^7.0.0", + "babel-helper-vue-jsx-merge-props": "^2.0.3", + "babel-plugin-dynamic-import-node": "^2.2.0", + "babel-plugin-transform-vue-jsx": "^4.0.1", + "core-js": "^2.5.7" } }, "@vue/cli-overlay": { @@ -912,9 +912,9 @@ "integrity": "sha1-RDRBRW6hFBs6gHAlUDQ0LdR4CeA=", "dev": true, "requires": { - "@babel/core": "7.1.6", - "@vue/babel-preset-app": "3.1.1", - "babel-loader": "8.0.4" + "@babel/core": "^7.0.0", + "@vue/babel-preset-app": "^3.1.0", + "babel-loader": "^8.0.4" } }, "@vue/cli-plugin-eslint": { @@ -923,12 +923,12 @@ "integrity": "sha512-ZcRJqqDeMxf5c6YkCT7nr29SGePBfyeuYfG8p3QVSND90nhS/952/G6ZAb7Ph1dNNsEONU4plQYnQAte6Caf4w==", "dev": true, "requires": { - "@vue/cli-shared-utils": "3.1.1", - "babel-eslint": "10.0.1", - "eslint": "4.19.1", - "eslint-loader": "2.1.1", - "eslint-plugin-vue": "4.7.1", - "globby": "8.0.1" + "@vue/cli-shared-utils": "^3.1.1", + "babel-eslint": "^10.0.1", + "eslint": "^4.19.1", + "eslint-loader": "^2.1.1", + "eslint-plugin-vue": "^4.7.1", + "globby": "^8.0.1" }, "dependencies": { "ajv": { @@ -937,10 +937,10 @@ "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=", "dev": true, "requires": { - "co": "4.6.0", - "fast-deep-equal": "1.1.0", - "fast-json-stable-stringify": "2.0.0", - "json-schema-traverse": "0.3.1" + "co": "^4.6.0", + "fast-deep-equal": "^1.0.0", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.3.0" } }, "cross-spawn": { @@ -949,9 +949,9 @@ "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", "dev": true, "requires": { - "lru-cache": "4.1.3", - "shebang-command": "1.2.0", - "which": "1.3.1" + "lru-cache": "^4.0.1", + "shebang-command": "^1.2.0", + "which": "^1.2.9" } }, "eslint": { @@ -960,44 +960,44 @@ "integrity": "sha512-bT3/1x1EbZB7phzYu7vCr1v3ONuzDtX8WjuM9c0iYxe+cq+pwcKEoQjl7zd3RpC6YOLgnSy3cTN58M2jcoPDIQ==", "dev": true, "requires": { - "ajv": "5.5.2", - "babel-code-frame": "6.26.0", - "chalk": "2.4.1", - "concat-stream": "1.6.2", - "cross-spawn": "5.1.0", - "debug": "3.1.0", - "doctrine": "2.1.0", - "eslint-scope": "3.7.1", - "eslint-visitor-keys": "1.0.0", - "espree": "3.5.4", - "esquery": "1.0.1", - "esutils": "2.0.2", - "file-entry-cache": "2.0.0", - "functional-red-black-tree": "1.0.1", - "glob": "7.1.3", - "globals": "11.9.0", - "ignore": "3.3.10", - "imurmurhash": "0.1.4", - "inquirer": "3.3.0", - "is-resolvable": "1.1.0", - "js-yaml": "3.12.0", - "json-stable-stringify-without-jsonify": "1.0.1", - "levn": "0.3.0", - "lodash": "4.17.11", - "minimatch": "3.0.4", - "mkdirp": "0.5.1", - "natural-compare": "1.4.0", - "optionator": "0.8.2", - "path-is-inside": "1.0.2", - "pluralize": "7.0.0", - "progress": "2.0.1", - "regexpp": "1.1.0", - "require-uncached": "1.0.3", - "semver": "5.6.0", - "strip-ansi": "4.0.0", - "strip-json-comments": "2.0.1", + "ajv": "^5.3.0", + "babel-code-frame": "^6.22.0", + "chalk": "^2.1.0", + "concat-stream": "^1.6.0", + "cross-spawn": "^5.1.0", + "debug": "^3.1.0", + "doctrine": "^2.1.0", + "eslint-scope": "^3.7.1", + "eslint-visitor-keys": "^1.0.0", + "espree": "^3.5.4", + "esquery": "^1.0.0", + "esutils": "^2.0.2", + "file-entry-cache": "^2.0.0", + "functional-red-black-tree": "^1.0.1", + "glob": "^7.1.2", + "globals": "^11.0.1", + "ignore": "^3.3.3", + "imurmurhash": "^0.1.4", + "inquirer": "^3.0.6", + "is-resolvable": "^1.0.0", + "js-yaml": "^3.9.1", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.3.0", + "lodash": "^4.17.4", + "minimatch": "^3.0.2", + "mkdirp": "^0.5.1", + "natural-compare": "^1.4.0", + "optionator": "^0.8.2", + "path-is-inside": "^1.0.2", + "pluralize": "^7.0.0", + "progress": "^2.0.0", + "regexpp": "^1.0.1", + "require-uncached": "^1.0.3", + "semver": "^5.3.0", + "strip-ansi": "^4.0.0", + "strip-json-comments": "~2.0.1", "table": "4.0.2", - "text-table": "0.2.0" + "text-table": "~0.2.0" } }, "eslint-plugin-vue": { @@ -1006,7 +1006,7 @@ "integrity": "sha1-yCm5/GJYLBiXtaC5Sv1E7MpRHmM=", "dev": true, "requires": { - "vue-eslint-parser": "2.0.3" + "vue-eslint-parser": "^2.0.3" } }, "fast-deep-equal": { @@ -1024,38 +1024,70 @@ } }, "@vue/cli-plugin-unit-jest": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/@vue/cli-plugin-unit-jest/-/cli-plugin-unit-jest-3.3.0.tgz", - "integrity": "sha512-Y/WkrO95vdvjVjeNO1vZRQUAxlZ6ngdgAzvMzCeEaujbRG4b8M6W7ePSAe8C9yfoVcJtbnoHcBv2er31sPwtyQ==", + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/@vue/cli-plugin-unit-jest/-/cli-plugin-unit-jest-3.4.0.tgz", + "integrity": "sha512-F1FzKG2JQmVPXH5OKFN4htBkGERDj5Kxd47Wmts2H0rhmtHR4a+k0X7+WyCzbb1aSRKNYdG4f2eSwyu6tSq28A==", "dev": true, "requires": { - "@vue/cli-shared-utils": "3.3.0", - "babel-jest": "23.6.0", - "babel-plugin-transform-es2015-modules-commonjs": "6.26.2", - "jest": "23.6.0", - "jest-serializer-vue": "2.0.2", - "jest-transform-stub": "1.0.0", - "vue-jest": "3.0.2" + "@vue/cli-shared-utils": "^3.4.0", + "babel-jest": "^23.6.0", + "babel-plugin-transform-es2015-modules-commonjs": "^6.26.2", + "jest": "^23.6.0", + "jest-serializer-vue": "^2.0.2", + "jest-transform-stub": "^1.0.0", + "vue-jest": "^3.0.2" }, "dependencies": { "@vue/cli-shared-utils": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/@vue/cli-shared-utils/-/cli-shared-utils-3.3.0.tgz", - "integrity": "sha512-V/sU1jc7/jMCAbU8uA5f4j9Yd8lTqdi3I6FEHfLG1nstwhaNi4BU3WKWOAl72NYVWFYG8VuCrYWDn75kMimtuw==", + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/@vue/cli-shared-utils/-/cli-shared-utils-3.4.0.tgz", + "integrity": "sha512-w9j2qIroUUC2ym4Lb0lLMdlGmYThhwV0OizOEVigB5eZOEUEBV2Mv43K+nWJ6OyRBACnvhJTDi1gIwJo8zUvOw==", + "dev": true, + "requires": { + "chalk": "^2.4.1", + "execa": "^1.0.0", + "joi": "^14.3.0", + "launch-editor": "^2.2.1", + "lru-cache": "^5.1.1", + "node-ipc": "^9.1.1", + "opn": "^5.3.0", + "ora": "^3.0.0", + "request": "^2.87.0", + "request-promise-native": "^1.0.5", + "semver": "^5.5.0", + "string.prototype.padstart": "^3.0.0" + } + }, + "ansi-regex": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.0.0.tgz", + "integrity": "sha512-iB5Dda8t/UqpPI/IjsejXu5jOGDrzn41wJyljwPH65VCIbk6+1BzFIMJGFwTNrYXT1CrD+B4l19U7awiQ8rk7w==", + "dev": true + }, + "babel-jest": { + "version": "23.6.0", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-23.6.0.tgz", + "integrity": "sha512-lqKGG6LYXYu+DQh/slrQ8nxXQkEkhugdXsU6St7GmhVS7Ilc/22ArwqXNJrf0QaOBjZB0360qZMwXqDYQHXaew==", + "dev": true, + "requires": { + "babel-plugin-istanbul": "^4.1.6", + "babel-preset-jest": "^23.2.0" + } + }, + "babel-plugin-jest-hoist": { + "version": "23.2.0", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-23.2.0.tgz", + "integrity": "sha1-5h+uBaHKiAGq3uV6bWa4zvr0QWc=", + "dev": true + }, + "babel-preset-jest": { + "version": "23.2.0", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-23.2.0.tgz", + "integrity": "sha1-jsegOhOPABoaj7HoETZSvxpV2kY=", "dev": true, "requires": { - "chalk": "2.4.1", - "execa": "1.0.0", - "joi": "14.3.1", - "launch-editor": "2.2.1", - "lru-cache": "5.1.1", - "node-ipc": "9.1.1", - "opn": "5.4.0", - "ora": "3.0.0", - "request": "2.88.0", - "request-promise-native": "1.0.5", - "semver": "5.6.0", - "string.prototype.padstart": "3.0.0" + "babel-plugin-jest-hoist": "^23.2.0", + "babel-plugin-syntax-object-rest-spread": "^6.13.0" } }, "hoek": { @@ -1070,9 +1102,9 @@ "integrity": "sha512-LQDdM+pkOrpAn4Lp+neNIFV3axv1Vna3j38bisbQhETPMANYRbFJFUyOZcOClYvM/hppMhGWuKSFEK9vjrB+bQ==", "dev": true, "requires": { - "hoek": "6.1.2", - "isemail": "3.2.0", - "topo": "3.0.3" + "hoek": "6.x.x", + "isemail": "3.x.x", + "topo": "3.x.x" } }, "lru-cache": { @@ -1081,21 +1113,43 @@ "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", "dev": true, "requires": { - "yallist": "3.0.3" + "yallist": "^3.0.2" } }, "ora": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ora/-/ora-3.0.0.tgz", - "integrity": "sha512-LBS97LFe2RV6GJmXBi6OKcETKyklHNMV0xw7BtsVn2MlsgsydyZetSCbCANr+PFLmDyv4KV88nn0eCKza665Mg==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/ora/-/ora-3.1.0.tgz", + "integrity": "sha512-vRBPaNCclUi8pUxRF/G8+5qEQkc6EgzKK1G2ZNJUIGu088Un5qIxFXeDgymvPRM9nmrcUOGzQgS1Vmtz+NtlMw==", "dev": true, "requires": { - "chalk": "2.4.1", - "cli-cursor": "2.1.0", - "cli-spinners": "1.3.1", - "log-symbols": "2.2.0", - "strip-ansi": "4.0.0", - "wcwidth": "1.0.1" + "chalk": "^2.4.2", + "cli-cursor": "^2.1.0", + "cli-spinners": "^1.3.1", + "log-symbols": "^2.2.0", + "strip-ansi": "^5.0.0", + "wcwidth": "^1.0.1" + }, + "dependencies": { + "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" + } + } + } + }, + "strip-ansi": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.0.0.tgz", + "integrity": "sha512-Uu7gQyZI7J7gn5qLn1Np3G9vcYGTVqB+lFTytnDJv83dd8T22aGH451P3jueT2/QemInJDfxHB5Tde5OzgG1Ow==", + "dev": true, + "requires": { + "ansi-regex": "^4.0.0" } }, "yallist": { @@ -1112,56 +1166,56 @@ "integrity": "sha512-dArLh5yd2B2an/jTD+cmkRmyRxKSE+5il9408vhciyqvZGVjkajTN95YjY5VLkBMQvrv/Z+goGSn+7wtnQSOFg==", "dev": true, "requires": { - "@intervolga/optimize-cssnano-plugin": "1.0.6", - "@vue/cli-overlay": "3.1.0", - "@vue/cli-shared-utils": "3.1.1", - "@vue/preload-webpack-plugin": "1.1.0", - "@vue/web-component-wrapper": "1.2.0", - "acorn": "6.0.4", - "acorn-walk": "6.1.1", - "address": "1.0.3", - "autoprefixer": "8.6.5", - "cache-loader": "1.2.5", - "case-sensitive-paths-webpack-plugin": "2.1.2", - "chalk": "2.4.1", - "clipboardy": "1.2.3", - "cliui": "4.1.0", - "copy-webpack-plugin": "4.6.0", - "css-loader": "1.0.1", - "cssnano": "4.1.7", - "debug": "4.1.0", - "escape-string-regexp": "1.0.5", - "file-loader": "2.0.0", - "friendly-errors-webpack-plugin": "1.7.0", - "fs-extra": "7.0.1", - "globby": "8.0.1", - "hash-sum": "1.0.2", - "html-webpack-plugin": "3.2.0", - "launch-editor-middleware": "2.2.1", - "lodash.defaultsdeep": "4.6.0", - "lodash.mapvalues": "4.6.0", - "lodash.transform": "4.6.0", - "mini-css-extract-plugin": "0.4.4", - "minimist": "1.2.0", - "ora": "3.0.0", - "portfinder": "1.0.19", - "postcss-loader": "3.0.0", - "read-pkg": "4.0.1", - "semver": "5.6.0", - "slash": "2.0.0", - "source-map-url": "0.4.0", - "ssri": "6.0.1", - "string.prototype.padend": "3.0.0", - "terser-webpack-plugin": "1.1.0", - "thread-loader": "1.2.0", - "url-loader": "1.1.2", - "vue-loader": "15.4.2", - "webpack": "4.25.1", - "webpack-bundle-analyzer": "3.0.3", - "webpack-chain": "4.12.1", - "webpack-dev-server": "3.1.14", - "webpack-merge": "4.1.4", - "yorkie": "2.0.0" + "@intervolga/optimize-cssnano-plugin": "^1.0.5", + "@vue/cli-overlay": "^3.1.0", + "@vue/cli-shared-utils": "^3.1.1", + "@vue/preload-webpack-plugin": "^1.1.0", + "@vue/web-component-wrapper": "^1.2.0", + "acorn": "^6.0.2", + "acorn-walk": "^6.1.0", + "address": "^1.0.3", + "autoprefixer": "^8.6.5", + "cache-loader": "^1.2.5", + "case-sensitive-paths-webpack-plugin": "^2.1.2", + "chalk": "^2.4.1", + "clipboardy": "^1.2.3", + "cliui": "^4.1.0", + "copy-webpack-plugin": "^4.6.0", + "css-loader": "^1.0.1", + "cssnano": "^4.1.7", + "debug": "^4.1.0", + "escape-string-regexp": "^1.0.5", + "file-loader": "^2.0.0", + "friendly-errors-webpack-plugin": "^1.7.0", + "fs-extra": "^7.0.0", + "globby": "^8.0.1", + "hash-sum": "^1.0.2", + "html-webpack-plugin": "^3.2.0", + "launch-editor-middleware": "^2.2.1", + "lodash.defaultsdeep": "^4.6.0", + "lodash.mapvalues": "^4.6.0", + "lodash.transform": "^4.6.0", + "mini-css-extract-plugin": "^0.4.4", + "minimist": "^1.2.0", + "ora": "^3.0.0", + "portfinder": "^1.0.19", + "postcss-loader": "^3.0.0", + "read-pkg": "^4.0.1", + "semver": "^5.6.0", + "slash": "^2.0.0", + "source-map-url": "^0.4.0", + "ssri": "^6.0.1", + "string.prototype.padend": "^3.0.0", + "terser-webpack-plugin": "^1.1.0", + "thread-loader": "^1.2.0", + "url-loader": "^1.1.2", + "vue-loader": "^15.4.2", + "webpack": "^4.18.1", + "webpack-bundle-analyzer": "^3.0.3", + "webpack-chain": "^4.11.0", + "webpack-dev-server": "^3.1.10", + "webpack-merge": "^4.1.4", + "yorkie": "^2.0.0" }, "dependencies": { "acorn": { @@ -1176,7 +1230,7 @@ "integrity": "sha1-NzaHv/pnizixzZH4YbY4UANd3Ic=", "dev": true, "requires": { - "ms": "2.1.1" + "ms": "^2.1.1" } }, "ms": { @@ -1191,12 +1245,12 @@ "integrity": "sha1-gXnjUluar9mSQtY8wgb9ZHMnQdA=", "dev": true, "requires": { - "chalk": "2.4.1", - "cli-cursor": "2.1.0", - "cli-spinners": "1.3.1", - "log-symbols": "2.2.0", - "strip-ansi": "4.0.0", - "wcwidth": "1.0.1" + "chalk": "^2.3.1", + "cli-cursor": "^2.1.0", + "cli-spinners": "^1.1.0", + "log-symbols": "^2.2.0", + "strip-ansi": "^4.0.0", + "wcwidth": "^1.0.1" } }, "slash": { @@ -1213,18 +1267,18 @@ "integrity": "sha1-q4Y4wlMY5YErV4d9fPxlzSr0N0A=", "dev": true, "requires": { - "chalk": "2.4.1", - "execa": "1.0.0", - "joi": "13.7.0", - "launch-editor": "2.2.1", - "lru-cache": "4.1.3", - "node-ipc": "9.1.1", - "opn": "5.4.0", - "ora": "2.1.0", - "request": "2.88.0", - "request-promise-native": "1.0.5", - "semver": "5.6.0", - "string.prototype.padstart": "3.0.0" + "chalk": "^2.4.1", + "execa": "^1.0.0", + "joi": "^13.0.0", + "launch-editor": "^2.2.1", + "lru-cache": "^4.1.3", + "node-ipc": "^9.1.1", + "opn": "^5.3.0", + "ora": "^2.1.0", + "request": "^2.87.0", + "request-promise-native": "^1.0.5", + "semver": "^5.5.0", + "string.prototype.padstart": "^3.0.0" } }, "@vue/component-compiler-utils": { @@ -1233,15 +1287,15 @@ "integrity": "sha1-T1gPGyj8doWFnYfqDpKhwCcck9o=", "dev": true, "requires": { - "consolidate": "0.15.1", - "hash-sum": "1.0.2", - "lru-cache": "4.1.3", - "merge-source-map": "1.1.0", - "postcss": "6.0.23", - "postcss-selector-parser": "3.1.1", + "consolidate": "^0.15.1", + "hash-sum": "^1.0.2", + "lru-cache": "^4.1.2", + "merge-source-map": "^1.1.0", + "postcss": "^6.0.20", + "postcss-selector-parser": "^3.1.1", "prettier": "1.13.7", - "source-map": "0.5.7", - "vue-template-es2015-compiler": "1.6.0" + "source-map": "^0.5.6", + "vue-template-es2015-compiler": "^1.6.0" }, "dependencies": { "postcss": { @@ -1250,9 +1304,9 @@ "integrity": "sha1-YcgswyisYOZ3ZF+XkFTrmLwOMyQ=", "dev": true, "requires": { - "chalk": "2.4.1", - "source-map": "0.6.1", - "supports-color": "5.5.0" + "chalk": "^2.4.1", + "source-map": "^0.6.1", + "supports-color": "^5.4.0" }, "dependencies": { "source-map": { @@ -1269,9 +1323,9 @@ "integrity": "sha1-T4dfSvsMllc9XPTXQBGu4lCn6GU=", "dev": true, "requires": { - "dot-prop": "4.2.0", - "indexes-of": "1.0.1", - "uniq": "1.0.1" + "dot-prop": "^4.1.1", + "indexes-of": "^1.0.1", + "uniq": "^1.0.1" } } } @@ -1282,9 +1336,9 @@ "integrity": "sha512-rJEDXPb61Hfgg8GllO3XXFP98bcIxdNNHSrNcxP/vBSukOolgOwQyZJ5f5z/c7ViPyh5/IDlC4qBnhx/0n+I4g==", "dev": true, "requires": { - "eslint-config-prettier": "3.3.0", - "eslint-plugin-prettier": "3.0.0", - "prettier": "1.15.2" + "eslint-config-prettier": "^3.3.0", + "eslint-plugin-prettier": "^3.0.0", + "prettier": "^1.15.2" }, "dependencies": { "prettier": { @@ -1307,8 +1361,8 @@ "integrity": "sha512-Lzrd4ZBkS70Tl8JbXbDrN/NcSaH9aZT6+7emU3QhTJ+CrorJpyFDA1dkvSIhH+rDTs8sHFbGeXjXV/qorXxtRw==", "dev": true, "requires": { - "dom-event-types": "1.0.0", - "lodash": "4.17.11" + "dom-event-types": "^1.0.0", + "lodash": "^4.17.4" } }, "@vue/web-component-wrapper": { @@ -1391,7 +1445,7 @@ "integrity": "sha512-Mmqx/cS68K1tSrvRLtaV/Lp3NZWzXtOHUW2IvDvl2sihAwJh4ACE0eL6A8FvMyDG9abes3saB6dMimLOs+HMoQ==", "dev": true, "requires": { - "@xtuc/ieee754": "1.2.0" + "@xtuc/ieee754": "^1.2.0" } }, "@webassemblyjs/leb128": { @@ -1519,7 +1573,7 @@ "integrity": "sha1-63d99gEXI6OxTopywIBcjoZ0a9I=", "dev": true, "requires": { - "mime-types": "2.1.21", + "mime-types": "~2.1.18", "negotiator": "0.6.1" } }, @@ -1535,7 +1589,7 @@ "integrity": "sha512-zVWV8Z8lislJoOKKqdNMOB+s6+XV5WERty8MnKBeFgwA+19XJjJHs2RP5dzM57FftIs+jQnRToLiWazKr6sSWg==", "dev": true, "requires": { - "acorn": "5.7.3" + "acorn": "^5.0.0" } }, "acorn-globals": { @@ -1544,14 +1598,14 @@ "integrity": "sha512-hMtHj3s5RnuhvHPowpBYvJVj3rAar82JiDQHvGs1zO0l10ocX/xEdBShNHTJaboucJUsScghp74pH3s7EnHHQw==", "dev": true, "requires": { - "acorn": "6.0.5", - "acorn-walk": "6.1.1" + "acorn": "^6.0.1", + "acorn-walk": "^6.0.1" }, "dependencies": { "acorn": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.0.5.tgz", - "integrity": "sha512-i33Zgp3XWtmZBMNvCr4azvOFeWVw1Rk6p3hfi3LUDvIFraOMywb1kAtrbi+med14m4Xfpqm3zRZMT+c0FNE7kg==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.1.0.tgz", + "integrity": "sha512-MW/FjM+IvU9CgBzjO3UIPCE2pyEwUsoFl+VGdczOPEdxfGFjuKny/gN54mOuX7Qxmb9Rg9MCn2oKiSUeW+pjrw==", "dev": true } } @@ -1562,7 +1616,7 @@ "integrity": "sha1-r9+UiPsezvyDSPb7IvRk4ypYs2s=", "dev": true, "requires": { - "acorn": "3.3.0" + "acorn": "^3.0.4" }, "dependencies": { "acorn": { @@ -1585,16 +1639,21 @@ "integrity": "sha512-z55ocwKBRLryBs394Sm3ushTtBeg6VAeuku7utSoSnsJKvKcnXFIyC6vh27n3rXyxSgkJBBCAvyOn7gSUcTYjg==", "dev": true }, + "after": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/after/-/after-0.8.2.tgz", + "integrity": "sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8=" + }, "ajv": { "version": "6.5.5", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.5.5.tgz", "integrity": "sha512-7q7gtRQDJSyuEHjuVgHoUa2VuemFiCMrfQc9Tc08XTAc4Zj/5U1buQJ0HU6i7fKjXU09SVgSmxa4sLvuvS8Iyg==", "dev": true, "requires": { - "fast-deep-equal": "2.0.1", - "fast-json-stable-stringify": "2.0.0", - "json-schema-traverse": "0.4.1", - "uri-js": "4.2.2" + "fast-deep-equal": "^2.0.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" } }, "ajv-errors": { @@ -1645,7 +1704,7 @@ "integrity": "sha1-QfuyAkPlCxK+DwS43tvwdSDOhB0=", "dev": true, "requires": { - "color-convert": "1.9.3" + "color-convert": "^1.9.0" } }, "anymatch": { @@ -1654,8 +1713,8 @@ "integrity": "sha1-vLJLTzeTTZqnrBe0ra+J58du8us=", "dev": true, "requires": { - "micromatch": "3.1.10", - "normalize-path": "2.1.1" + "micromatch": "^3.1.4", + "normalize-path": "^2.1.1" } }, "append-transform": { @@ -1664,7 +1723,7 @@ "integrity": "sha1-126/jKlNJ24keja61EpLdKthGZE=", "dev": true, "requires": { - "default-require-extensions": "1.0.0" + "default-require-extensions": "^1.0.0" } }, "aproba": { @@ -1685,7 +1744,7 @@ "integrity": "sha1-vNZ5HqWuCXJeF+WtmIE0zUCz2RE=", "dev": true, "requires": { - "sprintf-js": "1.0.3" + "sprintf-js": "~1.0.2" } }, "arr-diff": { @@ -1742,7 +1801,7 @@ "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", "dev": true, "requires": { - "array-uniq": "1.0.3" + "array-uniq": "^1.0.1" } }, "array-uniq": { @@ -1757,6 +1816,11 @@ "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", "dev": true }, + "arraybuffer.slice": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz", + "integrity": "sha512-wGUIVQXuehL5TCqQun8OW81jGzAWycqzFF8lFp+GOM5BXLYj3bKNsYC4daB7n6XjCqxQA/qgTJ+8ANR3acjrog==" + }, "arrify": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", @@ -1769,7 +1833,7 @@ "integrity": "sha1-jSR136tVO7M+d7VOWeiAu4ziMTY=", "dev": true, "requires": { - "safer-buffer": "2.1.2" + "safer-buffer": "~2.1.0" } }, "asn1.js": { @@ -1778,9 +1842,9 @@ "integrity": "sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw==", "dev": true, "requires": { - "bn.js": "4.11.8", - "inherits": "2.0.3", - "minimalistic-assert": "1.0.1" + "bn.js": "^4.0.0", + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0" } }, "assert": { @@ -1842,8 +1906,7 @@ "async-limiter": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.0.tgz", - "integrity": "sha1-ePrtjD0HSrgfIrTphdeehzj3IPg=", - "dev": true + "integrity": "sha1-ePrtjD0HSrgfIrTphdeehzj3IPg=" }, "asynckit": { "version": "0.4.0", @@ -1863,12 +1926,12 @@ "integrity": "sha512-PLWJN3Xo/rycNkx+mp8iBDMTm3FeWe4VmYaZDSqL5QQB9sLsQkG5k8n+LNDFnhh9kdq2K+egL/icpctOmDHwig==", "dev": true, "requires": { - "browserslist": "3.2.8", - "caniuse-lite": "1.0.30000907", - "normalize-range": "0.1.2", - "num2fraction": "1.2.2", - "postcss": "6.0.23", - "postcss-value-parser": "3.3.1" + "browserslist": "^3.2.8", + "caniuse-lite": "^1.0.30000864", + "normalize-range": "^0.1.2", + "num2fraction": "^1.2.2", + "postcss": "^6.0.23", + "postcss-value-parser": "^3.2.3" }, "dependencies": { "browserslist": { @@ -1877,8 +1940,8 @@ "integrity": "sha512-WHVocJYavUwVgVViC0ORikPHQquXwVh939TaelZ4WDqpWgTX/FsGhl/+P4qBUAGcRvtOgDgC+xftNWWp2RUTAQ==", "dev": true, "requires": { - "caniuse-lite": "1.0.30000907", - "electron-to-chromium": "1.3.84" + "caniuse-lite": "^1.0.30000844", + "electron-to-chromium": "^1.3.47" } }, "postcss": { @@ -1887,9 +1950,9 @@ "integrity": "sha512-soOk1h6J3VMTZtVeVpv15/Hpdl2cBLX3CAw4TAbkpTJiNPk9YP/zWcD1ND+xEtvyuuvKzbxliTOIyvkSeSJ6ag==", "dev": true, "requires": { - "chalk": "2.4.1", - "source-map": "0.6.1", - "supports-color": "5.5.0" + "chalk": "^2.4.1", + "source-map": "^0.6.1", + "supports-color": "^5.4.0" } }, "source-map": { @@ -1917,8 +1980,8 @@ "resolved": "http://registry.npmjs.org/axios/-/axios-0.18.0.tgz", "integrity": "sha1-MtU+SFHv3AoRmTts0AB4nXDAUQI=", "requires": { - "follow-redirects": "1.5.9", - "is-buffer": "1.1.6" + "follow-redirects": "^1.3.0", + "is-buffer": "^1.1.5" } }, "babel-code-frame": { @@ -1927,9 +1990,9 @@ "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", "dev": true, "requires": { - "chalk": "1.1.3", - "esutils": "2.0.2", - "js-tokens": "3.0.2" + "chalk": "^1.1.3", + "esutils": "^2.0.2", + "js-tokens": "^3.0.2" }, "dependencies": { "ansi-regex": { @@ -1950,11 +2013,11 @@ "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", "dev": true, "requires": { - "ansi-styles": "2.2.1", - "escape-string-regexp": "1.0.5", - "has-ansi": "2.0.0", - "strip-ansi": "3.0.1", - "supports-color": "2.0.0" + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" } }, "js-tokens": { @@ -1969,7 +2032,7 @@ "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "dev": true, "requires": { - "ansi-regex": "2.1.1" + "ansi-regex": "^2.0.0" } }, "supports-color": { @@ -1992,12 +2055,12 @@ "integrity": "sha1-kZaB3AmWFM19MdRciQhpUJKh+u0=", "dev": true, "requires": { - "@babel/code-frame": "7.0.0", - "@babel/parser": "7.1.6", - "@babel/traverse": "7.1.6", - "@babel/types": "7.1.6", + "@babel/code-frame": "^7.0.0", + "@babel/parser": "^7.0.0", + "@babel/traverse": "^7.0.0", + "@babel/types": "^7.0.0", "eslint-scope": "3.7.1", - "eslint-visitor-keys": "1.0.0" + "eslint-visitor-keys": "^1.0.0" } }, "babel-generator": { @@ -2006,14 +2069,14 @@ "integrity": "sha512-HyfwY6ApZj7BYTcJURpM5tznulaBvyio7/0d4zFOeMPUmfxkCjHocCuoLa2SAGzBI8AREcH3eP3758F672DppA==", "dev": true, "requires": { - "babel-messages": "6.23.0", - "babel-runtime": "6.26.0", - "babel-types": "6.26.0", - "detect-indent": "4.0.0", - "jsesc": "1.3.0", - "lodash": "4.17.11", - "source-map": "0.5.7", - "trim-right": "1.0.1" + "babel-messages": "^6.23.0", + "babel-runtime": "^6.26.0", + "babel-types": "^6.26.0", + "detect-indent": "^4.0.0", + "jsesc": "^1.3.0", + "lodash": "^4.17.4", + "source-map": "^0.5.7", + "trim-right": "^1.0.1" }, "dependencies": { "jsesc": { @@ -2036,18 +2099,165 @@ "integrity": "sha1-NHHenK7DiOXIUOWX5Yom3fN2ArI=", "dev": true, "requires": { - "babel-runtime": "6.26.0", - "babel-template": "6.26.0" + "babel-runtime": "^6.22.0", + "babel-template": "^6.24.1" } }, "babel-jest": { - "version": "23.6.0", - "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-23.6.0.tgz", - "integrity": "sha512-lqKGG6LYXYu+DQh/slrQ8nxXQkEkhugdXsU6St7GmhVS7Ilc/22ArwqXNJrf0QaOBjZB0360qZMwXqDYQHXaew==", + "version": "24.1.0", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-24.1.0.tgz", + "integrity": "sha512-MLcagnVrO9ybQGLEfZUqnOzv36iQzU7Bj4elm39vCukumLVSfoX+tRy3/jW7lUKc7XdpRmB/jech6L/UCsSZjw==", "dev": true, "requires": { - "babel-plugin-istanbul": "4.1.6", - "babel-preset-jest": "23.2.0" + "babel-plugin-istanbul": "^5.1.0", + "babel-preset-jest": "^24.1.0", + "chalk": "^2.4.2", + "slash": "^2.0.0" + }, + "dependencies": { + "babel-plugin-istanbul": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-5.1.0.tgz", + "integrity": "sha512-CLoXPRSUWiR8yao8bShqZUIC6qLfZVVY3X1wj+QPNXu0wfmrRRfarh1LYy+dYMVI+bDj0ghy3tuqFFRFZmL1Nw==", + "dev": true, + "requires": { + "find-up": "^3.0.0", + "istanbul-lib-instrument": "^3.0.0", + "test-exclude": "^5.0.0" + } + }, + "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" + } + }, + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "requires": { + "locate-path": "^3.0.0" + } + }, + "istanbul-lib-coverage": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.3.tgz", + "integrity": "sha512-dKWuzRGCs4G+67VfW9pBFFz2Jpi4vSp/k7zBcJ888ofV5Mi1g5CUML5GvMvV6u9Cjybftu+E8Cgp+k0dI1E5lw==", + "dev": true + }, + "istanbul-lib-instrument": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-3.1.0.tgz", + "integrity": "sha512-ooVllVGT38HIk8MxDj/OIHXSYvH+1tq/Vb38s8ixt9GoJadXska4WkGY+0wkmtYCZNYtaARniH/DixUGGLZ0uA==", + "dev": true, + "requires": { + "@babel/generator": "^7.0.0", + "@babel/parser": "^7.0.0", + "@babel/template": "^7.0.0", + "@babel/traverse": "^7.0.0", + "@babel/types": "^7.0.0", + "istanbul-lib-coverage": "^2.0.3", + "semver": "^5.5.0" + } + }, + "load-json-file": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", + "integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "parse-json": "^4.0.0", + "pify": "^3.0.0", + "strip-bom": "^3.0.0" + } + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "p-limit": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.1.0.tgz", + "integrity": "sha512-NhURkNcrVB+8hNfLuysU8enY5xn2KXphsHBaC2YmRNTZRc7RWusw6apSpdEj3jo4CMb6W9nrF6tTnsJsJeyu6g==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "requires": { + "p-limit": "^2.0.0" + } + }, + "p-try": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.0.0.tgz", + "integrity": "sha512-hMp0onDKIajHfIkdRk3P4CdCmErkYAxxDtP3Wx/4nZ3aGlau2VKh3mZpcuFkH27WQkL/3WBCPOktzA9ZOAnMQQ==", + "dev": true + }, + "read-pkg": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", + "integrity": "sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=", + "dev": true, + "requires": { + "load-json-file": "^4.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^3.0.0" + } + }, + "read-pkg-up": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-4.0.0.tgz", + "integrity": "sha512-6etQSH7nJGsK0RbG/2TeDzZFa8shjQ1um+SwQQ5cwKy0dhSXdOncEhb1CPpvQG4h7FyOV6EB6YlV0yJvZQNAkA==", + "dev": true, + "requires": { + "find-up": "^3.0.0", + "read-pkg": "^3.0.0" + } + }, + "slash": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", + "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", + "dev": true + }, + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true + }, + "test-exclude": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-5.1.0.tgz", + "integrity": "sha512-gwf0S2fFsANC55fSeSqpb8BYk6w3FDvwZxfNjeF6FRgvFa43r+7wRiA/Q0IxoRU37wB/LE8IQ4221BsNucTaCA==", + "dev": true, + "requires": { + "arrify": "^1.0.1", + "minimatch": "^3.0.4", + "read-pkg-up": "^4.0.0", + "require-main-filename": "^1.0.1" + } + } } }, "babel-loader": { @@ -2056,10 +2266,10 @@ "integrity": "sha512-fhBhNkUToJcW9nV46v8w87AJOwAJDz84c1CL57n3Stj73FANM/b9TbCUK4YhdOwEyZ+OxhYpdeZDNzSI29Firw==", "dev": true, "requires": { - "find-cache-dir": "1.0.0", - "loader-utils": "1.1.0", - "mkdirp": "0.5.1", - "util.promisify": "1.0.0" + "find-cache-dir": "^1.0.0", + "loader-utils": "^1.0.2", + "mkdirp": "^0.5.1", + "util.promisify": "^1.0.0" } }, "babel-messages": { @@ -2068,7 +2278,7 @@ "integrity": "sha1-8830cDhYA1sqKVHG7F7fbGLyYw4=", "dev": true, "requires": { - "babel-runtime": "6.26.0" + "babel-runtime": "^6.22.0" } }, "babel-plugin-dynamic-import-node": { @@ -2077,7 +2287,7 @@ "integrity": "sha512-fP899ELUnTaBcIzmrW7nniyqqdYWrWuJUyPWHxFa/c7r7hS6KC8FscNfLlBNIoPSc55kYMGEEKjPjJGCLbE1qA==", "dev": true, "requires": { - "object.assign": "4.1.0" + "object.assign": "^4.1.0" } }, "babel-plugin-istanbul": { @@ -2086,16 +2296,16 @@ "integrity": "sha512-PWP9FQ1AhZhS01T/4qLSKoHGY/xvkZdVBGlKM/HuxxS3+sC66HhTNR7+MpbO/so/cz/wY94MeSWJuP1hXIPfwQ==", "dev": true, "requires": { - "babel-plugin-syntax-object-rest-spread": "6.13.0", - "find-up": "2.1.0", - "istanbul-lib-instrument": "1.10.2", - "test-exclude": "4.2.3" + "babel-plugin-syntax-object-rest-spread": "^6.13.0", + "find-up": "^2.1.0", + "istanbul-lib-instrument": "^1.10.1", + "test-exclude": "^4.2.1" } }, "babel-plugin-jest-hoist": { - "version": "23.2.0", - "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-23.2.0.tgz", - "integrity": "sha1-5h+uBaHKiAGq3uV6bWa4zvr0QWc=", + "version": "24.1.0", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-24.1.0.tgz", + "integrity": "sha512-gljYrZz8w1b6fJzKcsfKsipSru2DU2DmQ39aB6nV3xQ0DDv3zpIzKGortA5gknrhNnPN8DweaEgrnZdmbGmhnw==", "dev": true }, "babel-plugin-syntax-object-rest-spread": { @@ -2110,10 +2320,10 @@ "integrity": "sha512-CV9ROOHEdrjcwhIaJNBGMBCodN+1cfkwtM1SbUHmvyy35KGT7fohbpOxkE2uLz1o6odKK2Ck/tz47z+VqQfi9Q==", "dev": true, "requires": { - "babel-plugin-transform-strict-mode": "6.24.1", - "babel-runtime": "6.26.0", - "babel-template": "6.26.0", - "babel-types": "6.26.0" + "babel-plugin-transform-strict-mode": "^6.24.1", + "babel-runtime": "^6.26.0", + "babel-template": "^6.26.0", + "babel-types": "^6.26.0" } }, "babel-plugin-transform-strict-mode": { @@ -2122,8 +2332,8 @@ "integrity": "sha1-1fr3qleKZbvlkc9e2uBKDGcCB1g=", "dev": true, "requires": { - "babel-runtime": "6.26.0", - "babel-types": "6.26.0" + "babel-runtime": "^6.22.0", + "babel-types": "^6.24.1" } }, "babel-plugin-transform-vue-jsx": { @@ -2132,17 +2342,17 @@ "integrity": "sha512-wbOz7ITB5cloLSjKUU1hWn8zhR+Dwah/RZiTiJY/CQliCwhowmzu6m7NEF+y5EJX/blDzGjRtZvC10Vdb3Q7vw==", "dev": true, "requires": { - "esutils": "2.0.2" + "esutils": "^2.0.2" } }, "babel-preset-jest": { - "version": "23.2.0", - "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-23.2.0.tgz", - "integrity": "sha1-jsegOhOPABoaj7HoETZSvxpV2kY=", + "version": "24.1.0", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-24.1.0.tgz", + "integrity": "sha512-FfNLDxFWsNX9lUmtwY7NheGlANnagvxq8LZdl5PKnVG3umP+S/g0XbVBfwtA4Ai3Ri/IMkWabBz3Tyk9wdspcw==", "dev": true, "requires": { - "babel-plugin-jest-hoist": "23.2.0", - "babel-plugin-syntax-object-rest-spread": "6.13.0" + "@babel/plugin-syntax-object-rest-spread": "^7.0.0", + "babel-plugin-jest-hoist": "^24.1.0" } }, "babel-register": { @@ -2151,13 +2361,13 @@ "integrity": "sha1-btAhFz4vy0htestFxgCahW9kcHE=", "dev": true, "requires": { - "babel-core": "6.26.3", - "babel-runtime": "6.26.0", - "core-js": "2.5.7", - "home-or-tmp": "2.0.0", - "lodash": "4.17.11", - "mkdirp": "0.5.1", - "source-map-support": "0.4.18" + "babel-core": "^6.26.0", + "babel-runtime": "^6.26.0", + "core-js": "^2.5.0", + "home-or-tmp": "^2.0.0", + "lodash": "^4.17.4", + "mkdirp": "^0.5.1", + "source-map-support": "^0.4.15" }, "dependencies": { "babel-core": { @@ -2166,25 +2376,25 @@ "integrity": "sha512-6jyFLuDmeidKmUEb3NM+/yawG0M2bDZ9Z1qbZP59cyHLz8kYGKYwpJP0UwUKKUiTRNvxfLesJnTedqczP7cTDA==", "dev": true, "requires": { - "babel-code-frame": "6.26.0", - "babel-generator": "6.26.1", - "babel-helpers": "6.24.1", - "babel-messages": "6.23.0", - "babel-register": "6.26.0", - "babel-runtime": "6.26.0", - "babel-template": "6.26.0", - "babel-traverse": "6.26.0", - "babel-types": "6.26.0", - "babylon": "6.18.0", - "convert-source-map": "1.6.0", - "debug": "2.6.9", - "json5": "0.5.1", - "lodash": "4.17.11", - "minimatch": "3.0.4", - "path-is-absolute": "1.0.1", - "private": "0.1.8", - "slash": "1.0.0", - "source-map": "0.5.7" + "babel-code-frame": "^6.26.0", + "babel-generator": "^6.26.0", + "babel-helpers": "^6.24.1", + "babel-messages": "^6.23.0", + "babel-register": "^6.26.0", + "babel-runtime": "^6.26.0", + "babel-template": "^6.26.0", + "babel-traverse": "^6.26.0", + "babel-types": "^6.26.0", + "babylon": "^6.18.0", + "convert-source-map": "^1.5.1", + "debug": "^2.6.9", + "json5": "^0.5.1", + "lodash": "^4.17.4", + "minimatch": "^3.0.4", + "path-is-absolute": "^1.0.1", + "private": "^0.1.8", + "slash": "^1.0.0", + "source-map": "^0.5.7" } }, "debug": { @@ -2208,7 +2418,7 @@ "integrity": "sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA==", "dev": true, "requires": { - "source-map": "0.5.7" + "source-map": "^0.5.6" } } } @@ -2219,8 +2429,8 @@ "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", "dev": true, "requires": { - "core-js": "2.5.7", - "regenerator-runtime": "0.11.1" + "core-js": "^2.4.0", + "regenerator-runtime": "^0.11.0" }, "dependencies": { "regenerator-runtime": { @@ -2237,11 +2447,11 @@ "integrity": "sha1-3gPi0WOWsGn0bdn/+FIfsaDjXgI=", "dev": true, "requires": { - "babel-runtime": "6.26.0", - "babel-traverse": "6.26.0", - "babel-types": "6.26.0", - "babylon": "6.18.0", - "lodash": "4.17.11" + "babel-runtime": "^6.26.0", + "babel-traverse": "^6.26.0", + "babel-types": "^6.26.0", + "babylon": "^6.18.0", + "lodash": "^4.17.4" } }, "babel-traverse": { @@ -2250,15 +2460,15 @@ "integrity": "sha1-RqnL1+3MYsjlwGTi0tjQ9ANXZu4=", "dev": true, "requires": { - "babel-code-frame": "6.26.0", - "babel-messages": "6.23.0", - "babel-runtime": "6.26.0", - "babel-types": "6.26.0", - "babylon": "6.18.0", - "debug": "2.6.9", - "globals": "9.18.0", - "invariant": "2.2.4", - "lodash": "4.17.11" + "babel-code-frame": "^6.26.0", + "babel-messages": "^6.23.0", + "babel-runtime": "^6.26.0", + "babel-types": "^6.26.0", + "babylon": "^6.18.0", + "debug": "^2.6.8", + "globals": "^9.18.0", + "invariant": "^2.2.2", + "lodash": "^4.17.4" }, "dependencies": { "debug": { @@ -2284,10 +2494,10 @@ "integrity": "sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=", "dev": true, "requires": { - "babel-runtime": "6.26.0", - "esutils": "2.0.2", - "lodash": "4.17.11", - "to-fast-properties": "1.0.3" + "babel-runtime": "^6.26.0", + "esutils": "^2.0.2", + "lodash": "^4.17.4", + "to-fast-properties": "^1.0.3" }, "dependencies": { "to-fast-properties": { @@ -2304,6 +2514,11 @@ "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==", "dev": true }, + "backo2": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz", + "integrity": "sha1-MasayLEpNjRj41s+u2n038+6eUc=" + }, "balanced-match": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", @@ -2316,13 +2531,13 @@ "integrity": "sha1-e95c7RRbbVUakNuH+DxVi060io8=", "dev": true, "requires": { - "cache-base": "1.0.1", - "class-utils": "0.3.6", - "component-emitter": "1.2.1", - "define-property": "1.0.0", - "isobject": "3.0.1", - "mixin-deep": "1.3.1", - "pascalcase": "0.1.1" + "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": { @@ -2331,7 +2546,7 @@ "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", "dev": true, "requires": { - "is-descriptor": "1.0.2" + "is-descriptor": "^1.0.0" } }, "is-accessor-descriptor": { @@ -2340,7 +2555,7 @@ "integrity": "sha1-FpwvbT3x+ZJhgHI2XJsOofaHhlY=", "dev": true, "requires": { - "kind-of": "6.0.2" + "kind-of": "^6.0.0" } }, "is-data-descriptor": { @@ -2349,7 +2564,7 @@ "integrity": "sha1-2Eh2Mh0Oet0DmQQGq7u9NrqSaMc=", "dev": true, "requires": { - "kind-of": "6.0.2" + "kind-of": "^6.0.0" } }, "is-descriptor": { @@ -2358,13 +2573,18 @@ "integrity": "sha1-OxWXRqZmBLBPjIFSS6NlxfFNhuw=", "dev": true, "requires": { - "is-accessor-descriptor": "1.0.0", - "is-data-descriptor": "1.0.0", - "kind-of": "6.0.2" + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" } } } }, + "base64-arraybuffer": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz", + "integrity": "sha1-c5JncZI7Whl0etZmqlzUv5xunOg=" + }, "base64-js": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.0.tgz", @@ -2383,7 +2603,15 @@ "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", "dev": true, "requires": { - "tweetnacl": "0.14.5" + "tweetnacl": "^0.14.3" + } + }, + "better-assert": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/better-assert/-/better-assert-1.0.2.tgz", + "integrity": "sha1-QIZrnhueC1W0gYlDEeaPr/rrxSI=", + "requires": { + "callsite": "1.0.0" } }, "bfj": { @@ -2392,10 +2620,10 @@ "integrity": "sha512-+GUNvzHR4nRyGybQc2WpNJL4MJazMuvf92ueIyA0bIkPRwhhQu3IfZQ2PSoVPpCBJfmoSdOxu5rnotfFLlvYRQ==", "dev": true, "requires": { - "bluebird": "3.5.3", - "check-types": "7.4.0", - "hoopy": "0.1.4", - "tryer": "1.0.1" + "bluebird": "^3.5.1", + "check-types": "^7.3.0", + "hoopy": "^0.1.2", + "tryer": "^1.0.0" } }, "big.js": { @@ -2410,6 +2638,11 @@ "integrity": "sha512-DYWGk01lDcxeS/K9IHPGWfT8PsJmbXRtRd2Sx72Tnb8pcYZQFF1oSDb8hJtS1vhp212q1Rzi5dUf9+nq0o9UIg==", "dev": true }, + "blob": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/blob/-/blob-0.0.5.tgz", + "integrity": "sha512-gaqbzQPqOoamawKg0LGVd7SzLgXS+JH61oWprSLH+P+abTczqJbhTR8CmJ2u9/bUYNmHTGJx/UEmn6doAvvuig==" + }, "bluebird": { "version": "3.5.3", "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.3.tgz", @@ -2429,15 +2662,15 @@ "dev": true, "requires": { "bytes": "3.0.0", - "content-type": "1.0.4", + "content-type": "~1.0.4", "debug": "2.6.9", - "depd": "1.1.2", - "http-errors": "1.6.3", + "depd": "~1.1.2", + "http-errors": "~1.6.3", "iconv-lite": "0.4.23", - "on-finished": "2.3.0", + "on-finished": "~2.3.0", "qs": "6.5.2", "raw-body": "2.3.3", - "type-is": "1.6.16" + "type-is": "~1.6.16" }, "dependencies": { "debug": { @@ -2455,7 +2688,7 @@ "integrity": "sha512-neyTUVFtahjf0mB3dZT77u+8O0QB89jFdnBkd5P1JgYPbPaia3gXXOVL2fq8VyU2gMMD7SaN7QukTB/pmXYvDA==", "dev": true, "requires": { - "safer-buffer": "2.1.2" + "safer-buffer": ">= 2.1.2 < 3" } } } @@ -2466,12 +2699,12 @@ "integrity": "sha1-jokKGD2O6aI5OzhExpGkK897yfU=", "dev": true, "requires": { - "array-flatten": "2.1.2", - "deep-equal": "1.0.1", - "dns-equal": "1.0.0", - "dns-txt": "2.0.2", - "multicast-dns": "6.2.3", - "multicast-dns-service-types": "1.1.0" + "array-flatten": "^2.1.0", + "deep-equal": "^1.0.1", + "dns-equal": "^1.0.0", + "dns-txt": "^2.0.2", + "multicast-dns": "^6.0.1", + "multicast-dns-service-types": "^1.1.0" }, "dependencies": { "array-flatten": { @@ -2499,7 +2732,7 @@ "integrity": "sha1-PH/L9SnYcibz0vUrlm/1Jx60Qd0=", "dev": true, "requires": { - "balanced-match": "1.0.0", + "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, @@ -2509,16 +2742,16 @@ "integrity": "sha1-WXn9PxTNUxVl5fot8av/8d+u5yk=", "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.3", - "snapdragon": "0.8.2", - "snapdragon-node": "2.1.1", - "split-string": "3.1.0", - "to-regex": "3.0.2" + "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": { @@ -2527,7 +2760,7 @@ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, "requires": { - "is-extendable": "0.1.1" + "is-extendable": "^0.1.0" } } } @@ -2567,12 +2800,12 @@ "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", "dev": true, "requires": { - "buffer-xor": "1.0.3", - "cipher-base": "1.0.4", - "create-hash": "1.2.0", - "evp_bytestokey": "1.0.3", - "inherits": "2.0.3", - "safe-buffer": "5.1.2" + "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": { @@ -2581,9 +2814,9 @@ "integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==", "dev": true, "requires": { - "browserify-aes": "1.2.0", - "browserify-des": "1.0.2", - "evp_bytestokey": "1.0.3" + "browserify-aes": "^1.0.4", + "browserify-des": "^1.0.0", + "evp_bytestokey": "^1.0.0" } }, "browserify-des": { @@ -2592,10 +2825,10 @@ "integrity": "sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==", "dev": true, "requires": { - "cipher-base": "1.0.4", - "des.js": "1.0.0", - "inherits": "2.0.3", - "safe-buffer": "5.1.2" + "cipher-base": "^1.0.1", + "des.js": "^1.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" } }, "browserify-rsa": { @@ -2604,8 +2837,8 @@ "integrity": "sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ=", "dev": true, "requires": { - "bn.js": "4.11.8", - "randombytes": "2.0.6" + "bn.js": "^4.1.0", + "randombytes": "^2.0.1" } }, "browserify-sign": { @@ -2614,13 +2847,13 @@ "integrity": "sha1-qk62jl17ZYuqa/alfmMMvXqT0pg=", "dev": true, "requires": { - "bn.js": "4.11.8", - "browserify-rsa": "4.0.1", - "create-hash": "1.2.0", - "create-hmac": "1.1.7", - "elliptic": "6.4.1", - "inherits": "2.0.3", - "parse-asn1": "5.1.1" + "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": { @@ -2629,7 +2862,7 @@ "integrity": "sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==", "dev": true, "requires": { - "pako": "1.0.6" + "pako": "~1.0.5" } }, "browserslist": { @@ -2638,9 +2871,9 @@ "integrity": "sha1-RHe3N9tqGwcHcnWyR5HmgNQwBCU=", "dev": true, "requires": { - "caniuse-lite": "1.0.30000907", - "electron-to-chromium": "1.3.84", - "node-releases": "1.0.3" + "caniuse-lite": "^1.0.30000899", + "electron-to-chromium": "^1.3.82", + "node-releases": "^1.0.1" } }, "bser": { @@ -2649,7 +2882,7 @@ "integrity": "sha1-mseNPtXZFYBP2HrLFYvHlxR6Fxk=", "dev": true, "requires": { - "node-int64": "0.4.0" + "node-int64": "^0.4.0" } }, "buffer": { @@ -2658,9 +2891,9 @@ "integrity": "sha1-bRu2AbB6TvztlwlBMgkwJ8lbwpg=", "dev": true, "requires": { - "base64-js": "1.3.0", - "ieee754": "1.1.12", - "isarray": "1.0.0" + "base64-js": "^1.0.2", + "ieee754": "^1.1.4", + "isarray": "^1.0.0" } }, "buffer-from": { @@ -2705,19 +2938,19 @@ "integrity": "sha512-Dph0MzuH+rTQzGPNT9fAnrPmMmjKfST6trxJeK7NQuHRaVw24VzPRWTmg9MpcwOVQZO0E1FBICUlFeNaKPIfHA==", "dev": true, "requires": { - "bluebird": "3.5.3", - "chownr": "1.1.1", - "glob": "7.1.3", - "graceful-fs": "4.1.15", - "lru-cache": "4.1.3", - "mississippi": "2.0.0", - "mkdirp": "0.5.1", - "move-concurrently": "1.0.1", - "promise-inflight": "1.0.1", - "rimraf": "2.6.2", - "ssri": "5.3.0", - "unique-filename": "1.1.1", - "y18n": "4.0.0" + "bluebird": "^3.5.1", + "chownr": "^1.0.1", + "glob": "^7.1.2", + "graceful-fs": "^4.1.11", + "lru-cache": "^4.1.1", + "mississippi": "^2.0.0", + "mkdirp": "^0.5.1", + "move-concurrently": "^1.0.1", + "promise-inflight": "^1.0.1", + "rimraf": "^2.6.2", + "ssri": "^5.2.4", + "unique-filename": "^1.1.0", + "y18n": "^4.0.0" }, "dependencies": { "ssri": { @@ -2726,7 +2959,7 @@ "integrity": "sha512-XRSIPqLij52MtgoQavH/x/dU1qVKtWUAAZeOHsR9c2Ddi4XerFy3mc1alf+dLJKl9EUIm/Ht+EowFkTUOA6GAQ==", "dev": true, "requires": { - "safe-buffer": "5.1.2" + "safe-buffer": "^5.1.1" } } } @@ -2737,15 +2970,15 @@ "integrity": "sha1-Cn9GQWgxyLZi7jb+TnxZ129marI=", "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" + "collection-visit": "^1.0.0", + "component-emitter": "^1.2.1", + "get-value": "^2.0.6", + "has-value": "^1.0.0", + "isobject": "^3.0.1", + "set-value": "^2.0.0", + "to-object-path": "^0.3.0", + "union-value": "^1.0.0", + "unset-value": "^1.0.0" } }, "cache-loader": { @@ -2754,10 +2987,10 @@ "integrity": "sha512-enWKEQ4kO3YreDFd7AtVRjtJBmNiqh/X9hVDReu0C4qm8gsGmySkwuWtdc+N5O+vq5FzxL1mIZc30NyXCB7o/Q==", "dev": true, "requires": { - "loader-utils": "1.1.0", - "mkdirp": "0.5.1", - "neo-async": "2.6.0", - "schema-utils": "0.4.7" + "loader-utils": "^1.1.0", + "mkdirp": "^0.5.1", + "neo-async": "^2.5.0", + "schema-utils": "^0.4.2" } }, "call-me-maybe": { @@ -2772,7 +3005,7 @@ "integrity": "sha1-hH4PzgoiN1CpoCfFSzNzGtMVQTQ=", "dev": true, "requires": { - "callsites": "2.0.0" + "callsites": "^2.0.0" }, "dependencies": { "callsites": { @@ -2789,9 +3022,14 @@ "integrity": "sha1-lAhe9jWB7NPaqSREqP6U6CV3dR8=", "dev": true, "requires": { - "callsites": "0.2.0" + "callsites": "^0.2.0" } }, + "callsite": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/callsite/-/callsite-1.0.0.tgz", + "integrity": "sha1-KAOY5dZkvXQDi28JBRU+borxvCA=" + }, "callsites": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-0.2.0.tgz", @@ -2804,8 +3042,8 @@ "integrity": "sha1-yjw2iKTpzzpM2nd9xNy8cTJJz3M=", "dev": true, "requires": { - "no-case": "2.3.2", - "upper-case": "1.1.3" + "no-case": "^2.2.0", + "upper-case": "^1.1.1" } }, "camelcase": { @@ -2820,10 +3058,10 @@ "integrity": "sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==", "dev": true, "requires": { - "browserslist": "4.3.4", - "caniuse-lite": "1.0.30000907", - "lodash.memoize": "4.1.2", - "lodash.uniq": "4.5.0" + "browserslist": "^4.0.0", + "caniuse-lite": "^1.0.0", + "lodash.memoize": "^4.1.2", + "lodash.uniq": "^4.5.0" } }, "caniuse-lite": { @@ -2838,7 +3076,7 @@ "integrity": "sha1-HF/MSJ/QqwDU8ax64QcuMXP7q28=", "dev": true, "requires": { - "rsvp": "3.6.2" + "rsvp": "^3.3.3" } }, "case-sensitive-paths-webpack-plugin": { @@ -2859,9 +3097,9 @@ "integrity": "sha1-GMSasWoDe26wFSzIPjRxM4IVtm4=", "dev": true, "requires": { - "ansi-styles": "3.2.1", - "escape-string-regexp": "1.0.5", - "supports-color": "5.5.0" + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" } }, "chardet": { @@ -2882,19 +3120,19 @@ "integrity": "sha512-z9n7yt9rOvIJrMhvDtDictKrkFHeihkNl6uWMmZlmL6tJtX9Cs+87oK+teBx+JIgzvbX3yZHT3eF8vpbDxHJXQ==", "dev": true, "requires": { - "anymatch": "2.0.0", - "async-each": "1.0.1", - "braces": "2.3.2", - "fsevents": "1.2.4", - "glob-parent": "3.1.0", - "inherits": "2.0.3", - "is-binary-path": "1.0.1", - "is-glob": "4.0.0", - "lodash.debounce": "4.0.8", - "normalize-path": "2.1.1", - "path-is-absolute": "1.0.1", - "readdirp": "2.2.1", - "upath": "1.1.0" + "anymatch": "^2.0.0", + "async-each": "^1.0.0", + "braces": "^2.3.0", + "fsevents": "^1.2.2", + "glob-parent": "^3.1.0", + "inherits": "^2.0.1", + "is-binary-path": "^1.0.0", + "is-glob": "^4.0.0", + "lodash.debounce": "^4.0.8", + "normalize-path": "^2.1.1", + "path-is-absolute": "^1.0.0", + "readdirp": "^2.0.0", + "upath": "^1.0.5" } }, "chownr": { @@ -2909,7 +3147,7 @@ "integrity": "sha512-xDbVgyfDTT2piup/h8dK/y4QZfJRSa73bw1WZ8b4XM1o7fsFubUVGYcE+1ANtOzJJELGpYoG2961z0Z6OAld9A==", "dev": true, "requires": { - "tslib": "1.9.3" + "tslib": "^1.9.0" } }, "ci-info": { @@ -2924,8 +3162,8 @@ "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", "dev": true, "requires": { - "inherits": "2.0.3", - "safe-buffer": "5.1.2" + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" } }, "circular-json": { @@ -2940,10 +3178,10 @@ "integrity": "sha1-+TNprouafOAv1B+q0MqDAzGQxGM=", "dev": true, "requires": { - "arr-union": "3.1.0", - "define-property": "0.2.5", - "isobject": "3.0.1", - "static-extend": "0.1.2" + "arr-union": "^3.1.0", + "define-property": "^0.2.5", + "isobject": "^3.0.0", + "static-extend": "^0.1.1" }, "dependencies": { "define-property": { @@ -2952,7 +3190,7 @@ "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", "dev": true, "requires": { - "is-descriptor": "0.1.6" + "is-descriptor": "^0.1.0" } } } @@ -2963,7 +3201,7 @@ "integrity": "sha512-4ZxI6dy4lrY6FHzfiy1aEOXgu4LIsW2MhwG0VBKdcoGoH/XLFgaHSdLTGr4O8Be6A8r3MOphEiI8Gc1n0ecf3g==", "dev": true, "requires": { - "source-map": "0.6.1" + "source-map": "~0.6.0" }, "dependencies": { "source-map": { @@ -2980,7 +3218,7 @@ "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=", "dev": true, "requires": { - "restore-cursor": "2.0.0" + "restore-cursor": "^2.0.0" } }, "cli-spinners": { @@ -3001,8 +3239,8 @@ "integrity": "sha512-2WNImOvCRe6r63Gk9pShfkwXsVtKCroMAevIbiae021mS850UkWPbevxsBz3tnvjZIEGvlwaqCPsw+4ulzNgJA==", "dev": true, "requires": { - "arch": "2.1.1", - "execa": "0.8.0" + "arch": "^2.1.0", + "execa": "^0.8.0" }, "dependencies": { "cross-spawn": { @@ -3011,9 +3249,9 @@ "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", "dev": true, "requires": { - "lru-cache": "4.1.3", - "shebang-command": "1.2.0", - "which": "1.3.1" + "lru-cache": "^4.0.1", + "shebang-command": "^1.2.0", + "which": "^1.2.9" } }, "execa": { @@ -3022,13 +3260,13 @@ "integrity": "sha1-2NdrvBtVIX7RkP1t1J08d07PyNo=", "dev": true, "requires": { - "cross-spawn": "5.1.0", - "get-stream": "3.0.0", - "is-stream": "1.1.0", - "npm-run-path": "2.0.2", - "p-finally": "1.0.0", - "signal-exit": "3.0.2", - "strip-eof": "1.0.0" + "cross-spawn": "^5.0.1", + "get-stream": "^3.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" } }, "get-stream": { @@ -3045,9 +3283,9 @@ "integrity": "sha1-NIQi2+gtgAswIu709qwQvy5NG0k=", "dev": true, "requires": { - "string-width": "2.1.1", - "strip-ansi": "4.0.0", - "wrap-ansi": "2.1.0" + "string-width": "^2.1.1", + "strip-ansi": "^4.0.0", + "wrap-ansi": "^2.0.0" } }, "clone": { @@ -3068,7 +3306,7 @@ "integrity": "sha1-8/iwsVBz411wJj+xBCyywCPbOK8=", "dev": true, "requires": { - "q": "1.5.1" + "q": "^1.1.2" } }, "code-point-at": { @@ -3083,8 +3321,8 @@ "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", "dev": true, "requires": { - "map-visit": "1.0.0", - "object-visit": "1.0.1" + "map-visit": "^1.0.0", + "object-visit": "^1.0.0" } }, "color": { @@ -3093,8 +3331,8 @@ "integrity": "sha512-CwyopLkuRYO5ei2EpzpIh6LqJMt6Mt+jZhO5VI5f/wJLZriXQE32/SSqzmrh+QB+AZT81Cj8yv+7zwToW8ahZg==", "dev": true, "requires": { - "color-convert": "1.9.3", - "color-string": "1.5.3" + "color-convert": "^1.9.1", + "color-string": "^1.5.2" } }, "color-convert": { @@ -3118,8 +3356,8 @@ "integrity": "sha512-dC2C5qeWoYkxki5UAXapdjqO672AM4vZuPGRQfO8b5HKuKGBbKWpITyDYN7TOFKvRW7kOgAn3746clDBMDJyQw==", "dev": true, "requires": { - "color-name": "1.1.3", - "simple-swizzle": "0.2.2" + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" } }, "colors": { @@ -3134,7 +3372,7 @@ "integrity": "sha1-LR0kMXr7ir6V1tLAsHtXgTU52Cg=", "dev": true, "requires": { - "delayed-stream": "1.0.0" + "delayed-stream": "~1.0.0" } }, "commander": { @@ -3149,11 +3387,20 @@ "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", "dev": true }, + "component-bind": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/component-bind/-/component-bind-1.0.0.tgz", + "integrity": "sha1-AMYIq33Nk4l8AAllGx06jh5zu9E=" + }, "component-emitter": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", - "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=", - "dev": true + "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=" + }, + "component-inherit": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/component-inherit/-/component-inherit-0.0.3.tgz", + "integrity": "sha1-ZF/ErfWLcrZJ1crmUTVhnbJv8UM=" }, "compressible": { "version": "2.0.15", @@ -3161,7 +3408,7 @@ "integrity": "sha512-4aE67DL33dSW9gw4CI2H/yTxqHLNcxp0yS6jB+4h+wr3e43+1z7vm0HU9qXOH8j+qjKuL8+UtkOxYQSMq60Ylw==", "dev": true, "requires": { - "mime-db": "1.37.0" + "mime-db": ">= 1.36.0 < 2" } }, "compression": { @@ -3170,13 +3417,13 @@ "integrity": "sha512-HSjyBG5N1Nnz7tF2+O7A9XUhyjru71/fwgNb7oIsEVHR0WShfs2tIS/EySLgiTe98aOK18YDlMXpzjCXY/n9mg==", "dev": true, "requires": { - "accepts": "1.3.5", + "accepts": "~1.3.5", "bytes": "3.0.0", - "compressible": "2.0.15", + "compressible": "~2.0.14", "debug": "2.6.9", - "on-headers": "1.0.1", + "on-headers": "~1.0.1", "safe-buffer": "5.1.2", - "vary": "1.1.2" + "vary": "~1.1.2" }, "dependencies": { "debug": { @@ -3202,10 +3449,10 @@ "integrity": "sha1-kEvfGUzTEi/Gdcd/xKw9T/D9GjQ=", "dev": true, "requires": { - "buffer-from": "1.1.1", - "inherits": "2.0.3", - "readable-stream": "2.3.6", - "typedarray": "0.0.6" + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" } }, "condense-newlines": { @@ -3214,9 +3461,9 @@ "integrity": "sha1-PemFVTE5R10yUCyDsC9gaE0kxV8=", "dev": true, "requires": { - "extend-shallow": "2.0.1", - "is-whitespace": "0.3.0", - "kind-of": "3.2.2" + "extend-shallow": "^2.0.1", + "is-whitespace": "^0.3.0", + "kind-of": "^3.0.2" }, "dependencies": { "extend-shallow": { @@ -3225,7 +3472,7 @@ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, "requires": { - "is-extendable": "0.1.1" + "is-extendable": "^0.1.0" } }, "kind-of": { @@ -3234,7 +3481,7 @@ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "requires": { - "is-buffer": "1.1.6" + "is-buffer": "^1.1.5" } } } @@ -3245,8 +3492,8 @@ "integrity": "sha512-a1eOIcu8+7lUInge4Rpf/n4Krkf3Dd9lqhljRzII1/Zno/kRtUWnznPO3jOKBmTEktkt3fkxisUcivoj0ebzoA==", "dev": true, "requires": { - "ini": "1.3.5", - "proto-list": "1.2.4" + "ini": "^1.3.4", + "proto-list": "~1.2.1" } }, "connect-history-api-fallback": { @@ -3261,7 +3508,7 @@ "integrity": "sha1-8CQcRXMKn8YyOyBtvzjtx0HQuxA=", "dev": true, "requires": { - "date-now": "0.1.4" + "date-now": "^0.1.4" } }, "consolidate": { @@ -3270,7 +3517,7 @@ "integrity": "sha512-DW46nrsMJgy9kqAbPt5rKaCr7uFtpo4mSUvLHIUbJEjm0vo+aY5QLwBUq3FK4tRnJr/X0Psc0C4jf/h+HtXSMw==", "dev": true, "requires": { - "bluebird": "3.5.3" + "bluebird": "^3.1.1" } }, "constants-browserify": { @@ -3297,7 +3544,7 @@ "integrity": "sha1-UbU3qMQ+DwTewZk7/83VBOdYrCA=", "dev": true, "requires": { - "safe-buffer": "5.1.2" + "safe-buffer": "~5.1.1" } }, "cookie": { @@ -3318,12 +3565,12 @@ "integrity": "sha512-f2domd9fsVDFtaFcbaRZuYXwtdmnzqbADSwhSWYxYB/Q8zsdUUFMXVRwXGDMWmbEzAn1kdRrtI1T/KTFOL4X2A==", "dev": true, "requires": { - "aproba": "1.2.0", - "fs-write-stream-atomic": "1.0.10", - "iferr": "0.1.5", - "mkdirp": "0.5.1", - "rimraf": "2.6.2", - "run-queue": "1.0.3" + "aproba": "^1.1.1", + "fs-write-stream-atomic": "^1.0.8", + "iferr": "^0.1.5", + "mkdirp": "^0.5.1", + "rimraf": "^2.5.4", + "run-queue": "^1.0.0" } }, "copy-descriptor": { @@ -3338,14 +3585,14 @@ "integrity": "sha512-Y+SQCF+0NoWQryez2zXn5J5knmr9z/9qSQt7fbL78u83rxmigOy8X5+BFn8CFSuX+nKT8gpYwJX68ekqtQt6ZA==", "dev": true, "requires": { - "cacache": "10.0.4", - "find-cache-dir": "1.0.0", - "globby": "7.1.1", - "is-glob": "4.0.0", - "loader-utils": "1.1.0", - "minimatch": "3.0.4", - "p-limit": "1.3.0", - "serialize-javascript": "1.5.0" + "cacache": "^10.0.4", + "find-cache-dir": "^1.0.0", + "globby": "^7.1.1", + "is-glob": "^4.0.0", + "loader-utils": "^1.1.0", + "minimatch": "^3.0.4", + "p-limit": "^1.0.0", + "serialize-javascript": "^1.4.0" }, "dependencies": { "globby": { @@ -3354,12 +3601,12 @@ "integrity": "sha1-+yzP+UAfhgCUXfral0QMypcrhoA=", "dev": true, "requires": { - "array-union": "1.0.2", - "dir-glob": "2.0.0", - "glob": "7.1.3", - "ignore": "3.3.10", - "pify": "3.0.0", - "slash": "1.0.0" + "array-union": "^1.0.1", + "dir-glob": "^2.0.0", + "glob": "^7.1.2", + "ignore": "^3.3.5", + "pify": "^3.0.0", + "slash": "^1.0.0" } } } @@ -3382,10 +3629,10 @@ "integrity": "sha512-PcLqxTKiDmNT6pSpy4N6KtuPwb53W+2tzNvwOZw0WH9N6O0vLIBq0x8aj8Oj75ere4YcGi48bDFCL+3fRJdlNA==", "dev": true, "requires": { - "import-fresh": "2.0.0", - "is-directory": "0.3.1", - "js-yaml": "3.12.0", - "parse-json": "4.0.0" + "import-fresh": "^2.0.0", + "is-directory": "^0.3.1", + "js-yaml": "^3.9.0", + "parse-json": "^4.0.0" } }, "create-ecdh": { @@ -3394,8 +3641,8 @@ "integrity": "sha512-GbEHQPMOswGpKXM9kCWVrremUcBmjteUaQ01T9rkKCPDXfUHX0IoP9LpHYo2NPFampa4e+/pFDc3jQdxrxQLaw==", "dev": true, "requires": { - "bn.js": "4.11.8", - "elliptic": "6.4.1" + "bn.js": "^4.1.0", + "elliptic": "^6.0.0" } }, "create-hash": { @@ -3404,11 +3651,11 @@ "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", "dev": true, "requires": { - "cipher-base": "1.0.4", - "inherits": "2.0.3", - "md5.js": "1.3.5", - "ripemd160": "2.0.2", - "sha.js": "2.4.11" + "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": { @@ -3417,12 +3664,12 @@ "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", "dev": true, "requires": { - "cipher-base": "1.0.4", - "create-hash": "1.2.0", - "inherits": "2.0.3", - "ripemd160": "2.0.2", - "safe-buffer": "5.1.2", - "sha.js": "2.4.11" + "cipher-base": "^1.0.3", + "create-hash": "^1.1.0", + "inherits": "^2.0.1", + "ripemd160": "^2.0.0", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" } }, "cross-spawn": { @@ -3431,11 +3678,11 @@ "integrity": "sha1-Sl7Hxk364iw6FBJNus3uhG2Ay8Q=", "dev": true, "requires": { - "nice-try": "1.0.5", - "path-key": "2.0.1", - "semver": "5.6.0", - "shebang-command": "1.2.0", - "which": "1.3.1" + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" } }, "crypto-browserify": { @@ -3444,17 +3691,17 @@ "integrity": "sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==", "dev": true, "requires": { - "browserify-cipher": "1.0.1", - "browserify-sign": "4.0.4", - "create-ecdh": "4.0.3", - "create-hash": "1.2.0", - "create-hmac": "1.1.7", - "diffie-hellman": "5.0.3", - "inherits": "2.0.3", - "pbkdf2": "3.0.17", - "public-encrypt": "4.0.3", - "randombytes": "2.0.6", - "randomfill": "1.0.4" + "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": { @@ -3463,10 +3710,10 @@ "integrity": "sha512-oUnjmWpy0niI3x/mPL8dVEI1l7MnG3+HHyRPHf+YFSbK+svOhXpmSOcDURUh2aOCgl2grzrOPt1nHLuCVFULLw==", "dev": true, "requires": { - "inherits": "2.0.3", - "source-map": "0.6.1", - "source-map-resolve": "0.5.2", - "urix": "0.1.0" + "inherits": "^2.0.3", + "source-map": "^0.6.1", + "source-map-resolve": "^0.5.2", + "urix": "^0.1.0" }, "dependencies": { "source-map": { @@ -3489,8 +3736,8 @@ "integrity": "sha512-BcxQSKTSEEQUftYpBVnsH4SF05NTuBokb19/sBt6asXGKZ/6VP7PLG1CBCkFDYOnhXhPh0jMhO6xZ71oYHXHBA==", "dev": true, "requires": { - "postcss": "7.0.5", - "timsort": "0.3.0" + "postcss": "^7.0.1", + "timsort": "^0.3.0" } }, "css-loader": { @@ -3499,18 +3746,18 @@ "integrity": "sha512-+ZHAZm/yqvJ2kDtPne3uX0C+Vr3Zn5jFn2N4HywtS5ujwvsVkyg0VArEXpl3BgczDA8anieki1FIzhchX4yrDw==", "dev": true, "requires": { - "babel-code-frame": "6.26.0", - "css-selector-tokenizer": "0.7.1", - "icss-utils": "2.1.0", - "loader-utils": "1.1.0", - "lodash": "4.17.11", - "postcss": "6.0.23", - "postcss-modules-extract-imports": "1.2.1", - "postcss-modules-local-by-default": "1.2.0", - "postcss-modules-scope": "1.1.0", - "postcss-modules-values": "1.3.0", - "postcss-value-parser": "3.3.1", - "source-list-map": "2.0.1" + "babel-code-frame": "^6.26.0", + "css-selector-tokenizer": "^0.7.0", + "icss-utils": "^2.1.0", + "loader-utils": "^1.0.2", + "lodash": "^4.17.11", + "postcss": "^6.0.23", + "postcss-modules-extract-imports": "^1.2.0", + "postcss-modules-local-by-default": "^1.2.0", + "postcss-modules-scope": "^1.1.0", + "postcss-modules-values": "^1.3.0", + "postcss-value-parser": "^3.3.0", + "source-list-map": "^2.0.0" }, "dependencies": { "postcss": { @@ -3519,9 +3766,9 @@ "integrity": "sha512-soOk1h6J3VMTZtVeVpv15/Hpdl2cBLX3CAw4TAbkpTJiNPk9YP/zWcD1ND+xEtvyuuvKzbxliTOIyvkSeSJ6ag==", "dev": true, "requires": { - "chalk": "2.4.1", - "source-map": "0.6.1", - "supports-color": "5.5.0" + "chalk": "^2.4.1", + "source-map": "^0.6.1", + "supports-color": "^5.4.0" } }, "source-map": { @@ -3538,10 +3785,10 @@ "integrity": "sha512-dSpYaDVoWaELjvZ3mS6IKZM/y2PMPa/XYoEfYNZePL4U/XgyxZNroHEHReDx/d+VgXh9VbCTtFqLkFbmeqeaRQ==", "dev": true, "requires": { - "boolbase": "1.0.0", - "css-what": "2.1.2", - "domutils": "1.7.0", - "nth-check": "1.0.2" + "boolbase": "^1.0.0", + "css-what": "^2.1.2", + "domutils": "^1.7.0", + "nth-check": "^1.0.2" } }, "css-select-base-adapter": { @@ -3556,9 +3803,9 @@ "integrity": "sha512-xYL0AMZJ4gFzJQsHUKa5jiWWi2vH77WVNg7JYRyewwj6oPh4yb/y6Y9ZCw9dsj/9UauMhtuxR+ogQd//EdEVNA==", "dev": true, "requires": { - "cssesc": "0.1.0", - "fastparse": "1.1.2", - "regexpu-core": "1.0.0" + "cssesc": "^0.1.0", + "fastparse": "^1.1.1", + "regexpu-core": "^1.0.0" }, "dependencies": { "cssesc": { @@ -3579,9 +3826,9 @@ "integrity": "sha1-hqdj9Y7k18L2sQLkdkBQ3n7ZDGs=", "dev": true, "requires": { - "regenerate": "1.4.0", - "regjsgen": "0.2.0", - "regjsparser": "0.1.5" + "regenerate": "^1.2.1", + "regjsgen": "^0.2.0", + "regjsparser": "^0.1.4" } }, "regjsgen": { @@ -3596,7 +3843,7 @@ "integrity": "sha1-fuj4Tcb6eS0/0K4ijSS9lJ6tIFw=", "dev": true, "requires": { - "jsesc": "0.5.0" + "jsesc": "~0.5.0" } } } @@ -3607,8 +3854,8 @@ "integrity": "sha512-joNNW1gCp3qFFzj4St6zk+Wh/NBv0vM5YbEreZk0SD4S23S+1xBKb6cLDg2uj4P4k/GUMlIm6cKIDqIG+vdt0w==", "dev": true, "requires": { - "mdn-data": "1.1.4", - "source-map": "0.5.7" + "mdn-data": "~1.1.0", + "source-map": "^0.5.3" } }, "css-unit-converter": { @@ -3641,10 +3888,10 @@ "integrity": "sha1-C/ESKUvsEDq19o0/gFcyyDJaCxs=", "dev": true, "requires": { - "cosmiconfig": "5.0.7", - "cssnano-preset-default": "4.0.5", - "is-resolvable": "1.1.0", - "postcss": "7.0.5" + "cosmiconfig": "^5.0.0", + "cssnano-preset-default": "^4.0.5", + "is-resolvable": "^1.0.0", + "postcss": "^7.0.0" } }, "cssnano-preset-default": { @@ -3653,36 +3900,36 @@ "integrity": "sha1-0XVsAlnZitMR5gG6dulcYPZ3GsE=", "dev": true, "requires": { - "css-declaration-sorter": "4.0.1", - "cssnano-util-raw-cache": "4.0.1", - "postcss": "7.0.5", - "postcss-calc": "7.0.1", - "postcss-colormin": "4.0.2", - "postcss-convert-values": "4.0.1", - "postcss-discard-comments": "4.0.1", - "postcss-discard-duplicates": "4.0.2", - "postcss-discard-empty": "4.0.1", - "postcss-discard-overridden": "4.0.1", - "postcss-merge-longhand": "4.0.9", - "postcss-merge-rules": "4.0.2", - "postcss-minify-font-values": "4.0.2", - "postcss-minify-gradients": "4.0.1", - "postcss-minify-params": "4.0.1", - "postcss-minify-selectors": "4.0.1", - "postcss-normalize-charset": "4.0.1", - "postcss-normalize-display-values": "4.0.1", - "postcss-normalize-positions": "4.0.1", - "postcss-normalize-repeat-style": "4.0.1", - "postcss-normalize-string": "4.0.1", - "postcss-normalize-timing-functions": "4.0.1", - "postcss-normalize-unicode": "4.0.1", - "postcss-normalize-url": "4.0.1", - "postcss-normalize-whitespace": "4.0.1", - "postcss-ordered-values": "4.1.1", - "postcss-reduce-initial": "4.0.2", - "postcss-reduce-transforms": "4.0.1", - "postcss-svgo": "4.0.1", - "postcss-unique-selectors": "4.0.1" + "css-declaration-sorter": "^4.0.1", + "cssnano-util-raw-cache": "^4.0.1", + "postcss": "^7.0.0", + "postcss-calc": "^7.0.0", + "postcss-colormin": "^4.0.2", + "postcss-convert-values": "^4.0.1", + "postcss-discard-comments": "^4.0.1", + "postcss-discard-duplicates": "^4.0.2", + "postcss-discard-empty": "^4.0.1", + "postcss-discard-overridden": "^4.0.1", + "postcss-merge-longhand": "^4.0.9", + "postcss-merge-rules": "^4.0.2", + "postcss-minify-font-values": "^4.0.2", + "postcss-minify-gradients": "^4.0.1", + "postcss-minify-params": "^4.0.1", + "postcss-minify-selectors": "^4.0.1", + "postcss-normalize-charset": "^4.0.1", + "postcss-normalize-display-values": "^4.0.1", + "postcss-normalize-positions": "^4.0.1", + "postcss-normalize-repeat-style": "^4.0.1", + "postcss-normalize-string": "^4.0.1", + "postcss-normalize-timing-functions": "^4.0.1", + "postcss-normalize-unicode": "^4.0.1", + "postcss-normalize-url": "^4.0.1", + "postcss-normalize-whitespace": "^4.0.1", + "postcss-ordered-values": "^4.1.1", + "postcss-reduce-initial": "^4.0.2", + "postcss-reduce-transforms": "^4.0.1", + "postcss-svgo": "^4.0.1", + "postcss-unique-selectors": "^4.0.1" } }, "cssnano-util-get-arguments": { @@ -3703,7 +3950,7 @@ "integrity": "sha512-qLuYtWK2b2Dy55I8ZX3ky1Z16WYsx544Q0UWViebptpwn/xDBmog2TLg4f+DBMg1rJ6JDWtn96WHbOKDWt1WQA==", "dev": true, "requires": { - "postcss": "7.0.5" + "postcss": "^7.0.0" } }, "cssnano-util-same-parent": { @@ -3727,16 +3974,16 @@ "integrity": "sha512-sRNb1XydwkW9IOci6iB2xmy8IGCj6r/fr+JWitvJ2JxQRPzN3T4AGGVWCMlVmVwM1gtgALJRmGIlWv5ppnGGkg==", "dev": true, "requires": { - "mdn-data": "1.1.4", - "source-map": "0.5.7" + "mdn-data": "~1.1.0", + "source-map": "^0.5.3" } } } }, "cssom": { - "version": "0.3.4", - "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.4.tgz", - "integrity": "sha512-+7prCSORpXNeR4/fUP3rL+TzqtiFfhMvTd7uEqMdgPvLPt4+uzFUeufx5RHjGTACCargg/DiEt/moMQmvnfkog==", + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.6.tgz", + "integrity": "sha512-DtUeseGk9/GBW0hl0vVPpU22iHL6YB5BUX7ml1hB+GMpo0NX5G4voX3kdWiMSEguFtcW3Vh3djqNF4aIe6ne0A==", "dev": true }, "cssstyle": { @@ -3745,7 +3992,7 @@ "integrity": "sha512-364AI1l/M5TYcFH83JnOH/pSqgaNnKmYgKrm0didZMGKWjQB60dymwWy1rKUgL3J1ffdq9xVi2yGLHdSjjSNog==", "dev": true, "requires": { - "cssom": "0.3.4" + "cssom": "0.3.x" } }, "cyclist": { @@ -3760,7 +4007,7 @@ "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", "dev": true, "requires": { - "assert-plus": "1.0.0" + "assert-plus": "^1.0.0" } }, "data-urls": { @@ -3769,9 +4016,9 @@ "integrity": "sha512-YTWYI9se1P55u58gL5GkQHW4P6VJBJ5iBT+B5a7i2Tjadhv52paJG0qHX4A0OR6/t52odI64KP2YvFpkDOi3eQ==", "dev": true, "requires": { - "abab": "2.0.0", - "whatwg-mimetype": "2.3.0", - "whatwg-url": "7.0.0" + "abab": "^2.0.0", + "whatwg-mimetype": "^2.2.0", + "whatwg-url": "^7.0.0" }, "dependencies": { "whatwg-url": { @@ -3780,9 +4027,9 @@ "integrity": "sha512-37GeVSIJ3kn1JgKyjiYNmSLP1yzbpb29jdmwBSgkD9h40/hyrR/OifpVUndji3tmwGgD8qpw7iQu3RSbCrBpsQ==", "dev": true, "requires": { - "lodash.sortby": "4.7.0", - "tr46": "1.0.1", - "webidl-conversions": "4.0.2" + "lodash.sortby": "^4.7.0", + "tr46": "^1.0.1", + "webidl-conversions": "^4.0.2" } } } @@ -3846,8 +4093,8 @@ "integrity": "sha512-lAc4i9QJR0YHSDFdzeBQKfZ1SRDG3hsJNEkrpcZa8QhBfidLAilT60BDEIVUUGqosFp425KOgB3uYqcnQrWafQ==", "dev": true, "requires": { - "execa": "0.10.0", - "ip-regex": "2.1.0" + "execa": "^0.10.0", + "ip-regex": "^2.1.0" }, "dependencies": { "execa": { @@ -3856,13 +4103,13 @@ "integrity": "sha512-7XOMnz8Ynx1gGo/3hyV9loYNPWM94jG3+3T3Y8tsfSstFmETmENCMU/A/zj8Lyaj1lkgEepKepvd6240tBRvlw==", "dev": true, "requires": { - "cross-spawn": "6.0.5", - "get-stream": "3.0.0", - "is-stream": "1.1.0", - "npm-run-path": "2.0.2", - "p-finally": "1.0.0", - "signal-exit": "3.0.2", - "strip-eof": "1.0.0" + "cross-spawn": "^6.0.0", + "get-stream": "^3.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" } }, "get-stream": { @@ -3879,7 +4126,7 @@ "integrity": "sha1-836hXT4T/9m0N9M+GnW1+5eHTLg=", "dev": true, "requires": { - "strip-bom": "2.0.0" + "strip-bom": "^2.0.0" } }, "defaults": { @@ -3888,7 +4135,7 @@ "integrity": "sha1-xlYFHpgX2f8I7YgUd/P+QBnz730=", "dev": true, "requires": { - "clone": "1.0.4" + "clone": "^1.0.2" } }, "define-properties": { @@ -3897,7 +4144,7 @@ "integrity": "sha1-z4jabL7ib+bbcJT2HYcMvYTO6fE=", "dev": true, "requires": { - "object-keys": "1.0.12" + "object-keys": "^1.0.12" } }, "define-property": { @@ -3906,8 +4153,8 @@ "integrity": "sha1-1Flono1lS6d+AqgX+HENcCyxbp0=", "dev": true, "requires": { - "is-descriptor": "1.0.2", - "isobject": "3.0.1" + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" }, "dependencies": { "is-accessor-descriptor": { @@ -3916,7 +4163,7 @@ "integrity": "sha1-FpwvbT3x+ZJhgHI2XJsOofaHhlY=", "dev": true, "requires": { - "kind-of": "6.0.2" + "kind-of": "^6.0.0" } }, "is-data-descriptor": { @@ -3925,7 +4172,7 @@ "integrity": "sha1-2Eh2Mh0Oet0DmQQGq7u9NrqSaMc=", "dev": true, "requires": { - "kind-of": "6.0.2" + "kind-of": "^6.0.0" } }, "is-descriptor": { @@ -3934,9 +4181,9 @@ "integrity": "sha1-OxWXRqZmBLBPjIFSS6NlxfFNhuw=", "dev": true, "requires": { - "is-accessor-descriptor": "1.0.0", - "is-data-descriptor": "1.0.0", - "kind-of": "6.0.2" + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" } } } @@ -3947,12 +4194,12 @@ "integrity": "sha1-U+z2mf/LyzljdpGrE7rxYIGXZuU=", "dev": true, "requires": { - "globby": "6.1.0", - "is-path-cwd": "1.0.0", - "is-path-in-cwd": "1.0.1", - "p-map": "1.2.0", - "pify": "3.0.0", - "rimraf": "2.6.2" + "globby": "^6.1.0", + "is-path-cwd": "^1.0.0", + "is-path-in-cwd": "^1.0.0", + "p-map": "^1.1.1", + "pify": "^3.0.0", + "rimraf": "^2.2.8" }, "dependencies": { "globby": { @@ -3961,11 +4208,11 @@ "integrity": "sha1-9abXDoOV4hyFj7BInWTfAkJNUGw=", "dev": true, "requires": { - "array-union": "1.0.2", - "glob": "7.1.3", - "object-assign": "4.1.1", - "pify": "2.3.0", - "pinkie-promise": "2.0.1" + "array-union": "^1.0.1", + "glob": "^7.0.3", + "object-assign": "^4.0.1", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0" }, "dependencies": { "pify": { @@ -3996,8 +4243,8 @@ "integrity": "sha1-wHTS4qpqipoH29YfmhXCzYPsjsw=", "dev": true, "requires": { - "inherits": "2.0.3", - "minimalistic-assert": "1.0.1" + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0" } }, "destroy": { @@ -4012,7 +4259,7 @@ "integrity": "sha1-920GQ1LN9Docts5hnE7jqUdd4gg=", "dev": true, "requires": { - "repeating": "2.0.1" + "repeating": "^2.0.0" } }, "detect-newline": { @@ -4039,9 +4286,9 @@ "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==", "dev": true, "requires": { - "bn.js": "4.11.8", - "miller-rabin": "4.0.1", - "randombytes": "2.0.6" + "bn.js": "^4.1.0", + "miller-rabin": "^4.0.0", + "randombytes": "^2.0.0" } }, "dir-glob": { @@ -4050,8 +4297,8 @@ "integrity": "sha512-37qirFDz8cA5fimp9feo43fSuRo2gHwaIn6dXL8Ber1dGwUosDrGZeCCXq57WnIqE4aQ+u3eQZzsk1yOzhdwag==", "dev": true, "requires": { - "arrify": "1.0.1", - "path-type": "3.0.0" + "arrify": "^1.0.1", + "path-type": "^3.0.0" } }, "dns-equal": { @@ -4066,8 +4313,8 @@ "integrity": "sha512-0UxfQkMhYAUaZI+xrNZOz/as5KgDU0M/fQ9b6SpkyLbk3GEswDi6PADJVaYJradtRVsRIlF1zLyOodbcTCDzUg==", "dev": true, "requires": { - "ip": "1.1.5", - "safe-buffer": "5.1.2" + "ip": "^1.1.0", + "safe-buffer": "^5.0.1" } }, "dns-txt": { @@ -4076,7 +4323,7 @@ "integrity": "sha1-uR2Ab10nGI5Ks+fRB9iBocxGQrY=", "dev": true, "requires": { - "buffer-indexof": "1.1.1" + "buffer-indexof": "^1.0.0" } }, "doctrine": { @@ -4085,7 +4332,7 @@ "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", "dev": true, "requires": { - "esutils": "2.0.2" + "esutils": "^2.0.2" } }, "dom-converter": { @@ -4094,7 +4341,7 @@ "integrity": "sha512-gd3ypIPfOMr9h5jIKq8E3sHOTCjeirnl0WK5ZdS1AW0Odt0b1PaWaHdJ4Qk4klv+YB9aJBS7mESXjFoDQPu6DA==", "dev": true, "requires": { - "utila": "0.4.0" + "utila": "~0.4" } }, "dom-event-types": { @@ -4109,8 +4356,8 @@ "integrity": "sha1-BzxpdUbOB4DOI75KKOKT5AvDDII=", "dev": true, "requires": { - "domelementtype": "1.1.3", - "entities": "1.1.2" + "domelementtype": "~1.1.1", + "entities": "~1.1.1" }, "dependencies": { "domelementtype": { @@ -4139,7 +4386,7 @@ "integrity": "sha512-raigMkn7CJNNo6Ihro1fzG7wr3fHuYVytzquZKX5n0yizGsTcYgzdIUwj1X9pK0VvjeihV+XiclP+DjwbsSKug==", "dev": true, "requires": { - "webidl-conversions": "4.0.2" + "webidl-conversions": "^4.0.2" } }, "domhandler": { @@ -4148,7 +4395,7 @@ "integrity": "sha1-0mRvXlf2w7qxHPbLBdPArPdBJZQ=", "dev": true, "requires": { - "domelementtype": "1.2.1" + "domelementtype": "1" } }, "domutils": { @@ -4157,8 +4404,8 @@ "integrity": "sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg==", "dev": true, "requires": { - "dom-serializer": "0.1.0", - "domelementtype": "1.2.1" + "dom-serializer": "0", + "domelementtype": "1" } }, "dot-prop": { @@ -4167,7 +4414,7 @@ "integrity": "sha512-tUMXrxlExSW6U2EXiiKGSBVdYgtV8qlHL+C10TsW4PURY/ic+eaysnSkwB4kA/mBlCyy/IKDJ+Lc3wbWeaXtuQ==", "dev": true, "requires": { - "is-obj": "1.0.1" + "is-obj": "^1.0.0" } }, "duplexer": { @@ -4182,10 +4429,10 @@ "integrity": "sha512-vM58DwdnKmty+FSPzT14K9JXb90H+j5emaR4KYbr2KTIz00WHGbWOe5ghQTx233ZCLZtrGDALzKwcjEtSt35mA==", "dev": true, "requires": { - "end-of-stream": "1.4.1", - "inherits": "2.0.3", - "readable-stream": "2.3.6", - "stream-shift": "1.0.0" + "end-of-stream": "^1.0.0", + "inherits": "^2.0.1", + "readable-stream": "^2.0.0", + "stream-shift": "^1.0.0" } }, "easy-stack": { @@ -4200,8 +4447,8 @@ "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", "dev": true, "requires": { - "jsbn": "0.1.1", - "safer-buffer": "2.1.2" + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" } }, "editorconfig": { @@ -4210,12 +4457,12 @@ "integrity": "sha512-GWjSI19PVJAM9IZRGOS+YKI8LN+/sjkSjNyvxL5ucqP9/IqtYNXBaQ/6c/hkPNYQHyOHra2KoXZI/JVpuqwmcQ==", "dev": true, "requires": { - "@types/node": "10.12.18", - "@types/semver": "5.5.0", - "commander": "2.19.0", - "lru-cache": "4.1.3", - "semver": "5.6.0", - "sigmund": "1.0.1" + "@types/node": "^10.11.7", + "@types/semver": "^5.5.0", + "commander": "^2.19.0", + "lru-cache": "^4.1.3", + "semver": "^5.6.0", + "sigmund": "^1.0.1" }, "dependencies": { "commander": { @@ -4250,13 +4497,13 @@ "integrity": "sha512-BsXLz5sqX8OHcsh7CqBMztyXARmGQ3LWPtGjJi6DiJHq5C/qvi9P3OqgswKSDftbu8+IoI/QDTAm2fFnQ9SZSQ==", "dev": true, "requires": { - "bn.js": "4.11.8", - "brorand": "1.1.0", - "hash.js": "1.1.5", - "hmac-drbg": "1.0.1", - "inherits": "2.0.3", - "minimalistic-assert": "1.0.1", - "minimalistic-crypto-utils": "1.0.1" + "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" } }, "emojis-list": { @@ -4277,7 +4524,37 @@ "integrity": "sha1-7SljTRm6ukY7bOa4CjchPqtx7EM=", "dev": true, "requires": { - "once": "1.4.0" + "once": "^1.4.0" + } + }, + "engine.io-client": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-3.3.2.tgz", + "integrity": "sha512-y0CPINnhMvPuwtqXfsGuWE8BB66+B6wTtCofQDRecMQPYX3MYUZXFNKDhdrSe3EVjgOu4V3rxdeqN/Tr91IgbQ==", + "requires": { + "component-emitter": "1.2.1", + "component-inherit": "0.0.3", + "debug": "~3.1.0", + "engine.io-parser": "~2.1.1", + "has-cors": "1.1.0", + "indexof": "0.0.1", + "parseqs": "0.0.5", + "parseuri": "0.0.5", + "ws": "~6.1.0", + "xmlhttprequest-ssl": "~1.5.4", + "yeast": "0.1.2" + } + }, + "engine.io-parser": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-2.1.3.tgz", + "integrity": "sha512-6HXPre2O4Houl7c4g7Ic/XzPnHBvaEmN90vtRO9uLmwtRqQmTOw0QMevL1TOfL2Cpu1VzsaTmMotQgMdkzGkVA==", + "requires": { + "after": "0.8.2", + "arraybuffer.slice": "~0.0.7", + "base64-arraybuffer": "0.1.5", + "blob": "0.0.5", + "has-binary2": "~1.0.2" } }, "enhanced-resolve": { @@ -4286,9 +4563,9 @@ "integrity": "sha512-F/7vkyTtyc/llOIn8oWclcB25KdRaiPBpZYDgJHgh/UHtpgT2p2eldQgtQnLtUvfMKPKxbRaQM/hHkvLHt1Vng==", "dev": true, "requires": { - "graceful-fs": "4.1.15", - "memory-fs": "0.4.1", - "tapable": "1.1.0" + "graceful-fs": "^4.1.2", + "memory-fs": "^0.4.0", + "tapable": "^1.0.0" } }, "entities": { @@ -4303,7 +4580,7 @@ "integrity": "sha512-MfrRBDWzIWifgq6tJj60gkAwtLNb6sQPlcFrSOflcP1aFmmruKQ2wRnze/8V6kgyz7H3FF8Npzv78mZ7XLLflg==", "dev": true, "requires": { - "prr": "1.0.1" + "prr": "~1.0.1" } }, "error-ex": { @@ -4312,7 +4589,7 @@ "integrity": "sha1-tKxAZIEH/c3PriQvQovqihTU8b8=", "dev": true, "requires": { - "is-arrayish": "0.2.1" + "is-arrayish": "^0.2.1" } }, "error-stack-parser": { @@ -4321,7 +4598,7 @@ "integrity": "sha512-E1fPutRDdIj/hohG0UpT5mayXNCxXP9d+snxFsPU9X0XgccOumKraa3juDMwTUyi7+Bu5+mCGagjg4IYeNbOdw==", "dev": true, "requires": { - "stackframe": "1.0.4" + "stackframe": "^1.0.4" } }, "es-abstract": { @@ -4330,11 +4607,11 @@ "integrity": "sha1-nbvdJ8aFbwABQhyhh4LXhr+KYWU=", "dev": true, "requires": { - "es-to-primitive": "1.2.0", - "function-bind": "1.1.1", - "has": "1.0.3", - "is-callable": "1.1.4", - "is-regex": "1.0.4" + "es-to-primitive": "^1.1.1", + "function-bind": "^1.1.1", + "has": "^1.0.1", + "is-callable": "^1.1.3", + "is-regex": "^1.0.4" } }, "es-to-primitive": { @@ -4343,9 +4620,9 @@ "integrity": "sha1-7fckeAM0VujdqO8J4ArZZQcH83c=", "dev": true, "requires": { - "is-callable": "1.1.4", - "is-date-object": "1.0.1", - "is-symbol": "1.0.2" + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" } }, "escape-html": { @@ -4366,11 +4643,11 @@ "integrity": "sha512-IeMV45ReixHS53K/OmfKAIztN/igDHzTJUhZM3k1jMhIZWjk45SMwAtBsEXiJp3vSPmTcu6CXn7mDvFHRN66fw==", "dev": true, "requires": { - "esprima": "3.1.3", - "estraverse": "4.2.0", - "esutils": "2.0.2", - "optionator": "0.8.2", - "source-map": "0.6.1" + "esprima": "^3.1.3", + "estraverse": "^4.2.0", + "esutils": "^2.0.2", + "optionator": "^0.8.1", + "source-map": "~0.6.1" }, "dependencies": { "esprima": { @@ -4394,44 +4671,44 @@ "integrity": "sha512-g4KWpPdqN0nth+goDNICNXGfJF7nNnepthp46CAlJoJtC5K/cLu3NgCM3AHu1CkJ5Hzt9V0Y0PBAO6Ay/gGb+w==", "dev": true, "requires": { - "@babel/code-frame": "7.0.0", - "ajv": "6.5.5", - "chalk": "2.4.1", - "cross-spawn": "6.0.5", - "debug": "4.1.0", - "doctrine": "2.1.0", - "eslint-scope": "4.0.0", - "eslint-utils": "1.3.1", - "eslint-visitor-keys": "1.0.0", - "espree": "4.1.0", - "esquery": "1.0.1", - "esutils": "2.0.2", - "file-entry-cache": "2.0.0", - "functional-red-black-tree": "1.0.1", - "glob": "7.1.3", - "globals": "11.9.0", - "ignore": "4.0.6", - "imurmurhash": "0.1.4", - "inquirer": "6.2.0", - "is-resolvable": "1.1.0", - "js-yaml": "3.12.0", - "json-stable-stringify-without-jsonify": "1.0.1", - "levn": "0.3.0", - "lodash": "4.17.11", - "minimatch": "3.0.4", - "mkdirp": "0.5.1", - "natural-compare": "1.4.0", - "optionator": "0.8.2", - "path-is-inside": "1.0.2", - "pluralize": "7.0.0", - "progress": "2.0.1", - "regexpp": "2.0.1", - "require-uncached": "1.0.3", - "semver": "5.6.0", - "strip-ansi": "4.0.0", - "strip-json-comments": "2.0.1", - "table": "5.1.0", - "text-table": "0.2.0" + "@babel/code-frame": "^7.0.0", + "ajv": "^6.5.3", + "chalk": "^2.1.0", + "cross-spawn": "^6.0.5", + "debug": "^4.0.1", + "doctrine": "^2.1.0", + "eslint-scope": "^4.0.0", + "eslint-utils": "^1.3.1", + "eslint-visitor-keys": "^1.0.0", + "espree": "^4.0.0", + "esquery": "^1.0.1", + "esutils": "^2.0.2", + "file-entry-cache": "^2.0.0", + "functional-red-black-tree": "^1.0.1", + "glob": "^7.1.2", + "globals": "^11.7.0", + "ignore": "^4.0.6", + "imurmurhash": "^0.1.4", + "inquirer": "^6.1.0", + "is-resolvable": "^1.1.0", + "js-yaml": "^3.12.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.3.0", + "lodash": "^4.17.5", + "minimatch": "^3.0.4", + "mkdirp": "^0.5.1", + "natural-compare": "^1.4.0", + "optionator": "^0.8.2", + "path-is-inside": "^1.0.2", + "pluralize": "^7.0.0", + "progress": "^2.0.0", + "regexpp": "^2.0.1", + "require-uncached": "^1.0.3", + "semver": "^5.5.1", + "strip-ansi": "^4.0.0", + "strip-json-comments": "^2.0.1", + "table": "^5.0.2", + "text-table": "^0.2.0" }, "dependencies": { "acorn": { @@ -4458,7 +4735,7 @@ "integrity": "sha1-NzaHv/pnizixzZH4YbY4UANd3Ic=", "dev": true, "requires": { - "ms": "2.1.1" + "ms": "^2.1.1" } }, "eslint-scope": { @@ -4467,8 +4744,8 @@ "integrity": "sha1-UL8wcekzi83EMzF5Sgy1M/ATYXI=", "dev": true, "requires": { - "esrecurse": "4.2.1", - "estraverse": "4.2.0" + "esrecurse": "^4.1.0", + "estraverse": "^4.1.1" } }, "espree": { @@ -4477,9 +4754,9 @@ "integrity": "sha1-co1UUeD9FWwEOEp62J7VH/VOsl8=", "dev": true, "requires": { - "acorn": "6.0.4", - "acorn-jsx": "5.0.0", - "eslint-visitor-keys": "1.0.0" + "acorn": "^6.0.2", + "acorn-jsx": "^5.0.0", + "eslint-visitor-keys": "^1.0.0" } }, "external-editor": { @@ -4488,9 +4765,9 @@ "integrity": "sha1-WGbbKal4Jtvkvzr9JAcOrZ6kOic=", "dev": true, "requires": { - "chardet": "0.7.0", - "iconv-lite": "0.4.24", - "tmp": "0.0.33" + "chardet": "^0.7.0", + "iconv-lite": "^0.4.24", + "tmp": "^0.0.33" } }, "ignore": { @@ -4505,19 +4782,19 @@ "integrity": "sha1-Ua3Nd29mE2ncHolIWcJWCiJKvdg=", "dev": true, "requires": { - "ansi-escapes": "3.1.0", - "chalk": "2.4.1", - "cli-cursor": "2.1.0", - "cli-width": "2.2.0", - "external-editor": "3.0.3", - "figures": "2.0.0", - "lodash": "4.17.11", + "ansi-escapes": "^3.0.0", + "chalk": "^2.0.0", + "cli-cursor": "^2.1.0", + "cli-width": "^2.0.0", + "external-editor": "^3.0.0", + "figures": "^2.0.0", + "lodash": "^4.17.10", "mute-stream": "0.0.7", - "run-async": "2.3.0", - "rxjs": "6.3.3", - "string-width": "2.1.1", - "strip-ansi": "4.0.0", - "through": "2.3.8" + "run-async": "^2.2.0", + "rxjs": "^6.1.0", + "string-width": "^2.1.0", + "strip-ansi": "^4.0.0", + "through": "^2.3.6" } }, "ms": { @@ -4538,10 +4815,10 @@ "integrity": "sha1-aaVGRPbwGtFij4F4cVtAjca/Efc=", "dev": true, "requires": { - "ajv": "6.5.5", - "lodash": "4.17.11", + "ajv": "^6.5.3", + "lodash": "^4.17.10", "slice-ansi": "1.0.0", - "string-width": "2.1.1" + "string-width": "^2.1.1" } } } @@ -4552,7 +4829,7 @@ "integrity": "sha512-Bc3bh5bAcKNvs3HOpSi6EfGA2IIp7EzWcg2tS4vP7stnXu/J1opihHDM7jI9JCIckyIDTgZLSWn7J3HY0j2JfA==", "dev": true, "requires": { - "get-stdin": "6.0.0" + "get-stdin": "^6.0.0" } }, "eslint-loader": { @@ -4561,11 +4838,11 @@ "integrity": "sha512-1GrJFfSevQdYpoDzx8mEE2TDWsb/zmFuY09l6hURg1AeFIKQOvZ+vH0UPjzmd1CZIbfTV5HUkMeBmFiDBkgIsQ==", "dev": true, "requires": { - "loader-fs-cache": "1.0.1", - "loader-utils": "1.1.0", - "object-assign": "4.1.1", - "object-hash": "1.3.1", - "rimraf": "2.6.2" + "loader-fs-cache": "^1.0.0", + "loader-utils": "^1.0.2", + "object-assign": "^4.0.1", + "object-hash": "^1.1.4", + "rimraf": "^2.6.1" } }, "eslint-plugin-prettier": { @@ -4574,7 +4851,7 @@ "integrity": "sha1-9rgj4GX4w2UpkYzbdm16Dpdewww=", "dev": true, "requires": { - "prettier-linter-helpers": "1.0.0" + "prettier-linter-helpers": "^1.0.0" } }, "eslint-plugin-vue": { @@ -4583,7 +4860,7 @@ "integrity": "sha512-roXXroqY2AcgF4dk0SG1reeeQz2X3Ef7q9B0GD0+vdc58vApig1hpTReT4Mf0YqTEI80/ldXD1ibV6n4vVUZrw==", "dev": true, "requires": { - "vue-eslint-parser": "3.2.2" + "vue-eslint-parser": "^3.2.1" }, "dependencies": { "acorn": { @@ -4604,8 +4881,8 @@ "integrity": "sha1-UL8wcekzi83EMzF5Sgy1M/ATYXI=", "dev": true, "requires": { - "esrecurse": "4.2.1", - "estraverse": "4.2.0" + "esrecurse": "^4.1.0", + "estraverse": "^4.1.1" } }, "espree": { @@ -4614,9 +4891,9 @@ "integrity": "sha1-co1UUeD9FWwEOEp62J7VH/VOsl8=", "dev": true, "requires": { - "acorn": "6.0.4", - "acorn-jsx": "5.0.0", - "eslint-visitor-keys": "1.0.0" + "acorn": "^6.0.2", + "acorn-jsx": "^5.0.0", + "eslint-visitor-keys": "^1.0.0" } }, "vue-eslint-parser": { @@ -4625,12 +4902,12 @@ "integrity": "sha1-R8lx7kw5sO59f14VTLYhvrIvejQ=", "dev": true, "requires": { - "debug": "3.1.0", - "eslint-scope": "4.0.0", - "eslint-visitor-keys": "1.0.0", - "espree": "4.1.0", - "esquery": "1.0.1", - "lodash": "4.17.11" + "debug": "^3.1.0", + "eslint-scope": "^4.0.0", + "eslint-visitor-keys": "^1.0.0", + "espree": "^4.0.0", + "esquery": "^1.0.1", + "lodash": "^4.17.10" } } } @@ -4641,8 +4918,8 @@ "integrity": "sha1-PWPD7f2gLgbgGkUq2IyqzHzctug=", "dev": true, "requires": { - "esrecurse": "4.2.1", - "estraverse": "4.2.0" + "esrecurse": "^4.1.0", + "estraverse": "^4.1.1" } }, "eslint-utils": { @@ -4663,8 +4940,8 @@ "integrity": "sha512-yAcIQxtmMiB/jL32dzEp2enBeidsB7xWPLNiw3IIkpVds1P+h7qF9YwJq1yUNzp2OKXgAprs4F61ih66UsoD1A==", "dev": true, "requires": { - "acorn": "5.7.3", - "acorn-jsx": "3.0.1" + "acorn": "^5.5.0", + "acorn-jsx": "^3.0.0" } }, "esprima": { @@ -4679,7 +4956,7 @@ "integrity": "sha512-SmiyZ5zIWH9VM+SRUReLS5Q8a7GxtRdxEBVZpm98rJM7Sb+A9DVCndXfkeFUd3byderg+EbDkfnevfCwynWaNA==", "dev": true, "requires": { - "estraverse": "4.2.0" + "estraverse": "^4.0.0" } }, "esrecurse": { @@ -4688,7 +4965,7 @@ "integrity": "sha1-AHo7n9vCs7uH5IeeoZyS/b05Qs8=", "dev": true, "requires": { - "estraverse": "4.2.0" + "estraverse": "^4.1.0" } }, "estraverse": { @@ -4733,7 +5010,7 @@ "integrity": "sha512-4Ln17+vVT0k8aWq+t/bF5arcS3EpT9gYtW66EPacdj/mAFevznsnyoHLPy2BA8gbIQeIHoPsvwmfBftfcG//BQ==", "dev": true, "requires": { - "original": "1.0.2" + "original": "^1.0.0" } }, "evp_bytestokey": { @@ -4742,8 +5019,8 @@ "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", "dev": true, "requires": { - "md5.js": "1.3.5", - "safe-buffer": "5.1.2" + "md5.js": "^1.3.4", + "safe-buffer": "^5.1.1" } }, "exec-sh": { @@ -4752,7 +5029,7 @@ "integrity": "sha512-FIUCJz1RbuS0FKTdaAafAByGS0CPvU3R0MeHxgtl+djzCc//F8HakL8GzmVNZanasTbTAY/3DRFA0KpVqj/eAw==", "dev": true, "requires": { - "merge": "1.2.1" + "merge": "^1.2.0" } }, "execa": { @@ -4761,13 +5038,13 @@ "integrity": "sha1-xiNqW7TfbW8V6I5/AXeYIWdJ3dg=", "dev": true, "requires": { - "cross-spawn": "6.0.5", - "get-stream": "4.1.0", - "is-stream": "1.1.0", - "npm-run-path": "2.0.2", - "p-finally": "1.0.0", - "signal-exit": "3.0.2", - "strip-eof": "1.0.0" + "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" } }, "exit": { @@ -4782,13 +5059,13 @@ "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", "dev": true, "requires": { - "debug": "2.6.9", - "define-property": "0.2.5", - "extend-shallow": "2.0.1", - "posix-character-classes": "0.1.1", - "regex-not": "1.0.2", - "snapdragon": "0.8.2", - "to-regex": "3.0.2" + "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": { @@ -4806,7 +5083,7 @@ "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", "dev": true, "requires": { - "is-descriptor": "0.1.6" + "is-descriptor": "^0.1.0" } }, "extend-shallow": { @@ -4815,7 +5092,7 @@ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, "requires": { - "is-extendable": "0.1.1" + "is-extendable": "^0.1.0" } } } @@ -4826,7 +5103,7 @@ "integrity": "sha1-opnv/TNf4nIeuujiV+x5ZE/IUzc=", "dev": true, "requires": { - "fill-range": "2.2.4" + "fill-range": "^2.1.0" }, "dependencies": { "fill-range": { @@ -4835,11 +5112,11 @@ "integrity": "sha512-cnrcCbj01+j2gTG921VZPnHbjmdAf8oQV/iGeV2kZxGSyfYjjTyY79ErsK1WJWMpw6DaApEX72binqJE+/d+5Q==", "dev": true, "requires": { - "is-number": "2.1.0", - "isobject": "2.1.0", - "randomatic": "3.1.1", - "repeat-element": "1.1.3", - "repeat-string": "1.6.1" + "is-number": "^2.1.0", + "isobject": "^2.0.0", + "randomatic": "^3.0.0", + "repeat-element": "^1.1.2", + "repeat-string": "^1.5.2" } }, "is-number": { @@ -4848,7 +5125,7 @@ "integrity": "sha1-Afy7s5NGOlSPL0ZszhbezknbkI8=", "dev": true, "requires": { - "kind-of": "3.2.2" + "kind-of": "^3.0.2" } }, "isobject": { @@ -4866,7 +5143,7 @@ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "requires": { - "is-buffer": "1.1.6" + "is-buffer": "^1.1.5" } } } @@ -4877,12 +5154,12 @@ "integrity": "sha512-dgSoOHgmtn/aDGRVFWclQyPDKl2CQRq0hmIEoUAuQs/2rn2NcvCWcSCovm6BLeuB/7EZuLGu2QfnR+qRt5OM4w==", "dev": true, "requires": { - "ansi-styles": "3.2.1", - "jest-diff": "23.6.0", - "jest-get-type": "22.4.3", - "jest-matcher-utils": "23.6.0", - "jest-message-util": "23.4.0", - "jest-regex-util": "23.3.0" + "ansi-styles": "^3.2.0", + "jest-diff": "^23.6.0", + "jest-get-type": "^22.1.0", + "jest-matcher-utils": "^23.6.0", + "jest-message-util": "^23.4.0", + "jest-regex-util": "^23.3.0" } }, "express": { @@ -4891,36 +5168,36 @@ "integrity": "sha512-j12Uuyb4FMrd/qQAm6uCHAkPtO8FDTRJZBDd5D2KOL2eLaz1yUNdUB/NOIyq0iU4q4cFarsUCrnFDPBcnksuOg==", "dev": true, "requires": { - "accepts": "1.3.5", + "accepts": "~1.3.5", "array-flatten": "1.1.1", "body-parser": "1.18.3", "content-disposition": "0.5.2", - "content-type": "1.0.4", + "content-type": "~1.0.4", "cookie": "0.3.1", "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", + "depd": "~1.1.2", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", "finalhandler": "1.1.1", "fresh": "0.5.2", "merge-descriptors": "1.0.1", - "methods": "1.1.2", - "on-finished": "2.3.0", - "parseurl": "1.3.2", + "methods": "~1.1.2", + "on-finished": "~2.3.0", + "parseurl": "~1.3.2", "path-to-regexp": "0.1.7", - "proxy-addr": "2.0.4", + "proxy-addr": "~2.0.4", "qs": "6.5.2", - "range-parser": "1.2.0", + "range-parser": "~1.2.0", "safe-buffer": "5.1.2", "send": "0.16.2", "serve-static": "1.13.2", "setprototypeof": "1.1.0", - "statuses": "1.4.0", - "type-is": "1.6.16", + "statuses": "~1.4.0", + "type-is": "~1.6.16", "utils-merge": "1.0.1", - "vary": "1.1.2" + "vary": "~1.1.2" }, "dependencies": { "debug": { @@ -4946,8 +5223,8 @@ "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", "dev": true, "requires": { - "assign-symbols": "1.0.0", - "is-extendable": "1.0.1" + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" }, "dependencies": { "is-extendable": { @@ -4956,7 +5233,7 @@ "integrity": "sha1-p0cPnkJnM9gb2B4RVSZOOjUHyrQ=", "dev": true, "requires": { - "is-plain-object": "2.0.4" + "is-plain-object": "^2.0.4" } } } @@ -4967,9 +5244,9 @@ "integrity": "sha512-bSn6gvGxKt+b7+6TKEv1ZycHleA7aHhRHyAqJyp5pbUFuYYNIzpZnQDk7AsYckyWdEnTeAnay0aCy2aV6iTk9A==", "dev": true, "requires": { - "chardet": "0.4.2", - "iconv-lite": "0.4.24", - "tmp": "0.0.33" + "chardet": "^0.4.0", + "iconv-lite": "^0.4.17", + "tmp": "^0.0.33" } }, "extglob": { @@ -4978,14 +5255,14 @@ "integrity": "sha1-rQD+TcYSqSMuhxhxHcXLWrAoVUM=", "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.2", - "snapdragon": "0.8.2", - "to-regex": "3.0.2" + "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": { @@ -4994,7 +5271,7 @@ "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", "dev": true, "requires": { - "is-descriptor": "1.0.2" + "is-descriptor": "^1.0.0" } }, "extend-shallow": { @@ -5003,7 +5280,7 @@ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, "requires": { - "is-extendable": "0.1.1" + "is-extendable": "^0.1.0" } }, "is-accessor-descriptor": { @@ -5012,7 +5289,7 @@ "integrity": "sha1-FpwvbT3x+ZJhgHI2XJsOofaHhlY=", "dev": true, "requires": { - "kind-of": "6.0.2" + "kind-of": "^6.0.0" } }, "is-data-descriptor": { @@ -5021,7 +5298,7 @@ "integrity": "sha1-2Eh2Mh0Oet0DmQQGq7u9NrqSaMc=", "dev": true, "requires": { - "kind-of": "6.0.2" + "kind-of": "^6.0.0" } }, "is-descriptor": { @@ -5030,9 +5307,9 @@ "integrity": "sha1-OxWXRqZmBLBPjIFSS6NlxfFNhuw=", "dev": true, "requires": { - "is-accessor-descriptor": "1.0.0", - "is-data-descriptor": "1.0.0", - "kind-of": "6.0.2" + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" } } } @@ -5043,7 +5320,7 @@ "integrity": "sha1-HqffLnx8brmSL6COitrqSG9vj5I=", "dev": true, "requires": { - "css": "2.2.4" + "css": "^2.1.0" } }, "extsprintf": { @@ -5070,12 +5347,12 @@ "integrity": "sha512-FjK2nCGI/McyzgNtTESqaWP3trPvHyRyoyY70hxjc3oKPNmDe8taohLZpoVKoUjW85tbU5txaYUZCNtVzygl1g==", "dev": true, "requires": { - "@mrmlnc/readdir-enhanced": "2.2.1", - "@nodelib/fs.stat": "1.1.3", - "glob-parent": "3.1.0", - "is-glob": "4.0.0", - "merge2": "1.2.3", - "micromatch": "3.1.10" + "@mrmlnc/readdir-enhanced": "^2.2.1", + "@nodelib/fs.stat": "^1.1.2", + "glob-parent": "^3.1.0", + "is-glob": "^4.0.0", + "merge2": "^1.2.3", + "micromatch": "^3.1.10" } }, "fast-json-stable-stringify": { @@ -5102,7 +5379,7 @@ "integrity": "sha1-TkkvjQTftviQA1B/btvy1QHnxvQ=", "dev": true, "requires": { - "websocket-driver": "0.7.0" + "websocket-driver": ">=0.5.1" } }, "fb-watchman": { @@ -5111,7 +5388,7 @@ "integrity": "sha1-VOmr99+i8mzZsWNsWIwa/AXeXVg=", "dev": true, "requires": { - "bser": "2.0.0" + "bser": "^2.0.0" } }, "figgy-pudding": { @@ -5126,7 +5403,7 @@ "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=", "dev": true, "requires": { - "escape-string-regexp": "1.0.5" + "escape-string-regexp": "^1.0.5" } }, "file-entry-cache": { @@ -5135,8 +5412,8 @@ "integrity": "sha1-w5KZDD5oR4PYOLjISkXYoEhFg2E=", "dev": true, "requires": { - "flat-cache": "1.3.4", - "object-assign": "4.1.1" + "flat-cache": "^1.2.1", + "object-assign": "^4.0.1" } }, "file-loader": { @@ -5145,8 +5422,8 @@ "integrity": "sha512-YCsBfd1ZGCyonOKLxPiKPdu+8ld9HAaMEvJewzz+b2eTF7uL5Zm/HdBF6FjCrpCMRq25Mi0U1gl4pwn2TlH7hQ==", "dev": true, "requires": { - "loader-utils": "1.1.0", - "schema-utils": "1.0.0" + "loader-utils": "^1.0.2", + "schema-utils": "^1.0.0" }, "dependencies": { "ajv-keywords": { @@ -5161,9 +5438,9 @@ "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", "dev": true, "requires": { - "ajv": "6.5.5", - "ajv-errors": "1.0.0", - "ajv-keywords": "3.2.0" + "ajv": "^6.1.0", + "ajv-errors": "^1.0.0", + "ajv-keywords": "^3.1.0" } } } @@ -5180,8 +5457,8 @@ "integrity": "sha1-jnVIqW08wjJ+5eZ0FocjozO7oqA=", "dev": true, "requires": { - "glob": "7.1.3", - "minimatch": "3.0.4" + "glob": "^7.0.3", + "minimatch": "^3.0.3" } }, "filesize": { @@ -5196,10 +5473,10 @@ "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.1" + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" }, "dependencies": { "extend-shallow": { @@ -5208,7 +5485,7 @@ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, "requires": { - "is-extendable": "0.1.1" + "is-extendable": "^0.1.0" } } } @@ -5220,12 +5497,12 @@ "dev": true, "requires": { "debug": "2.6.9", - "encodeurl": "1.0.2", - "escape-html": "1.0.3", - "on-finished": "2.3.0", - "parseurl": "1.3.2", - "statuses": "1.4.0", - "unpipe": "1.0.0" + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.2", + "statuses": "~1.4.0", + "unpipe": "~1.0.0" }, "dependencies": { "debug": { @@ -5245,8 +5522,8 @@ "integrity": "sha1-rMAQQ6Z0n+w0Qpvmtk9ULrtdY1U=", "dev": true, "requires": { - "json5": "0.5.1", - "path-exists": "3.0.0" + "json5": "^0.5.1", + "path-exists": "^3.0.0" }, "dependencies": { "json5": { @@ -5263,9 +5540,9 @@ "integrity": "sha1-kojj6ePMN0hxfTnq3hfPcfww7m8=", "dev": true, "requires": { - "commondir": "1.0.1", - "make-dir": "1.3.0", - "pkg-dir": "2.0.0" + "commondir": "^1.0.1", + "make-dir": "^1.0.0", + "pkg-dir": "^2.0.0" } }, "find-up": { @@ -5274,7 +5551,7 @@ "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", "dev": true, "requires": { - "locate-path": "2.0.0" + "locate-path": "^2.0.0" } }, "flat-cache": { @@ -5283,10 +5560,10 @@ "integrity": "sha512-VwyB3Lkgacfik2vhqR4uv2rvebqmDvFu4jlN/C1RzWoJEo8I7z4Q404oiqYCkq41mni8EzQnm95emU9seckwtg==", "dev": true, "requires": { - "circular-json": "0.3.3", - "graceful-fs": "4.1.15", - "rimraf": "2.6.2", - "write": "0.2.1" + "circular-json": "^0.3.1", + "graceful-fs": "^4.1.2", + "rimraf": "~2.6.2", + "write": "^0.2.1" } }, "flush-write-stream": { @@ -5295,8 +5572,8 @@ "integrity": "sha512-calZMC10u0FMUqoiunI2AiGIIUtUIvifNwkHhNupZH4cbNnW1Itkoh/Nf5HFYmDrwWPjrUxpkZT0KhuCq0jmGw==", "dev": true, "requires": { - "inherits": "2.0.3", - "readable-stream": "2.3.6" + "inherits": "^2.0.1", + "readable-stream": "^2.0.4" } }, "follow-redirects": { @@ -5304,7 +5581,7 @@ "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.5.9.tgz", "integrity": "sha1-ye2ddIuBSjlTVxblMbkZaoRdicY=", "requires": { - "debug": "3.1.0" + "debug": "=3.1.0" } }, "for-in": { @@ -5319,7 +5596,7 @@ "integrity": "sha1-UmXGgaTylNq78XyVCbZ2OqhFEM4=", "dev": true, "requires": { - "for-in": "1.0.2" + "for-in": "^1.0.1" } }, "forever-agent": { @@ -5334,9 +5611,9 @@ "integrity": "sha1-3M5SwF9kTymManq5Nr1yTO/786Y=", "dev": true, "requires": { - "asynckit": "0.4.0", - "combined-stream": "1.0.7", - "mime-types": "2.1.21" + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" } }, "forwarded": { @@ -5351,7 +5628,7 @@ "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", "dev": true, "requires": { - "map-cache": "0.2.2" + "map-cache": "^0.2.2" } }, "fresh": { @@ -5366,9 +5643,9 @@ "integrity": "sha512-K27M3VK30wVoOarP651zDmb93R9zF28usW4ocaK3mfQeIEI5BPht/EzZs5E8QLLwbLRJQMwscAjDxYPb1FuNiw==", "dev": true, "requires": { - "chalk": "1.1.3", - "error-stack-parser": "2.0.2", - "string-width": "2.1.1" + "chalk": "^1.1.3", + "error-stack-parser": "^2.0.0", + "string-width": "^2.0.0" }, "dependencies": { "ansi-regex": { @@ -5389,11 +5666,11 @@ "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", "dev": true, "requires": { - "ansi-styles": "2.2.1", - "escape-string-regexp": "1.0.5", - "has-ansi": "2.0.0", - "strip-ansi": "3.0.1", - "supports-color": "2.0.0" + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" } }, "strip-ansi": { @@ -5402,7 +5679,7 @@ "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "dev": true, "requires": { - "ansi-regex": "2.1.1" + "ansi-regex": "^2.0.0" } }, "supports-color": { @@ -5419,8 +5696,8 @@ "integrity": "sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8=", "dev": true, "requires": { - "inherits": "2.0.3", - "readable-stream": "2.3.6" + "inherits": "^2.0.1", + "readable-stream": "^2.0.0" } }, "fs-extra": { @@ -5429,9 +5706,9 @@ "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==", "dev": true, "requires": { - "graceful-fs": "4.1.15", - "jsonfile": "4.0.0", - "universalify": "0.1.2" + "graceful-fs": "^4.1.2", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" } }, "fs-write-stream-atomic": { @@ -5440,10 +5717,10 @@ "integrity": "sha1-tH31NJPvkR33VzHnCp3tAYnbQMk=", "dev": true, "requires": { - "graceful-fs": "4.1.15", - "iferr": "0.1.5", - "imurmurhash": "0.1.4", - "readable-stream": "2.3.6" + "graceful-fs": "^4.1.2", + "iferr": "^0.1.5", + "imurmurhash": "^0.1.4", + "readable-stream": "1 || 2" } }, "fs.realpath": { @@ -5459,8 +5736,8 @@ "dev": true, "optional": true, "requires": { - "nan": "2.11.1", - "node-pre-gyp": "0.10.0" + "nan": "^2.9.2", + "node-pre-gyp": "^0.10.0" }, "dependencies": { "abbrev": { @@ -5486,8 +5763,8 @@ "dev": true, "optional": true, "requires": { - "delegates": "1.0.0", - "readable-stream": "2.3.6" + "delegates": "^1.0.0", + "readable-stream": "^2.0.6" } }, "balanced-match": { @@ -5500,7 +5777,7 @@ "bundled": true, "dev": true, "requires": { - "balanced-match": "1.0.0", + "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, @@ -5564,7 +5841,7 @@ "dev": true, "optional": true, "requires": { - "minipass": "2.2.4" + "minipass": "^2.2.1" } }, "fs.realpath": { @@ -5579,14 +5856,14 @@ "dev": true, "optional": true, "requires": { - "aproba": "1.2.0", - "console-control-strings": "1.1.0", - "has-unicode": "2.0.1", - "object-assign": "4.1.1", - "signal-exit": "3.0.2", - "string-width": "1.0.2", - "strip-ansi": "3.0.1", - "wide-align": "1.1.2" + "aproba": "^1.0.3", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.0", + "object-assign": "^4.1.0", + "signal-exit": "^3.0.0", + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wide-align": "^1.1.0" } }, "glob": { @@ -5595,12 +5872,12 @@ "dev": true, "optional": true, "requires": { - "fs.realpath": "1.0.0", - "inflight": "1.0.6", - "inherits": "2.0.3", - "minimatch": "3.0.4", - "once": "1.4.0", - "path-is-absolute": "1.0.1" + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" } }, "has-unicode": { @@ -5615,7 +5892,7 @@ "dev": true, "optional": true, "requires": { - "safer-buffer": "2.1.2" + "safer-buffer": "^2.1.0" } }, "ignore-walk": { @@ -5624,7 +5901,7 @@ "dev": true, "optional": true, "requires": { - "minimatch": "3.0.4" + "minimatch": "^3.0.4" } }, "inflight": { @@ -5633,8 +5910,8 @@ "dev": true, "optional": true, "requires": { - "once": "1.4.0", - "wrappy": "1.0.2" + "once": "^1.3.0", + "wrappy": "1" } }, "inherits": { @@ -5653,7 +5930,7 @@ "bundled": true, "dev": true, "requires": { - "number-is-nan": "1.0.1" + "number-is-nan": "^1.0.0" } }, "isarray": { @@ -5667,7 +5944,7 @@ "bundled": true, "dev": true, "requires": { - "brace-expansion": "1.1.11" + "brace-expansion": "^1.1.7" } }, "minimist": { @@ -5680,8 +5957,8 @@ "bundled": true, "dev": true, "requires": { - "safe-buffer": "5.1.1", - "yallist": "3.0.2" + "safe-buffer": "^5.1.1", + "yallist": "^3.0.0" } }, "minizlib": { @@ -5690,7 +5967,7 @@ "dev": true, "optional": true, "requires": { - "minipass": "2.2.4" + "minipass": "^2.2.1" } }, "mkdirp": { @@ -5713,9 +5990,9 @@ "dev": true, "optional": true, "requires": { - "debug": "2.6.9", - "iconv-lite": "0.4.21", - "sax": "1.2.4" + "debug": "^2.1.2", + "iconv-lite": "^0.4.4", + "sax": "^1.2.4" } }, "node-pre-gyp": { @@ -5724,16 +6001,16 @@ "dev": true, "optional": true, "requires": { - "detect-libc": "1.0.3", - "mkdirp": "0.5.1", - "needle": "2.2.0", - "nopt": "4.0.1", - "npm-packlist": "1.1.10", - "npmlog": "4.1.2", - "rc": "1.2.7", - "rimraf": "2.6.2", - "semver": "5.5.0", - "tar": "4.4.1" + "detect-libc": "^1.0.2", + "mkdirp": "^0.5.1", + "needle": "^2.2.0", + "nopt": "^4.0.1", + "npm-packlist": "^1.1.6", + "npmlog": "^4.0.2", + "rc": "^1.1.7", + "rimraf": "^2.6.1", + "semver": "^5.3.0", + "tar": "^4" } }, "nopt": { @@ -5742,8 +6019,8 @@ "dev": true, "optional": true, "requires": { - "abbrev": "1.1.1", - "osenv": "0.1.5" + "abbrev": "1", + "osenv": "^0.1.4" } }, "npm-bundled": { @@ -5758,8 +6035,8 @@ "dev": true, "optional": true, "requires": { - "ignore-walk": "3.0.1", - "npm-bundled": "1.0.3" + "ignore-walk": "^3.0.1", + "npm-bundled": "^1.0.1" } }, "npmlog": { @@ -5768,10 +6045,10 @@ "dev": true, "optional": true, "requires": { - "are-we-there-yet": "1.1.4", - "console-control-strings": "1.1.0", - "gauge": "2.7.4", - "set-blocking": "2.0.0" + "are-we-there-yet": "~1.1.2", + "console-control-strings": "~1.1.0", + "gauge": "~2.7.3", + "set-blocking": "~2.0.0" } }, "number-is-nan": { @@ -5790,7 +6067,7 @@ "bundled": true, "dev": true, "requires": { - "wrappy": "1.0.2" + "wrappy": "1" } }, "os-homedir": { @@ -5811,8 +6088,8 @@ "dev": true, "optional": true, "requires": { - "os-homedir": "1.0.2", - "os-tmpdir": "1.0.2" + "os-homedir": "^1.0.0", + "os-tmpdir": "^1.0.0" } }, "path-is-absolute": { @@ -5833,10 +6110,10 @@ "dev": true, "optional": true, "requires": { - "deep-extend": "0.5.1", - "ini": "1.3.5", - "minimist": "1.2.0", - "strip-json-comments": "2.0.1" + "deep-extend": "^0.5.1", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" }, "dependencies": { "minimist": { @@ -5853,13 +6130,13 @@ "dev": true, "optional": true, "requires": { - "core-util-is": "1.0.2", - "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.2" + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" } }, "rimraf": { @@ -5868,7 +6145,7 @@ "dev": true, "optional": true, "requires": { - "glob": "7.1.2" + "glob": "^7.0.5" } }, "safe-buffer": { @@ -5911,9 +6188,9 @@ "bundled": true, "dev": true, "requires": { - "code-point-at": "1.1.0", - "is-fullwidth-code-point": "1.0.0", - "strip-ansi": "3.0.1" + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" } }, "string_decoder": { @@ -5922,7 +6199,7 @@ "dev": true, "optional": true, "requires": { - "safe-buffer": "5.1.1" + "safe-buffer": "~5.1.0" } }, "strip-ansi": { @@ -5930,7 +6207,7 @@ "bundled": true, "dev": true, "requires": { - "ansi-regex": "2.1.1" + "ansi-regex": "^2.0.0" } }, "strip-json-comments": { @@ -5945,13 +6222,13 @@ "dev": true, "optional": true, "requires": { - "chownr": "1.0.1", - "fs-minipass": "1.2.5", - "minipass": "2.2.4", - "minizlib": "1.1.0", - "mkdirp": "0.5.1", - "safe-buffer": "5.1.1", - "yallist": "3.0.2" + "chownr": "^1.0.1", + "fs-minipass": "^1.2.5", + "minipass": "^2.2.4", + "minizlib": "^1.1.0", + "mkdirp": "^0.5.0", + "safe-buffer": "^5.1.1", + "yallist": "^3.0.2" } }, "util-deprecate": { @@ -5966,7 +6243,7 @@ "dev": true, "optional": true, "requires": { - "string-width": "1.0.2" + "string-width": "^1.0.2" } }, "wrappy": { @@ -6011,7 +6288,7 @@ "integrity": "sha1-wbJVV189wh1Zv8ec09K0axw6VLU=", "dev": true, "requires": { - "pump": "3.0.0" + "pump": "^3.0.0" } }, "get-value": { @@ -6026,7 +6303,7 @@ "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", "dev": true, "requires": { - "assert-plus": "1.0.0" + "assert-plus": "^1.0.0" } }, "glob": { @@ -6035,12 +6312,12 @@ "integrity": "sha1-OWCDLT8VdBCDQtr9OmezMsCWnfE=", "dev": true, "requires": { - "fs.realpath": "1.0.0", - "inflight": "1.0.6", - "inherits": "2.0.3", - "minimatch": "3.0.4", - "once": "1.4.0", - "path-is-absolute": "1.0.1" + "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-base": { @@ -6049,8 +6326,8 @@ "integrity": "sha1-27Fk9iIbHAscz4Kuoyi0l98Oo8Q=", "dev": true, "requires": { - "glob-parent": "2.0.0", - "is-glob": "2.0.1" + "glob-parent": "^2.0.0", + "is-glob": "^2.0.0" }, "dependencies": { "glob-parent": { @@ -6059,7 +6336,7 @@ "integrity": "sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg=", "dev": true, "requires": { - "is-glob": "2.0.1" + "is-glob": "^2.0.0" } }, "is-extglob": { @@ -6074,7 +6351,7 @@ "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", "dev": true, "requires": { - "is-extglob": "1.0.0" + "is-extglob": "^1.0.0" } } } @@ -6085,8 +6362,8 @@ "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", "dev": true, "requires": { - "is-glob": "3.1.0", - "path-dirname": "1.0.2" + "is-glob": "^3.1.0", + "path-dirname": "^1.0.0" }, "dependencies": { "is-glob": { @@ -6095,7 +6372,7 @@ "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", "dev": true, "requires": { - "is-extglob": "2.1.1" + "is-extglob": "^2.1.0" } } } @@ -6118,13 +6395,13 @@ "integrity": "sha512-oMrYrJERnKBLXNLVTqhm3vPEdJ/b2ZE28xN4YARiix1NOIOBPEpOUnm844K1iu/BkphCaf2WNFwMszv8Soi1pw==", "dev": true, "requires": { - "array-union": "1.0.2", - "dir-glob": "2.0.0", - "fast-glob": "2.2.4", - "glob": "7.1.3", - "ignore": "3.3.10", - "pify": "3.0.0", - "slash": "1.0.0" + "array-union": "^1.0.1", + "dir-glob": "^2.0.0", + "fast-glob": "^2.0.2", + "glob": "^7.1.2", + "ignore": "^3.3.5", + "pify": "^3.0.0", + "slash": "^1.0.0" } }, "graceful-fs": { @@ -6145,8 +6422,8 @@ "integrity": "sha512-5iI7omclyqrnWw4XbXAmGhPsABkSIDQonv2K0h61lybgofWa6iZyvrI3r2zsJH4P8Nb64fFVzlvfhs0g7BBxAA==", "dev": true, "requires": { - "duplexer": "0.1.1", - "pify": "3.0.0" + "duplexer": "^0.1.1", + "pify": "^3.0.0" } }, "handle-thing": { @@ -6156,24 +6433,24 @@ "dev": true }, "handlebars": { - "version": "4.0.12", - "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.0.12.tgz", - "integrity": "sha512-RhmTekP+FZL+XNhwS1Wf+bTTZpdLougwt5pcgA1tuz6Jcx0fpH/7z0qd71RKnZHBCxIRBHfBOnio4gViPemNzA==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.1.0.tgz", + "integrity": "sha512-l2jRuU1NAWK6AW5qqcTATWQJvNPEwkM7NEKSiv/gqOsoSQbVoWyqVEY5GS+XPQ88zLNmqASRpzfdm8d79hJS+w==", "dev": true, "requires": { - "async": "2.6.1", - "optimist": "0.6.1", - "source-map": "0.6.1", - "uglify-js": "3.4.9" + "async": "^2.5.0", + "optimist": "^0.6.1", + "source-map": "^0.6.1", + "uglify-js": "^3.1.4" }, "dependencies": { "async": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/async/-/async-2.6.1.tgz", - "integrity": "sha512-fNEiL2+AZt6AlAw/29Cr0UDe4sRAHCpEHh54WMz+Bb7QfNcFw4h3loofyJpLeQs4Yx7yuqu/2dLgM5hKOs6HlQ==", + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.2.tgz", + "integrity": "sha512-H1qVYh1MYhEEFLsP97cVKqCGo7KfCyTt6uEWqsTBr9SO84oK9Uwbyd/yCW+6rKJLHksBNUVWZDAjfS+Ccx0Bbg==", "dev": true, "requires": { - "lodash": "4.17.11" + "lodash": "^4.17.11" } }, "source-map": { @@ -6196,8 +6473,8 @@ "integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==", "dev": true, "requires": { - "ajv": "6.5.5", - "har-schema": "2.0.0" + "ajv": "^6.5.5", + "har-schema": "^2.0.0" } }, "has": { @@ -6206,7 +6483,7 @@ "integrity": "sha1-ci18v8H2qoJB8W3YFOAR4fQeh5Y=", "dev": true, "requires": { - "function-bind": "1.1.1" + "function-bind": "^1.1.1" } }, "has-ansi": { @@ -6215,7 +6492,7 @@ "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", "dev": true, "requires": { - "ansi-regex": "2.1.1" + "ansi-regex": "^2.0.0" }, "dependencies": { "ansi-regex": { @@ -6226,6 +6503,26 @@ } } }, + "has-binary2": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-binary2/-/has-binary2-1.0.3.tgz", + "integrity": "sha512-G1LWKhDSvhGeAQ8mPVQlqNcOB2sJdwATtZKl2pDKKHfpf/rYj24lkinxf69blJbnsvtqqNU+L3SL50vzZhXOnw==", + "requires": { + "isarray": "2.0.1" + }, + "dependencies": { + "isarray": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz", + "integrity": "sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4=" + } + } + }, + "has-cors": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-cors/-/has-cors-1.1.0.tgz", + "integrity": "sha1-XkdHk/fqmEPRu5nCPu9J/xJv/zk=" + }, "has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", @@ -6244,9 +6541,9 @@ "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", "dev": true, "requires": { - "get-value": "2.0.6", - "has-values": "1.0.0", - "isobject": "3.0.1" + "get-value": "^2.0.6", + "has-values": "^1.0.0", + "isobject": "^3.0.0" } }, "has-values": { @@ -6255,8 +6552,8 @@ "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", "dev": true, "requires": { - "is-number": "3.0.0", - "kind-of": "4.0.0" + "is-number": "^3.0.0", + "kind-of": "^4.0.0" }, "dependencies": { "kind-of": { @@ -6265,7 +6562,7 @@ "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", "dev": true, "requires": { - "is-buffer": "1.1.6" + "is-buffer": "^1.1.5" } } } @@ -6276,8 +6573,8 @@ "integrity": "sha1-X8hoaEfs1zSZQDMZprCj8/auSRg=", "dev": true, "requires": { - "inherits": "2.0.3", - "safe-buffer": "5.1.2" + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" } }, "hash-sum": { @@ -6292,8 +6589,8 @@ "integrity": "sha1-44q0uF37HgxA/pJlwOm1SFTCOBI=", "dev": true, "requires": { - "inherits": "2.0.3", - "minimalistic-assert": "1.0.1" + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" } }, "he": { @@ -6314,9 +6611,9 @@ "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=", "dev": true, "requires": { - "hash.js": "1.1.5", - "minimalistic-assert": "1.0.1", - "minimalistic-crypto-utils": "1.0.1" + "hash.js": "^1.0.3", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.1" } }, "hoek": { @@ -6331,8 +6628,8 @@ "integrity": "sha1-42w/LSyufXRqhX440Y1fMqeILbg=", "dev": true, "requires": { - "os-homedir": "1.0.2", - "os-tmpdir": "1.0.2" + "os-homedir": "^1.0.0", + "os-tmpdir": "^1.0.1" } }, "hoopy": { @@ -6353,10 +6650,10 @@ "integrity": "sha1-h3dMCUnlE/QuhFdbPEVoH63ioLI=", "dev": true, "requires": { - "inherits": "2.0.3", - "obuf": "1.1.2", - "readable-stream": "2.3.6", - "wbuf": "1.7.3" + "inherits": "^2.0.1", + "obuf": "^1.0.0", + "readable-stream": "^2.0.1", + "wbuf": "^1.1.0" } }, "hsl-regex": { @@ -6383,7 +6680,7 @@ "integrity": "sha512-71lZziiDnsuabfdYiUeWdCVyKuqwWi23L8YeIgV9jSSZHCtb6wB1BKWooH7L3tn4/FuZJMVWyNaIDr4RGmaSYw==", "dev": true, "requires": { - "whatwg-encoding": "1.0.5" + "whatwg-encoding": "^1.0.1" } }, "html-entities": { @@ -6398,13 +6695,13 @@ "integrity": "sha512-LKUKwuJDhxNa3uf/LPR/KVjm/l3rBqtYeCOAekvG8F1vItxMUpueGd94i/asDDr8/1u7InxzFA5EeGjhhG5mMA==", "dev": true, "requires": { - "camel-case": "3.0.0", - "clean-css": "4.2.1", - "commander": "2.17.1", - "he": "1.2.0", - "param-case": "2.1.1", - "relateurl": "0.2.7", - "uglify-js": "3.4.9" + "camel-case": "3.0.x", + "clean-css": "4.2.x", + "commander": "2.17.x", + "he": "1.2.x", + "param-case": "2.1.x", + "relateurl": "0.2.x", + "uglify-js": "3.4.x" } }, "html-webpack-plugin": { @@ -6413,12 +6710,12 @@ "integrity": "sha1-sBq71yOsqqeze2r0SS69oD2d03s=", "dev": true, "requires": { - "html-minifier": "3.5.21", - "loader-utils": "0.2.17", - "lodash": "4.17.11", - "pretty-error": "2.1.1", - "tapable": "1.1.0", - "toposort": "1.0.7", + "html-minifier": "^3.2.3", + "loader-utils": "^0.2.16", + "lodash": "^4.17.3", + "pretty-error": "^2.0.2", + "tapable": "^1.0.0", + "toposort": "^1.0.0", "util.promisify": "1.0.0" }, "dependencies": { @@ -6434,10 +6731,10 @@ "integrity": "sha1-+G5jdNQyBabmxg6RlvF8Apm/s0g=", "dev": true, "requires": { - "big.js": "3.2.0", - "emojis-list": "2.1.0", - "json5": "0.5.1", - "object-assign": "4.1.1" + "big.js": "^3.1.3", + "emojis-list": "^2.0.0", + "json5": "^0.5.0", + "object-assign": "^4.0.1" } } } @@ -6448,10 +6745,10 @@ "integrity": "sha1-zHDQWln2VC5D8OaFyYLhTJJKnv4=", "dev": true, "requires": { - "domelementtype": "1.2.1", - "domhandler": "2.1.0", - "domutils": "1.1.6", - "readable-stream": "1.0.34" + "domelementtype": "1", + "domhandler": "2.1", + "domutils": "1.1", + "readable-stream": "1.0" }, "dependencies": { "domutils": { @@ -6460,7 +6757,7 @@ "integrity": "sha1-vdw94Jm5ou+sxRxiPyj0FuzFdIU=", "dev": true, "requires": { - "domelementtype": "1.2.1" + "domelementtype": "1" } }, "isarray": { @@ -6475,10 +6772,10 @@ "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", "dev": true, "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.3", + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", "isarray": "0.0.1", - "string_decoder": "0.10.31" + "string_decoder": "~0.10.x" } }, "string_decoder": { @@ -6501,10 +6798,10 @@ "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", "dev": true, "requires": { - "depd": "1.1.2", + "depd": "~1.1.2", "inherits": "2.0.3", "setprototypeof": "1.1.0", - "statuses": "1.4.0" + "statuses": ">= 1.4.0 < 2" } }, "http-parser-js": { @@ -6519,9 +6816,9 @@ "integrity": "sha512-Taqn+3nNvYRfJ3bGvKfBSRwy1v6eePlm3oc/aWVxZp57DQr5Eq3xhKJi7Z4hZpS8PC3H4qI+Yly5EmFacGuA/g==", "dev": true, "requires": { - "eventemitter3": "3.1.0", - "follow-redirects": "1.5.9", - "requires-port": "1.0.0" + "eventemitter3": "^3.0.0", + "follow-redirects": "^1.0.0", + "requires-port": "^1.0.0" } }, "http-proxy-middleware": { @@ -6530,10 +6827,10 @@ "integrity": "sha512-Fs25KVMPAIIcgjMZkVHJoKg9VcXcC1C8yb9JUgeDvVXY0S/zgVIhMb+qVswDIgtJe2DfckMSY2d6TuTEutlk6Q==", "dev": true, "requires": { - "http-proxy": "1.17.0", - "is-glob": "4.0.0", - "lodash": "4.17.11", - "micromatch": "3.1.10" + "http-proxy": "^1.16.2", + "is-glob": "^4.0.0", + "lodash": "^4.17.5", + "micromatch": "^3.1.9" } }, "http-signature": { @@ -6542,9 +6839,9 @@ "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", "dev": true, "requires": { - "assert-plus": "1.0.0", - "jsprim": "1.4.1", - "sshpk": "1.15.2" + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" } }, "https-browserify": { @@ -6559,7 +6856,7 @@ "integrity": "sha1-ICK0sl+93CHS9SSXSkdKr+czkIs=", "dev": true, "requires": { - "safer-buffer": "2.1.2" + "safer-buffer": ">= 2.1.2 < 3" } }, "icss-replace-symbols": { @@ -6574,7 +6871,7 @@ "integrity": "sha1-g/Cg7DeL8yRheLbCrZE28TWxyWI=", "dev": true, "requires": { - "postcss": "6.0.23" + "postcss": "^6.0.1" }, "dependencies": { "postcss": { @@ -6583,9 +6880,9 @@ "integrity": "sha512-soOk1h6J3VMTZtVeVpv15/Hpdl2cBLX3CAw4TAbkpTJiNPk9YP/zWcD1ND+xEtvyuuvKzbxliTOIyvkSeSJ6ag==", "dev": true, "requires": { - "chalk": "2.4.1", - "source-map": "0.6.1", - "supports-color": "5.5.0" + "chalk": "^2.4.1", + "source-map": "^0.6.1", + "supports-color": "^5.4.0" } }, "source-map": { @@ -6620,7 +6917,7 @@ "integrity": "sha1-qmzzbnInYShcs3HsZRn1PiQ1sKk=", "dev": true, "requires": { - "import-from": "2.1.0" + "import-from": "^2.1.0" } }, "import-fresh": { @@ -6629,8 +6926,8 @@ "integrity": "sha1-2BNVwVYS04bGH53dOSLUMEgipUY=", "dev": true, "requires": { - "caller-path": "2.0.0", - "resolve-from": "3.0.0" + "caller-path": "^2.0.0", + "resolve-from": "^3.0.0" }, "dependencies": { "caller-path": { @@ -6639,7 +6936,7 @@ "integrity": "sha1-Ro+DBE42mrIBD6xfBs7uFbsssfQ=", "dev": true, "requires": { - "caller-callsite": "2.0.0" + "caller-callsite": "^2.0.0" } }, "resolve-from": { @@ -6656,7 +6953,7 @@ "integrity": "sha1-M1238qev/VOqpHHUuAId7ja387E=", "dev": true, "requires": { - "resolve-from": "3.0.0" + "resolve-from": "^3.0.0" }, "dependencies": { "resolve-from": { @@ -6673,8 +6970,8 @@ "integrity": "sha512-b6s04m3O+s3CGSbqDIyP4R6aAwAeYlVq9+WUWep6iHa8ETRf9yei1U48C5MmfJmV9AiLYYBKPMq/W+/WRpQmCQ==", "dev": true, "requires": { - "pkg-dir": "3.0.0", - "resolve-cwd": "2.0.0" + "pkg-dir": "^3.0.0", + "resolve-cwd": "^2.0.0" }, "dependencies": { "find-up": { @@ -6683,7 +6980,7 @@ "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", "dev": true, "requires": { - "locate-path": "3.0.0" + "locate-path": "^3.0.0" } }, "locate-path": { @@ -6692,8 +6989,8 @@ "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", "dev": true, "requires": { - "p-locate": "3.0.0", - "path-exists": "3.0.0" + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" } }, "p-limit": { @@ -6702,7 +6999,7 @@ "integrity": "sha512-NhURkNcrVB+8hNfLuysU8enY5xn2KXphsHBaC2YmRNTZRc7RWusw6apSpdEj3jo4CMb6W9nrF6tTnsJsJeyu6g==", "dev": true, "requires": { - "p-try": "2.0.0" + "p-try": "^2.0.0" } }, "p-locate": { @@ -6711,7 +7008,7 @@ "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", "dev": true, "requires": { - "p-limit": "2.1.0" + "p-limit": "^2.0.0" } }, "p-try": { @@ -6726,7 +7023,7 @@ "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", "dev": true, "requires": { - "find-up": "3.0.0" + "find-up": "^3.0.0" } } } @@ -6746,8 +7043,7 @@ "indexof": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz", - "integrity": "sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10=", - "dev": true + "integrity": "sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10=" }, "inflight": { "version": "1.0.6", @@ -6755,8 +7051,8 @@ "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", "dev": true, "requires": { - "once": "1.4.0", - "wrappy": "1.0.2" + "once": "^1.3.0", + "wrappy": "1" } }, "inherits": { @@ -6777,20 +7073,20 @@ "integrity": "sha512-h+xtnyk4EwKvFWHrUYsWErEVR+igKtLdchu+o0Z1RL7VU/jVMFbYir2bp6bAj8efFNxWqHX0dIss6fJQ+/+qeQ==", "dev": true, "requires": { - "ansi-escapes": "3.1.0", - "chalk": "2.4.1", - "cli-cursor": "2.1.0", - "cli-width": "2.2.0", - "external-editor": "2.2.0", - "figures": "2.0.0", - "lodash": "4.17.11", + "ansi-escapes": "^3.0.0", + "chalk": "^2.0.0", + "cli-cursor": "^2.1.0", + "cli-width": "^2.0.0", + "external-editor": "^2.0.4", + "figures": "^2.0.0", + "lodash": "^4.3.0", "mute-stream": "0.0.7", - "run-async": "2.3.0", - "rx-lite": "4.0.8", - "rx-lite-aggregates": "4.0.8", - "string-width": "2.1.1", - "strip-ansi": "4.0.0", - "through": "2.3.8" + "run-async": "^2.2.0", + "rx-lite": "^4.0.8", + "rx-lite-aggregates": "^4.0.8", + "string-width": "^2.1.0", + "strip-ansi": "^4.0.0", + "through": "^2.3.6" } }, "internal-ip": { @@ -6799,17 +7095,22 @@ "integrity": "sha512-NXXgESC2nNVtU+pqmC9e6R8B1GpKxzsAQhffvh5AL79qKnodd+L7tnEQmTiUAVngqLalPbSqRA7XGIEL5nCd0Q==", "dev": true, "requires": { - "default-gateway": "2.7.2", - "ipaddr.js": "1.8.0" + "default-gateway": "^2.6.0", + "ipaddr.js": "^1.5.2" } }, + "intersection-observer": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/intersection-observer/-/intersection-observer-0.5.1.tgz", + "integrity": "sha512-Zd7Plneq82kiXFixs7bX62YnuZ0BMRci9br7io88LwDyF3V43cQMI+G5IiTlTNTt+LsDUppl19J/M2Fp9UkH6g==" + }, "invariant": { "version": "2.2.4", "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", "integrity": "sha1-YQ88ksk1nOHbYW5TgAjSP/NRWOY=", "dev": true, "requires": { - "loose-envify": "1.4.0" + "loose-envify": "^1.0.0" } }, "invert-kv": { @@ -6848,7 +7149,7 @@ "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", "dev": true, "requires": { - "kind-of": "3.2.2" + "kind-of": "^3.0.2" }, "dependencies": { "kind-of": { @@ -6857,7 +7158,7 @@ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "requires": { - "is-buffer": "1.1.6" + "is-buffer": "^1.1.5" } } } @@ -6874,7 +7175,7 @@ "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", "dev": true, "requires": { - "binary-extensions": "1.12.0" + "binary-extensions": "^1.0.0" } }, "is-buffer": { @@ -6888,7 +7189,7 @@ "integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=", "dev": true, "requires": { - "builtin-modules": "1.1.1" + "builtin-modules": "^1.0.0" } }, "is-callable": { @@ -6903,7 +7204,7 @@ "integrity": "sha1-43ecjuF/zPQoSI9uKBGH8uYyhBw=", "dev": true, "requires": { - "ci-info": "1.6.0" + "ci-info": "^1.5.0" } }, "is-color-stop": { @@ -6912,12 +7213,12 @@ "integrity": "sha1-z/9HGu5N1cnhWFmPvhKWe1za00U=", "dev": true, "requires": { - "css-color-names": "0.0.4", - "hex-color-regex": "1.1.0", - "hsl-regex": "1.0.0", - "hsla-regex": "1.0.0", - "rgb-regex": "1.0.1", - "rgba-regex": "1.0.0" + "css-color-names": "^0.0.4", + "hex-color-regex": "^1.1.0", + "hsl-regex": "^1.0.0", + "hsla-regex": "^1.0.0", + "rgb-regex": "^1.0.1", + "rgba-regex": "^1.0.0" } }, "is-data-descriptor": { @@ -6926,7 +7227,7 @@ "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", "dev": true, "requires": { - "kind-of": "3.2.2" + "kind-of": "^3.0.2" }, "dependencies": { "kind-of": { @@ -6935,7 +7236,7 @@ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "requires": { - "is-buffer": "1.1.6" + "is-buffer": "^1.1.5" } } } @@ -6952,9 +7253,9 @@ "integrity": "sha1-Nm2CQN3kh8pRgjsaufB6EKeCUco=", "dev": true, "requires": { - "is-accessor-descriptor": "0.1.6", - "is-data-descriptor": "0.1.4", - "kind-of": "5.1.0" + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" }, "dependencies": { "kind-of": { @@ -6983,7 +7284,7 @@ "integrity": "sha1-IjgJj8Ih3gvPpdnqxMRdY4qhxTQ=", "dev": true, "requires": { - "is-primitive": "2.0.0" + "is-primitive": "^2.0.0" } }, "is-extendable": { @@ -7004,7 +7305,7 @@ "integrity": "sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko=", "dev": true, "requires": { - "number-is-nan": "1.0.1" + "number-is-nan": "^1.0.0" } }, "is-fullwidth-code-point": { @@ -7025,7 +7326,7 @@ "integrity": "sha1-lSHHaEXMJhCoUgPd8ICpWML/q8A=", "dev": true, "requires": { - "is-extglob": "2.1.1" + "is-extglob": "^2.1.1" } }, "is-number": { @@ -7034,7 +7335,7 @@ "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", "dev": true, "requires": { - "kind-of": "3.2.2" + "kind-of": "^3.0.2" }, "dependencies": { "kind-of": { @@ -7043,7 +7344,7 @@ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "requires": { - "is-buffer": "1.1.6" + "is-buffer": "^1.1.5" } } } @@ -7066,7 +7367,7 @@ "integrity": "sha512-FjV1RTW48E7CWM7eE/J2NJvAEEVektecDBVBE5Hh3nM1Jd0kvhHtX68Pr3xsDf857xt3Y4AkwVULK1Vku62aaQ==", "dev": true, "requires": { - "is-path-inside": "1.0.1" + "is-path-inside": "^1.0.0" } }, "is-path-inside": { @@ -7075,7 +7376,7 @@ "integrity": "sha1-jvW33lBDej/cprToZe96pVy0gDY=", "dev": true, "requires": { - "path-is-inside": "1.0.2" + "path-is-inside": "^1.0.1" } }, "is-plain-object": { @@ -7084,7 +7385,7 @@ "integrity": "sha1-LBY7P6+xtgbZ0Xko8FwqHDjgdnc=", "dev": true, "requires": { - "isobject": "3.0.1" + "isobject": "^3.0.1" } }, "is-posix-bracket": { @@ -7111,7 +7412,7 @@ "integrity": "sha1-VRdIm1RwkbCTDglWVM7SXul+lJE=", "dev": true, "requires": { - "has": "1.0.3" + "has": "^1.0.1" } }, "is-resolvable": { @@ -7132,7 +7433,7 @@ "integrity": "sha512-gi4iHK53LR2ujhLVVj+37Ykh9GLqYHX6JOVXbLAucaG/Cqw9xwdFOjDM2qeifLs1sF1npXXFvDu0r5HNgCMrzQ==", "dev": true, "requires": { - "html-comment-regex": "1.1.2" + "html-comment-regex": "^1.1.0" } }, "is-symbol": { @@ -7141,7 +7442,7 @@ "integrity": "sha1-oFX2rlcZLK7jKeeoYBGLSXqVDzg=", "dev": true, "requires": { - "has-symbols": "1.0.0" + "has-symbols": "^1.0.0" } }, "is-typedarray": { @@ -7186,7 +7487,7 @@ "integrity": "sha1-WTEKAhkxqfsGu7UeFVzgs/I2gyw=", "dev": true, "requires": { - "punycode": "2.1.1" + "punycode": "2.x.x" } }, "isexe": { @@ -7213,26 +7514,26 @@ "integrity": "sha512-4/ApBnMVeEPG3EkSzcw25wDe4N66wxwn+KKn6b47vyek8Xb3NBAcg4xfuQbS7BqcZuTX4wxfD5lVagdggR3gyA==", "dev": true, "requires": { - "async": "2.6.1", - "fileset": "2.0.3", - "istanbul-lib-coverage": "1.2.1", - "istanbul-lib-hook": "1.2.2", - "istanbul-lib-instrument": "1.10.2", - "istanbul-lib-report": "1.1.5", - "istanbul-lib-source-maps": "1.2.6", - "istanbul-reports": "1.5.1", - "js-yaml": "3.12.0", - "mkdirp": "0.5.1", - "once": "1.4.0" + "async": "^2.1.4", + "fileset": "^2.0.2", + "istanbul-lib-coverage": "^1.2.1", + "istanbul-lib-hook": "^1.2.2", + "istanbul-lib-instrument": "^1.10.2", + "istanbul-lib-report": "^1.1.5", + "istanbul-lib-source-maps": "^1.2.6", + "istanbul-reports": "^1.5.1", + "js-yaml": "^3.7.0", + "mkdirp": "^0.5.1", + "once": "^1.4.0" }, "dependencies": { "async": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/async/-/async-2.6.1.tgz", - "integrity": "sha512-fNEiL2+AZt6AlAw/29Cr0UDe4sRAHCpEHh54WMz+Bb7QfNcFw4h3loofyJpLeQs4Yx7yuqu/2dLgM5hKOs6HlQ==", + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.2.tgz", + "integrity": "sha512-H1qVYh1MYhEEFLsP97cVKqCGo7KfCyTt6uEWqsTBr9SO84oK9Uwbyd/yCW+6rKJLHksBNUVWZDAjfS+Ccx0Bbg==", "dev": true, "requires": { - "lodash": "4.17.11" + "lodash": "^4.17.11" } } } @@ -7249,7 +7550,7 @@ "integrity": "sha512-/Jmq7Y1VeHnZEQ3TL10VHyb564mn6VrQXHchON9Jf/AEcmQ3ZIiyD1BVzNOKTZf/G3gE+kiGK6SmpF9y3qGPLw==", "dev": true, "requires": { - "append-transform": "0.4.0" + "append-transform": "^0.4.0" } }, "istanbul-lib-instrument": { @@ -7258,13 +7559,13 @@ "integrity": "sha512-aWHxfxDqvh/ZlxR8BBaEPVSWDPUkGD63VjGQn3jcw8jCp7sHEMKcrj4xfJn/ABzdMEHiQNyvDQhqm5o8+SQg7A==", "dev": true, "requires": { - "babel-generator": "6.26.1", - "babel-template": "6.26.0", - "babel-traverse": "6.26.0", - "babel-types": "6.26.0", - "babylon": "6.18.0", - "istanbul-lib-coverage": "1.2.1", - "semver": "5.6.0" + "babel-generator": "^6.18.0", + "babel-template": "^6.16.0", + "babel-traverse": "^6.18.0", + "babel-types": "^6.18.0", + "babylon": "^6.18.0", + "istanbul-lib-coverage": "^1.2.1", + "semver": "^5.3.0" } }, "istanbul-lib-report": { @@ -7273,10 +7574,10 @@ "integrity": "sha512-UsYfRMoi6QO/doUshYNqcKJqVmFe9w51GZz8BS3WB0lYxAllQYklka2wP9+dGZeHYaWIdcXUx8JGdbqaoXRXzw==", "dev": true, "requires": { - "istanbul-lib-coverage": "1.2.1", - "mkdirp": "0.5.1", - "path-parse": "1.0.6", - "supports-color": "3.2.3" + "istanbul-lib-coverage": "^1.2.1", + "mkdirp": "^0.5.1", + "path-parse": "^1.0.5", + "supports-color": "^3.1.2" }, "dependencies": { "has-flag": { @@ -7291,7 +7592,7 @@ "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=", "dev": true, "requires": { - "has-flag": "1.0.0" + "has-flag": "^1.0.0" } } } @@ -7302,11 +7603,11 @@ "integrity": "sha512-TtbsY5GIHgbMsMiRw35YBHGpZ1DVFEO19vxxeiDMYaeOFOCzfnYVxvl6pOUIZR4dtPhAGpSMup8OyF8ubsaqEg==", "dev": true, "requires": { - "debug": "3.1.0", - "istanbul-lib-coverage": "1.2.1", - "mkdirp": "0.5.1", - "rimraf": "2.6.2", - "source-map": "0.5.7" + "debug": "^3.1.0", + "istanbul-lib-coverage": "^1.2.1", + "mkdirp": "^0.5.1", + "rimraf": "^2.6.1", + "source-map": "^0.5.3" } }, "istanbul-reports": { @@ -7315,7 +7616,7 @@ "integrity": "sha512-+cfoZ0UXzWjhAdzosCPP3AN8vvef8XDkWtTfgaN+7L3YTpNYITnCaEkceo5SEYy644VkHka/P1FvkWvrG/rrJw==", "dev": true, "requires": { - "handlebars": "4.0.12" + "handlebars": "^4.0.3" } }, "javascript-stringify": { @@ -7330,8 +7631,8 @@ "integrity": "sha512-lWzcd+HSiqeuxyhG+EnZds6iO3Y3ZEnMrfZq/OTGvF/C+Z4fPMCdhWTGSAiO2Oym9rbEXfwddHhh6jqrTF3+Lw==", "dev": true, "requires": { - "import-local": "1.0.0", - "jest-cli": "23.6.0" + "import-local": "^1.0.0", + "jest-cli": "^23.6.0" }, "dependencies": { "arr-diff": { @@ -7340,7 +7641,7 @@ "integrity": "sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8=", "dev": true, "requires": { - "arr-flatten": "1.1.0" + "arr-flatten": "^1.0.1" } }, "array-unique": { @@ -7355,9 +7656,9 @@ "integrity": "sha1-uneWLhLf+WnWt2cR6RS3N4V79qc=", "dev": true, "requires": { - "expand-range": "1.8.2", - "preserve": "0.2.0", - "repeat-element": "1.1.3" + "expand-range": "^1.8.1", + "preserve": "^0.2.0", + "repeat-element": "^1.1.2" } }, "cross-spawn": { @@ -7366,9 +7667,9 @@ "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", "dev": true, "requires": { - "lru-cache": "4.1.3", - "shebang-command": "1.2.0", - "which": "1.3.1" + "lru-cache": "^4.0.1", + "shebang-command": "^1.2.0", + "which": "^1.2.9" } }, "decamelize": { @@ -7383,13 +7684,13 @@ "integrity": "sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c=", "dev": true, "requires": { - "cross-spawn": "5.1.0", - "get-stream": "3.0.0", - "is-stream": "1.1.0", - "npm-run-path": "2.0.2", - "p-finally": "1.0.0", - "signal-exit": "3.0.2", - "strip-eof": "1.0.0" + "cross-spawn": "^5.0.1", + "get-stream": "^3.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" } }, "expand-brackets": { @@ -7398,7 +7699,7 @@ "integrity": "sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s=", "dev": true, "requires": { - "is-posix-bracket": "0.1.1" + "is-posix-bracket": "^0.1.0" } }, "extglob": { @@ -7407,7 +7708,7 @@ "integrity": "sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE=", "dev": true, "requires": { - "is-extglob": "1.0.0" + "is-extglob": "^1.0.0" } }, "get-stream": { @@ -7422,8 +7723,8 @@ "integrity": "sha512-vAaZHieK9qjGo58agRBg+bhHX3hoTZU/Oa3GESWLz7t1U62fk63aHuDJJEteXoDeTCcPmUT+z38gkHPZkkmpmQ==", "dev": true, "requires": { - "pkg-dir": "2.0.0", - "resolve-cwd": "2.0.0" + "pkg-dir": "^2.0.0", + "resolve-cwd": "^2.0.0" } }, "invert-kv": { @@ -7444,7 +7745,7 @@ "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", "dev": true, "requires": { - "is-extglob": "1.0.0" + "is-extglob": "^1.0.0" } }, "jest-cli": { @@ -7453,42 +7754,42 @@ "integrity": "sha512-hgeD1zRUp1E1zsiyOXjEn4LzRLWdJBV//ukAHGlx6s5mfCNJTbhbHjgxnDUXA8fsKWN/HqFFF6X5XcCwC/IvYQ==", "dev": true, "requires": { - "ansi-escapes": "3.1.0", - "chalk": "2.4.1", - "exit": "0.1.2", - "glob": "7.1.3", - "graceful-fs": "4.1.15", - "import-local": "1.0.0", - "is-ci": "1.2.1", - "istanbul-api": "1.3.7", - "istanbul-lib-coverage": "1.2.1", - "istanbul-lib-instrument": "1.10.2", - "istanbul-lib-source-maps": "1.2.6", - "jest-changed-files": "23.4.2", - "jest-config": "23.6.0", - "jest-environment-jsdom": "23.4.0", - "jest-get-type": "22.4.3", - "jest-haste-map": "23.6.0", - "jest-message-util": "23.4.0", - "jest-regex-util": "23.3.0", - "jest-resolve-dependencies": "23.6.0", - "jest-runner": "23.6.0", - "jest-runtime": "23.6.0", - "jest-snapshot": "23.6.0", - "jest-util": "23.4.0", - "jest-validate": "23.6.0", - "jest-watcher": "23.4.0", - "jest-worker": "23.2.0", - "micromatch": "2.3.11", - "node-notifier": "5.3.0", - "prompts": "0.1.14", - "realpath-native": "1.0.2", - "rimraf": "2.6.2", - "slash": "1.0.0", - "string-length": "2.0.0", - "strip-ansi": "4.0.0", - "which": "1.3.1", - "yargs": "11.1.0" + "ansi-escapes": "^3.0.0", + "chalk": "^2.0.1", + "exit": "^0.1.2", + "glob": "^7.1.2", + "graceful-fs": "^4.1.11", + "import-local": "^1.0.0", + "is-ci": "^1.0.10", + "istanbul-api": "^1.3.1", + "istanbul-lib-coverage": "^1.2.0", + "istanbul-lib-instrument": "^1.10.1", + "istanbul-lib-source-maps": "^1.2.4", + "jest-changed-files": "^23.4.2", + "jest-config": "^23.6.0", + "jest-environment-jsdom": "^23.4.0", + "jest-get-type": "^22.1.0", + "jest-haste-map": "^23.6.0", + "jest-message-util": "^23.4.0", + "jest-regex-util": "^23.3.0", + "jest-resolve-dependencies": "^23.6.0", + "jest-runner": "^23.6.0", + "jest-runtime": "^23.6.0", + "jest-snapshot": "^23.6.0", + "jest-util": "^23.4.0", + "jest-validate": "^23.6.0", + "jest-watcher": "^23.4.0", + "jest-worker": "^23.2.0", + "micromatch": "^2.3.11", + "node-notifier": "^5.2.1", + "prompts": "^0.1.9", + "realpath-native": "^1.0.0", + "rimraf": "^2.5.4", + "slash": "^1.0.0", + "string-length": "^2.0.0", + "strip-ansi": "^4.0.0", + "which": "^1.2.12", + "yargs": "^11.0.0" } }, "kind-of": { @@ -7497,7 +7798,7 @@ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "requires": { - "is-buffer": "1.1.6" + "is-buffer": "^1.1.5" } }, "lcid": { @@ -7506,7 +7807,7 @@ "integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=", "dev": true, "requires": { - "invert-kv": "1.0.0" + "invert-kv": "^1.0.0" } }, "mem": { @@ -7515,7 +7816,7 @@ "integrity": "sha1-Xt1StIXKHZAP5kiVUFOZoN+kX3Y=", "dev": true, "requires": { - "mimic-fn": "1.2.0" + "mimic-fn": "^1.0.0" } }, "micromatch": { @@ -7524,19 +7825,19 @@ "integrity": "sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU=", "dev": true, "requires": { - "arr-diff": "2.0.0", - "array-unique": "0.2.1", - "braces": "1.8.5", - "expand-brackets": "0.1.5", - "extglob": "0.3.2", - "filename-regex": "2.0.1", - "is-extglob": "1.0.0", - "is-glob": "2.0.1", - "kind-of": "3.2.2", - "normalize-path": "2.1.1", - "object.omit": "2.0.1", - "parse-glob": "3.0.4", - "regex-cache": "0.4.4" + "arr-diff": "^2.0.0", + "array-unique": "^0.2.1", + "braces": "^1.8.2", + "expand-brackets": "^0.1.4", + "extglob": "^0.3.1", + "filename-regex": "^2.0.0", + "is-extglob": "^1.0.0", + "is-glob": "^2.0.1", + "kind-of": "^3.0.2", + "normalize-path": "^2.0.1", + "object.omit": "^2.0.0", + "parse-glob": "^3.0.4", + "regex-cache": "^0.4.2" } }, "os-locale": { @@ -7545,9 +7846,9 @@ "integrity": "sha512-3sslG3zJbEYcaC4YVAvDorjGxc7tv6KVATnLPZONiljsUncvihe9BQoVCEs0RZ1kmf4Hk9OBqlZfJZWI4GanKA==", "dev": true, "requires": { - "execa": "0.7.0", - "lcid": "1.0.0", - "mem": "1.1.0" + "execa": "^0.7.0", + "lcid": "^1.0.0", + "mem": "^1.1.0" } }, "y18n": { @@ -7562,18 +7863,18 @@ "integrity": "sha512-NwW69J42EsCSanF8kyn5upxvjp5ds+t3+udGBeTbFnERA+lF541DDpMawzo4z6W/QrzNM18D+BPMiOBibnFV5A==", "dev": true, "requires": { - "cliui": "4.1.0", - "decamelize": "1.2.0", - "find-up": "2.1.0", - "get-caller-file": "1.0.3", - "os-locale": "2.1.0", - "require-directory": "2.1.1", - "require-main-filename": "1.0.1", - "set-blocking": "2.0.0", - "string-width": "2.1.1", - "which-module": "2.0.0", - "y18n": "3.2.1", - "yargs-parser": "9.0.2" + "cliui": "^4.0.0", + "decamelize": "^1.1.1", + "find-up": "^2.1.0", + "get-caller-file": "^1.0.1", + "os-locale": "^2.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", + "yargs-parser": "^9.0.2" } }, "yargs-parser": { @@ -7582,7 +7883,7 @@ "integrity": "sha1-nM9qQ0YP5O1Aqbto9I1DuKaMwHc=", "dev": true, "requires": { - "camelcase": "4.1.0" + "camelcase": "^4.1.0" } } } @@ -7593,7 +7894,7 @@ "integrity": "sha512-EyNhTAUWEfwnK0Is/09LxoqNDOn7mU7S3EHskG52djOFS/z+IT0jT3h3Ql61+dklcG7bJJitIWEMB4Sp1piHmA==", "dev": true, "requires": { - "throat": "4.1.0" + "throat": "^4.0.0" } }, "jest-config": { @@ -7602,20 +7903,20 @@ "integrity": "sha512-i8V7z9BeDXab1+VNo78WM0AtWpBRXJLnkT+lyT+Slx/cbP5sZJ0+NDuLcmBE5hXAoK0aUp7vI+MOxR+R4d8SRQ==", "dev": true, "requires": { - "babel-core": "6.26.3", - "babel-jest": "23.6.0", - "chalk": "2.4.1", - "glob": "7.1.3", - "jest-environment-jsdom": "23.4.0", - "jest-environment-node": "23.4.0", - "jest-get-type": "22.4.3", - "jest-jasmine2": "23.6.0", - "jest-regex-util": "23.3.0", - "jest-resolve": "23.6.0", - "jest-util": "23.4.0", - "jest-validate": "23.6.0", - "micromatch": "2.3.11", - "pretty-format": "23.6.0" + "babel-core": "^6.0.0", + "babel-jest": "^23.6.0", + "chalk": "^2.0.1", + "glob": "^7.1.1", + "jest-environment-jsdom": "^23.4.0", + "jest-environment-node": "^23.4.0", + "jest-get-type": "^22.1.0", + "jest-jasmine2": "^23.6.0", + "jest-regex-util": "^23.3.0", + "jest-resolve": "^23.6.0", + "jest-util": "^23.4.0", + "jest-validate": "^23.6.0", + "micromatch": "^2.3.11", + "pretty-format": "^23.6.0" }, "dependencies": { "arr-diff": { @@ -7624,7 +7925,7 @@ "integrity": "sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8=", "dev": true, "requires": { - "arr-flatten": "1.1.0" + "arr-flatten": "^1.0.1" } }, "array-unique": { @@ -7639,25 +7940,51 @@ "integrity": "sha512-6jyFLuDmeidKmUEb3NM+/yawG0M2bDZ9Z1qbZP59cyHLz8kYGKYwpJP0UwUKKUiTRNvxfLesJnTedqczP7cTDA==", "dev": true, "requires": { - "babel-code-frame": "6.26.0", - "babel-generator": "6.26.1", - "babel-helpers": "6.24.1", - "babel-messages": "6.23.0", - "babel-register": "6.26.0", - "babel-runtime": "6.26.0", - "babel-template": "6.26.0", - "babel-traverse": "6.26.0", - "babel-types": "6.26.0", - "babylon": "6.18.0", - "convert-source-map": "1.6.0", - "debug": "2.6.9", - "json5": "0.5.1", - "lodash": "4.17.11", - "minimatch": "3.0.4", - "path-is-absolute": "1.0.1", - "private": "0.1.8", - "slash": "1.0.0", - "source-map": "0.5.7" + "babel-code-frame": "^6.26.0", + "babel-generator": "^6.26.0", + "babel-helpers": "^6.24.1", + "babel-messages": "^6.23.0", + "babel-register": "^6.26.0", + "babel-runtime": "^6.26.0", + "babel-template": "^6.26.0", + "babel-traverse": "^6.26.0", + "babel-types": "^6.26.0", + "babylon": "^6.18.0", + "convert-source-map": "^1.5.1", + "debug": "^2.6.9", + "json5": "^0.5.1", + "lodash": "^4.17.4", + "minimatch": "^3.0.4", + "path-is-absolute": "^1.0.1", + "private": "^0.1.8", + "slash": "^1.0.0", + "source-map": "^0.5.7" + } + }, + "babel-jest": { + "version": "23.6.0", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-23.6.0.tgz", + "integrity": "sha512-lqKGG6LYXYu+DQh/slrQ8nxXQkEkhugdXsU6St7GmhVS7Ilc/22ArwqXNJrf0QaOBjZB0360qZMwXqDYQHXaew==", + "dev": true, + "requires": { + "babel-plugin-istanbul": "^4.1.6", + "babel-preset-jest": "^23.2.0" + } + }, + "babel-plugin-jest-hoist": { + "version": "23.2.0", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-23.2.0.tgz", + "integrity": "sha1-5h+uBaHKiAGq3uV6bWa4zvr0QWc=", + "dev": true + }, + "babel-preset-jest": { + "version": "23.2.0", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-23.2.0.tgz", + "integrity": "sha1-jsegOhOPABoaj7HoETZSvxpV2kY=", + "dev": true, + "requires": { + "babel-plugin-jest-hoist": "^23.2.0", + "babel-plugin-syntax-object-rest-spread": "^6.13.0" } }, "braces": { @@ -7666,9 +7993,9 @@ "integrity": "sha1-uneWLhLf+WnWt2cR6RS3N4V79qc=", "dev": true, "requires": { - "expand-range": "1.8.2", - "preserve": "0.2.0", - "repeat-element": "1.1.3" + "expand-range": "^1.8.1", + "preserve": "^0.2.0", + "repeat-element": "^1.1.2" } }, "debug": { @@ -7686,7 +8013,7 @@ "integrity": "sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s=", "dev": true, "requires": { - "is-posix-bracket": "0.1.1" + "is-posix-bracket": "^0.1.0" } }, "extglob": { @@ -7695,7 +8022,7 @@ "integrity": "sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE=", "dev": true, "requires": { - "is-extglob": "1.0.0" + "is-extglob": "^1.0.0" } }, "is-extglob": { @@ -7710,7 +8037,7 @@ "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", "dev": true, "requires": { - "is-extglob": "1.0.0" + "is-extglob": "^1.0.0" } }, "json5": { @@ -7725,7 +8052,7 @@ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "requires": { - "is-buffer": "1.1.6" + "is-buffer": "^1.1.5" } }, "micromatch": { @@ -7734,19 +8061,19 @@ "integrity": "sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU=", "dev": true, "requires": { - "arr-diff": "2.0.0", - "array-unique": "0.2.1", - "braces": "1.8.5", - "expand-brackets": "0.1.5", - "extglob": "0.3.2", - "filename-regex": "2.0.1", - "is-extglob": "1.0.0", - "is-glob": "2.0.1", - "kind-of": "3.2.2", - "normalize-path": "2.1.1", - "object.omit": "2.0.1", - "parse-glob": "3.0.4", - "regex-cache": "0.4.4" + "arr-diff": "^2.0.0", + "array-unique": "^0.2.1", + "braces": "^1.8.2", + "expand-brackets": "^0.1.4", + "extglob": "^0.3.1", + "filename-regex": "^2.0.0", + "is-extglob": "^1.0.0", + "is-glob": "^2.0.1", + "kind-of": "^3.0.2", + "normalize-path": "^2.0.1", + "object.omit": "^2.0.0", + "parse-glob": "^3.0.4", + "regex-cache": "^0.4.2" } } } @@ -7757,10 +8084,10 @@ "integrity": "sha512-Gz9l5Ov+X3aL5L37IT+8hoCUsof1CVYBb2QEkOupK64XyRR3h+uRpYIm97K7sY8diFxowR8pIGEdyfMKTixo3g==", "dev": true, "requires": { - "chalk": "2.4.1", - "diff": "3.5.0", - "jest-get-type": "22.4.3", - "pretty-format": "23.6.0" + "chalk": "^2.0.1", + "diff": "^3.2.0", + "jest-get-type": "^22.1.0", + "pretty-format": "^23.6.0" } }, "jest-docblock": { @@ -7769,7 +8096,7 @@ "integrity": "sha1-8IXh8YVI2Z/dabICB+b9VdkTg6c=", "dev": true, "requires": { - "detect-newline": "2.1.0" + "detect-newline": "^2.1.0" } }, "jest-each": { @@ -7778,8 +8105,8 @@ "integrity": "sha512-x7V6M/WGJo6/kLoissORuvLIeAoyo2YqLOoCDkohgJ4XOXSqOtyvr8FbInlAWS77ojBsZrafbozWoKVRdtxFCg==", "dev": true, "requires": { - "chalk": "2.4.1", - "pretty-format": "23.6.0" + "chalk": "^2.0.1", + "pretty-format": "^23.6.0" } }, "jest-environment-jsdom": { @@ -7788,9 +8115,9 @@ "integrity": "sha1-BWp5UrP+pROsYqFAosNox52eYCM=", "dev": true, "requires": { - "jest-mock": "23.2.0", - "jest-util": "23.4.0", - "jsdom": "11.12.0" + "jest-mock": "^23.2.0", + "jest-util": "^23.4.0", + "jsdom": "^11.5.1" } }, "jest-environment-node": { @@ -7799,8 +8126,8 @@ "integrity": "sha1-V+gO0IQd6jAxZ8zozXlSHeuv3hA=", "dev": true, "requires": { - "jest-mock": "23.2.0", - "jest-util": "23.4.0" + "jest-mock": "^23.2.0", + "jest-util": "^23.4.0" } }, "jest-get-type": { @@ -7815,14 +8142,14 @@ "integrity": "sha512-uyNhMyl6dr6HaXGHp8VF7cK6KpC6G9z9LiMNsst+rJIZ8l7wY0tk8qwjPmEghczojZ2/ZhtEdIabZ0OQRJSGGg==", "dev": true, "requires": { - "fb-watchman": "2.0.0", - "graceful-fs": "4.1.15", - "invariant": "2.2.4", - "jest-docblock": "23.2.0", - "jest-serializer": "23.0.1", - "jest-worker": "23.2.0", - "micromatch": "2.3.11", - "sane": "2.5.2" + "fb-watchman": "^2.0.0", + "graceful-fs": "^4.1.11", + "invariant": "^2.2.4", + "jest-docblock": "^23.2.0", + "jest-serializer": "^23.0.1", + "jest-worker": "^23.2.0", + "micromatch": "^2.3.11", + "sane": "^2.0.0" }, "dependencies": { "arr-diff": { @@ -7831,7 +8158,7 @@ "integrity": "sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8=", "dev": true, "requires": { - "arr-flatten": "1.1.0" + "arr-flatten": "^1.0.1" } }, "array-unique": { @@ -7846,9 +8173,9 @@ "integrity": "sha1-uneWLhLf+WnWt2cR6RS3N4V79qc=", "dev": true, "requires": { - "expand-range": "1.8.2", - "preserve": "0.2.0", - "repeat-element": "1.1.3" + "expand-range": "^1.8.1", + "preserve": "^0.2.0", + "repeat-element": "^1.1.2" } }, "expand-brackets": { @@ -7857,7 +8184,7 @@ "integrity": "sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s=", "dev": true, "requires": { - "is-posix-bracket": "0.1.1" + "is-posix-bracket": "^0.1.0" } }, "extglob": { @@ -7866,7 +8193,7 @@ "integrity": "sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE=", "dev": true, "requires": { - "is-extglob": "1.0.0" + "is-extglob": "^1.0.0" } }, "is-extglob": { @@ -7881,7 +8208,7 @@ "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", "dev": true, "requires": { - "is-extglob": "1.0.0" + "is-extglob": "^1.0.0" } }, "kind-of": { @@ -7890,7 +8217,7 @@ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "requires": { - "is-buffer": "1.1.6" + "is-buffer": "^1.1.5" } }, "micromatch": { @@ -7899,19 +8226,19 @@ "integrity": "sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU=", "dev": true, "requires": { - "arr-diff": "2.0.0", - "array-unique": "0.2.1", - "braces": "1.8.5", - "expand-brackets": "0.1.5", - "extglob": "0.3.2", - "filename-regex": "2.0.1", - "is-extglob": "1.0.0", - "is-glob": "2.0.1", - "kind-of": "3.2.2", - "normalize-path": "2.1.1", - "object.omit": "2.0.1", - "parse-glob": "3.0.4", - "regex-cache": "0.4.4" + "arr-diff": "^2.0.0", + "array-unique": "^0.2.1", + "braces": "^1.8.2", + "expand-brackets": "^0.1.4", + "extglob": "^0.3.1", + "filename-regex": "^2.0.0", + "is-extglob": "^1.0.0", + "is-glob": "^2.0.1", + "kind-of": "^3.0.2", + "normalize-path": "^2.0.1", + "object.omit": "^2.0.0", + "parse-glob": "^3.0.4", + "regex-cache": "^0.4.2" } } } @@ -7922,18 +8249,18 @@ "integrity": "sha512-pe2Ytgs1nyCs8IvsEJRiRTPC0eVYd8L/dXJGU08GFuBwZ4sYH/lmFDdOL3ZmvJR8QKqV9MFuwlsAi/EWkFUbsQ==", "dev": true, "requires": { - "babel-traverse": "6.26.0", - "chalk": "2.4.1", - "co": "4.6.0", - "expect": "23.6.0", - "is-generator-fn": "1.0.0", - "jest-diff": "23.6.0", - "jest-each": "23.6.0", - "jest-matcher-utils": "23.6.0", - "jest-message-util": "23.4.0", - "jest-snapshot": "23.6.0", - "jest-util": "23.4.0", - "pretty-format": "23.6.0" + "babel-traverse": "^6.0.0", + "chalk": "^2.0.1", + "co": "^4.6.0", + "expect": "^23.6.0", + "is-generator-fn": "^1.0.0", + "jest-diff": "^23.6.0", + "jest-each": "^23.6.0", + "jest-matcher-utils": "^23.6.0", + "jest-message-util": "^23.4.0", + "jest-snapshot": "^23.6.0", + "jest-util": "^23.4.0", + "pretty-format": "^23.6.0" } }, "jest-leak-detector": { @@ -7942,7 +8269,7 @@ "integrity": "sha512-f/8zA04rsl1Nzj10HIyEsXvYlMpMPcy0QkQilVZDFOaPbv2ur71X5u2+C4ZQJGyV/xvVXtCCZ3wQ99IgQxftCg==", "dev": true, "requires": { - "pretty-format": "23.6.0" + "pretty-format": "^23.6.0" } }, "jest-matcher-utils": { @@ -7951,9 +8278,9 @@ "integrity": "sha512-rosyCHQfBcol4NsckTn01cdelzWLU9Cq7aaigDf8VwwpIRvWE/9zLgX2bON+FkEW69/0UuYslUe22SOdEf2nog==", "dev": true, "requires": { - "chalk": "2.4.1", - "jest-get-type": "22.4.3", - "pretty-format": "23.6.0" + "chalk": "^2.0.1", + "jest-get-type": "^22.1.0", + "pretty-format": "^23.6.0" } }, "jest-message-util": { @@ -7962,11 +8289,11 @@ "integrity": "sha1-F2EMUJQjSVCNAaPR4L2iwHkIap8=", "dev": true, "requires": { - "@babel/code-frame": "7.0.0", - "chalk": "2.4.1", - "micromatch": "2.3.11", - "slash": "1.0.0", - "stack-utils": "1.0.2" + "@babel/code-frame": "^7.0.0-beta.35", + "chalk": "^2.0.1", + "micromatch": "^2.3.11", + "slash": "^1.0.0", + "stack-utils": "^1.0.1" }, "dependencies": { "arr-diff": { @@ -7975,7 +8302,7 @@ "integrity": "sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8=", "dev": true, "requires": { - "arr-flatten": "1.1.0" + "arr-flatten": "^1.0.1" } }, "array-unique": { @@ -7990,9 +8317,9 @@ "integrity": "sha1-uneWLhLf+WnWt2cR6RS3N4V79qc=", "dev": true, "requires": { - "expand-range": "1.8.2", - "preserve": "0.2.0", - "repeat-element": "1.1.3" + "expand-range": "^1.8.1", + "preserve": "^0.2.0", + "repeat-element": "^1.1.2" } }, "expand-brackets": { @@ -8001,7 +8328,7 @@ "integrity": "sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s=", "dev": true, "requires": { - "is-posix-bracket": "0.1.1" + "is-posix-bracket": "^0.1.0" } }, "extglob": { @@ -8010,7 +8337,7 @@ "integrity": "sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE=", "dev": true, "requires": { - "is-extglob": "1.0.0" + "is-extglob": "^1.0.0" } }, "is-extglob": { @@ -8025,7 +8352,7 @@ "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", "dev": true, "requires": { - "is-extglob": "1.0.0" + "is-extglob": "^1.0.0" } }, "kind-of": { @@ -8034,7 +8361,7 @@ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "requires": { - "is-buffer": "1.1.6" + "is-buffer": "^1.1.5" } }, "micromatch": { @@ -8043,19 +8370,19 @@ "integrity": "sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU=", "dev": true, "requires": { - "arr-diff": "2.0.0", - "array-unique": "0.2.1", - "braces": "1.8.5", - "expand-brackets": "0.1.5", - "extglob": "0.3.2", - "filename-regex": "2.0.1", - "is-extglob": "1.0.0", - "is-glob": "2.0.1", - "kind-of": "3.2.2", - "normalize-path": "2.1.1", - "object.omit": "2.0.1", - "parse-glob": "3.0.4", - "regex-cache": "0.4.4" + "arr-diff": "^2.0.0", + "array-unique": "^0.2.1", + "braces": "^1.8.2", + "expand-brackets": "^0.1.4", + "extglob": "^0.3.1", + "filename-regex": "^2.0.0", + "is-extglob": "^1.0.0", + "is-glob": "^2.0.1", + "kind-of": "^3.0.2", + "normalize-path": "^2.0.1", + "object.omit": "^2.0.0", + "parse-glob": "^3.0.4", + "regex-cache": "^0.4.2" } } } @@ -8078,9 +8405,9 @@ "integrity": "sha512-XyoRxNtO7YGpQDmtQCmZjum1MljDqUCob7XlZ6jy9gsMugHdN2hY4+Acz9Qvjz2mSsOnPSH7skBmDYCHXVZqkA==", "dev": true, "requires": { - "browser-resolve": "1.11.3", - "chalk": "2.4.1", - "realpath-native": "1.0.2" + "browser-resolve": "^1.11.3", + "chalk": "^2.0.1", + "realpath-native": "^1.0.0" } }, "jest-resolve-dependencies": { @@ -8089,8 +8416,8 @@ "integrity": "sha512-EkQWkFWjGKwRtRyIwRwI6rtPAEyPWlUC2MpzHissYnzJeHcyCn1Hc8j7Nn1xUVrS5C6W5+ZL37XTem4D4pLZdA==", "dev": true, "requires": { - "jest-regex-util": "23.3.0", - "jest-snapshot": "23.6.0" + "jest-regex-util": "^23.3.0", + "jest-snapshot": "^23.6.0" } }, "jest-runner": { @@ -8099,19 +8426,19 @@ "integrity": "sha512-kw0+uj710dzSJKU6ygri851CObtCD9cN8aNkg8jWJf4ewFyEa6kwmiH/r/M1Ec5IL/6VFa0wnAk6w+gzUtjJzA==", "dev": true, "requires": { - "exit": "0.1.2", - "graceful-fs": "4.1.15", - "jest-config": "23.6.0", - "jest-docblock": "23.2.0", - "jest-haste-map": "23.6.0", - "jest-jasmine2": "23.6.0", - "jest-leak-detector": "23.6.0", - "jest-message-util": "23.4.0", - "jest-runtime": "23.6.0", - "jest-util": "23.4.0", - "jest-worker": "23.2.0", - "source-map-support": "0.5.9", - "throat": "4.1.0" + "exit": "^0.1.2", + "graceful-fs": "^4.1.11", + "jest-config": "^23.6.0", + "jest-docblock": "^23.2.0", + "jest-haste-map": "^23.6.0", + "jest-jasmine2": "^23.6.0", + "jest-leak-detector": "^23.6.0", + "jest-message-util": "^23.4.0", + "jest-runtime": "^23.6.0", + "jest-util": "^23.4.0", + "jest-worker": "^23.2.0", + "source-map-support": "^0.5.6", + "throat": "^4.0.0" } }, "jest-runtime": { @@ -8120,27 +8447,27 @@ "integrity": "sha512-ycnLTNPT2Gv+TRhnAYAQ0B3SryEXhhRj1kA6hBPSeZaNQkJ7GbZsxOLUkwg6YmvWGdX3BB3PYKFLDQCAE1zNOw==", "dev": true, "requires": { - "babel-core": "6.26.3", - "babel-plugin-istanbul": "4.1.6", - "chalk": "2.4.1", - "convert-source-map": "1.6.0", - "exit": "0.1.2", - "fast-json-stable-stringify": "2.0.0", - "graceful-fs": "4.1.15", - "jest-config": "23.6.0", - "jest-haste-map": "23.6.0", - "jest-message-util": "23.4.0", - "jest-regex-util": "23.3.0", - "jest-resolve": "23.6.0", - "jest-snapshot": "23.6.0", - "jest-util": "23.4.0", - "jest-validate": "23.6.0", - "micromatch": "2.3.11", - "realpath-native": "1.0.2", - "slash": "1.0.0", + "babel-core": "^6.0.0", + "babel-plugin-istanbul": "^4.1.6", + "chalk": "^2.0.1", + "convert-source-map": "^1.4.0", + "exit": "^0.1.2", + "fast-json-stable-stringify": "^2.0.0", + "graceful-fs": "^4.1.11", + "jest-config": "^23.6.0", + "jest-haste-map": "^23.6.0", + "jest-message-util": "^23.4.0", + "jest-regex-util": "^23.3.0", + "jest-resolve": "^23.6.0", + "jest-snapshot": "^23.6.0", + "jest-util": "^23.4.0", + "jest-validate": "^23.6.0", + "micromatch": "^2.3.11", + "realpath-native": "^1.0.0", + "slash": "^1.0.0", "strip-bom": "3.0.0", - "write-file-atomic": "2.3.0", - "yargs": "11.1.0" + "write-file-atomic": "^2.1.0", + "yargs": "^11.0.0" }, "dependencies": { "arr-diff": { @@ -8149,7 +8476,7 @@ "integrity": "sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8=", "dev": true, "requires": { - "arr-flatten": "1.1.0" + "arr-flatten": "^1.0.1" } }, "array-unique": { @@ -8164,25 +8491,25 @@ "integrity": "sha512-6jyFLuDmeidKmUEb3NM+/yawG0M2bDZ9Z1qbZP59cyHLz8kYGKYwpJP0UwUKKUiTRNvxfLesJnTedqczP7cTDA==", "dev": true, "requires": { - "babel-code-frame": "6.26.0", - "babel-generator": "6.26.1", - "babel-helpers": "6.24.1", - "babel-messages": "6.23.0", - "babel-register": "6.26.0", - "babel-runtime": "6.26.0", - "babel-template": "6.26.0", - "babel-traverse": "6.26.0", - "babel-types": "6.26.0", - "babylon": "6.18.0", - "convert-source-map": "1.6.0", - "debug": "2.6.9", - "json5": "0.5.1", - "lodash": "4.17.11", - "minimatch": "3.0.4", - "path-is-absolute": "1.0.1", - "private": "0.1.8", - "slash": "1.0.0", - "source-map": "0.5.7" + "babel-code-frame": "^6.26.0", + "babel-generator": "^6.26.0", + "babel-helpers": "^6.24.1", + "babel-messages": "^6.23.0", + "babel-register": "^6.26.0", + "babel-runtime": "^6.26.0", + "babel-template": "^6.26.0", + "babel-traverse": "^6.26.0", + "babel-types": "^6.26.0", + "babylon": "^6.18.0", + "convert-source-map": "^1.5.1", + "debug": "^2.6.9", + "json5": "^0.5.1", + "lodash": "^4.17.4", + "minimatch": "^3.0.4", + "path-is-absolute": "^1.0.1", + "private": "^0.1.8", + "slash": "^1.0.0", + "source-map": "^0.5.7" } }, "braces": { @@ -8191,9 +8518,9 @@ "integrity": "sha1-uneWLhLf+WnWt2cR6RS3N4V79qc=", "dev": true, "requires": { - "expand-range": "1.8.2", - "preserve": "0.2.0", - "repeat-element": "1.1.3" + "expand-range": "^1.8.1", + "preserve": "^0.2.0", + "repeat-element": "^1.1.2" } }, "cross-spawn": { @@ -8202,9 +8529,9 @@ "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", "dev": true, "requires": { - "lru-cache": "4.1.3", - "shebang-command": "1.2.0", - "which": "1.3.1" + "lru-cache": "^4.0.1", + "shebang-command": "^1.2.0", + "which": "^1.2.9" } }, "debug": { @@ -8228,13 +8555,13 @@ "integrity": "sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c=", "dev": true, "requires": { - "cross-spawn": "5.1.0", - "get-stream": "3.0.0", - "is-stream": "1.1.0", - "npm-run-path": "2.0.2", - "p-finally": "1.0.0", - "signal-exit": "3.0.2", - "strip-eof": "1.0.0" + "cross-spawn": "^5.0.1", + "get-stream": "^3.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" } }, "expand-brackets": { @@ -8243,7 +8570,7 @@ "integrity": "sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s=", "dev": true, "requires": { - "is-posix-bracket": "0.1.1" + "is-posix-bracket": "^0.1.0" } }, "extglob": { @@ -8252,7 +8579,7 @@ "integrity": "sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE=", "dev": true, "requires": { - "is-extglob": "1.0.0" + "is-extglob": "^1.0.0" } }, "get-stream": { @@ -8279,7 +8606,7 @@ "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", "dev": true, "requires": { - "is-extglob": "1.0.0" + "is-extglob": "^1.0.0" } }, "json5": { @@ -8294,7 +8621,7 @@ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "requires": { - "is-buffer": "1.1.6" + "is-buffer": "^1.1.5" } }, "lcid": { @@ -8303,7 +8630,7 @@ "integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=", "dev": true, "requires": { - "invert-kv": "1.0.0" + "invert-kv": "^1.0.0" } }, "mem": { @@ -8312,7 +8639,7 @@ "integrity": "sha1-Xt1StIXKHZAP5kiVUFOZoN+kX3Y=", "dev": true, "requires": { - "mimic-fn": "1.2.0" + "mimic-fn": "^1.0.0" } }, "micromatch": { @@ -8321,19 +8648,19 @@ "integrity": "sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU=", "dev": true, "requires": { - "arr-diff": "2.0.0", - "array-unique": "0.2.1", - "braces": "1.8.5", - "expand-brackets": "0.1.5", - "extglob": "0.3.2", - "filename-regex": "2.0.1", - "is-extglob": "1.0.0", - "is-glob": "2.0.1", - "kind-of": "3.2.2", - "normalize-path": "2.1.1", - "object.omit": "2.0.1", - "parse-glob": "3.0.4", - "regex-cache": "0.4.4" + "arr-diff": "^2.0.0", + "array-unique": "^0.2.1", + "braces": "^1.8.2", + "expand-brackets": "^0.1.4", + "extglob": "^0.3.1", + "filename-regex": "^2.0.0", + "is-extglob": "^1.0.0", + "is-glob": "^2.0.1", + "kind-of": "^3.0.2", + "normalize-path": "^2.0.1", + "object.omit": "^2.0.0", + "parse-glob": "^3.0.4", + "regex-cache": "^0.4.2" } }, "os-locale": { @@ -8342,9 +8669,9 @@ "integrity": "sha512-3sslG3zJbEYcaC4YVAvDorjGxc7tv6KVATnLPZONiljsUncvihe9BQoVCEs0RZ1kmf4Hk9OBqlZfJZWI4GanKA==", "dev": true, "requires": { - "execa": "0.7.0", - "lcid": "1.0.0", - "mem": "1.1.0" + "execa": "^0.7.0", + "lcid": "^1.0.0", + "mem": "^1.1.0" } }, "strip-bom": { @@ -8365,18 +8692,18 @@ "integrity": "sha512-NwW69J42EsCSanF8kyn5upxvjp5ds+t3+udGBeTbFnERA+lF541DDpMawzo4z6W/QrzNM18D+BPMiOBibnFV5A==", "dev": true, "requires": { - "cliui": "4.1.0", - "decamelize": "1.2.0", - "find-up": "2.1.0", - "get-caller-file": "1.0.3", - "os-locale": "2.1.0", - "require-directory": "2.1.1", - "require-main-filename": "1.0.1", - "set-blocking": "2.0.0", - "string-width": "2.1.1", - "which-module": "2.0.0", - "y18n": "3.2.1", - "yargs-parser": "9.0.2" + "cliui": "^4.0.0", + "decamelize": "^1.1.1", + "find-up": "^2.1.0", + "get-caller-file": "^1.0.1", + "os-locale": "^2.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", + "yargs-parser": "^9.0.2" } }, "yargs-parser": { @@ -8385,7 +8712,7 @@ "integrity": "sha1-nM9qQ0YP5O1Aqbto9I1DuKaMwHc=", "dev": true, "requires": { - "camelcase": "4.1.0" + "camelcase": "^4.1.0" } } } @@ -8411,16 +8738,16 @@ "integrity": "sha512-tM7/Bprftun6Cvj2Awh/ikS7zV3pVwjRYU2qNYS51VZHgaAMBs5l4o/69AiDHhQrj5+LA2Lq4VIvK7zYk/bswg==", "dev": true, "requires": { - "babel-types": "6.26.0", - "chalk": "2.4.1", - "jest-diff": "23.6.0", - "jest-matcher-utils": "23.6.0", - "jest-message-util": "23.4.0", - "jest-resolve": "23.6.0", - "mkdirp": "0.5.1", - "natural-compare": "1.4.0", - "pretty-format": "23.6.0", - "semver": "5.6.0" + "babel-types": "^6.0.0", + "chalk": "^2.0.1", + "jest-diff": "^23.6.0", + "jest-matcher-utils": "^23.6.0", + "jest-message-util": "^23.4.0", + "jest-resolve": "^23.6.0", + "mkdirp": "^0.5.1", + "natural-compare": "^1.4.0", + "pretty-format": "^23.6.0", + "semver": "^5.5.0" } }, "jest-transform-stub": { @@ -8435,14 +8762,14 @@ "integrity": "sha1-TQY8uSe68KI4Mf9hvsLLv0l5NWE=", "dev": true, "requires": { - "callsites": "2.0.0", - "chalk": "2.4.1", - "graceful-fs": "4.1.15", - "is-ci": "1.2.1", - "jest-message-util": "23.4.0", - "mkdirp": "0.5.1", - "slash": "1.0.0", - "source-map": "0.6.1" + "callsites": "^2.0.0", + "chalk": "^2.0.1", + "graceful-fs": "^4.1.11", + "is-ci": "^1.0.10", + "jest-message-util": "^23.4.0", + "mkdirp": "^0.5.1", + "slash": "^1.0.0", + "source-map": "^0.6.0" }, "dependencies": { "callsites": { @@ -8465,10 +8792,10 @@ "integrity": "sha512-OFKapYxe72yz7agrDAWi8v2WL8GIfVqcbKRCLbRG9PAxtzF9b1SEDdTpytNDN12z2fJynoBwpMpvj2R39plI2A==", "dev": true, "requires": { - "chalk": "2.4.1", - "jest-get-type": "22.4.3", - "leven": "2.1.0", - "pretty-format": "23.6.0" + "chalk": "^2.0.1", + "jest-get-type": "^22.1.0", + "leven": "^2.1.0", + "pretty-format": "^23.6.0" } }, "jest-watcher": { @@ -8477,9 +8804,9 @@ "integrity": "sha1-0uKM50+NrWxq/JIrksq+9u0FyRw=", "dev": true, "requires": { - "ansi-escapes": "3.1.0", - "chalk": "2.4.1", - "string-length": "2.0.0" + "ansi-escapes": "^3.0.0", + "chalk": "^2.0.1", + "string-length": "^2.0.0" } }, "jest-worker": { @@ -8488,7 +8815,7 @@ "integrity": "sha1-+vcGqNo2+uYOsmlXJX+ntdjqArk=", "dev": true, "requires": { - "merge-stream": "1.0.1" + "merge-stream": "^1.0.1" } }, "joi": { @@ -8497,9 +8824,9 @@ "integrity": "sha1-z9hev+Z+ihkAQyQAtNA7vZP7h58=", "dev": true, "requires": { - "hoek": "5.0.4", - "isemail": "3.2.0", - "topo": "3.0.3" + "hoek": "5.x.x", + "isemail": "3.x.x", + "topo": "3.x.x" } }, "jquery": { @@ -8513,11 +8840,11 @@ "integrity": "sha512-MwPmLywK9RSX0SPsUJjN7i+RQY9w/yC17Lbrq9ViEefpLRgqAR2BgrMN2AbifkUuhDV8tRauLhLda/9+bE0YQA==", "dev": true, "requires": { - "config-chain": "1.1.12", - "editorconfig": "0.15.2", - "glob": "7.1.3", - "mkdirp": "0.5.1", - "nopt": "4.0.1" + "config-chain": "^1.1.12", + "editorconfig": "^0.15.2", + "glob": "^7.1.3", + "mkdirp": "~0.5.0", + "nopt": "~4.0.1" } }, "js-levenshtein": { @@ -8538,7 +8865,7 @@ "integrity": "sha1-NiITz4YPRo8BJfxslqvBdCUx+Ug=", "dev": true, "requires": { - "easy-stack": "1.0.0" + "easy-stack": "^1.0.0" } }, "js-tokens": { @@ -8553,8 +8880,8 @@ "integrity": "sha1-6u1lbsg0TxD1J8a/obbiJE3hZ9E=", "dev": true, "requires": { - "argparse": "1.0.10", - "esprima": "4.0.1" + "argparse": "^1.0.7", + "esprima": "^4.0.0" } }, "jsbn": { @@ -8569,32 +8896,32 @@ "integrity": "sha512-y8Px43oyiBM13Zc1z780FrfNLJCXTL40EWlty/LXUtcjykRBNgLlCjWXpfSPBl2iv+N7koQN+dvqszHZgT/Fjw==", "dev": true, "requires": { - "abab": "2.0.0", - "acorn": "5.7.3", - "acorn-globals": "4.3.0", - "array-equal": "1.0.0", - "cssom": "0.3.4", - "cssstyle": "1.1.1", - "data-urls": "1.1.0", - "domexception": "1.0.1", - "escodegen": "1.11.0", - "html-encoding-sniffer": "1.0.2", - "left-pad": "1.3.0", - "nwsapi": "2.0.9", + "abab": "^2.0.0", + "acorn": "^5.5.3", + "acorn-globals": "^4.1.0", + "array-equal": "^1.0.0", + "cssom": ">= 0.3.2 < 0.4.0", + "cssstyle": "^1.0.0", + "data-urls": "^1.0.0", + "domexception": "^1.0.1", + "escodegen": "^1.9.1", + "html-encoding-sniffer": "^1.0.2", + "left-pad": "^1.3.0", + "nwsapi": "^2.0.7", "parse5": "4.0.0", - "pn": "1.1.0", - "request": "2.88.0", - "request-promise-native": "1.0.5", - "sax": "1.2.4", - "symbol-tree": "3.2.2", - "tough-cookie": "2.4.3", - "w3c-hr-time": "1.0.1", - "webidl-conversions": "4.0.2", - "whatwg-encoding": "1.0.5", - "whatwg-mimetype": "2.3.0", - "whatwg-url": "6.5.0", - "ws": "5.2.2", - "xml-name-validator": "3.0.0" + "pn": "^1.1.0", + "request": "^2.87.0", + "request-promise-native": "^1.0.5", + "sax": "^1.2.4", + "symbol-tree": "^3.2.2", + "tough-cookie": "^2.3.4", + "w3c-hr-time": "^1.0.1", + "webidl-conversions": "^4.0.2", + "whatwg-encoding": "^1.0.3", + "whatwg-mimetype": "^2.1.0", + "whatwg-url": "^6.4.1", + "ws": "^5.2.0", + "xml-name-validator": "^3.0.0" }, "dependencies": { "ws": { @@ -8603,7 +8930,7 @@ "integrity": "sha512-jaHFD6PFv6UgoIVda6qZllptQsMlDEJkTQcybzzXDYM1XO9Y8em691FGMPmM46WGyLU4z9KMgQN+qrux/nhlHA==", "dev": true, "requires": { - "async-limiter": "1.0.0" + "async-limiter": "~1.0.0" } } } @@ -8656,7 +8983,7 @@ "integrity": "sha512-8Mh9h6xViijj36g7Dxi+Y4S6hNGV96vcJZr/SrlHh1LR/pEn/8j/+qIBbs44YKl69Lrfctp4QD+AdWLTMqEZAQ==", "dev": true, "requires": { - "minimist": "1.2.0" + "minimist": "^1.2.0" } }, "jsonfile": { @@ -8665,7 +8992,7 @@ "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", "dev": true, "requires": { - "graceful-fs": "4.1.15" + "graceful-fs": "^4.1.6" } }, "jsonify": { @@ -8710,8 +9037,8 @@ "integrity": "sha1-hxtaPuOdZoD8wm03kwtu7aidsMo=", "dev": true, "requires": { - "chalk": "2.4.1", - "shell-quote": "1.6.1" + "chalk": "^2.3.0", + "shell-quote": "^1.6.1" } }, "launch-editor-middleware": { @@ -8720,7 +9047,7 @@ "integrity": "sha512-s0UO2/gEGiCgei3/2UN3SMuUj1phjQN8lcpnvgLSz26fAzNWPQ6Nf/kF5IFClnfU2ehp6LrmKdMU/beveO+2jg==", "dev": true, "requires": { - "launch-editor": "2.2.1" + "launch-editor": "^2.2.1" } }, "lcid": { @@ -8729,7 +9056,7 @@ "integrity": "sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA==", "dev": true, "requires": { - "invert-kv": "2.0.0" + "invert-kv": "^2.0.0" } }, "left-pad": { @@ -8750,8 +9077,8 @@ "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", "dev": true, "requires": { - "prelude-ls": "1.1.2", - "type-check": "0.3.2" + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" } }, "load-json-file": { @@ -8760,11 +9087,11 @@ "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", "dev": true, "requires": { - "graceful-fs": "4.1.15", - "parse-json": "2.2.0", - "pify": "2.3.0", - "pinkie-promise": "2.0.1", - "strip-bom": "2.0.0" + "graceful-fs": "^4.1.2", + "parse-json": "^2.2.0", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0", + "strip-bom": "^2.0.0" }, "dependencies": { "parse-json": { @@ -8773,7 +9100,7 @@ "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", "dev": true, "requires": { - "error-ex": "1.3.2" + "error-ex": "^1.2.0" } }, "pify": { @@ -8790,7 +9117,7 @@ "integrity": "sha1-VuC/CL2XCLJqdltoUJhAyN7J/bw=", "dev": true, "requires": { - "find-cache-dir": "0.1.1", + "find-cache-dir": "^0.1.1", "mkdirp": "0.5.1" }, "dependencies": { @@ -8800,9 +9127,9 @@ "integrity": "sha1-yN765XyKUqinhPnjHFfHQumToLk=", "dev": true, "requires": { - "commondir": "1.0.1", - "mkdirp": "0.5.1", - "pkg-dir": "1.0.0" + "commondir": "^1.0.1", + "mkdirp": "^0.5.1", + "pkg-dir": "^1.0.0" } }, "find-up": { @@ -8811,8 +9138,8 @@ "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", "dev": true, "requires": { - "path-exists": "2.1.0", - "pinkie-promise": "2.0.1" + "path-exists": "^2.0.0", + "pinkie-promise": "^2.0.0" } }, "path-exists": { @@ -8821,7 +9148,7 @@ "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", "dev": true, "requires": { - "pinkie-promise": "2.0.1" + "pinkie-promise": "^2.0.0" } }, "pkg-dir": { @@ -8830,7 +9157,7 @@ "integrity": "sha1-ektQio1bstYp1EcFb/TpyTFM89Q=", "dev": true, "requires": { - "find-up": "1.1.2" + "find-up": "^1.0.0" } } } @@ -8847,9 +9174,9 @@ "integrity": "sha1-yYrvSIvM7aL/teLeZG1qdUQp9c0=", "dev": true, "requires": { - "big.js": "3.2.0", - "emojis-list": "2.1.0", - "json5": "0.5.1" + "big.js": "^3.1.3", + "emojis-list": "^2.0.0", + "json5": "^0.5.0" }, "dependencies": { "json5": { @@ -8866,8 +9193,8 @@ "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", "dev": true, "requires": { - "p-locate": "2.0.0", - "path-exists": "3.0.0" + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" } }, "lodash": { @@ -8929,7 +9256,7 @@ "integrity": "sha1-V0Dhxdbw39pK2TI7UzIQfva0xAo=", "dev": true, "requires": { - "chalk": "2.4.1" + "chalk": "^2.0.1" } }, "loglevel": { @@ -8944,7 +9271,7 @@ "integrity": "sha1-ce5R+nvkyuwaY4OffmgtgTLTDK8=", "dev": true, "requires": { - "js-tokens": "4.0.0" + "js-tokens": "^3.0.0 || ^4.0.0" } }, "lower-case": { @@ -8959,8 +9286,8 @@ "integrity": "sha1-oRdc80lt/IQ2wVbDNLSVWZK85pw=", "dev": true, "requires": { - "pseudomap": "1.0.2", - "yallist": "2.1.2" + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" } }, "make-dir": { @@ -8969,7 +9296,7 @@ "integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==", "dev": true, "requires": { - "pify": "3.0.0" + "pify": "^3.0.0" } }, "makeerror": { @@ -8978,7 +9305,7 @@ "integrity": "sha1-4BpckQnyr3lmDk6LlYd5AYT1qWw=", "dev": true, "requires": { - "tmpl": "1.0.4" + "tmpl": "1.0.x" } }, "map-age-cleaner": { @@ -8987,7 +9314,7 @@ "integrity": "sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w==", "dev": true, "requires": { - "p-defer": "1.0.0" + "p-defer": "^1.0.0" } }, "map-cache": { @@ -9002,7 +9329,7 @@ "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", "dev": true, "requires": { - "object-visit": "1.0.1" + "object-visit": "^1.0.0" } }, "math-random": { @@ -9017,9 +9344,9 @@ "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", "dev": true, "requires": { - "hash-base": "3.0.4", - "inherits": "2.0.3", - "safe-buffer": "5.1.2" + "hash-base": "^3.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" } }, "mdn-data": { @@ -9040,9 +9367,9 @@ "integrity": "sha512-WQxG/5xYc3tMbYLXoXPm81ET2WDULiU5FxbuIoNbJqLOOI8zehXFdZuiUEgfdrU2mVB1pxBZUGlYORSrpuJreA==", "dev": true, "requires": { - "map-age-cleaner": "0.1.3", - "mimic-fn": "1.2.0", - "p-is-promise": "1.1.0" + "map-age-cleaner": "^0.1.1", + "mimic-fn": "^1.0.0", + "p-is-promise": "^1.1.0" } }, "memory-fs": { @@ -9051,8 +9378,8 @@ "integrity": "sha1-OpoguEYlI+RHz7x+i7gO1me/xVI=", "dev": true, "requires": { - "errno": "0.1.7", - "readable-stream": "2.3.6" + "errno": "^0.1.3", + "readable-stream": "^2.0.1" } }, "merge": { @@ -9073,7 +9400,7 @@ "integrity": "sha512-Qkcp7P2ygktpMPh2mCQZaf3jhN6D3Z/qVZHSdWvQ+2Ef5HgRAPBO57A77+ENm0CPx2+1Ce/MYKi3ymqdfuqibw==", "dev": true, "requires": { - "source-map": "0.6.1" + "source-map": "^0.6.1" }, "dependencies": { "source-map": { @@ -9090,7 +9417,7 @@ "integrity": "sha1-QEEgLVCKNCugAXQAjfDCUbjBNeE=", "dev": true, "requires": { - "readable-stream": "2.3.6" + "readable-stream": "^2.0.1" } }, "merge2": { @@ -9111,19 +9438,19 @@ "integrity": "sha1-cIWbyVyYQJUvNZoGij/En57PrCM=", "dev": true, "requires": { - "arr-diff": "4.0.0", - "array-unique": "0.3.2", - "braces": "2.3.2", - "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.13", - "object.pick": "1.3.0", - "regex-not": "1.0.2", - "snapdragon": "0.8.2", - "to-regex": "3.0.2" + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" } }, "miller-rabin": { @@ -9132,8 +9459,8 @@ "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==", "dev": true, "requires": { - "bn.js": "4.11.8", - "brorand": "1.1.0" + "bn.js": "^4.0.0", + "brorand": "^1.0.1" } }, "mime": { @@ -9154,7 +9481,7 @@ "integrity": "sha1-KJlaoey3cHQv5q5+WPkYHHRLP5Y=", "dev": true, "requires": { - "mime-db": "1.37.0" + "mime-db": "~1.37.0" } }, "mimic-fn": { @@ -9169,9 +9496,9 @@ "integrity": "sha1-wQQQoASVG9PO2sHaaQU5QPzLYl0=", "dev": true, "requires": { - "loader-utils": "1.1.0", - "schema-utils": "1.0.0", - "webpack-sources": "1.3.0" + "loader-utils": "^1.1.0", + "schema-utils": "^1.0.0", + "webpack-sources": "^1.1.0" }, "dependencies": { "ajv-keywords": { @@ -9186,9 +9513,9 @@ "integrity": "sha1-C3mpMgTXtgDUsoUNH2bCo0lRx3A=", "dev": true, "requires": { - "ajv": "6.5.5", - "ajv-errors": "1.0.0", - "ajv-keywords": "3.2.0" + "ajv": "^6.1.0", + "ajv-errors": "^1.0.0", + "ajv-keywords": "^3.1.0" } } } @@ -9211,7 +9538,7 @@ "integrity": "sha1-UWbihkV/AzBgZL5Ul+jbsMPTIIM=", "dev": true, "requires": { - "brace-expansion": "1.1.11" + "brace-expansion": "^1.1.7" } }, "minimist": { @@ -9226,16 +9553,16 @@ "integrity": "sha512-zHo8v+otD1J10j/tC+VNoGK9keCuByhKovAvdn74dmxJl9+mWHnx6EMsDN4lgRoMI/eYo2nchAxniIbUPb5onw==", "dev": true, "requires": { - "concat-stream": "1.6.2", - "duplexify": "3.6.1", - "end-of-stream": "1.4.1", - "flush-write-stream": "1.0.3", - "from2": "2.3.0", - "parallel-transform": "1.1.0", - "pump": "2.0.1", - "pumpify": "1.5.1", - "stream-each": "1.2.3", - "through2": "2.0.5" + "concat-stream": "^1.5.0", + "duplexify": "^3.4.2", + "end-of-stream": "^1.1.0", + "flush-write-stream": "^1.0.0", + "from2": "^2.1.0", + "parallel-transform": "^1.1.0", + "pump": "^2.0.1", + "pumpify": "^1.3.3", + "stream-each": "^1.1.0", + "through2": "^2.0.0" }, "dependencies": { "pump": { @@ -9244,8 +9571,8 @@ "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==", "dev": true, "requires": { - "end-of-stream": "1.4.1", - "once": "1.4.0" + "end-of-stream": "^1.1.0", + "once": "^1.3.1" } } } @@ -9256,8 +9583,8 @@ "integrity": "sha1-pJ5yaNzhoNlpjkUybFYm3zVD0P4=", "dev": true, "requires": { - "for-in": "1.0.2", - "is-extendable": "1.0.1" + "for-in": "^1.0.2", + "is-extendable": "^1.0.1" }, "dependencies": { "is-extendable": { @@ -9266,7 +9593,7 @@ "integrity": "sha1-p0cPnkJnM9gb2B4RVSZOOjUHyrQ=", "dev": true, "requires": { - "is-plain-object": "2.0.4" + "is-plain-object": "^2.0.4" } } } @@ -9294,12 +9621,12 @@ "integrity": "sha1-viwAX9oy4LKa8fBdfEszIUxwH5I=", "dev": true, "requires": { - "aproba": "1.2.0", - "copy-concurrently": "1.0.5", - "fs-write-stream-atomic": "1.0.10", - "mkdirp": "0.5.1", - "rimraf": "2.6.2", - "run-queue": "1.0.3" + "aproba": "^1.1.1", + "copy-concurrently": "^1.0.0", + "fs-write-stream-atomic": "^1.0.8", + "mkdirp": "^0.5.1", + "rimraf": "^2.5.4", + "run-queue": "^1.0.3" } }, "ms": { @@ -9313,8 +9640,8 @@ "integrity": "sha512-ji6J5enbMyGRHIAkAOu3WdV8nggqviKCEKtXcOqfphZZtQrmHKycfynJ2V7eVPUA4NhJ6V7Wf4TmGbTwKE9B6g==", "dev": true, "requires": { - "dns-packet": "1.3.1", - "thunky": "1.0.3" + "dns-packet": "^1.3.1", + "thunky": "^1.0.2" } }, "multicast-dns-service-types": { @@ -9342,17 +9669,17 @@ "integrity": "sha1-uHqKpPwN6P5r6IiVs4mD/yZb0Rk=", "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.2", - "snapdragon": "0.8.2", - "to-regex": "3.0.2" + "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": { @@ -9385,7 +9712,7 @@ "integrity": "sha512-rmTZ9kz+f3rCvK2TD1Ue/oZlns7OGoIWP4fc3llxxRXlOkHKoWPPWJOfFYpITabSow43QJbRIoHQXtt10VldyQ==", "dev": true, "requires": { - "lower-case": "1.1.4" + "lower-case": "^1.1.1" } }, "node-cache": { @@ -9394,8 +9721,8 @@ "integrity": "sha512-obRu6/f7S024ysheAjoYFEEBqqDWv4LOMNJEuO8vMeEw2AT4z+NCzO4hlc2lhI4vATzbCQv6kke9FVdx0RbCOw==", "dev": true, "requires": { - "clone": "2.1.2", - "lodash": "4.17.11" + "clone": "2.x", + "lodash": "4.x" }, "dependencies": { "clone": { @@ -9435,28 +9762,28 @@ "integrity": "sha512-5AzFzdoIMb89hBGMZglEegffzgRg+ZFoUmisQ8HI4j1KDdpx13J0taNp2y9xPbur6W61gepGDDotGBVQ7mfUCg==", "dev": true, "requires": { - "assert": "1.4.1", - "browserify-zlib": "0.2.0", - "buffer": "4.9.1", - "console-browserify": "1.1.0", - "constants-browserify": "1.0.0", - "crypto-browserify": "3.12.0", - "domain-browser": "1.2.0", - "events": "1.1.1", - "https-browserify": "1.0.0", - "os-browserify": "0.3.0", + "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": "^1.0.0", + "https-browserify": "^1.0.0", + "os-browserify": "^0.3.0", "path-browserify": "0.0.0", - "process": "0.11.10", - "punycode": "1.4.1", - "querystring-es3": "0.2.1", - "readable-stream": "2.3.6", - "stream-browserify": "2.0.1", - "stream-http": "2.8.3", - "string_decoder": "1.1.1", - "timers-browserify": "2.0.10", + "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.10.4", + "url": "^0.11.0", + "util": "^0.10.3", "vm-browserify": "0.0.4" }, "dependencies": { @@ -9469,15 +9796,16 @@ } }, "node-notifier": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/node-notifier/-/node-notifier-5.3.0.tgz", - "integrity": "sha512-AhENzCSGZnZJgBARsUjnQ7DnZbzyP+HxlVXuD0xqAnvL8q+OqtSX7lGg9e8nHzwXkMMXNdVeqq4E2M3EUAqX6Q==", + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/node-notifier/-/node-notifier-5.4.0.tgz", + "integrity": "sha512-SUDEb+o71XR5lXSTyivXd9J7fCloE3SyP4lSgt3lU2oSANiox+SxlNRGPjDKrwU1YN3ix2KN/VGGCg0t01rttQ==", "dev": true, "requires": { - "growly": "1.3.0", - "semver": "5.6.0", - "shellwords": "0.1.1", - "which": "1.3.1" + "growly": "^1.3.0", + "is-wsl": "^1.1.0", + "semver": "^5.5.0", + "shellwords": "^0.1.1", + "which": "^1.3.0" } }, "node-releases": { @@ -9486,7 +9814,7 @@ "integrity": "sha1-NBTthFlQlkWcJRaZv8tH2IMkqeQ=", "dev": true, "requires": { - "semver": "5.6.0" + "semver": "^5.3.0" } }, "nopt": { @@ -9495,8 +9823,8 @@ "integrity": "sha1-0NRoWv1UFRk8jHUFYC0NF81kR00=", "dev": true, "requires": { - "abbrev": "1.1.1", - "osenv": "0.1.5" + "abbrev": "1", + "osenv": "^0.1.4" } }, "normalize-package-data": { @@ -9505,10 +9833,10 @@ "integrity": "sha1-EvlaMH1YNSB1oEkHuErIvpisAS8=", "dev": true, "requires": { - "hosted-git-info": "2.7.1", - "is-builtin-module": "1.0.0", - "semver": "5.6.0", - "validate-npm-package-license": "3.0.4" + "hosted-git-info": "^2.1.4", + "is-builtin-module": "^1.0.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" } }, "normalize-path": { @@ -9517,7 +9845,7 @@ "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", "dev": true, "requires": { - "remove-trailing-separator": "1.1.0" + "remove-trailing-separator": "^1.0.1" } }, "normalize-range": { @@ -9538,7 +9866,7 @@ "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", "dev": true, "requires": { - "path-key": "2.0.1" + "path-key": "^2.0.0" } }, "nth-check": { @@ -9547,7 +9875,7 @@ "integrity": "sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg==", "dev": true, "requires": { - "boolbase": "1.0.0" + "boolbase": "~1.0.0" } }, "num2fraction": { @@ -9563,9 +9891,9 @@ "dev": true }, "nwsapi": { - "version": "2.0.9", - "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.0.9.tgz", - "integrity": "sha512-nlWFSCTYQcHk/6A9FFnfhKc14c3aFhfdNBXgo8Qgi9QTBu/qg3Ww+Uiz9wMzXd1T8GFxPc2QIHB6Qtf2XFryFQ==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.1.0.tgz", + "integrity": "sha512-ZG3bLAvdHmhIjaQ/Db1qvBxsGvFMLIRpQszyqbg31VJ53UP++uZX1/gf3Ut96pdwN9AuDwlMqIYLm0UPCdUeHg==", "dev": true }, "oauth-sign": { @@ -9580,15 +9908,20 @@ "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", "dev": true }, + "object-component": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/object-component/-/object-component-0.0.3.tgz", + "integrity": "sha1-8MaapQ78lbhmwYb0AKM3acsvEpE=" + }, "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.1", - "define-property": "0.2.5", - "kind-of": "3.2.2" + "copy-descriptor": "^0.1.0", + "define-property": "^0.2.5", + "kind-of": "^3.0.3" }, "dependencies": { "define-property": { @@ -9597,7 +9930,7 @@ "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", "dev": true, "requires": { - "is-descriptor": "0.1.6" + "is-descriptor": "^0.1.0" } }, "kind-of": { @@ -9606,7 +9939,7 @@ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "requires": { - "is-buffer": "1.1.6" + "is-buffer": "^1.1.5" } } } @@ -9629,7 +9962,7 @@ "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", "dev": true, "requires": { - "isobject": "3.0.1" + "isobject": "^3.0.0" } }, "object.assign": { @@ -9638,10 +9971,10 @@ "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", "dev": true, "requires": { - "define-properties": "1.1.3", - "function-bind": "1.1.1", - "has-symbols": "1.0.0", - "object-keys": "1.0.12" + "define-properties": "^1.1.2", + "function-bind": "^1.1.1", + "has-symbols": "^1.0.0", + "object-keys": "^1.0.11" } }, "object.getownpropertydescriptors": { @@ -9650,8 +9983,8 @@ "integrity": "sha1-h1jIRvW0B62rDyNuCYbxSwUcqhY=", "dev": true, "requires": { - "define-properties": "1.1.3", - "es-abstract": "1.12.0" + "define-properties": "^1.1.2", + "es-abstract": "^1.5.1" } }, "object.omit": { @@ -9660,8 +9993,8 @@ "integrity": "sha1-Gpx0SCnznbuFjHbKNXmuKlTr0fo=", "dev": true, "requires": { - "for-own": "0.1.5", - "is-extendable": "0.1.1" + "for-own": "^0.1.4", + "is-extendable": "^0.1.1" } }, "object.pick": { @@ -9670,7 +10003,7 @@ "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", "dev": true, "requires": { - "isobject": "3.0.1" + "isobject": "^3.0.1" } }, "object.values": { @@ -9679,10 +10012,10 @@ "integrity": "sha1-5STaCbT2b/Bd9FdUbscqyZ8TBpo=", "dev": true, "requires": { - "define-properties": "1.1.3", - "es-abstract": "1.12.0", - "function-bind": "1.1.1", - "has": "1.0.3" + "define-properties": "^1.1.2", + "es-abstract": "^1.6.1", + "function-bind": "^1.1.0", + "has": "^1.0.1" } }, "obuf": { @@ -9712,7 +10045,7 @@ "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", "dev": true, "requires": { - "wrappy": "1.0.2" + "wrappy": "1" } }, "onetime": { @@ -9721,7 +10054,7 @@ "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", "dev": true, "requires": { - "mimic-fn": "1.2.0" + "mimic-fn": "^1.0.0" } }, "opener": { @@ -9736,7 +10069,7 @@ "integrity": "sha1-y1Reeqt4VivrEao7+rxwQuF2EDU=", "dev": true, "requires": { - "is-wsl": "1.1.0" + "is-wsl": "^1.1.0" } }, "optimist": { @@ -9745,8 +10078,8 @@ "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=", "dev": true, "requires": { - "minimist": "0.0.10", - "wordwrap": "0.0.3" + "minimist": "~0.0.1", + "wordwrap": "~0.0.2" }, "dependencies": { "minimist": { @@ -9769,12 +10102,12 @@ "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=", "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", - "wordwrap": "1.0.0" + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.4", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "wordwrap": "~1.0.0" } }, "ora": { @@ -9783,12 +10116,12 @@ "integrity": "sha1-bK8oMOuSSUGGHsU6FzeZ4Ai1Hls=", "dev": true, "requires": { - "chalk": "2.4.1", - "cli-cursor": "2.1.0", - "cli-spinners": "1.3.1", - "log-symbols": "2.2.0", - "strip-ansi": "4.0.0", - "wcwidth": "1.0.1" + "chalk": "^2.3.1", + "cli-cursor": "^2.1.0", + "cli-spinners": "^1.1.0", + "log-symbols": "^2.2.0", + "strip-ansi": "^4.0.0", + "wcwidth": "^1.0.1" } }, "original": { @@ -9797,7 +10130,7 @@ "integrity": "sha512-hyBVl6iqqUOJ8FqRe+l/gS8H+kKYjrEndd5Pm1MfBtsEKA038HkkdbAl/72EAXGyonD/PFsvmVG+EvcIpliMBg==", "dev": true, "requires": { - "url-parse": "1.4.4" + "url-parse": "^1.4.3" } }, "os-browserify": { @@ -9818,9 +10151,9 @@ "integrity": "sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q==", "dev": true, "requires": { - "execa": "1.0.0", - "lcid": "2.0.0", - "mem": "4.0.0" + "execa": "^1.0.0", + "lcid": "^2.0.0", + "mem": "^4.0.0" } }, "os-tmpdir": { @@ -9835,8 +10168,8 @@ "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", "dev": true, "requires": { - "os-homedir": "1.0.2", - "os-tmpdir": "1.0.2" + "os-homedir": "^1.0.0", + "os-tmpdir": "^1.0.0" } }, "p-defer": { @@ -9863,7 +10196,7 @@ "integrity": "sha1-uGvV8MJWkJEcdZD8v8IBDVSzzLg=", "dev": true, "requires": { - "p-try": "1.0.0" + "p-try": "^1.0.0" } }, "p-locate": { @@ -9872,7 +10205,7 @@ "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", "dev": true, "requires": { - "p-limit": "1.3.0" + "p-limit": "^1.1.0" } }, "p-map": { @@ -9904,9 +10237,9 @@ "integrity": "sha1-1BDwZbBdojCB/NEPKIVMKb2jOwY=", "dev": true, "requires": { - "cyclist": "0.2.2", - "inherits": "2.0.3", - "readable-stream": "2.3.6" + "cyclist": "~0.2.2", + "inherits": "^2.0.3", + "readable-stream": "^2.1.5" } }, "param-case": { @@ -9915,7 +10248,7 @@ "integrity": "sha1-35T9jPZTHs915r75oIWPvHK+Ikc=", "dev": true, "requires": { - "no-case": "2.3.2" + "no-case": "^2.2.0" } }, "parse-asn1": { @@ -9924,11 +10257,11 @@ "integrity": "sha512-KPx7flKXg775zZpnp9SxJlz00gTd4BmJ2yJufSc44gMCRrRQ7NSzAcSJQfifuOLgW6bEi+ftrALtsgALeB2Adw==", "dev": true, "requires": { - "asn1.js": "4.10.1", - "browserify-aes": "1.2.0", - "create-hash": "1.2.0", - "evp_bytestokey": "1.0.3", - "pbkdf2": "3.0.17" + "asn1.js": "^4.0.0", + "browserify-aes": "^1.0.0", + "create-hash": "^1.1.0", + "evp_bytestokey": "^1.0.0", + "pbkdf2": "^3.0.3" } }, "parse-glob": { @@ -9937,10 +10270,10 @@ "integrity": "sha1-ssN2z7EfNVE7rdFz7wu246OIORw=", "dev": true, "requires": { - "glob-base": "0.3.0", - "is-dotfile": "1.0.3", - "is-extglob": "1.0.0", - "is-glob": "2.0.1" + "glob-base": "^0.3.0", + "is-dotfile": "^1.0.0", + "is-extglob": "^1.0.0", + "is-glob": "^2.0.0" }, "dependencies": { "is-extglob": { @@ -9955,7 +10288,7 @@ "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", "dev": true, "requires": { - "is-extglob": "1.0.0" + "is-extglob": "^1.0.0" } } } @@ -9966,8 +10299,8 @@ "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", "dev": true, "requires": { - "error-ex": "1.3.2", - "json-parse-better-errors": "1.0.2" + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" } }, "parse5": { @@ -9976,6 +10309,22 @@ "integrity": "sha512-VrZ7eOd3T1Fk4XWNXMgiGBK/z0MG48BWG2uQNU4I72fkQuKUTZpl+u9k+CxEG0twMVzSmXEEz12z5Fnw1jIQFA==", "dev": true }, + "parseqs": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/parseqs/-/parseqs-0.0.5.tgz", + "integrity": "sha1-1SCKNzjkZ2bikbouoXNoSSGouJ0=", + "requires": { + "better-assert": "~1.0.0" + } + }, + "parseuri": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/parseuri/-/parseuri-0.0.5.tgz", + "integrity": "sha1-gCBKUNTbt3m/3G6+J3jZDkvOMgo=", + "requires": { + "better-assert": "~1.0.0" + } + }, "parseurl": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.2.tgz", @@ -10042,7 +10391,7 @@ "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", "dev": true, "requires": { - "pify": "3.0.0" + "pify": "^3.0.0" } }, "pbkdf2": { @@ -10051,11 +10400,11 @@ "integrity": "sha512-U/il5MsrZp7mGg3mSQfn742na2T+1/vHDCG5/iTI3X9MKUuYUZVLQhyRsg06mCgDBTd57TxzgZt7P+fYfjRLtA==", "dev": true, "requires": { - "create-hash": "1.2.0", - "create-hmac": "1.1.7", - "ripemd160": "2.0.2", - "safe-buffer": "5.1.2", - "sha.js": "2.4.11" + "create-hash": "^1.1.2", + "create-hmac": "^1.1.4", + "ripemd160": "^2.0.1", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" } }, "performance-now": { @@ -10082,7 +10431,7 @@ "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", "dev": true, "requires": { - "pinkie": "2.0.4" + "pinkie": "^2.0.0" } }, "pkg-dir": { @@ -10091,7 +10440,7 @@ "integrity": "sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s=", "dev": true, "requires": { - "find-up": "2.1.0" + "find-up": "^2.1.0" } }, "pluralize": { @@ -10117,9 +10466,9 @@ "integrity": "sha1-B+h5FKVSQtzaW4M9QvAY1odbWV8=", "dev": true, "requires": { - "async": "1.5.2", - "debug": "2.6.9", - "mkdirp": "0.5.1" + "async": "^1.5.2", + "debug": "^2.2.0", + "mkdirp": "0.5.x" }, "dependencies": { "debug": { @@ -10145,9 +10494,9 @@ "integrity": "sha1-cOZEPjam1SCw/U51k/zKNjXun1U=", "dev": true, "requires": { - "chalk": "2.4.1", - "source-map": "0.6.1", - "supports-color": "5.5.0" + "chalk": "^2.4.1", + "source-map": "^0.6.1", + "supports-color": "^5.5.0" }, "dependencies": { "source-map": { @@ -10164,10 +10513,10 @@ "integrity": "sha512-oXqx0m6tb4N3JGdmeMSc/i91KppbYsFZKdH0xMOqK8V1rJlzrKlTdokz8ozUXLVejydRN6u2IddxpcijRj2FqQ==", "dev": true, "requires": { - "css-unit-converter": "1.1.1", - "postcss": "7.0.5", - "postcss-selector-parser": "5.0.0-rc.4", - "postcss-value-parser": "3.3.1" + "css-unit-converter": "^1.1.1", + "postcss": "^7.0.5", + "postcss-selector-parser": "^5.0.0-rc.4", + "postcss-value-parser": "^3.3.1" } }, "postcss-colormin": { @@ -10176,11 +10525,11 @@ "integrity": "sha512-1QJc2coIehnVFsz0otges8kQLsryi4lo19WD+U5xCWvXd0uw/Z+KKYnbiNDCnO9GP+PvErPHCG0jNvWTngk9Rw==", "dev": true, "requires": { - "browserslist": "4.3.4", - "color": "3.1.0", - "has": "1.0.3", - "postcss": "7.0.5", - "postcss-value-parser": "3.3.1" + "browserslist": "^4.0.0", + "color": "^3.0.0", + "has": "^1.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" } }, "postcss-convert-values": { @@ -10189,8 +10538,8 @@ "integrity": "sha512-Kisdo1y77KUC0Jmn0OXU/COOJbzM8cImvw1ZFsBgBgMgb1iL23Zs/LXRe3r+EZqM3vGYKdQ2YJVQ5VkJI+zEJQ==", "dev": true, "requires": { - "postcss": "7.0.5", - "postcss-value-parser": "3.3.1" + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" } }, "postcss-discard-comments": { @@ -10199,7 +10548,7 @@ "integrity": "sha512-Ay+rZu1Sz6g8IdzRjUgG2NafSNpp2MSMOQUb+9kkzzzP+kh07fP0yNbhtFejURnyVXSX3FYy2nVNW1QTnNjgBQ==", "dev": true, "requires": { - "postcss": "7.0.5" + "postcss": "^7.0.0" } }, "postcss-discard-duplicates": { @@ -10208,7 +10557,7 @@ "integrity": "sha512-ZNQfR1gPNAiXZhgENFfEglF93pciw0WxMkJeVmw8eF+JZBbMD7jp6C67GqJAXVZP2BWbOztKfbsdmMp/k8c6oQ==", "dev": true, "requires": { - "postcss": "7.0.5" + "postcss": "^7.0.0" } }, "postcss-discard-empty": { @@ -10217,7 +10566,7 @@ "integrity": "sha512-B9miTzbznhDjTfjvipfHoqbWKwd0Mj+/fL5s1QOz06wufguil+Xheo4XpOnc4NqKYBCNqqEzgPv2aPBIJLox0w==", "dev": true, "requires": { - "postcss": "7.0.5" + "postcss": "^7.0.0" } }, "postcss-discard-overridden": { @@ -10226,7 +10575,7 @@ "integrity": "sha512-IYY2bEDD7g1XM1IDEsUT4//iEYCxAmP5oDSFMVU/JVvT7gh+l4fmjciLqGgwjdWpQIdb0Che2VX00QObS5+cTg==", "dev": true, "requires": { - "postcss": "7.0.5" + "postcss": "^7.0.0" } }, "postcss-load-config": { @@ -10235,8 +10584,8 @@ "integrity": "sha512-V5JBLzw406BB8UIfsAWSK2KSwIJ5yoEIVFb4gVkXci0QdKgA24jLmHZ/ghe/GgX0lJ0/D1uUK1ejhzEY94MChQ==", "dev": true, "requires": { - "cosmiconfig": "4.0.0", - "import-cwd": "2.1.0" + "cosmiconfig": "^4.0.0", + "import-cwd": "^2.0.0" }, "dependencies": { "cosmiconfig": { @@ -10245,10 +10594,10 @@ "integrity": "sha512-6e5vDdrXZD+t5v0L8CrurPeybg4Fmf+FCSYxXKYVAqLUtyCSbuyqE059d0kDthTNRzKVjL7QMgNpEUlsoYH3iQ==", "dev": true, "requires": { - "is-directory": "0.3.1", - "js-yaml": "3.12.0", - "parse-json": "4.0.0", - "require-from-string": "2.0.2" + "is-directory": "^0.3.1", + "js-yaml": "^3.9.0", + "parse-json": "^4.0.0", + "require-from-string": "^2.0.1" } } } @@ -10259,10 +10608,10 @@ "integrity": "sha512-cLWoDEY5OwHcAjDnkyRQzAXfs2jrKjXpO/HQFcc5b5u/r7aa471wdmChmwfnv7x2u840iat/wi0lQ5nbRgSkUA==", "dev": true, "requires": { - "loader-utils": "1.1.0", - "postcss": "7.0.5", - "postcss-load-config": "2.0.0", - "schema-utils": "1.0.0" + "loader-utils": "^1.1.0", + "postcss": "^7.0.0", + "postcss-load-config": "^2.0.0", + "schema-utils": "^1.0.0" }, "dependencies": { "ajv-keywords": { @@ -10277,9 +10626,9 @@ "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", "dev": true, "requires": { - "ajv": "6.5.5", - "ajv-errors": "1.0.0", - "ajv-keywords": "3.2.0" + "ajv": "^6.1.0", + "ajv-errors": "^1.0.0", + "ajv-keywords": "^3.1.0" } } } @@ -10291,9 +10640,9 @@ "dev": true, "requires": { "css-color-names": "0.0.4", - "postcss": "7.0.5", - "postcss-value-parser": "3.3.1", - "stylehacks": "4.0.1" + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0", + "stylehacks": "^4.0.0" } }, "postcss-merge-rules": { @@ -10302,12 +10651,12 @@ "integrity": "sha512-UiuXwCCJtQy9tAIxsnurfF0mrNHKc4NnNx6NxqmzNNjXpQwLSukUxELHTRF0Rg1pAmcoKLih8PwvZbiordchag==", "dev": true, "requires": { - "browserslist": "4.3.4", - "caniuse-api": "3.0.0", - "cssnano-util-same-parent": "4.0.1", - "postcss": "7.0.5", - "postcss-selector-parser": "3.1.1", - "vendors": "1.0.2" + "browserslist": "^4.0.0", + "caniuse-api": "^3.0.0", + "cssnano-util-same-parent": "^4.0.0", + "postcss": "^7.0.0", + "postcss-selector-parser": "^3.0.0", + "vendors": "^1.0.0" }, "dependencies": { "postcss-selector-parser": { @@ -10316,9 +10665,9 @@ "integrity": "sha1-T4dfSvsMllc9XPTXQBGu4lCn6GU=", "dev": true, "requires": { - "dot-prop": "4.2.0", - "indexes-of": "1.0.1", - "uniq": "1.0.1" + "dot-prop": "^4.1.1", + "indexes-of": "^1.0.1", + "uniq": "^1.0.1" } } } @@ -10329,8 +10678,8 @@ "integrity": "sha512-j85oO6OnRU9zPf04+PZv1LYIYOprWm6IA6zkXkrJXyRveDEuQggG6tvoy8ir8ZwjLxLuGfNkCZEQG7zan+Hbtg==", "dev": true, "requires": { - "postcss": "7.0.5", - "postcss-value-parser": "3.3.1" + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" } }, "postcss-minify-gradients": { @@ -10339,10 +10688,10 @@ "integrity": "sha512-pySEW3E6Ly5mHm18rekbWiAjVi/Wj8KKt2vwSfVFAWdW6wOIekgqxKxLU7vJfb107o3FDNPkaYFCxGAJBFyogA==", "dev": true, "requires": { - "cssnano-util-get-arguments": "4.0.0", - "is-color-stop": "1.1.0", - "postcss": "7.0.5", - "postcss-value-parser": "3.3.1" + "cssnano-util-get-arguments": "^4.0.0", + "is-color-stop": "^1.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" } }, "postcss-minify-params": { @@ -10351,12 +10700,12 @@ "integrity": "sha512-h4W0FEMEzBLxpxIVelRtMheskOKKp52ND6rJv+nBS33G1twu2tCyurYj/YtgU76+UDCvWeNs0hs8HFAWE2OUFg==", "dev": true, "requires": { - "alphanum-sort": "1.0.2", - "browserslist": "4.3.4", - "cssnano-util-get-arguments": "4.0.0", - "postcss": "7.0.5", - "postcss-value-parser": "3.3.1", - "uniqs": "2.0.0" + "alphanum-sort": "^1.0.0", + "browserslist": "^4.0.0", + "cssnano-util-get-arguments": "^4.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0", + "uniqs": "^2.0.0" } }, "postcss-minify-selectors": { @@ -10365,10 +10714,10 @@ "integrity": "sha512-8+plQkomve3G+CodLCgbhAKrb5lekAnLYuL1d7Nz+/7RANpBEVdgBkPNwljfSKvZ9xkkZTZITd04KP+zeJTJqg==", "dev": true, "requires": { - "alphanum-sort": "1.0.2", - "has": "1.0.3", - "postcss": "7.0.5", - "postcss-selector-parser": "3.1.1" + "alphanum-sort": "^1.0.0", + "has": "^1.0.0", + "postcss": "^7.0.0", + "postcss-selector-parser": "^3.0.0" }, "dependencies": { "postcss-selector-parser": { @@ -10377,9 +10726,9 @@ "integrity": "sha1-T4dfSvsMllc9XPTXQBGu4lCn6GU=", "dev": true, "requires": { - "dot-prop": "4.2.0", - "indexes-of": "1.0.1", - "uniq": "1.0.1" + "dot-prop": "^4.1.1", + "indexes-of": "^1.0.1", + "uniq": "^1.0.1" } } } @@ -10390,7 +10739,7 @@ "integrity": "sha512-6jt9XZwUhwmRUhb/CkyJY020PYaPJsCyt3UjbaWo6XEbH/94Hmv6MP7fG2C5NDU/BcHzyGYxNtHvM+LTf9HrYw==", "dev": true, "requires": { - "postcss": "6.0.23" + "postcss": "^6.0.1" }, "dependencies": { "postcss": { @@ -10399,9 +10748,9 @@ "integrity": "sha512-soOk1h6J3VMTZtVeVpv15/Hpdl2cBLX3CAw4TAbkpTJiNPk9YP/zWcD1ND+xEtvyuuvKzbxliTOIyvkSeSJ6ag==", "dev": true, "requires": { - "chalk": "2.4.1", - "source-map": "0.6.1", - "supports-color": "5.5.0" + "chalk": "^2.4.1", + "source-map": "^0.6.1", + "supports-color": "^5.4.0" } }, "source-map": { @@ -10418,8 +10767,8 @@ "integrity": "sha1-99gMOYxaOT+nlkRmvRlQCn1hwGk=", "dev": true, "requires": { - "css-selector-tokenizer": "0.7.1", - "postcss": "6.0.23" + "css-selector-tokenizer": "^0.7.0", + "postcss": "^6.0.1" }, "dependencies": { "postcss": { @@ -10428,9 +10777,9 @@ "integrity": "sha512-soOk1h6J3VMTZtVeVpv15/Hpdl2cBLX3CAw4TAbkpTJiNPk9YP/zWcD1ND+xEtvyuuvKzbxliTOIyvkSeSJ6ag==", "dev": true, "requires": { - "chalk": "2.4.1", - "source-map": "0.6.1", - "supports-color": "5.5.0" + "chalk": "^2.4.1", + "source-map": "^0.6.1", + "supports-color": "^5.4.0" } }, "source-map": { @@ -10447,8 +10796,8 @@ "integrity": "sha1-1upkmUx5+XtipytCb75gVqGUu5A=", "dev": true, "requires": { - "css-selector-tokenizer": "0.7.1", - "postcss": "6.0.23" + "css-selector-tokenizer": "^0.7.0", + "postcss": "^6.0.1" }, "dependencies": { "postcss": { @@ -10457,9 +10806,9 @@ "integrity": "sha512-soOk1h6J3VMTZtVeVpv15/Hpdl2cBLX3CAw4TAbkpTJiNPk9YP/zWcD1ND+xEtvyuuvKzbxliTOIyvkSeSJ6ag==", "dev": true, "requires": { - "chalk": "2.4.1", - "source-map": "0.6.1", - "supports-color": "5.5.0" + "chalk": "^2.4.1", + "source-map": "^0.6.1", + "supports-color": "^5.4.0" } }, "source-map": { @@ -10476,8 +10825,8 @@ "integrity": "sha1-7P+p1+GSUYOJ9CrQ6D9yrsRW6iA=", "dev": true, "requires": { - "icss-replace-symbols": "1.1.0", - "postcss": "6.0.23" + "icss-replace-symbols": "^1.1.0", + "postcss": "^6.0.1" }, "dependencies": { "postcss": { @@ -10486,9 +10835,9 @@ "integrity": "sha512-soOk1h6J3VMTZtVeVpv15/Hpdl2cBLX3CAw4TAbkpTJiNPk9YP/zWcD1ND+xEtvyuuvKzbxliTOIyvkSeSJ6ag==", "dev": true, "requires": { - "chalk": "2.4.1", - "source-map": "0.6.1", - "supports-color": "5.5.0" + "chalk": "^2.4.1", + "source-map": "^0.6.1", + "supports-color": "^5.4.0" } }, "source-map": { @@ -10505,7 +10854,7 @@ "integrity": "sha512-gMXCrrlWh6G27U0hF3vNvR3w8I1s2wOBILvA87iNXaPvSNo5uZAMYsZG7XjCUf1eVxuPfyL4TJ7++SGZLc9A3g==", "dev": true, "requires": { - "postcss": "7.0.5" + "postcss": "^7.0.0" } }, "postcss-normalize-display-values": { @@ -10514,9 +10863,9 @@ "integrity": "sha512-R5mC4vaDdvsrku96yXP7zak+O3Mm9Y8IslUobk7IMP+u/g+lXvcN4jngmHY5zeJnrQvE13dfAg5ViU05ZFDwdg==", "dev": true, "requires": { - "cssnano-util-get-match": "4.0.0", - "postcss": "7.0.5", - "postcss-value-parser": "3.3.1" + "cssnano-util-get-match": "^4.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" } }, "postcss-normalize-positions": { @@ -10525,10 +10874,10 @@ "integrity": "sha512-GNoOaLRBM0gvH+ZRb2vKCIujzz4aclli64MBwDuYGU2EY53LwiP7MxOZGE46UGtotrSnmarPPZ69l2S/uxdaWA==", "dev": true, "requires": { - "cssnano-util-get-arguments": "4.0.0", - "has": "1.0.3", - "postcss": "7.0.5", - "postcss-value-parser": "3.3.1" + "cssnano-util-get-arguments": "^4.0.0", + "has": "^1.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" } }, "postcss-normalize-repeat-style": { @@ -10537,10 +10886,10 @@ "integrity": "sha512-fFHPGIjBUyUiswY2rd9rsFcC0t3oRta4wxE1h3lpwfQZwFeFjXFSiDtdJ7APCmHQOnUZnqYBADNRPKPwFAONgA==", "dev": true, "requires": { - "cssnano-util-get-arguments": "4.0.0", - "cssnano-util-get-match": "4.0.0", - "postcss": "7.0.5", - "postcss-value-parser": "3.3.1" + "cssnano-util-get-arguments": "^4.0.0", + "cssnano-util-get-match": "^4.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" } }, "postcss-normalize-string": { @@ -10549,9 +10898,9 @@ "integrity": "sha512-IJoexFTkAvAq5UZVxWXAGE0yLoNN/012v7TQh5nDo6imZJl2Fwgbhy3J2qnIoaDBrtUP0H7JrXlX1jjn2YcvCQ==", "dev": true, "requires": { - "has": "1.0.3", - "postcss": "7.0.5", - "postcss-value-parser": "3.3.1" + "has": "^1.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" } }, "postcss-normalize-timing-functions": { @@ -10560,9 +10909,9 @@ "integrity": "sha512-1nOtk7ze36+63ONWD8RCaRDYsnzorrj+Q6fxkQV+mlY5+471Qx9kspqv0O/qQNMeApg8KNrRf496zHwJ3tBZ7w==", "dev": true, "requires": { - "cssnano-util-get-match": "4.0.0", - "postcss": "7.0.5", - "postcss-value-parser": "3.3.1" + "cssnano-util-get-match": "^4.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" } }, "postcss-normalize-unicode": { @@ -10571,9 +10920,9 @@ "integrity": "sha512-od18Uq2wCYn+vZ/qCOeutvHjB5jm57ToxRaMeNuf0nWVHaP9Hua56QyMF6fs/4FSUnVIw0CBPsU0K4LnBPwYwg==", "dev": true, "requires": { - "browserslist": "4.3.4", - "postcss": "7.0.5", - "postcss-value-parser": "3.3.1" + "browserslist": "^4.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" } }, "postcss-normalize-url": { @@ -10582,10 +10931,10 @@ "integrity": "sha512-p5oVaF4+IHwu7VpMan/SSpmpYxcJMtkGppYf0VbdH5B6hN8YNmVyJLuY9FmLQTzY3fag5ESUUHDqM+heid0UVA==", "dev": true, "requires": { - "is-absolute-url": "2.1.0", - "normalize-url": "3.3.0", - "postcss": "7.0.5", - "postcss-value-parser": "3.3.1" + "is-absolute-url": "^2.0.0", + "normalize-url": "^3.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" } }, "postcss-normalize-whitespace": { @@ -10594,8 +10943,8 @@ "integrity": "sha512-U8MBODMB2L+nStzOk6VvWWjZgi5kQNShCyjRhMT3s+W9Jw93yIjOnrEkKYD3Ul7ChWbEcjDWmXq0qOL9MIAnAw==", "dev": true, "requires": { - "postcss": "7.0.5", - "postcss-value-parser": "3.3.1" + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" } }, "postcss-ordered-values": { @@ -10604,9 +10953,9 @@ "integrity": "sha512-PeJiLgJWPzkVF8JuKSBcylaU+hDJ/TX3zqAMIjlghgn1JBi6QwQaDZoDIlqWRcCAI8SxKrt3FCPSRmOgKRB97Q==", "dev": true, "requires": { - "cssnano-util-get-arguments": "4.0.0", - "postcss": "7.0.5", - "postcss-value-parser": "3.3.1" + "cssnano-util-get-arguments": "^4.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" } }, "postcss-reduce-initial": { @@ -10615,10 +10964,10 @@ "integrity": "sha512-epUiC39NonKUKG+P3eAOKKZtm5OtAtQJL7Ye0CBN1f+UQTHzqotudp+hki7zxXm7tT0ZAKDMBj1uihpPjP25ug==", "dev": true, "requires": { - "browserslist": "4.3.4", - "caniuse-api": "3.0.0", - "has": "1.0.3", - "postcss": "7.0.5" + "browserslist": "^4.0.0", + "caniuse-api": "^3.0.0", + "has": "^1.0.0", + "postcss": "^7.0.0" } }, "postcss-reduce-transforms": { @@ -10627,10 +10976,10 @@ "integrity": "sha512-sZVr3QlGs0pjh6JAIe6DzWvBaqYw05V1t3d9Tp+VnFRT5j+rsqoWsysh/iSD7YNsULjq9IAylCznIwVd5oU/zA==", "dev": true, "requires": { - "cssnano-util-get-match": "4.0.0", - "has": "1.0.3", - "postcss": "7.0.5", - "postcss-value-parser": "3.3.1" + "cssnano-util-get-match": "^4.0.0", + "has": "^1.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" } }, "postcss-selector-parser": { @@ -10639,9 +10988,9 @@ "integrity": "sha1-yl53I4vxUpZjeME+ka1tYRVo6oc=", "dev": true, "requires": { - "cssesc": "2.0.0", - "indexes-of": "1.0.1", - "uniq": "1.0.1" + "cssesc": "^2.0.0", + "indexes-of": "^1.0.1", + "uniq": "^1.0.1" } }, "postcss-svgo": { @@ -10650,10 +10999,10 @@ "integrity": "sha512-YD5uIk5NDRySy0hcI+ZJHwqemv2WiqqzDgtvgMzO8EGSkK5aONyX8HMVFRFJSdO8wUWTuisUFn/d7yRRbBr5Qw==", "dev": true, "requires": { - "is-svg": "3.0.0", - "postcss": "7.0.5", - "postcss-value-parser": "3.3.1", - "svgo": "1.1.1" + "is-svg": "^3.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0", + "svgo": "^1.0.0" } }, "postcss-unique-selectors": { @@ -10662,9 +11011,9 @@ "integrity": "sha512-+JanVaryLo9QwZjKrmJgkI4Fn8SBgRO6WXQBJi7KiAVPlmxikB5Jzc4EvXMT2H0/m0RjrVVm9rGNhZddm/8Spg==", "dev": true, "requires": { - "alphanum-sort": "1.0.2", - "postcss": "7.0.5", - "uniqs": "2.0.0" + "alphanum-sort": "^1.0.0", + "postcss": "^7.0.0", + "uniqs": "^2.0.0" } }, "postcss-value-parser": { @@ -10697,7 +11046,7 @@ "integrity": "sha1-0j1B/hN1ZG3i0BBNNFSjAIgCz3s=", "dev": true, "requires": { - "fast-diff": "1.2.0" + "fast-diff": "^1.1.2" } }, "pretty": { @@ -10706,9 +11055,9 @@ "integrity": "sha1-rbx5YLe7/iiaVX3F9zdhmiINBqU=", "dev": true, "requires": { - "condense-newlines": "0.2.1", - "extend-shallow": "2.0.1", - "js-beautify": "1.8.9" + "condense-newlines": "^0.2.1", + "extend-shallow": "^2.0.1", + "js-beautify": "^1.6.12" }, "dependencies": { "extend-shallow": { @@ -10717,7 +11066,7 @@ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, "requires": { - "is-extendable": "0.1.1" + "is-extendable": "^0.1.0" } } } @@ -10728,8 +11077,8 @@ "integrity": "sha1-X0+HyPkeWuPzuoerTPXgOxoX8aM=", "dev": true, "requires": { - "renderkid": "2.0.2", - "utila": "0.4.0" + "renderkid": "^2.0.1", + "utila": "~0.4" } }, "pretty-format": { @@ -10738,8 +11087,8 @@ "integrity": "sha512-zf9NV1NSlDLDjycnwm6hpFATCGl/K1lt0R/GdkAK2O5LN/rwJoB+Mh93gGJjut4YbmecbfgLWVGSTCr0Ewvvbw==", "dev": true, "requires": { - "ansi-regex": "3.0.0", - "ansi-styles": "3.2.1" + "ansi-regex": "^3.0.0", + "ansi-styles": "^3.2.0" } }, "private": { @@ -10778,8 +11127,8 @@ "integrity": "sha512-rxkyiE9YH6zAz/rZpywySLKkpaj0NMVyNw1qhsubdbjjSgcayjTShDreZGlFMcGSu5sab3bAKPfFk78PB90+8w==", "dev": true, "requires": { - "kleur": "2.0.2", - "sisteransi": "0.1.1" + "kleur": "^2.0.1", + "sisteransi": "^0.1.1" } }, "proto-list": { @@ -10794,7 +11143,7 @@ "integrity": "sha512-5erio2h9jp5CHGwcybmxmVqHmnCBZeewlfJ0pex+UW7Qny7OOZXTtH56TGNyBizkgiOwhJtMKrVzDTeKcySZwA==", "dev": true, "requires": { - "forwarded": "0.1.2", + "forwarded": "~0.1.2", "ipaddr.js": "1.8.0" } }, @@ -10822,12 +11171,12 @@ "integrity": "sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==", "dev": true, "requires": { - "bn.js": "4.11.8", - "browserify-rsa": "4.0.1", - "create-hash": "1.2.0", - "parse-asn1": "5.1.1", - "randombytes": "2.0.6", - "safe-buffer": "5.1.2" + "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": { @@ -10836,8 +11185,8 @@ "integrity": "sha1-tKIRaBW94vTh6mAjVOjHVWUQemQ=", "dev": true, "requires": { - "end-of-stream": "1.4.1", - "once": "1.4.0" + "end-of-stream": "^1.1.0", + "once": "^1.3.1" } }, "pumpify": { @@ -10846,9 +11195,9 @@ "integrity": "sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==", "dev": true, "requires": { - "duplexify": "3.6.1", - "inherits": "2.0.3", - "pump": "2.0.1" + "duplexify": "^3.6.0", + "inherits": "^2.0.3", + "pump": "^2.0.0" }, "dependencies": { "pump": { @@ -10857,8 +11206,8 @@ "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==", "dev": true, "requires": { - "end-of-stream": "1.4.1", - "once": "1.4.0" + "end-of-stream": "^1.1.0", + "once": "^1.3.1" } } } @@ -10905,9 +11254,9 @@ "integrity": "sha512-TuDE5KxZ0J461RVjrJZCJc+J+zCkTb1MbH9AQUq68sMhOMcy9jLcb3BrZKgp9q9Ncltdg4QVqWrH02W2EFFVYw==", "dev": true, "requires": { - "is-number": "4.0.0", - "kind-of": "6.0.2", - "math-random": "1.0.1" + "is-number": "^4.0.0", + "kind-of": "^6.0.0", + "math-random": "^1.0.1" }, "dependencies": { "is-number": { @@ -10924,7 +11273,7 @@ "integrity": "sha512-CIQ5OFxf4Jou6uOKe9t1AOgqpeU5fd70A8NPdHSGeYXqXsPe6peOwI0cUl88RWZ6sP1vPMV3avd/R6cZ5/sP1A==", "dev": true, "requires": { - "safe-buffer": "5.1.2" + "safe-buffer": "^5.1.0" } }, "randomfill": { @@ -10933,8 +11282,8 @@ "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==", "dev": true, "requires": { - "randombytes": "2.0.6", - "safe-buffer": "5.1.2" + "randombytes": "^2.0.5", + "safe-buffer": "^5.1.0" } }, "range-parser": { @@ -10961,7 +11310,7 @@ "integrity": "sha512-neyTUVFtahjf0mB3dZT77u+8O0QB89jFdnBkd5P1JgYPbPaia3gXXOVL2fq8VyU2gMMD7SaN7QukTB/pmXYvDA==", "dev": true, "requires": { - "safer-buffer": "2.1.2" + "safer-buffer": ">= 2.1.2 < 3" } } } @@ -10972,9 +11321,9 @@ "integrity": "sha1-ljYlN48+HE1IyFhytabsfV0JMjc=", "dev": true, "requires": { - "normalize-package-data": "2.4.0", - "parse-json": "4.0.0", - "pify": "3.0.0" + "normalize-package-data": "^2.3.2", + "parse-json": "^4.0.0", + "pify": "^3.0.0" } }, "read-pkg-up": { @@ -10983,8 +11332,8 @@ "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=", "dev": true, "requires": { - "find-up": "1.1.2", - "read-pkg": "1.1.0" + "find-up": "^1.0.0", + "read-pkg": "^1.0.0" }, "dependencies": { "find-up": { @@ -10993,8 +11342,8 @@ "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", "dev": true, "requires": { - "path-exists": "2.1.0", - "pinkie-promise": "2.0.1" + "path-exists": "^2.0.0", + "pinkie-promise": "^2.0.0" } }, "path-exists": { @@ -11003,7 +11352,7 @@ "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", "dev": true, "requires": { - "pinkie-promise": "2.0.1" + "pinkie-promise": "^2.0.0" } }, "path-type": { @@ -11012,9 +11361,9 @@ "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=", "dev": true, "requires": { - "graceful-fs": "4.1.15", - "pify": "2.3.0", - "pinkie-promise": "2.0.1" + "graceful-fs": "^4.1.2", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0" } }, "pify": { @@ -11029,9 +11378,9 @@ "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=", "dev": true, "requires": { - "load-json-file": "1.1.0", - "normalize-package-data": "2.4.0", - "path-type": "1.1.0" + "load-json-file": "^1.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^1.0.0" } } } @@ -11042,13 +11391,13 @@ "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "dev": true, "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.3", - "isarray": "1.0.0", - "process-nextick-args": "2.0.0", - "safe-buffer": "5.1.2", - "string_decoder": "1.1.1", - "util-deprecate": "1.0.2" + "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": { @@ -11057,18 +11406,18 @@ "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", "dev": true, "requires": { - "graceful-fs": "4.1.15", - "micromatch": "3.1.10", - "readable-stream": "2.3.6" + "graceful-fs": "^4.1.11", + "micromatch": "^3.1.10", + "readable-stream": "^2.0.2" } }, "realpath-native": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/realpath-native/-/realpath-native-1.0.2.tgz", - "integrity": "sha512-+S3zTvVt9yTntFrBpm7TQmQ3tzpCrnA1a/y+3cUHAc9ZR6aIjG0WNLR+Rj79QpJktY+VeW/TQtFlQ1bzsehI8g==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/realpath-native/-/realpath-native-1.1.0.tgz", + "integrity": "sha512-wlgPA6cCIIg9gKz0fgAPjnzh4yR/LnXovwuo9hvyGvx3h8nX4+/iLZplfUWasXpqD8BdnGnP5njOFjkUwPzvjA==", "dev": true, "requires": { - "util.promisify": "1.0.0" + "util.promisify": "^1.0.0" } }, "regenerate": { @@ -11083,7 +11432,7 @@ "integrity": "sha512-s5NGghCE4itSlUS+0WUj88G6cfMVMmH8boTPNvABf8od+2dhT9WDlWu8n01raQAJZMOK8Ch6jSexaRO7swd6aw==", "dev": true, "requires": { - "regenerate": "1.4.0" + "regenerate": "^1.4.0" } }, "regenerator-runtime": { @@ -11098,7 +11447,7 @@ "integrity": "sha512-5ipTrZFSq5vU2YoGoww4uaRVAK4wyYC4TSICibbfEPOruUu8FFP7ErV0BjmbIOEpn3O/k9na9UEdYR/3m7N6uA==", "dev": true, "requires": { - "private": "0.1.8" + "private": "^0.1.6" } }, "regex-cache": { @@ -11107,7 +11456,7 @@ "integrity": "sha512-nVIZwtCjkC9YgvWkpM55B5rBhBYRZhAaJbgcFYXXsHnbZ9UZI9nnVWYZpBlCqv9ho2eZryPnWrZGsOdPwVWXWQ==", "dev": true, "requires": { - "is-equal-shallow": "0.1.3" + "is-equal-shallow": "^0.1.3" } }, "regex-not": { @@ -11116,8 +11465,8 @@ "integrity": "sha1-H07OJ+ALC2XgJHpoEOaoXYOldSw=", "dev": true, "requires": { - "extend-shallow": "3.0.2", - "safe-regex": "1.1.0" + "extend-shallow": "^3.0.2", + "safe-regex": "^1.1.0" } }, "regexpp": { @@ -11132,12 +11481,12 @@ "integrity": "sha1-o3RPoDgGz/4UbepEIaPnO9zEex0=", "dev": true, "requires": { - "regenerate": "1.4.0", - "regenerate-unicode-properties": "7.0.0", - "regjsgen": "0.4.0", - "regjsparser": "0.3.0", - "unicode-match-property-ecmascript": "1.0.4", - "unicode-match-property-value-ecmascript": "1.0.2" + "regenerate": "^1.4.0", + "regenerate-unicode-properties": "^7.0.0", + "regjsgen": "^0.4.0", + "regjsparser": "^0.3.0", + "unicode-match-property-ecmascript": "^1.0.4", + "unicode-match-property-value-ecmascript": "^1.0.2" } }, "regjsgen": { @@ -11152,7 +11501,7 @@ "integrity": "sha1-PDJtp/z9afoNMyV1pByMDN9YjJY=", "dev": true, "requires": { - "jsesc": "0.5.0" + "jsesc": "~0.5.0" }, "dependencies": { "jsesc": { @@ -11181,11 +11530,11 @@ "integrity": "sha512-FsygIxevi1jSiPY9h7vZmBFUbAOcbYm9UwyiLNdVsLRs/5We9Ob5NMPbGYUTWiLq5L+ezlVdE0A8bbME5CWTpg==", "dev": true, "requires": { - "css-select": "1.2.0", - "dom-converter": "0.2.0", - "htmlparser2": "3.3.0", - "strip-ansi": "3.0.1", - "utila": "0.4.0" + "css-select": "^1.1.0", + "dom-converter": "~0.2", + "htmlparser2": "~3.3.0", + "strip-ansi": "^3.0.0", + "utila": "^0.4.0" }, "dependencies": { "ansi-regex": { @@ -11200,10 +11549,10 @@ "integrity": "sha1-KzoRBTnFNV8c2NMUYj6HCxIeyFg=", "dev": true, "requires": { - "boolbase": "1.0.0", - "css-what": "2.1.2", + "boolbase": "~1.0.0", + "css-what": "2.1", "domutils": "1.5.1", - "nth-check": "1.0.2" + "nth-check": "~1.0.1" } }, "domutils": { @@ -11212,8 +11561,8 @@ "integrity": "sha1-3NhIiib1Y9YQeeSMn3t+Mjc2gs8=", "dev": true, "requires": { - "dom-serializer": "0.1.0", - "domelementtype": "1.2.1" + "dom-serializer": "0", + "domelementtype": "1" } }, "strip-ansi": { @@ -11222,7 +11571,7 @@ "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "dev": true, "requires": { - "ansi-regex": "2.1.1" + "ansi-regex": "^2.0.0" } } } @@ -11245,7 +11594,7 @@ "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=", "dev": true, "requires": { - "is-finite": "1.0.2" + "is-finite": "^1.0.0" } }, "request": { @@ -11254,26 +11603,26 @@ "integrity": "sha1-nC/KT301tZLv5Xx/ClXoEFIST+8=", "dev": true, "requires": { - "aws-sign2": "0.7.0", - "aws4": "1.8.0", - "caseless": "0.12.0", - "combined-stream": "1.0.7", - "extend": "3.0.2", - "forever-agent": "0.6.1", - "form-data": "2.3.3", - "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.21", - "oauth-sign": "0.9.0", - "performance-now": "2.1.0", - "qs": "6.5.2", - "safe-buffer": "5.1.2", - "tough-cookie": "2.4.3", - "tunnel-agent": "0.6.0", - "uuid": "3.3.2" + "aws-sign2": "~0.7.0", + "aws4": "^1.8.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", + "forever-agent": "~0.6.1", + "form-data": "~2.3.2", + "har-validator": "~5.1.0", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.19", + "oauth-sign": "~0.9.0", + "performance-now": "^2.1.0", + "qs": "~6.5.2", + "safe-buffer": "^5.1.2", + "tough-cookie": "~2.4.3", + "tunnel-agent": "^0.6.0", + "uuid": "^3.3.2" } }, "request-promise-core": { @@ -11282,7 +11631,7 @@ "integrity": "sha1-Pu4AssWqgyOc+wTFcA2jb4HNCLY=", "dev": true, "requires": { - "lodash": "4.17.11" + "lodash": "^4.13.1" } }, "request-promise-native": { @@ -11292,8 +11641,8 @@ "dev": true, "requires": { "request-promise-core": "1.1.1", - "stealthy-require": "1.1.1", - "tough-cookie": "2.4.3" + "stealthy-require": "^1.1.0", + "tough-cookie": ">=2.3.3" } }, "require-directory": { @@ -11320,8 +11669,8 @@ "integrity": "sha1-Tg1W1slmL9MeQwEcS5WqSZVUIdM=", "dev": true, "requires": { - "caller-path": "0.1.0", - "resolve-from": "1.0.1" + "caller-path": "^0.1.0", + "resolve-from": "^1.0.0" } }, "requires-port": { @@ -11336,7 +11685,7 @@ "integrity": "sha1-gvHsGaQjrB+9CAsLqwa6NuhKeiY=", "dev": true, "requires": { - "path-parse": "1.0.6" + "path-parse": "^1.0.5" } }, "resolve-cwd": { @@ -11345,7 +11694,7 @@ "integrity": "sha1-AKn3OHVW4nA46uIyyqNypqWbZlo=", "dev": true, "requires": { - "resolve-from": "3.0.0" + "resolve-from": "^3.0.0" }, "dependencies": { "resolve-from": { @@ -11374,8 +11723,8 @@ "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", "dev": true, "requires": { - "onetime": "2.0.1", - "signal-exit": "3.0.2" + "onetime": "^2.0.0", + "signal-exit": "^3.0.2" } }, "ret": { @@ -11402,7 +11751,7 @@ "integrity": "sha1-LtgVDSShbqhlHm1u8PR8QVjOejY=", "dev": true, "requires": { - "glob": "7.1.3" + "glob": "^7.0.5" } }, "ripemd160": { @@ -11411,8 +11760,8 @@ "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", "dev": true, "requires": { - "hash-base": "3.0.4", - "inherits": "2.0.3" + "hash-base": "^3.0.0", + "inherits": "^2.0.1" } }, "rsvp": { @@ -11427,7 +11776,7 @@ "integrity": "sha1-A3GrSuC91yDUFm19/aZP96RFpsA=", "dev": true, "requires": { - "is-promise": "2.1.0" + "is-promise": "^2.1.0" } }, "run-queue": { @@ -11436,7 +11785,7 @@ "integrity": "sha1-6Eg5bwV9Ij8kOGkkYY4laUFh7Ec=", "dev": true, "requires": { - "aproba": "1.2.0" + "aproba": "^1.1.1" } }, "rx-lite": { @@ -11451,7 +11800,7 @@ "integrity": "sha1-dTuHqJoRyVRnxKwWJsTvxOBcZ74=", "dev": true, "requires": { - "rx-lite": "4.0.8" + "rx-lite": "*" } }, "rxjs": { @@ -11460,7 +11809,7 @@ "integrity": "sha512-JTWmoY9tWCs7zvIk/CvRjhjGaOd+OVBM987mxFo+OW66cGpdKjZcpmc74ES1sB//7Kl/PAe8+wEakuhG4pcgOw==", "dev": true, "requires": { - "tslib": "1.9.3" + "tslib": "^1.9.0" } }, "safe-buffer": { @@ -11475,7 +11824,7 @@ "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", "dev": true, "requires": { - "ret": "0.1.15" + "ret": "~0.1.10" } }, "safer-buffer": { @@ -11490,15 +11839,15 @@ "integrity": "sha1-tNwYYcIbQn6SlQej51HiosuKs/o=", "dev": true, "requires": { - "anymatch": "2.0.0", - "capture-exit": "1.2.0", - "exec-sh": "0.2.2", - "fb-watchman": "2.0.0", - "fsevents": "1.2.4", - "micromatch": "3.1.10", - "minimist": "1.2.0", - "walker": "1.0.7", - "watch": "0.18.0" + "anymatch": "^2.0.0", + "capture-exit": "^1.2.0", + "exec-sh": "^0.2.0", + "fb-watchman": "^2.0.0", + "fsevents": "^1.2.3", + "micromatch": "^3.1.4", + "minimist": "^1.1.1", + "walker": "~1.0.5", + "watch": "~0.18.0" } }, "sax": { @@ -11513,8 +11862,8 @@ "integrity": "sha512-v/iwU6wvwGK8HbU9yi3/nhGzP0yGSuhQMzL6ySiec1FSrZZDkhm4noOSWzrNFo/jEc+SJY6jRTwuwbSXJPDUnQ==", "dev": true, "requires": { - "ajv": "6.5.5", - "ajv-keywords": "3.2.0" + "ajv": "^6.1.0", + "ajv-keywords": "^3.1.0" }, "dependencies": { "ajv-keywords": { @@ -11553,18 +11902,18 @@ "dev": true, "requires": { "debug": "2.6.9", - "depd": "1.1.2", - "destroy": "1.0.4", - "encodeurl": "1.0.2", - "escape-html": "1.0.3", - "etag": "1.8.1", + "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.6.3", + "http-errors": "~1.6.2", "mime": "1.4.1", "ms": "2.0.0", - "on-finished": "2.3.0", - "range-parser": "1.2.0", - "statuses": "1.4.0" + "on-finished": "~2.3.0", + "range-parser": "~1.2.0", + "statuses": "~1.4.0" }, "dependencies": { "debug": { @@ -11596,13 +11945,13 @@ "integrity": "sha1-03aNabHn2C5c4FD/9bRTvqEqkjk=", "dev": true, "requires": { - "accepts": "1.3.5", + "accepts": "~1.3.4", "batch": "0.6.1", "debug": "2.6.9", - "escape-html": "1.0.3", - "http-errors": "1.6.3", - "mime-types": "2.1.21", - "parseurl": "1.3.2" + "escape-html": "~1.0.3", + "http-errors": "~1.6.2", + "mime-types": "~2.1.17", + "parseurl": "~1.3.2" }, "dependencies": { "debug": { @@ -11622,9 +11971,9 @@ "integrity": "sha512-p/tdJrO4U387R9oMjb1oj7qSMaMfmOyd4j9hOFoxZe2baQszgHcSWjuya/CiT5kgZZKRudHNOA0pYXOl8rQ5nw==", "dev": true, "requires": { - "encodeurl": "1.0.2", - "escape-html": "1.0.3", - "parseurl": "1.3.2", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.2", "send": "0.16.2" } }, @@ -11640,10 +11989,10 @@ "integrity": "sha1-ca5KiPD+77v1LR6mBPP7MV67YnQ=", "dev": true, "requires": { - "extend-shallow": "2.0.1", - "is-extendable": "0.1.1", - "is-plain-object": "2.0.4", - "split-string": "3.1.0" + "extend-shallow": "^2.0.1", + "is-extendable": "^0.1.1", + "is-plain-object": "^2.0.3", + "split-string": "^3.0.1" }, "dependencies": { "extend-shallow": { @@ -11652,7 +12001,7 @@ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, "requires": { - "is-extendable": "0.1.1" + "is-extendable": "^0.1.0" } } } @@ -11675,8 +12024,8 @@ "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", "dev": true, "requires": { - "inherits": "2.0.3", - "safe-buffer": "5.1.2" + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" } }, "shebang-command": { @@ -11685,7 +12034,7 @@ "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", "dev": true, "requires": { - "shebang-regex": "1.0.0" + "shebang-regex": "^1.0.0" } }, "shebang-regex": { @@ -11700,10 +12049,10 @@ "integrity": "sha1-9HgZSczkAmlxJ0MOo7PFR29IF2c=", "dev": true, "requires": { - "array-filter": "0.0.1", - "array-map": "0.0.0", - "array-reduce": "0.0.0", - "jsonify": "0.0.0" + "array-filter": "~0.0.0", + "array-map": "~0.0.0", + "array-reduce": "~0.0.0", + "jsonify": "~0.0.0" } }, "shellwords": { @@ -11730,7 +12079,7 @@ "integrity": "sha1-pNprY1/8zMoz9w0Xy5JZLeleVXo=", "dev": true, "requires": { - "is-arrayish": "0.3.2" + "is-arrayish": "^0.3.1" }, "dependencies": { "is-arrayish": { @@ -11764,7 +12113,7 @@ "integrity": "sha512-POqxBK6Lb3q6s047D/XsDVNPnF9Dl8JSaqe9h9lURl0OdNqy/ujDrOiIHtsqXMGbWWTIomRzAMaTyawAU//Reg==", "dev": true, "requires": { - "is-fullwidth-code-point": "2.0.0" + "is-fullwidth-code-point": "^2.0.0" } }, "snapdragon": { @@ -11773,14 +12122,14 @@ "integrity": "sha1-ZJIufFZbDhQgS6GqfWlkJ40lGC0=", "dev": true, "requires": { - "base": "0.11.2", - "debug": "2.6.9", - "define-property": "0.2.5", - "extend-shallow": "2.0.1", - "map-cache": "0.2.2", - "source-map": "0.5.7", - "source-map-resolve": "0.5.2", - "use": "3.1.1" + "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": { @@ -11798,7 +12147,7 @@ "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", "dev": true, "requires": { - "is-descriptor": "0.1.6" + "is-descriptor": "^0.1.0" } }, "extend-shallow": { @@ -11807,7 +12156,7 @@ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, "requires": { - "is-extendable": "0.1.1" + "is-extendable": "^0.1.0" } } } @@ -11818,9 +12167,9 @@ "integrity": "sha1-bBdfhv8UvbByRWPo88GwIaKGhTs=", "dev": true, "requires": { - "define-property": "1.0.0", - "isobject": "3.0.1", - "snapdragon-util": "3.0.1" + "define-property": "^1.0.0", + "isobject": "^3.0.0", + "snapdragon-util": "^3.0.1" }, "dependencies": { "define-property": { @@ -11829,7 +12178,7 @@ "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", "dev": true, "requires": { - "is-descriptor": "1.0.2" + "is-descriptor": "^1.0.0" } }, "is-accessor-descriptor": { @@ -11838,7 +12187,7 @@ "integrity": "sha1-FpwvbT3x+ZJhgHI2XJsOofaHhlY=", "dev": true, "requires": { - "kind-of": "6.0.2" + "kind-of": "^6.0.0" } }, "is-data-descriptor": { @@ -11847,7 +12196,7 @@ "integrity": "sha1-2Eh2Mh0Oet0DmQQGq7u9NrqSaMc=", "dev": true, "requires": { - "kind-of": "6.0.2" + "kind-of": "^6.0.0" } }, "is-descriptor": { @@ -11856,9 +12205,9 @@ "integrity": "sha1-OxWXRqZmBLBPjIFSS6NlxfFNhuw=", "dev": true, "requires": { - "is-accessor-descriptor": "1.0.0", - "is-data-descriptor": "1.0.0", - "kind-of": "6.0.2" + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" } } } @@ -11869,7 +12218,7 @@ "integrity": "sha1-+VZHlIbyrNeXAGk/b3uAXkWrVuI=", "dev": true, "requires": { - "kind-of": "3.2.2" + "kind-of": "^3.2.0" }, "dependencies": { "kind-of": { @@ -11878,19 +12227,57 @@ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "requires": { - "is-buffer": "1.1.6" + "is-buffer": "^1.1.5" } } } }, + "socket.io-client": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-2.2.0.tgz", + "integrity": "sha512-56ZrkTDbdTLmBIyfFYesgOxsjcLnwAKoN4CiPyTVkMQj3zTUh0QAx3GbvIvLpFEOvQWu92yyWICxB0u7wkVbYA==", + "requires": { + "backo2": "1.0.2", + "base64-arraybuffer": "0.1.5", + "component-bind": "1.0.0", + "component-emitter": "1.2.1", + "debug": "~3.1.0", + "engine.io-client": "~3.3.1", + "has-binary2": "~1.0.2", + "has-cors": "1.1.0", + "indexof": "0.0.1", + "object-component": "0.0.3", + "parseqs": "0.0.5", + "parseuri": "0.0.5", + "socket.io-parser": "~3.3.0", + "to-array": "0.1.4" + } + }, + "socket.io-parser": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-3.3.0.tgz", + "integrity": "sha512-hczmV6bDgdaEbVqhAeVMM/jfUfzuEZHsQg6eOmLgJht6G3mPKMxYm75w2+qhAQZ+4X+1+ATZ+QFKeOZD5riHng==", + "requires": { + "component-emitter": "1.2.1", + "debug": "~3.1.0", + "isarray": "2.0.1" + }, + "dependencies": { + "isarray": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz", + "integrity": "sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4=" + } + } + }, "sockjs": { "version": "0.3.19", "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.19.tgz", "integrity": "sha512-V48klKZl8T6MzatbLlzzRNhMepEys9Y4oGFpypBFFn1gLI/QQ9HtLLyWJNbPlwGLelOVOEijUbTTJeLLI59jLw==", "dev": true, "requires": { - "faye-websocket": "0.10.0", - "uuid": "3.3.2" + "faye-websocket": "^0.10.0", + "uuid": "^3.0.1" } }, "sockjs-client": { @@ -11899,12 +12286,12 @@ "integrity": "sha512-R9jxEzhnnrdxLCNln0xg5uGHqMnkhPSTzUZH2eXcR03S/On9Yvoq2wyUZILRUhZCNVu2PmwWVoyuiPz8th8zbg==", "dev": true, "requires": { - "debug": "3.2.6", - "eventsource": "1.0.7", - "faye-websocket": "0.11.1", - "inherits": "2.0.3", - "json3": "3.3.2", - "url-parse": "1.4.4" + "debug": "^3.2.5", + "eventsource": "^1.0.7", + "faye-websocket": "~0.11.1", + "inherits": "^2.0.3", + "json3": "^3.3.2", + "url-parse": "^1.4.3" }, "dependencies": { "debug": { @@ -11913,7 +12300,7 @@ "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", "dev": true, "requires": { - "ms": "2.1.1" + "ms": "^2.1.1" } }, "faye-websocket": { @@ -11922,7 +12309,7 @@ "integrity": "sha1-8O/hjE9W5PQK/H4Gxxn9XuYYjzg=", "dev": true, "requires": { - "websocket-driver": "0.7.0" + "websocket-driver": ">=0.5.1" } }, "ms": { @@ -11951,11 +12338,11 @@ "integrity": "sha1-cuLMNAlVQ+Q7LGKyxMENSpBU8lk=", "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" + "atob": "^2.1.1", + "decode-uri-component": "^0.2.0", + "resolve-url": "^0.2.1", + "source-map-url": "^0.4.0", + "urix": "^0.1.0" } }, "source-map-support": { @@ -11964,8 +12351,8 @@ "integrity": "sha1-QbyVOyU0Jn6i1gW8z6e/oxEc7V8=", "dev": true, "requires": { - "buffer-from": "1.1.1", - "source-map": "0.6.1" + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" }, "dependencies": { "source-map": { @@ -11988,8 +12375,8 @@ "integrity": "sha1-GbtAnpG0exrVQVkkP3MSqFjbPC4=", "dev": true, "requires": { - "spdx-expression-parse": "3.0.0", - "spdx-license-ids": "3.0.2" + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" } }, "spdx-exceptions": { @@ -12004,8 +12391,8 @@ "integrity": "sha1-meEZt6XaAOBUkcn6M4t5BII7QdA=", "dev": true, "requires": { - "spdx-exceptions": "2.2.0", - "spdx-license-ids": "3.0.2" + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" } }, "spdx-license-ids": { @@ -12020,11 +12407,11 @@ "integrity": "sha512-ot0oEGT/PGUpzf/6uk4AWLqkq+irlqHXkrdbk51oWONh3bxQmBuljxPNl66zlRRcIJStWq0QkLUCPOPjgjvU0Q==", "dev": true, "requires": { - "debug": "4.1.1", - "handle-thing": "2.0.0", - "http-deceiver": "1.2.7", - "select-hose": "2.0.0", - "spdy-transport": "3.0.0" + "debug": "^4.1.0", + "handle-thing": "^2.0.0", + "http-deceiver": "^1.2.7", + "select-hose": "^2.0.0", + "spdy-transport": "^3.0.0" }, "dependencies": { "debug": { @@ -12033,7 +12420,7 @@ "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", "dev": true, "requires": { - "ms": "2.1.1" + "ms": "^2.1.1" } }, "ms": { @@ -12050,12 +12437,12 @@ "integrity": "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==", "dev": true, "requires": { - "debug": "4.1.1", - "detect-node": "2.0.4", - "hpack.js": "2.1.6", - "obuf": "1.1.2", - "readable-stream": "3.1.1", - "wbuf": "1.7.3" + "debug": "^4.1.0", + "detect-node": "^2.0.4", + "hpack.js": "^2.1.6", + "obuf": "^1.1.2", + "readable-stream": "^3.0.6", + "wbuf": "^1.7.3" }, "dependencies": { "debug": { @@ -12064,7 +12451,7 @@ "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", "dev": true, "requires": { - "ms": "2.1.1" + "ms": "^2.1.1" } }, "ms": { @@ -12079,9 +12466,9 @@ "integrity": "sha512-DkN66hPyqDhnIQ6Jcsvx9bFjhw214O4poMBcIMgPVpQvNy9a0e0Uhg5SqySyDKAmUlwt8LonTBz1ezOnM8pUdA==", "dev": true, "requires": { - "inherits": "2.0.3", - "string_decoder": "1.1.1", - "util-deprecate": "1.0.2" + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" } } } @@ -12092,7 +12479,7 @@ "integrity": "sha1-fLCd2jqGWFcFxks5pkZgOGguj+I=", "dev": true, "requires": { - "extend-shallow": "3.0.2" + "extend-shallow": "^3.0.0" } }, "sprintf-js": { @@ -12107,15 +12494,15 @@ "integrity": "sha1-yUbWvZsaOdDoY1dj9SQtbtbctik=", "dev": true, "requires": { - "asn1": "0.2.4", - "assert-plus": "1.0.0", - "bcrypt-pbkdf": "1.0.2", - "dashdash": "1.14.1", - "ecc-jsbn": "0.1.2", - "getpass": "0.1.7", - "jsbn": "0.1.1", - "safer-buffer": "2.1.2", - "tweetnacl": "0.14.5" + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "bcrypt-pbkdf": "^1.0.0", + "dashdash": "^1.12.0", + "ecc-jsbn": "~0.1.1", + "getpass": "^0.1.1", + "jsbn": "~0.1.0", + "safer-buffer": "^2.0.2", + "tweetnacl": "~0.14.0" } }, "ssri": { @@ -12124,7 +12511,7 @@ "integrity": "sha512-3Wge10hNcT1Kur4PDFwEieXSCMCJs/7WvSACcrMYrNp+b8kDL1/0wJch5Ni2WrtwEa2IO8OsVfeKIciKCDx/QA==", "dev": true, "requires": { - "figgy-pudding": "3.5.1" + "figgy-pudding": "^3.5.1" } }, "stable": { @@ -12151,8 +12538,8 @@ "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", "dev": true, "requires": { - "define-property": "0.2.5", - "object-copy": "0.1.0" + "define-property": "^0.2.5", + "object-copy": "^0.1.0" }, "dependencies": { "define-property": { @@ -12161,7 +12548,7 @@ "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", "dev": true, "requires": { - "is-descriptor": "0.1.6" + "is-descriptor": "^0.1.0" } } } @@ -12184,8 +12571,8 @@ "integrity": "sha1-ZiZu5fm9uZQKTkUUyvtDu3Hlyds=", "dev": true, "requires": { - "inherits": "2.0.3", - "readable-stream": "2.3.6" + "inherits": "~2.0.1", + "readable-stream": "^2.0.2" } }, "stream-each": { @@ -12194,8 +12581,8 @@ "integrity": "sha512-vlMC2f8I2u/bZGqkdfLQW/13Zihpej/7PmSiMQsbYddxuTsJp8vRe2x2FvVExZg7FaOds43ROAuFJwPR4MTZLw==", "dev": true, "requires": { - "end-of-stream": "1.4.1", - "stream-shift": "1.0.0" + "end-of-stream": "^1.1.0", + "stream-shift": "^1.0.0" } }, "stream-http": { @@ -12204,11 +12591,11 @@ "integrity": "sha512-+TSkfINHDo4J+ZobQLWiMouQYB+UVYFttRA94FpEzzJ7ZdqcL4uUUQ7WkdkI4DSozGmgBUE/a47L+38PenXhUw==", "dev": true, "requires": { - "builtin-status-codes": "3.0.0", - "inherits": "2.0.3", - "readable-stream": "2.3.6", - "to-arraybuffer": "1.0.1", - "xtend": "4.0.1" + "builtin-status-codes": "^3.0.0", + "inherits": "^2.0.1", + "readable-stream": "^2.3.6", + "to-arraybuffer": "^1.0.0", + "xtend": "^4.0.0" } }, "stream-shift": { @@ -12223,8 +12610,8 @@ "integrity": "sha1-1A27aGo6zpYMHP/KVivyxF+DY+0=", "dev": true, "requires": { - "astral-regex": "1.0.0", - "strip-ansi": "4.0.0" + "astral-regex": "^1.0.0", + "strip-ansi": "^4.0.0" } }, "string-width": { @@ -12233,8 +12620,8 @@ "integrity": "sha1-q5Pyeo3BPSjKyBXEYhQ6bZASrp4=", "dev": true, "requires": { - "is-fullwidth-code-point": "2.0.0", - "strip-ansi": "4.0.0" + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" } }, "string.prototype.padend": { @@ -12243,9 +12630,9 @@ "integrity": "sha1-86rvfBcZ8XDF6rHDK/eA2W4h8vA=", "dev": true, "requires": { - "define-properties": "1.1.3", - "es-abstract": "1.12.0", - "function-bind": "1.1.1" + "define-properties": "^1.1.2", + "es-abstract": "^1.4.3", + "function-bind": "^1.0.2" } }, "string.prototype.padstart": { @@ -12254,9 +12641,9 @@ "integrity": "sha1-W8+tOfRkm7LQMSkuGbzwtRDUskI=", "dev": true, "requires": { - "define-properties": "1.1.3", - "es-abstract": "1.12.0", - "function-bind": "1.1.1" + "define-properties": "^1.1.2", + "es-abstract": "^1.4.3", + "function-bind": "^1.0.2" } }, "string_decoder": { @@ -12265,7 +12652,7 @@ "integrity": "sha1-nPFhG6YmhdcDCunkujQUnDrwP8g=", "dev": true, "requires": { - "safe-buffer": "5.1.2" + "safe-buffer": "~5.1.0" } }, "strip-ansi": { @@ -12274,7 +12661,7 @@ "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", "dev": true, "requires": { - "ansi-regex": "3.0.0" + "ansi-regex": "^3.0.0" } }, "strip-bom": { @@ -12283,7 +12670,7 @@ "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", "dev": true, "requires": { - "is-utf8": "0.2.1" + "is-utf8": "^0.2.0" } }, "strip-eof": { @@ -12310,9 +12697,9 @@ "integrity": "sha512-TK5zEPeD9NyC1uPIdjikzsgWxdQQN/ry1X3d1iOz1UkYDCmcr928gWD1KHgyC27F50UnE0xCTrBOO1l6KR8M4w==", "dev": true, "requires": { - "browserslist": "4.3.4", - "postcss": "7.0.5", - "postcss-selector-parser": "3.1.1" + "browserslist": "^4.0.0", + "postcss": "^7.0.0", + "postcss-selector-parser": "^3.0.0" }, "dependencies": { "postcss-selector-parser": { @@ -12321,9 +12708,9 @@ "integrity": "sha1-T4dfSvsMllc9XPTXQBGu4lCn6GU=", "dev": true, "requires": { - "dot-prop": "4.2.0", - "indexes-of": "1.0.1", - "uniq": "1.0.1" + "dot-prop": "^4.1.1", + "indexes-of": "^1.0.1", + "uniq": "^1.0.1" } } } @@ -12334,7 +12721,7 @@ "integrity": "sha1-4uaaRKyHcveKHsCzW2id9lMO/I8=", "dev": true, "requires": { - "has-flag": "3.0.0" + "has-flag": "^3.0.0" } }, "svgo": { @@ -12343,20 +12730,20 @@ "integrity": "sha512-GBkJbnTuFpM4jFbiERHDWhZc/S/kpHToqmZag3aEBjPYK44JAN2QBjvrGIxLOoCyMZjuFQIfTO2eJd8uwLY/9g==", "dev": true, "requires": { - "coa": "2.0.1", - "colors": "1.1.2", - "css-select": "2.0.2", - "css-select-base-adapter": "0.1.1", + "coa": "~2.0.1", + "colors": "~1.1.2", + "css-select": "^2.0.0", + "css-select-base-adapter": "~0.1.0", "css-tree": "1.0.0-alpha.28", - "css-url-regex": "1.1.0", - "csso": "3.5.1", - "js-yaml": "3.12.0", - "mkdirp": "0.5.1", - "object.values": "1.0.4", - "sax": "1.2.4", - "stable": "0.1.8", - "unquote": "1.1.1", - "util.promisify": "1.0.0" + "css-url-regex": "^1.1.0", + "csso": "^3.5.0", + "js-yaml": "^3.12.0", + "mkdirp": "~0.5.1", + "object.values": "^1.0.4", + "sax": "~1.2.4", + "stable": "~0.1.6", + "unquote": "~1.1.1", + "util.promisify": "~1.0.0" } }, "symbol-tree": { @@ -12371,12 +12758,12 @@ "integrity": "sha512-UUkEAPdSGxtRpiV9ozJ5cMTtYiqz7Ni1OGqLXRCynrvzdtR1p+cfOWe2RJLwvUG8hNanaSRjecIqwOjqeatDsA==", "dev": true, "requires": { - "ajv": "5.5.2", - "ajv-keywords": "2.1.1", - "chalk": "2.4.1", - "lodash": "4.17.11", + "ajv": "^5.2.3", + "ajv-keywords": "^2.1.0", + "chalk": "^2.1.0", + "lodash": "^4.17.4", "slice-ansi": "1.0.0", - "string-width": "2.1.1" + "string-width": "^2.1.1" }, "dependencies": { "ajv": { @@ -12385,10 +12772,10 @@ "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=", "dev": true, "requires": { - "co": "4.6.0", - "fast-deep-equal": "1.1.0", - "fast-json-stable-stringify": "2.0.0", - "json-schema-traverse": "0.3.1" + "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": { @@ -12417,9 +12804,9 @@ "integrity": "sha1-4GPadLGU3en68KVh86Q4xUnS2j8=", "dev": true, "requires": { - "commander": "2.17.1", - "source-map": "0.6.1", - "source-map-support": "0.5.9" + "commander": "~2.17.1", + "source-map": "~0.6.1", + "source-map-support": "~0.5.6" }, "dependencies": { "source-map": { @@ -12436,14 +12823,14 @@ "integrity": "sha1-z3wloe7iW/Eh9KWHu54ATj+A5Sg=", "dev": true, "requires": { - "cacache": "11.3.1", - "find-cache-dir": "2.0.0", - "schema-utils": "1.0.0", - "serialize-javascript": "1.5.0", - "source-map": "0.6.1", - "terser": "3.10.11", - "webpack-sources": "1.3.0", - "worker-farm": "1.6.0" + "cacache": "^11.0.2", + "find-cache-dir": "^2.0.0", + "schema-utils": "^1.0.0", + "serialize-javascript": "^1.4.0", + "source-map": "^0.6.1", + "terser": "^3.8.1", + "webpack-sources": "^1.1.0", + "worker-farm": "^1.5.2" }, "dependencies": { "ajv-keywords": { @@ -12458,20 +12845,20 @@ "integrity": "sha512-2PEw4cRRDu+iQvBTTuttQifacYjLPhET+SYO/gEFMy8uhi+jlJREDAjSF5FWSdV/Aw5h18caHA7vMTw2c+wDzA==", "dev": true, "requires": { - "bluebird": "3.5.3", - "chownr": "1.1.1", - "figgy-pudding": "3.5.1", - "glob": "7.1.3", - "graceful-fs": "4.1.15", - "lru-cache": "4.1.3", - "mississippi": "3.0.0", - "mkdirp": "0.5.1", - "move-concurrently": "1.0.1", - "promise-inflight": "1.0.1", - "rimraf": "2.6.2", - "ssri": "6.0.1", - "unique-filename": "1.1.1", - "y18n": "4.0.0" + "bluebird": "^3.5.1", + "chownr": "^1.0.1", + "figgy-pudding": "^3.1.0", + "glob": "^7.1.2", + "graceful-fs": "^4.1.11", + "lru-cache": "^4.1.3", + "mississippi": "^3.0.0", + "mkdirp": "^0.5.1", + "move-concurrently": "^1.0.1", + "promise-inflight": "^1.0.1", + "rimraf": "^2.6.2", + "ssri": "^6.0.0", + "unique-filename": "^1.1.0", + "y18n": "^4.0.0" } }, "find-cache-dir": { @@ -12480,9 +12867,9 @@ "integrity": "sha1-TB+u1Z9FGEUw+51/oSOk0EqYRy0=", "dev": true, "requires": { - "commondir": "1.0.1", - "make-dir": "1.3.0", - "pkg-dir": "3.0.0" + "commondir": "^1.0.1", + "make-dir": "^1.0.0", + "pkg-dir": "^3.0.0" } }, "find-up": { @@ -12491,7 +12878,7 @@ "integrity": "sha1-SRafHXmTQwZG2mHsxa41XCHJe3M=", "dev": true, "requires": { - "locate-path": "3.0.0" + "locate-path": "^3.0.0" } }, "locate-path": { @@ -12500,8 +12887,8 @@ "integrity": "sha1-2+w7OrdZdYBxtY/ln8QYca8hQA4=", "dev": true, "requires": { - "p-locate": "3.0.0", - "path-exists": "3.0.0" + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" } }, "mississippi": { @@ -12510,16 +12897,16 @@ "integrity": "sha1-6goykfl+C16HdrNj1fChLZTGcCI=", "dev": true, "requires": { - "concat-stream": "1.6.2", - "duplexify": "3.6.1", - "end-of-stream": "1.4.1", - "flush-write-stream": "1.0.3", - "from2": "2.3.0", - "parallel-transform": "1.1.0", - "pump": "3.0.0", - "pumpify": "1.5.1", - "stream-each": "1.2.3", - "through2": "2.0.5" + "concat-stream": "^1.5.0", + "duplexify": "^3.4.2", + "end-of-stream": "^1.1.0", + "flush-write-stream": "^1.0.0", + "from2": "^2.1.0", + "parallel-transform": "^1.1.0", + "pump": "^3.0.0", + "pumpify": "^1.3.3", + "stream-each": "^1.1.0", + "through2": "^2.0.0" } }, "p-limit": { @@ -12528,7 +12915,7 @@ "integrity": "sha1-5iTtVO6MRgp3izyfNnBJb/ileuw=", "dev": true, "requires": { - "p-try": "2.0.0" + "p-try": "^2.0.0" } }, "p-locate": { @@ -12537,7 +12924,7 @@ "integrity": "sha1-Mi1poFwCZLJZl9n0DNiokasAZKQ=", "dev": true, "requires": { - "p-limit": "2.0.0" + "p-limit": "^2.0.0" } }, "p-try": { @@ -12552,7 +12939,7 @@ "integrity": "sha1-J0kCDyOe2ZCIGx9xIQ1R62UjvqM=", "dev": true, "requires": { - "find-up": "3.0.0" + "find-up": "^3.0.0" } }, "schema-utils": { @@ -12561,9 +12948,9 @@ "integrity": "sha1-C3mpMgTXtgDUsoUNH2bCo0lRx3A=", "dev": true, "requires": { - "ajv": "6.5.5", - "ajv-errors": "1.0.0", - "ajv-keywords": "3.2.0" + "ajv": "^6.1.0", + "ajv-errors": "^1.0.0", + "ajv-keywords": "^3.1.0" } }, "source-map": { @@ -12580,11 +12967,11 @@ "integrity": "sha512-SYbXgY64PT+4GAL2ocI3HwPa4Q4TBKm0cwAVeKOt/Aoc0gSpNRjJX8w0pA1LMKZ3LBmd8pYBqApFNQLII9kavA==", "dev": true, "requires": { - "arrify": "1.0.1", - "micromatch": "2.3.11", - "object-assign": "4.1.1", - "read-pkg-up": "1.0.1", - "require-main-filename": "1.0.1" + "arrify": "^1.0.1", + "micromatch": "^2.3.11", + "object-assign": "^4.1.0", + "read-pkg-up": "^1.0.1", + "require-main-filename": "^1.0.1" }, "dependencies": { "arr-diff": { @@ -12593,7 +12980,7 @@ "integrity": "sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8=", "dev": true, "requires": { - "arr-flatten": "1.1.0" + "arr-flatten": "^1.0.1" } }, "array-unique": { @@ -12608,9 +12995,9 @@ "integrity": "sha1-uneWLhLf+WnWt2cR6RS3N4V79qc=", "dev": true, "requires": { - "expand-range": "1.8.2", - "preserve": "0.2.0", - "repeat-element": "1.1.3" + "expand-range": "^1.8.1", + "preserve": "^0.2.0", + "repeat-element": "^1.1.2" } }, "expand-brackets": { @@ -12619,7 +13006,7 @@ "integrity": "sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s=", "dev": true, "requires": { - "is-posix-bracket": "0.1.1" + "is-posix-bracket": "^0.1.0" } }, "extglob": { @@ -12628,7 +13015,7 @@ "integrity": "sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE=", "dev": true, "requires": { - "is-extglob": "1.0.0" + "is-extglob": "^1.0.0" } }, "is-extglob": { @@ -12643,7 +13030,7 @@ "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", "dev": true, "requires": { - "is-extglob": "1.0.0" + "is-extglob": "^1.0.0" } }, "kind-of": { @@ -12652,7 +13039,7 @@ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "requires": { - "is-buffer": "1.1.6" + "is-buffer": "^1.1.5" } }, "micromatch": { @@ -12661,19 +13048,19 @@ "integrity": "sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU=", "dev": true, "requires": { - "arr-diff": "2.0.0", - "array-unique": "0.2.1", - "braces": "1.8.5", - "expand-brackets": "0.1.5", - "extglob": "0.3.2", - "filename-regex": "2.0.1", - "is-extglob": "1.0.0", - "is-glob": "2.0.1", - "kind-of": "3.2.2", - "normalize-path": "2.1.1", - "object.omit": "2.0.1", - "parse-glob": "3.0.4", - "regex-cache": "0.4.4" + "arr-diff": "^2.0.0", + "array-unique": "^0.2.1", + "braces": "^1.8.2", + "expand-brackets": "^0.1.4", + "extglob": "^0.3.1", + "filename-regex": "^2.0.0", + "is-extglob": "^1.0.0", + "is-glob": "^2.0.1", + "kind-of": "^3.0.2", + "normalize-path": "^2.0.1", + "object.omit": "^2.0.0", + "parse-glob": "^3.0.4", + "regex-cache": "^0.4.2" } } } @@ -12690,9 +13077,9 @@ "integrity": "sha512-acJ0rvUk53+ly9cqYWNOpPqOgCkNpmHLPDGduNm4hDQWF7EDKEJXAopG9iEWsPPcml09wePkq3NF+ZUqnO6tbg==", "dev": true, "requires": { - "async": "2.6.1", - "loader-runner": "2.3.1", - "loader-utils": "1.1.0" + "async": "^2.3.0", + "loader-runner": "^2.3.0", + "loader-utils": "^1.1.0" }, "dependencies": { "async": { @@ -12701,7 +13088,7 @@ "integrity": "sha512-fNEiL2+AZt6AlAw/29Cr0UDe4sRAHCpEHh54WMz+Bb7QfNcFw4h3loofyJpLeQs4Yx7yuqu/2dLgM5hKOs6HlQ==", "dev": true, "requires": { - "lodash": "4.17.11" + "lodash": "^4.17.10" } } } @@ -12724,8 +13111,8 @@ "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", "dev": true, "requires": { - "readable-stream": "2.3.6", - "xtend": "4.0.1" + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" } }, "thunky": { @@ -12740,7 +13127,7 @@ "integrity": "sha512-YvC1SV1XdOUaL6gx5CoGroT3Gu49pK9+TZ38ErPldOWW4j49GI1HKs9DV+KGq/w6y+LZ72W1c8cKz2vzY+qpzg==", "dev": true, "requires": { - "setimmediate": "1.0.5" + "setimmediate": "^1.0.4" } }, "timsort": { @@ -12755,7 +13142,7 @@ "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", "dev": true, "requires": { - "os-tmpdir": "1.0.2" + "os-tmpdir": "~1.0.2" } }, "tmpl": { @@ -12764,6 +13151,11 @@ "integrity": "sha1-I2QN17QtAEM5ERQIIOXPRA5SHdE=", "dev": true }, + "to-array": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/to-array/-/to-array-0.1.4.tgz", + "integrity": "sha1-F+bBH3PdTz10zaek/zI46a2b+JA=" + }, "to-arraybuffer": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz", @@ -12782,7 +13174,7 @@ "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", "dev": true, "requires": { - "kind-of": "3.2.2" + "kind-of": "^3.0.2" }, "dependencies": { "kind-of": { @@ -12791,7 +13183,7 @@ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "requires": { - "is-buffer": "1.1.6" + "is-buffer": "^1.1.5" } } } @@ -12802,10 +13194,10 @@ "integrity": "sha1-E8/dmzNlUvMLUfM6iuG0Knp1mc4=", "dev": true, "requires": { - "define-property": "2.0.2", - "extend-shallow": "3.0.2", - "regex-not": "1.0.2", - "safe-regex": "1.1.0" + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "regex-not": "^1.0.2", + "safe-regex": "^1.1.0" } }, "to-regex-range": { @@ -12814,8 +13206,8 @@ "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", "dev": true, "requires": { - "is-number": "3.0.0", - "repeat-string": "1.6.1" + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" } }, "toastr": { @@ -12823,7 +13215,7 @@ "resolved": "https://registry.npmjs.org/toastr/-/toastr-2.1.4.tgz", "integrity": "sha1-i0O+ZPudDEFIcURvLbjoyk6V8YE=", "requires": { - "jquery": "3.3.1" + "jquery": ">=1.12.0" } }, "topo": { @@ -12832,7 +13224,7 @@ "integrity": "sha1-1aZ/suaTB+vusIQC7Coqb1962Vw=", "dev": true, "requires": { - "hoek": "6.0.3" + "hoek": "6.x.x" }, "dependencies": { "hoek": { @@ -12855,8 +13247,8 @@ "integrity": "sha1-U/Nto/R3g7CSWvoG/587FlKA94E=", "dev": true, "requires": { - "psl": "1.1.29", - "punycode": "1.4.1" + "psl": "^1.1.24", + "punycode": "^1.4.1" }, "dependencies": { "punycode": { @@ -12873,7 +13265,7 @@ "integrity": "sha1-qLE/1r/SSJUZZ0zN5VujaTtwbQk=", "dev": true, "requires": { - "punycode": "2.1.1" + "punycode": "^2.1.0" } }, "trim-right": { @@ -12894,10 +13286,10 @@ "integrity": "sha512-vZXmzPrL+EmC4T/4rVlT2jNVMWCi/O4DIiSj3UHg1OE5kCKbk4mfrXc6dZksLgRM/TZlKnousKH9bbTazUWRRw==", "dev": true, "requires": { - "@types/strip-bom": "3.0.0", + "@types/strip-bom": "^3.0.0", "@types/strip-json-comments": "0.0.30", - "strip-bom": "3.0.0", - "strip-json-comments": "2.0.1" + "strip-bom": "^3.0.0", + "strip-json-comments": "^2.0.0" }, "dependencies": { "strip-bom": { @@ -12926,7 +13318,7 @@ "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", "dev": true, "requires": { - "safe-buffer": "5.1.2" + "safe-buffer": "^5.0.1" } }, "tweetnacl": { @@ -12941,7 +13333,7 @@ "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", "dev": true, "requires": { - "prelude-ls": "1.1.2" + "prelude-ls": "~1.1.2" } }, "type-is": { @@ -12951,7 +13343,7 @@ "dev": true, "requires": { "media-typer": "0.3.0", - "mime-types": "2.1.21" + "mime-types": "~2.1.18" } }, "typedarray": { @@ -12966,8 +13358,8 @@ "integrity": "sha1-rwLxgMEgfXZDLkc+0koo9KeCuuM=", "dev": true, "requires": { - "commander": "2.17.1", - "source-map": "0.6.1" + "commander": "~2.17.1", + "source-map": "~0.6.1" }, "dependencies": { "source-map": { @@ -12984,14 +13376,14 @@ "integrity": "sha1-dfVIFghYFjoIZD4IbV/v4YpdZ94=", "dev": true, "requires": { - "cacache": "10.0.4", - "find-cache-dir": "1.0.0", - "schema-utils": "0.4.7", - "serialize-javascript": "1.5.0", - "source-map": "0.6.1", - "uglify-es": "3.3.9", - "webpack-sources": "1.3.0", - "worker-farm": "1.6.0" + "cacache": "^10.0.4", + "find-cache-dir": "^1.0.0", + "schema-utils": "^0.4.5", + "serialize-javascript": "^1.4.0", + "source-map": "^0.6.1", + "uglify-es": "^3.3.4", + "webpack-sources": "^1.1.0", + "worker-farm": "^1.5.2" }, "dependencies": { "commander": { @@ -13012,8 +13404,8 @@ "integrity": "sha1-DBxPBwC+2NvBJM2zBNJZLKID5nc=", "dev": true, "requires": { - "commander": "2.13.0", - "source-map": "0.6.1" + "commander": "~2.13.0", + "source-map": "~0.6.1" } } } @@ -13030,8 +13422,8 @@ "integrity": "sha512-L4Qoh15vTfntsn4P1zqnHulG0LdXgjSO035fEpdtp6YxXhMT51Q6vgM5lYdG/5X3MjS+k/Y9Xw4SFCY9IkR0rg==", "dev": true, "requires": { - "unicode-canonical-property-names-ecmascript": "1.0.4", - "unicode-property-aliases-ecmascript": "1.0.4" + "unicode-canonical-property-names-ecmascript": "^1.0.4", + "unicode-property-aliases-ecmascript": "^1.0.4" } }, "unicode-match-property-value-ecmascript": { @@ -13052,10 +13444,10 @@ "integrity": "sha1-XHHDTLW61dzr4+oM0IIHulqhrqQ=", "dev": true, "requires": { - "arr-union": "3.1.0", - "get-value": "2.0.6", - "is-extendable": "0.1.1", - "set-value": "0.4.3" + "arr-union": "^3.1.0", + "get-value": "^2.0.6", + "is-extendable": "^0.1.1", + "set-value": "^0.4.3" }, "dependencies": { "extend-shallow": { @@ -13064,7 +13456,7 @@ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, "requires": { - "is-extendable": "0.1.1" + "is-extendable": "^0.1.0" } }, "set-value": { @@ -13073,10 +13465,10 @@ "integrity": "sha1-fbCPnT0i3H945Trzw79GZuzfzPE=", "dev": true, "requires": { - "extend-shallow": "2.0.1", - "is-extendable": "0.1.1", - "is-plain-object": "2.0.4", - "to-object-path": "0.3.0" + "extend-shallow": "^2.0.1", + "is-extendable": "^0.1.1", + "is-plain-object": "^2.0.1", + "to-object-path": "^0.3.0" } } } @@ -13099,7 +13491,7 @@ "integrity": "sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==", "dev": true, "requires": { - "unique-slug": "2.0.1" + "unique-slug": "^2.0.0" } }, "unique-slug": { @@ -13108,7 +13500,7 @@ "integrity": "sha512-n9cU6+gITaVu7VGj1Z8feKMmfAjEAQGhwD9fE3zvpRRa0wEIx8ODYkVGfSc94M2OX00tUFV8wH3zYbm1I8mxFg==", "dev": true, "requires": { - "imurmurhash": "0.1.4" + "imurmurhash": "^0.1.4" } }, "universalify": { @@ -13135,8 +13527,8 @@ "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", "dev": true, "requires": { - "has-value": "0.3.1", - "isobject": "3.0.1" + "has-value": "^0.3.1", + "isobject": "^3.0.0" }, "dependencies": { "has-value": { @@ -13145,9 +13537,9 @@ "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", "dev": true, "requires": { - "get-value": "2.0.6", - "has-values": "0.1.4", - "isobject": "2.1.0" + "get-value": "^2.0.3", + "has-values": "^0.1.4", + "isobject": "^2.0.0" }, "dependencies": { "isobject": { @@ -13184,10 +13576,10 @@ "uri-js": { "version": "4.2.2", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", - "integrity": "sha1-lMVA4f93KVbiKZUHwBCupsiDjrA=", + "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", "dev": true, "requires": { - "punycode": "2.1.1" + "punycode": "^2.1.0" } }, "urix": { @@ -13220,9 +13612,9 @@ "integrity": "sha512-dXHkKmw8FhPqu8asTc1puBfe3TehOCo2+RmOOev5suNCIYBcT626kxiWg1NBVkwc4rO8BGa7gP70W7VXuqHrjg==", "dev": true, "requires": { - "loader-utils": "1.1.0", - "mime": "2.3.1", - "schema-utils": "1.0.0" + "loader-utils": "^1.1.0", + "mime": "^2.0.3", + "schema-utils": "^1.0.0" }, "dependencies": { "ajv-keywords": { @@ -13237,9 +13629,9 @@ "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", "dev": true, "requires": { - "ajv": "6.5.5", - "ajv-errors": "1.0.0", - "ajv-keywords": "3.2.0" + "ajv": "^6.1.0", + "ajv-errors": "^1.0.0", + "ajv-keywords": "^3.1.0" } } } @@ -13250,8 +13642,8 @@ "integrity": "sha512-/92DTTorg4JjktLNLe6GPS2/RvAd/RGr6LuktmWSMLEOa6rjnlrFXNgSbSmkNvCoL2T028A0a1JaJLzRMlFoHg==", "dev": true, "requires": { - "querystringify": "2.1.0", - "requires-port": "1.0.0" + "querystringify": "^2.0.0", + "requires-port": "^1.0.0" } }, "use": { @@ -13281,8 +13673,8 @@ "integrity": "sha1-RA9xZaRZyaFtwUXrjnLzVocJcDA=", "dev": true, "requires": { - "define-properties": "1.1.3", - "object.getownpropertydescriptors": "2.0.3" + "define-properties": "^1.1.2", + "object.getownpropertydescriptors": "^2.0.3" } }, "utila": { @@ -13303,14 +13695,19 @@ "integrity": "sha1-G0r0lV6zB3xQHCOHL8ZROBFYcTE=", "dev": true }, + "v-lazy-image": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/v-lazy-image/-/v-lazy-image-1.3.2.tgz", + "integrity": "sha512-yZYMLoy95S4K9mWE/2DMZcwvaWnGiAHGXcKRruyrFvAdFm2fsnfyL0yj2UwXEGliNZO7I4mRy9/RB7J4CT0HAQ==" + }, "v-tooltip": { "version": "2.0.0-rc.33", "resolved": "https://registry.npmjs.org/v-tooltip/-/v-tooltip-2.0.0-rc.33.tgz", "integrity": "sha1-ePfY6cNCZWIr5lup3HjGfx3AK3M=", "requires": { - "lodash.merge": "4.6.1", - "popper.js": "1.14.5", - "vue-resize": "0.4.4" + "lodash.merge": "^4.6.0", + "popper.js": "^1.12.9", + "vue-resize": "^0.4.3" } }, "validate-npm-package-license": { @@ -13319,8 +13716,8 @@ "integrity": "sha1-/JH2uce6FchX9MssXe/uw51PQQo=", "dev": true, "requires": { - "spdx-correct": "3.0.2", - "spdx-expression-parse": "3.0.0" + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" } }, "vary": { @@ -13341,9 +13738,9 @@ "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", "dev": true, "requires": { - "assert-plus": "1.0.0", + "assert-plus": "^1.0.0", "core-util-is": "1.0.2", - "extsprintf": "1.3.0" + "extsprintf": "^1.2.0" } }, "vm-browserify": { @@ -13366,12 +13763,12 @@ "integrity": "sha1-wmjJbG2Uz+PZOKX3WTlZsMozYNE=", "dev": true, "requires": { - "debug": "3.1.0", - "eslint-scope": "3.7.1", - "eslint-visitor-keys": "1.0.0", - "espree": "3.5.4", - "esquery": "1.0.1", - "lodash": "4.17.11" + "debug": "^3.1.0", + "eslint-scope": "^3.7.1", + "eslint-visitor-keys": "^1.0.0", + "espree": "^3.5.2", + "esquery": "^1.0.0", + "lodash": "^4.17.4" } }, "vue-hot-reload-api": { @@ -13381,21 +13778,21 @@ "dev": true }, "vue-jest": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/vue-jest/-/vue-jest-3.0.2.tgz", - "integrity": "sha512-5XIQ1xQFW0ZnWxHWM7adVA2IqbDsdw1vhgZfGFX4oWd75J38KIS3YT41PtiE7lpMLmNM6+VJ0uprT2mhHjUgkA==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/vue-jest/-/vue-jest-3.0.3.tgz", + "integrity": "sha512-QwFQjkv2vXYPKUkNZkMbV/ZTHyQhRM1JY8nP68dRLQmdvCN+VUEKhlByH/PgPqDr2p/NuhaM3PUjJ9nreR++3w==", "dev": true, "requires": { - "babel-plugin-transform-es2015-modules-commonjs": "6.26.2", - "chalk": "2.4.1", - "extract-from-css": "0.4.4", - "find-babel-config": "1.1.0", - "js-beautify": "1.8.9", - "node-cache": "4.2.0", - "object-assign": "4.1.1", - "source-map": "0.5.7", - "tsconfig": "7.0.0", - "vue-template-es2015-compiler": "1.6.0" + "babel-plugin-transform-es2015-modules-commonjs": "^6.26.0", + "chalk": "^2.1.0", + "extract-from-css": "^0.4.4", + "find-babel-config": "^1.1.0", + "js-beautify": "^1.6.14", + "node-cache": "^4.1.1", + "object-assign": "^4.1.1", + "source-map": "^0.5.6", + "tsconfig": "^7.0.0", + "vue-template-es2015-compiler": "^1.6.0" } }, "vue-loader": { @@ -13404,11 +13801,11 @@ "integrity": "sha512-nVV27GNIA9MeoD8yQ3dkUzwlAaAsWeYSWZHsu/K04KCD339lW0Jv2sJWsjj3721SP7sl2lYdPmjcHgkWQSp5bg==", "dev": true, "requires": { - "@vue/component-compiler-utils": "2.3.0", - "hash-sum": "1.0.2", - "loader-utils": "1.1.0", - "vue-hot-reload-api": "2.3.1", - "vue-style-loader": "4.1.2" + "@vue/component-compiler-utils": "^2.0.0", + "hash-sum": "^1.0.2", + "loader-utils": "^1.1.0", + "vue-hot-reload-api": "^2.3.0", + "vue-style-loader": "^4.1.0" } }, "vue-loading-overlay": { @@ -13426,14 +13823,22 @@ "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-3.0.2.tgz", "integrity": "sha512-opKtsxjp9eOcFWdp6xLQPLmRGgfM932Tl56U9chYTnoWqKxQ8M20N7AkdEbM5beUh6wICoFGYugAX9vQjyJLFg==" }, + "vue-socket.io": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/vue-socket.io/-/vue-socket.io-3.0.5.tgz", + "integrity": "sha512-+caWHVSphz0iEJOdHK8inAth7E4r97/9w3XD+vxMxCkfKtZNf/D07/ZmRrwFUSlCLJ1EDph/gYFoHy06KBUBCg==", + "requires": { + "socket.io-client": "^2.1.1" + } + }, "vue-style-loader": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/vue-style-loader/-/vue-style-loader-4.1.2.tgz", "integrity": "sha512-0ip8ge6Gzz/Bk0iHovU9XAUQaFt/G2B61bnWa2tCcqqdgfHs1lF9xXorFbE55Gmy92okFT+8bfmySuUOu13vxQ==", "dev": true, "requires": { - "hash-sum": "1.0.2", - "loader-utils": "1.1.0" + "hash-sum": "^1.0.2", + "loader-utils": "^1.0.2" } }, "vue-template-compiler": { @@ -13442,8 +13847,8 @@ "integrity": "sha1-UqSgeMMn3rk3SCpQmuhcBvNGw8s=", "dev": true, "requires": { - "de-indent": "1.0.2", - "he": "1.2.0" + "de-indent": "^1.0.2", + "he": "^1.1.0" } }, "vue-template-es2015-compiler": { @@ -13469,7 +13874,7 @@ "integrity": "sha1-gqwr/2PZUOqeMYmlimViX+3xkEU=", "dev": true, "requires": { - "browser-process-hrtime": "0.1.3" + "browser-process-hrtime": "^0.1.2" } }, "walker": { @@ -13478,7 +13883,7 @@ "integrity": "sha1-L3+bj9ENZ3JisYqITijRlhjgKPs=", "dev": true, "requires": { - "makeerror": "1.0.11" + "makeerror": "1.0.x" } }, "watch": { @@ -13487,8 +13892,8 @@ "integrity": "sha1-KAlUdsbffJDJYxOJkMClQj60uYY=", "dev": true, "requires": { - "exec-sh": "0.2.2", - "minimist": "1.2.0" + "exec-sh": "^0.2.0", + "minimist": "^1.2.0" } }, "watchpack": { @@ -13497,9 +13902,9 @@ "integrity": "sha512-i6dHe3EyLjMmDlU1/bGQpEw25XSjkJULPuAVKCbNRefQVq48yXKUpwg538F7AZTf9kyr57zj++pQFltUa5H7yA==", "dev": true, "requires": { - "chokidar": "2.0.4", - "graceful-fs": "4.1.15", - "neo-async": "2.6.0" + "chokidar": "^2.0.2", + "graceful-fs": "^4.1.2", + "neo-async": "^2.5.0" } }, "wbuf": { @@ -13508,7 +13913,7 @@ "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==", "dev": true, "requires": { - "minimalistic-assert": "1.0.1" + "minimalistic-assert": "^1.0.0" } }, "wcwidth": { @@ -13517,7 +13922,7 @@ "integrity": "sha1-8LDc+RW8X/FSivrbLA4XtTLaL+g=", "dev": true, "requires": { - "defaults": "1.0.3" + "defaults": "^1.0.3" } }, "webidl-conversions": { @@ -13536,26 +13941,26 @@ "@webassemblyjs/helper-module-context": "1.7.11", "@webassemblyjs/wasm-edit": "1.7.11", "@webassemblyjs/wasm-parser": "1.7.11", - "acorn": "5.7.3", - "acorn-dynamic-import": "3.0.0", - "ajv": "6.5.5", - "ajv-keywords": "3.2.0", - "chrome-trace-event": "1.0.0", - "enhanced-resolve": "4.1.0", - "eslint-scope": "4.0.0", - "json-parse-better-errors": "1.0.2", - "loader-runner": "2.3.1", - "loader-utils": "1.1.0", - "memory-fs": "0.4.1", - "micromatch": "3.1.10", - "mkdirp": "0.5.1", - "neo-async": "2.6.0", - "node-libs-browser": "2.1.0", - "schema-utils": "0.4.7", - "tapable": "1.1.0", - "uglifyjs-webpack-plugin": "1.3.0", - "watchpack": "1.6.0", - "webpack-sources": "1.3.0" + "acorn": "^5.6.2", + "acorn-dynamic-import": "^3.0.0", + "ajv": "^6.1.0", + "ajv-keywords": "^3.1.0", + "chrome-trace-event": "^1.0.0", + "enhanced-resolve": "^4.1.0", + "eslint-scope": "^4.0.0", + "json-parse-better-errors": "^1.0.2", + "loader-runner": "^2.3.0", + "loader-utils": "^1.1.0", + "memory-fs": "~0.4.1", + "micromatch": "^3.1.8", + "mkdirp": "~0.5.0", + "neo-async": "^2.5.0", + "node-libs-browser": "^2.0.0", + "schema-utils": "^0.4.4", + "tapable": "^1.1.0", + "uglifyjs-webpack-plugin": "^1.2.4", + "watchpack": "^1.5.0", + "webpack-sources": "^1.3.0" }, "dependencies": { "ajv-keywords": { @@ -13570,8 +13975,8 @@ "integrity": "sha1-UL8wcekzi83EMzF5Sgy1M/ATYXI=", "dev": true, "requires": { - "esrecurse": "4.2.1", - "estraverse": "4.2.0" + "esrecurse": "^4.1.0", + "estraverse": "^4.1.1" } } } @@ -13582,18 +13987,18 @@ "integrity": "sha512-naLWiRfmtH4UJgtUktRTLw6FdoZJ2RvCR9ePbwM9aRMsS/KjFerkPZG9epEvXRAw5d5oPdrs9+3p+afNjxW8Xw==", "dev": true, "requires": { - "acorn": "5.7.3", - "bfj": "6.1.1", - "chalk": "2.4.1", - "commander": "2.19.0", - "ejs": "2.6.1", - "express": "4.16.4", - "filesize": "3.6.1", - "gzip-size": "5.0.0", - "lodash": "4.17.11", - "mkdirp": "0.5.1", - "opener": "1.5.1", - "ws": "6.1.0" + "acorn": "^5.7.3", + "bfj": "^6.1.1", + "chalk": "^2.4.1", + "commander": "^2.18.0", + "ejs": "^2.6.1", + "express": "^4.16.3", + "filesize": "^3.6.1", + "gzip-size": "^5.0.0", + "lodash": "^4.17.10", + "mkdirp": "^0.5.1", + "opener": "^1.5.1", + "ws": "^6.0.0" }, "dependencies": { "commander": { @@ -13610,8 +14015,8 @@ "integrity": "sha512-BCfKo2YkDe2ByqkEWe1Rw+zko4LsyS75LVr29C6xIrxAg9JHJ4pl8kaIZ396SUSNp6b4815dRZPSTAS8LlURRQ==", "dev": true, "requires": { - "deepmerge": "1.5.2", - "javascript-stringify": "1.6.0" + "deepmerge": "^1.5.2", + "javascript-stringify": "^1.6.0" } }, "webpack-dev-middleware": { @@ -13620,10 +14025,10 @@ "integrity": "sha512-Q9Iyc0X9dP9bAsYskAVJ/hmIZZQwf/3Sy4xCAZgL5cUkjZmUZLt4l5HpbST/Pdgjn3u6pE7u5OdGd1apgzRujA==", "dev": true, "requires": { - "memory-fs": "0.4.1", - "mime": "2.3.1", - "range-parser": "1.2.0", - "webpack-log": "2.0.0" + "memory-fs": "~0.4.1", + "mime": "^2.3.1", + "range-parser": "^1.0.3", + "webpack-log": "^2.0.0" } }, "webpack-dev-server": { @@ -13633,34 +14038,34 @@ "dev": true, "requires": { "ansi-html": "0.0.7", - "bonjour": "3.5.0", - "chokidar": "2.0.4", - "compression": "1.7.3", - "connect-history-api-fallback": "1.6.0", - "debug": "3.1.0", - "del": "3.0.0", - "express": "4.16.4", - "html-entities": "1.2.1", - "http-proxy-middleware": "0.18.0", - "import-local": "2.0.0", - "internal-ip": "3.0.1", - "ip": "1.1.5", - "killable": "1.0.1", - "loglevel": "1.6.1", - "opn": "5.4.0", - "portfinder": "1.0.19", - "schema-utils": "1.0.0", - "selfsigned": "1.10.4", - "semver": "5.6.0", - "serve-index": "1.9.1", + "bonjour": "^3.5.0", + "chokidar": "^2.0.0", + "compression": "^1.5.2", + "connect-history-api-fallback": "^1.3.0", + "debug": "^3.1.0", + "del": "^3.0.0", + "express": "^4.16.2", + "html-entities": "^1.2.0", + "http-proxy-middleware": "~0.18.0", + "import-local": "^2.0.0", + "internal-ip": "^3.0.1", + "ip": "^1.1.5", + "killable": "^1.0.0", + "loglevel": "^1.4.1", + "opn": "^5.1.0", + "portfinder": "^1.0.9", + "schema-utils": "^1.0.0", + "selfsigned": "^1.9.1", + "semver": "^5.6.0", + "serve-index": "^1.7.2", "sockjs": "0.3.19", "sockjs-client": "1.3.0", - "spdy": "4.0.0", - "strip-ansi": "3.0.1", - "supports-color": "5.5.0", - "url": "0.11.0", + "spdy": "^4.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^5.1.0", + "url": "^0.11.0", "webpack-dev-middleware": "3.4.0", - "webpack-log": "2.0.0", + "webpack-log": "^2.0.0", "yargs": "12.0.2" }, "dependencies": { @@ -13682,9 +14087,9 @@ "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", "dev": true, "requires": { - "ajv": "6.5.5", - "ajv-errors": "1.0.0", - "ajv-keywords": "3.2.0" + "ajv": "^6.1.0", + "ajv-errors": "^1.0.0", + "ajv-keywords": "^3.1.0" } }, "strip-ansi": { @@ -13693,7 +14098,7 @@ "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "dev": true, "requires": { - "ansi-regex": "2.1.1" + "ansi-regex": "^2.0.0" } } } @@ -13704,8 +14109,8 @@ "integrity": "sha512-cX8G2vR/85UYG59FgkoMamwHUIkSSlV3bBMRsbxVXVUk2j6NleCKjQ/WE9eYg9WY4w25O9w8wKP4rzNZFmUcUg==", "dev": true, "requires": { - "ansi-colors": "3.2.3", - "uuid": "3.3.2" + "ansi-colors": "^3.0.0", + "uuid": "^3.3.2" } }, "webpack-merge": { @@ -13714,7 +14119,7 @@ "integrity": "sha1-D9446r8tX9hSUcJKWoxI+KP063s=", "dev": true, "requires": { - "lodash": "4.17.11" + "lodash": "^4.17.5" } }, "webpack-sources": { @@ -13723,8 +14128,8 @@ "integrity": "sha512-OiVgSrbGu7NEnEvQJJgdSFPl2qWKkWq5lHMhgiToIiN9w34EBnjYzSYs+VbL5KoYiLNtFFa7BZIKxRED3I32pA==", "dev": true, "requires": { - "source-list-map": "2.0.1", - "source-map": "0.6.1" + "source-list-map": "^2.0.0", + "source-map": "~0.6.1" }, "dependencies": { "source-map": { @@ -13741,8 +14146,8 @@ "integrity": "sha1-DK+dLXVdk67gSdS90NP+LMoqJOs=", "dev": true, "requires": { - "http-parser-js": "0.5.0", - "websocket-extensions": "0.1.3" + "http-parser-js": ">=0.4.0", + "websocket-extensions": ">=0.1.1" } }, "websocket-extensions": { @@ -13772,9 +14177,9 @@ "integrity": "sha512-rhRZRqx/TLJQWUpQ6bmrt2UV4f0HCQ463yQuONJqC6fO2VoEb1pTYddbe59SkYq87aoM5A3bdhMZiUiVws+fzQ==", "dev": true, "requires": { - "lodash.sortby": "4.7.0", - "tr46": "1.0.1", - "webidl-conversions": "4.0.2" + "lodash.sortby": "^4.7.0", + "tr46": "^1.0.1", + "webidl-conversions": "^4.0.2" } }, "which": { @@ -13783,7 +14188,7 @@ "integrity": "sha1-pFBD1U9YBTFtqNYvn1CRjT2nCwo=", "dev": true, "requires": { - "isexe": "2.0.0" + "isexe": "^2.0.0" } }, "which-module": { @@ -13804,7 +14209,7 @@ "integrity": "sha512-6w+3tHbM87WnSWnENBUvA2pxJPLhQUg5LKwUQHq3r+XPhIM+Gh2R5ycbwPCyuGbNg+lPgdcnQUhuC02kJCvffQ==", "dev": true, "requires": { - "errno": "0.1.7" + "errno": "~0.1.7" } }, "wrap-ansi": { @@ -13813,8 +14218,8 @@ "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", "dev": true, "requires": { - "string-width": "1.0.2", - "strip-ansi": "3.0.1" + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1" }, "dependencies": { "ansi-regex": { @@ -13829,7 +14234,7 @@ "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", "dev": true, "requires": { - "number-is-nan": "1.0.1" + "number-is-nan": "^1.0.0" } }, "string-width": { @@ -13838,9 +14243,9 @@ "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", "dev": true, "requires": { - "code-point-at": "1.1.0", - "is-fullwidth-code-point": "1.0.0", - "strip-ansi": "3.0.1" + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" } }, "strip-ansi": { @@ -13849,7 +14254,7 @@ "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "dev": true, "requires": { - "ansi-regex": "2.1.1" + "ansi-regex": "^2.0.0" } } } @@ -13866,27 +14271,26 @@ "integrity": "sha1-X8A4KOJkzqP+kUVUdvejxWbLB1c=", "dev": true, "requires": { - "mkdirp": "0.5.1" + "mkdirp": "^0.5.1" } }, "write-file-atomic": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.3.0.tgz", - "integrity": "sha512-xuPeK4OdjWqtfi59ylvVL0Yn35SF3zgcAcv7rBPFHVaEapaDr4GdGgm3j7ckTwH9wHL7fGmgfAnb0+THrHb8tA==", + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.4.2.tgz", + "integrity": "sha512-s0b6vB3xIVRLWywa6X9TOMA7k9zio0TMOsl9ZnDkliA/cfJlpHXAscj0gbHVJiTdIuAYpIyqS5GW91fqm6gG5g==", "dev": true, "requires": { - "graceful-fs": "4.1.15", - "imurmurhash": "0.1.4", - "signal-exit": "3.0.2" + "graceful-fs": "^4.1.11", + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.2" } }, "ws": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/ws/-/ws-6.1.0.tgz", "integrity": "sha1-EZqdv5LFThkOwY0Q6HHVXJXPk3M=", - "dev": true, "requires": { - "async-limiter": "1.0.0" + "async-limiter": "~1.0.0" } }, "xml-name-validator": { @@ -13895,6 +14299,11 @@ "integrity": "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==", "dev": true }, + "xmlhttprequest-ssl": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.5.tgz", + "integrity": "sha1-wodrBhaKrcQOV9l+gRkayPQ5iz4=" + }, "xregexp": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/xregexp/-/xregexp-4.0.0.tgz", @@ -13925,18 +14334,18 @@ "integrity": "sha512-e7SkEx6N6SIZ5c5H22RTZae61qtn3PYUE8JYbBFlK9sYmh3DMQ6E5ygtaG/2BW0JZi4WGgTR2IV5ChqlqrDGVQ==", "dev": true, "requires": { - "cliui": "4.1.0", - "decamelize": "2.0.0", - "find-up": "3.0.0", - "get-caller-file": "1.0.3", - "os-locale": "3.1.0", - "require-directory": "2.1.1", - "require-main-filename": "1.0.1", - "set-blocking": "2.0.0", - "string-width": "2.1.1", - "which-module": "2.0.0", - "y18n": "4.0.0", - "yargs-parser": "10.1.0" + "cliui": "^4.0.0", + "decamelize": "^2.0.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": "^10.1.0" }, "dependencies": { "find-up": { @@ -13945,7 +14354,7 @@ "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", "dev": true, "requires": { - "locate-path": "3.0.0" + "locate-path": "^3.0.0" } }, "locate-path": { @@ -13954,8 +14363,8 @@ "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", "dev": true, "requires": { - "p-locate": "3.0.0", - "path-exists": "3.0.0" + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" } }, "p-limit": { @@ -13964,7 +14373,7 @@ "integrity": "sha512-NhURkNcrVB+8hNfLuysU8enY5xn2KXphsHBaC2YmRNTZRc7RWusw6apSpdEj3jo4CMb6W9nrF6tTnsJsJeyu6g==", "dev": true, "requires": { - "p-try": "2.0.0" + "p-try": "^2.0.0" } }, "p-locate": { @@ -13973,7 +14382,7 @@ "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", "dev": true, "requires": { - "p-limit": "2.1.0" + "p-limit": "^2.0.0" } }, "p-try": { @@ -13990,19 +14399,24 @@ "integrity": "sha512-VCIyR1wJoEBZUqk5PA+oOBF6ypbwh5aNB3I50guxAL/quggdfs4TtNHQrSazFA3fYZ+tEqfs0zIGlv0c/rgjbQ==", "dev": true, "requires": { - "camelcase": "4.1.0" + "camelcase": "^4.1.0" } }, + "yeast": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/yeast/-/yeast-0.1.2.tgz", + "integrity": "sha1-AI4G2AlDIMNy28L47XagymyKxBk=" + }, "yorkie": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/yorkie/-/yorkie-2.0.0.tgz", "integrity": "sha512-jcKpkthap6x63MB4TxwCyuIGkV0oYP/YRyuQU5UO0Yz/E/ZAu+653/uov+phdmO54n6BcvFRyyt0RRrWdN2mpw==", "dev": true, "requires": { - "execa": "0.8.0", - "is-ci": "1.2.1", - "normalize-path": "1.0.0", - "strip-indent": "2.0.0" + "execa": "^0.8.0", + "is-ci": "^1.0.10", + "normalize-path": "^1.0.0", + "strip-indent": "^2.0.0" }, "dependencies": { "cross-spawn": { @@ -14011,9 +14425,9 @@ "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", "dev": true, "requires": { - "lru-cache": "4.1.3", - "shebang-command": "1.2.0", - "which": "1.3.1" + "lru-cache": "^4.0.1", + "shebang-command": "^1.2.0", + "which": "^1.2.9" } }, "execa": { @@ -14022,13 +14436,13 @@ "integrity": "sha1-2NdrvBtVIX7RkP1t1J08d07PyNo=", "dev": true, "requires": { - "cross-spawn": "5.1.0", - "get-stream": "3.0.0", - "is-stream": "1.1.0", - "npm-run-path": "2.0.2", - "p-finally": "1.0.0", - "signal-exit": "3.0.2", - "strip-eof": "1.0.0" + "cross-spawn": "^5.0.1", + "get-stream": "^3.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" } }, "get-stream": { diff --git a/client/package.json b/client/package.json index d2f4440b..6cec41a7 100755 --- a/client/package.json +++ b/client/package.json @@ -11,27 +11,31 @@ "dependencies": { "axios": "^0.18.0", "bootstrap": "^4.1.3", + "intersection-observer": "^0.5.1", "jquery": "^3.3.1", "paper": "^0.11.8", "popper.js": "^1.14.5", "simplify-js": "^1.2.3", "toastr": "^2.1.4", + "v-lazy-image": "^1.3.2", "v-tooltip": "^2.0.0-rc.33", "vue": "^2.5.17", "vue-loading-overlay": "^3.1.1", "vue-router": "^3.0.2", + "vue-socket.io": "^3.0.5", + "vue-touch": "^2.0.0-beta.4", "vuex": "^3.0.1" }, "devDependencies": { "@vue/cli-plugin-babel": "^3.1.1", "@vue/cli-plugin-eslint": "^3.1.1", - "@vue/cli-plugin-unit-jest": "^3.3.0", + "@vue/cli-plugin-unit-jest": "^3.4.0", "@vue/cli-service": "^3.1.1", "@vue/eslint-config-prettier": "^4.0.0", "@vue/test-utils": "^1.0.0-beta.20", "babel-core": "7.0.0-bridge.0", "babel-eslint": "^10.0.1", - "babel-jest": "^23.6.0", + "babel-jest": "^24.1.0", "eslint": "^5.8.0", "eslint-plugin-vue": "^5.0.0-0", "vue-template-compiler": "^2.5.17", diff --git a/client/src/App.vue b/client/src/App.vue index 5673c4b1..24402735 100755 --- a/client/src/App.vue +++ b/client/src/App.vue @@ -1,6 +1,6 @@ @@ -14,7 +14,7 @@ export default { components: { NavBar }, methods: { ...mapMutations("user", ["setUserInfo"]), - ...mapMutations("info", ["getServerInfo"]), + ...mapMutations("info", ["getServerInfo", "socket"]), toAuthPage() { this.$router.push({ name: "authentication" @@ -43,6 +43,9 @@ export default { }, loading() { return this.$store.state.info.loading; + }, + socketConnection() { + return this.$store.state.info.socket; } }, watch: { @@ -51,6 +54,22 @@ export default { this.loader.hide(); } }, + socketConnection() { + if (this.socketConnection) return; + + setTimeout(() => { + if (this.socketConnection) return; + let options = { + positionClass: "toast-bottom-left" + }; + + this.$toastr.warning( + "Connection lost to the backend", + "Connection Lost", + options + ); + }, 1000); + }, loginRequired: { handler(newValue) { if (newValue) { @@ -66,6 +85,14 @@ export default { immediate: true } }, + sockets: { + connect() { + this.socket(true); + }, + disconnect() { + this.socket(false); + } + }, mounted() { if (this.$route.name.toLowerCase() !== "annotate") { this.loader = this.$loading.show({ diff --git a/client/src/assets/loader.gif b/client/src/assets/loader.gif new file mode 100644 index 00000000..33fac914 Binary files /dev/null and b/client/src/assets/loader.gif differ diff --git a/client/src/components/KeypointsDefinition.vue b/client/src/components/KeypointsDefinition.vue new file mode 100755 index 00000000..782d3644 --- /dev/null +++ b/client/src/components/KeypointsDefinition.vue @@ -0,0 +1,390 @@ + + + + + diff --git a/client/src/components/Metadata.vue b/client/src/components/Metadata.vue index 73aaa7b2..30c93d6a 100755 --- a/client/src/components/Metadata.vue +++ b/client/src/components/Metadata.vue @@ -1,6 +1,10 @@ diff --git a/client/src/components/PanelText.vue b/client/src/components/PanelText.vue new file mode 100755 index 00000000..8b8a25d3 --- /dev/null +++ b/client/src/components/PanelText.vue @@ -0,0 +1,28 @@ + + + + + diff --git a/client/src/components/annotator/panels/PanelToggle.vue b/client/src/components/PanelToggle.vue similarity index 79% rename from client/src/components/annotator/panels/PanelToggle.vue rename to client/src/components/PanelToggle.vue index ccea7721..3ad48c91 100755 --- a/client/src/components/annotator/panels/PanelToggle.vue +++ b/client/src/components/PanelToggle.vue @@ -1,5 +1,9 @@ diff --git a/client/src/components/Status.vue b/client/src/components/Status.vue index 5ed4f4e6..d9fe847c 100755 --- a/client/src/components/Status.vue +++ b/client/src/components/Status.vue @@ -1,7 +1,16 @@