From 6f6855b57e76483ec55fc8d06ea463c1b873ca61 Mon Sep 17 00:00:00 2001 From: Omkar Ekbote Date: Wed, 27 Mar 2019 21:34:04 +0530 Subject: [PATCH 01/64] Ignore PyCharm files --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 18a246d..a2903fe 100644 --- a/.gitignore +++ b/.gitignore @@ -101,6 +101,7 @@ wittymail_ve/ # VS Code .vscode/ +.idea/ # WittyMail log file -wittymail_log.txt \ No newline at end of file +wittymail_log.txt From 5956b69fb1d538d8f891d634c8bb9e36ef0515d0 Mon Sep 17 00:00:00 2001 From: Omkar Ekbote Date: Wed, 27 Mar 2019 22:39:56 +0530 Subject: [PATCH 02/64] Refactor REST APIs to use class views (flask-classy) --- backend/requirements.txt | 3 +- .../webserver/wittymail_server/__init__.py | 1 + .../webserver/wittymail_server/rest_api.py | 535 ++++++++++-------- 3 files changed, 309 insertions(+), 230 deletions(-) diff --git a/backend/requirements.txt b/backend/requirements.txt index c96a6a2..4a440d2 100644 --- a/backend/requirements.txt +++ b/backend/requirements.txt @@ -3,4 +3,5 @@ flask-cors openpyxl requests PyPDF2 -pyinstaller \ No newline at end of file +pyinstaller +flask-classy \ No newline at end of file diff --git a/backend/webserver/wittymail_server/__init__.py b/backend/webserver/wittymail_server/__init__.py index ea6fb7d..e59df89 100644 --- a/backend/webserver/wittymail_server/__init__.py +++ b/backend/webserver/wittymail_server/__init__.py @@ -62,6 +62,7 @@ def get_attachments_dir(): flask_app.config['ATTACHMENTS_DIR'] = a flask_app.config['FODDER_DIR'] = f + flask_app.config['URL_DEFAULT_PREFIX_FOR_API'] = '/api/' # Import other Flask sub-modules containing URL handlers import wittymail_server.default_routes diff --git a/backend/webserver/wittymail_server/rest_api.py b/backend/webserver/wittymail_server/rest_api.py index 4343ab2..a4f55c9 100644 --- a/backend/webserver/wittymail_server/rest_api.py +++ b/backend/webserver/wittymail_server/rest_api.py @@ -2,12 +2,13 @@ # coding=utf-8 import os, sys + sys.path.append(os.path.abspath(os.path.join(os.curdir, '..', '..'))) -import pdb import mailer.emailapi_broker as emailapi_broker from wittymail_server import flask_app from flask import jsonify, request, json +from flask_classy import FlaskView import util.version as version import util.logger as logger from flask import send_file @@ -19,81 +20,324 @@ HTTP_NOT_FOUND = 404 HTTP_BAD_INPUT = 400 -@flask_app.route("/api/version", methods=['GET']) -def get_version(): - log.debug('Current version = %s' % (version.__pretty_version__)) - return (jsonify({'version': version.__pretty_version__}), - HTTP_OK, - {'ContentType':'application/json'}) - -@flask_app.route("/api/fodder/regurgitate", methods=['GET']) -def get_fodder_regurgitate(): - e = emailapi_broker.get_email_fodder_names() - if e[0] is not 0: - return (jsonify({"err_msg": e[1]}), - HTTP_BAD_INPUT, - {'ContentType':'application/json'}) +class SheetView(FlaskView): + """ + APIs for the sheet containing sponsor/beneficiary details - fodder_names = e[1] - fodder = emailapi_broker.get_email_fodder() + /api/sheet/... + """ + route_prefix = flask_app.config['URL_DEFAULT_PREFIX_FOR_API'] - if len(fodder_names) == 0 or len(fodder) == 0: - return (jsonify({"err_msg": "Data sheet is empty or not provided"}), - HTTP_BAD_INPUT, - {'ContentType':'application/json'}) + @flask_app.route('upload', methods=['POST']) + def upload(self): + """ + Upload a new Excel sheet as input - cnt = 0 - fodder_list = [] - for f in fodder: - if cnt == 2: - break - fodder_list.append(dict(zip(fodder_names, f))) - cnt += 1 - - if cnt == 0: - return (jsonify({'error_message': "Data sheet is empty or data sheet is not provided"}), - HTTP_BAD_INPUT, - {'ContentType':'application/json'}) - - return (jsonify({'headers': fodder_names, 'contents': fodder_list}), - HTTP_OK, - {'ContentType':'application/json'}) - -@flask_app.route("/api/fodder", methods=['GET']) -def get_fodder(): - fodder_file = emailapi_broker.save_fodder_to_file() - return send_file(fodder_file) - -@flask_app.route("/api/fodder", methods=['POST']) -def post_fodder(): - log.info(request.files) - try: + :return: + """ + log.debug("Uploading sheet: ", request.files) fodder_dir = flask_app.config['FODDER_DIR'] f = request.files['fodder'] fodder_file = os.path.join(fodder_dir, f.filename) f.save(fodder_file) - log.info('fodder file saved as = %s' % (fodder_file)) + log.info('Sheet file saved as: %s', fodder_file) + # Parse the Excel sheet and store the contents in-memory emailapi_broker.save_fodder_from_file(fodder_file) - except: - log.exception("Message") - return (jsonify({}), - HTTP_OK, - {'ContentType':'application/json'}) + return (jsonify({}), + HTTP_OK, + {'ContentType': 'application/json'}) + + def get_file(self): + """ + Get the Excel sheet (*.xlsx file) updated with 'status' and other columns + + :return: + """ + fodder_file = emailapi_broker.save_fodder_to_file() + log.info("Send sheet back to frontend: %s", fodder_file) + + return send_file(fodder_file) + + def get_contents(self): + """ + Get the contents of the sheet updated with 'status' and other columns + + :return: + """ + e = emailapi_broker.get_email_fodder_names() + if e[0] is not 0: + return (jsonify({"err_msg": e[1]}), + HTTP_BAD_INPUT, + {'ContentType': 'application/json'}) + + fodder_names = e[1] + + if emailapi_broker.email_from == None: + return (jsonify({"err_msg": "Login details not yet provided"}), + HTTP_BAD_INPUT, + {'ContentType': 'application/json'}) + + fodder = emailapi_broker.get_email_fodder() + extended_fodder = emailapi_broker.get_extended_email_fodder() + + if len(fodder_names) == 0 or len(fodder) == 0 or len(extended_fodder) == 0: + return (jsonify({'error_message': "Data sheet or email template not provided"}), + HTTP_BAD_INPUT, + {'ContentType': 'application/json'}) + + assert len(fodder) == len(extended_fodder), "Count of fodder and extended_fodder do not match" + + if emailapi_broker.EMAIL_FODDER_TO_INDEX == None or emailapi_broker.EMAIL_FODDER_CC_INDEX == None: + return (jsonify({'error_message': "'To' or 'CC' index not provided"}), + HTTP_BAD_INPUT, + {'ContentType': 'application/json'}) + + # Create fodder_list in email_broker + fodder_list = [] + for f, e in zip(fodder, extended_fodder): + at = [] + for a in e[-2]: + at_dict = {"name": a, "url": os.path.join("/api/fodder/achar/", a)} + at.append(at_dict) + email = { \ + "from": emailapi_broker.email_from, + "to": f[emailapi_broker.EMAIL_FODDER_TO_INDEX], + "cc": f[emailapi_broker.EMAIL_FODDER_CC_INDEX], + "attachment": at, + "subject": e[-4], + "body": e[-3], + } + + tmp = dict(zip(fodder_names, f)) + tmp["email"] = email + fodder_list.append(tmp) + + return (jsonify({'headers': fodder_names, 'contents': fodder_list}), + HTTP_OK, + {'ContentType': 'application/json'}) + + def headers(self): + """ + Get the header row in the Excel sheet with the first 3 rows as sample values + + :return: + """ + e = emailapi_broker.get_email_fodder_names() + if e[0] is not 0: + return (jsonify({"err_msg": e[1]}), + HTTP_BAD_INPUT, + {'ContentType': 'application/json'}) + + fodder_names = e[1] + fodder = emailapi_broker.get_email_fodder() + + if len(fodder_names) == 0 or len(fodder) == 0: + return (jsonify({"err_msg": "Data sheet is empty or not provided"}), + HTTP_BAD_INPUT, + {'ContentType': 'application/json'}) + + cnt = 0 + fodder_list = [] + for f in fodder: + if cnt == 2: + break + fodder_list.append(dict(zip(fodder_names, f))) + cnt += 1 + + if cnt == 0: + return (jsonify({'error_message': "Data sheet is empty or data sheet is not provided"}), + HTTP_BAD_INPUT, + {'ContentType': 'application/json'}) + + return (jsonify({'headers': fodder_names, 'contents': fodder_list}), + HTTP_OK, + {'ContentType': 'application/json'}) + + @flask_app.route('mapping', methods=['POST']) + def mapping(self): + """ + Specify the mapping of columns in the Excel sheet to targets (eg. attachment names) + + :return: + """ + data = json.loads(request.data) + emailapi_broker.save_attachment_column(data['attachment_column']) + return (jsonify({}), + HTTP_OK, + {'ContentType': 'application/json'}) + + +class AttachmentView(FlaskView): + """ + APIs for attachments to be used with the Sheet (by mapping) and sent with emails + """ + route_prefix = flask_app.config['URL_DEFAULT_PREFIX_FOR_API'] + + @flask_app.route('upload', methods=['POST']) + def upload(self): + """ + The 3rd party Angular plugin ng6-file-upload makes one POST call per file instead of + sending them all at once. + + To workaround this stupidity, this API is idempotent and will just keep saving + all files in the same dir + """ + a = request.files['attachment'] + attachment_dir = flask_app.config['ATTACHMENTS_DIR'] + + a.save(os.path.join(attachment_dir, a.filename)) + log.info('Attachment file saved as = %s' % (attachment_dir + a.filename)) + + emailapi_broker.save_attachment_dir(attachment_dir) + # TODO Call change_email_fodder_status() from save_attachment_dir() + emailapi_broker.change_email_fodder_status(a.filename) + return "Attachments saved successfully", HTTP_OK + + +class EmailView(FlaskView): + """ + APIs for email server, contents and actions + """ + route_prefix = flask_app.config['URL_DEFAULT_PREFIX_FOR_API'] + + + def server_details(self): + """ + SMTP server URL and credentials + + :return: + """ + data = json.loads(request.data) + + assert len(data['username']) > 0 and len(data['password']) > 0, "username or password not provided" + + e = emailapi_broker.set_login_details(data['username'], data['password']) + + if e[0] is not 0: + return (jsonify({'error_message': e[1]}), + HTTP_BAD_INPUT, + {'ContentType': 'application/json'}) + + return (jsonify({'error_message': ""}), + HTTP_OK, + {'ContentType': 'application/json'}) + + @flask_app.route('template_to_reality', methods=['POST']) + def template_to_reality(self): + """ + Convert an email template (subject or body) by replacing column name placeholders with actual data + + :return: + """ + data = json.loads(request.data) + fodder = emailapi_broker.get_email_fodder() + result_str = emailapi_broker.template_to_str(data['template'], fodder[0]) + + return (jsonify({'reality': result_str}), + HTTP_OK, + {'ContentType': 'application/json'}) + + @flask_app.route('metadata_contents', methods=['POST']) + def metadata_contents(self): + """ + Soecify email metadata (to, cc etc.) and content templates (subject, body) + + :return: + """ + data = json.loads(request.data) + if data['to_column'] == None or data['cc_column'] == None or data['subject_template'] == None or data[ + 'body_template'] == None: + return (jsonify({'error_message': "to, cc, subject or body not provided"}), + HTTP_BAD_INPUT, + {'ContentType': 'application/json'}) + + e = emailapi_broker.save_extended_fodder(data['to_column'], data['cc_column'], data['subject_template'], + data['body_template']) + if e[0] is not 0: + return (jsonify({"err_msg": e[1]}), + HTTP_BAD_INPUT, + {'ContentType': 'application/json'}) + + return (jsonify({}), + HTTP_OK, + {'ContentType': 'application/json'}) + + @flask_app.route('send_test', methods=['POST']) + def send_test(self): + """ + Send a test email (metadata and actual content in payload) + + :return: + """ + try: + data = json.loads(request.data) + tos = [] + tos.append(data['to']) + e = emailapi_broker.test_email(tos) + if e[0] is not 0: + return (jsonify({"err_msg": e[1]}), + HTTP_BAD_INPUT, + {'ContentType': 'application/json'}) + + return (jsonify({}), + HTTP_OK, + {'ContentType': 'application/json'}) + except: + log.exception("Failed to send test email") + + def send(self): + """ + Send a single email (metadata and actual content in payload) + + :return: + """ + try: + data = json.loads(request.data) + + tos = [] + tos.append(data['to']) + + ccs = [] + ccs.append(data['cc']) + + attachments = [] + at = data['attachment'] + for a in at: + attachments.append(a["name"]) + + e = emailapi_broker.send_email(data['from'], tos, data['subject'], data['body'], ccs, attachments) + if e[0] is not 0: + return (jsonify({"err_msg": e[1]}), + HTTP_BAD_INPUT, + {'ContentType': 'application/json'}) + + return (jsonify({}), + HTTP_OK, + {'ContentType': 'application/json'}) + except: + log.exception("Failed to send email") + + +SheetView.register(flask_app) +AttachmentView.register(flask_app) -# TODO Change this to a get request because using post for get is, well, stupid -# Check how to send multi line data in GET request -@flask_app.route("/api/burp/template", methods=['POST']) -def get_email_template(): - data = json.loads(request.data) - fodder = emailapi_broker.get_email_fodder() - result_str = emailapi_broker.template_to_str(data['template'], fodder[0]) +@flask_app.route("/api/version", methods=['GET']) +def get_version(): + """ + Get backend version (this doesn't need a CLassView since its a single API) - return (jsonify({'reality': result_str}), + :return: + """ + log.debug('Current version = %s' % (version.__pretty_version__)) + return (jsonify({'version': version.__pretty_version__}), HTTP_OK, - {'ContentType':'application/json'}) + {'ContentType':'application/json'}) + + +# The below APIs are never called by the GUI, who knows what they are for? @flask_app.route("/api/fodder/ingredients", methods=['GET']) def get_fodder_ingredients(): @@ -113,14 +357,6 @@ def get_fodder_ingredients(): HTTP_OK, {'ContentType':'application/json'}) -@flask_app.route("/api/fodder/achar/mapping", methods=['POST']) -def post_attachment_mapping(): - data = json.loads(request.data) - emailapi_broker.save_attachment_column(data['attachment_column']) - return (jsonify({}), - HTTP_OK, - {'ContentType':'application/json'}) - @flask_app.route("/api/attachment/validate", methods=['GET']) def get_attachment_validate(): @@ -149,162 +385,3 @@ def get_attachment_validate(): return (jsonify({'headers': fodder_names, 'content': fodder_list}), HTTP_OK, {'ContentType':'application/json'}) - -@flask_app.route("/api/fodder/achar", methods=['POST']) -def post_attachment(): - ''' - The 3rd party Angular plugin ng6-file-upload makes one POST call per file instead of - sending them all at once. - - To workaround this stupitidy, this API is idempotent and will just keep saving - all files in the same dir - ''' - try: - a = request.files['attachment'] - attachment_dir = flask_app.config['ATTACHMENTS_DIR'] - - a.save(os.path.join(attachment_dir, a.filename)) - log.info('Attachment file saved as = %s' % (attachment_dir + a.filename)) - - emailapi_broker.save_attachment_dir(attachment_dir) - # TODO Call change_email_fodder_status() from save_attachment_dir() - emailapi_broker.change_email_fodder_status(a.filename) - return "Attachments saved successfully", HTTP_OK - except: - log.exception("") - -@flask_app.route("/api/burp", methods=['POST']) -def post_email(): - data = json.loads(request.data) - if data['to_column'] == None or data['cc_column'] == None or data['subject_template'] == None or data['body_template'] == None: - return (jsonify({'error_message': "to, cc, subject or body not provided"}), - HTTP_BAD_INPUT, - {'ContentType':'application/json'}) - - e = emailapi_broker.save_extended_fodder(data['to_column'], data['cc_column'], data['subject_template'], data['body_template']) - if e[0] is not 0: - return (jsonify({"err_msg": e[1]}), - HTTP_BAD_INPUT, - {'ContentType':'application/json'}) - - return (jsonify({}), - HTTP_OK, - {'ContentType':'application/json'}) - - -@flask_app.route("/api/burp/test", methods=['POST']) -def post_email_test(): - try: - data = json.loads(request.data) - tos = [] - tos.append(data['to']) - e = emailapi_broker.test_email(tos) - if e[0] is not 0: - return (jsonify({"err_msg": e[1]}), - HTTP_BAD_INPUT, - {'ContentType':'application/json'}) - - return (jsonify({}), - HTTP_OK, - {'ContentType':'application/json'}) - except: - log.exception("Failed to send test email") - -@flask_app.route("/api/burp/send", methods=['POST']) -def post_email_send(): - try: - data = json.loads(request.data) - - tos = [] - tos.append(data['to']) - - ccs = [] - ccs.append(data['cc']) - - attachments = [] - at = data['attachment'] - for a in at: - attachments.append(a["name"]) - - e = emailapi_broker.send_email(data['from'], tos, data['subject'], data['body'], ccs, attachments) - if e[0] is not 0: - return (jsonify({"err_msg": e[1]}), - HTTP_BAD_INPUT, - {'ContentType':'application/json'}) - - return (jsonify({}), - HTTP_OK, - {'ContentType':'application/json'}) - except: - log.exception("Failed to send email"); - -@flask_app.route("/api/vomit", methods=['GET']) -def get_vomit(): - e = emailapi_broker.get_email_fodder_names() - if e[0] is not 0: - return (jsonify({"err_msg": e[1]}), - HTTP_BAD_INPUT, - {'ContentType':'application/json'}) - - fodder_names = e[1] - - if emailapi_broker.email_from == None: - return (jsonify({"err_msg": "Login details not yet provided"}), - HTTP_BAD_INPUT, - {'ContentType':'application/json'}) - - fodder = emailapi_broker.get_email_fodder() - extended_fodder = emailapi_broker.get_extended_email_fodder() - - if len(fodder_names) == 0 or len(fodder) == 0 or len(extended_fodder) == 0: - return (jsonify({'error_message': "Data sheet or email template not provided"}), - HTTP_BAD_INPUT, - {'ContentType':'application/json'}) - - assert len(fodder) == len(extended_fodder), "Count of fodder and extended_fodder do not match" - - if emailapi_broker.EMAIL_FODDER_TO_INDEX == None or emailapi_broker.EMAIL_FODDER_CC_INDEX == None: - return (jsonify({'error_message': "'To' or 'CC' index not provided"}), - HTTP_BAD_INPUT, - {'ContentType':'application/json'}) - - # Create fodder_list in email_broker - fodder_list = [] - for f, e in zip(fodder, extended_fodder): - at = [] - for a in e[-2]: - at_dict = {"name": a, "url": os.path.join("/api/fodder/achar/", a)} - at.append(at_dict) - email = { \ - "from": emailapi_broker.email_from, - "to": f[emailapi_broker.EMAIL_FODDER_TO_INDEX], - "cc": f[emailapi_broker.EMAIL_FODDER_CC_INDEX], - "attachment": at, - "subject": e[-4], - "body": e[-3], - } - - tmp = dict(zip(fodder_names, f)) - tmp["email"] = email - fodder_list.append(tmp) - - return (jsonify({'headers': fodder_names, 'contents': fodder_list}), - HTTP_OK, - {'ContentType':'application/json'}) - -@flask_app.route("/api/burp/server", methods=['POST']) -def post_email_server(): - data = json.loads(request.data) - - assert len(data['username']) > 0 and len(data['password']) > 0, "username or password not provided" - - e = emailapi_broker.set_login_details(data['username'], data['password']) - - if e[0] is not 0: - return (jsonify({'error_message': e[1]}), - HTTP_BAD_INPUT, - {'ContentType':'application/json'}) - - return (jsonify({'error_message': ""}), - HTTP_OK, - {'ContentType':'application/json'}) \ No newline at end of file From f3054952b8ffb01a0f2c23cf6350fa9de084724f Mon Sep 17 00:00:00 2001 From: Omkar Ekbote Date: Fri, 29 Mar 2019 23:00:21 +0530 Subject: [PATCH 03/64] Fix Flask runtime errors --- .../webserver/wittymail_server/rest_api.py | 26 ++++++++++--------- 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/backend/webserver/wittymail_server/rest_api.py b/backend/webserver/wittymail_server/rest_api.py index a4f55c9..e4af7e5 100644 --- a/backend/webserver/wittymail_server/rest_api.py +++ b/backend/webserver/wittymail_server/rest_api.py @@ -28,8 +28,8 @@ class SheetView(FlaskView): """ route_prefix = flask_app.config['URL_DEFAULT_PREFIX_FOR_API'] - @flask_app.route('upload', methods=['POST']) - def upload(self): + @flask_app.route('/api/sheet/upload', methods=['POST']) + def upload_sheet(self): """ Upload a new Excel sheet as input @@ -50,7 +50,7 @@ def upload(self): HTTP_OK, {'ContentType': 'application/json'}) - def get_file(self): + def file(self): """ Get the Excel sheet (*.xlsx file) updated with 'status' and other columns @@ -61,7 +61,7 @@ def get_file(self): return send_file(fodder_file) - def get_contents(self): + def contents(self): """ Get the contents of the sheet updated with 'status' and other columns @@ -156,7 +156,7 @@ def headers(self): HTTP_OK, {'ContentType': 'application/json'}) - @flask_app.route('mapping', methods=['POST']) + @flask_app.route('/api/sheet/mapping', methods=['POST']) def mapping(self): """ Specify the mapping of columns in the Excel sheet to targets (eg. attachment names) @@ -176,8 +176,8 @@ class AttachmentView(FlaskView): """ route_prefix = flask_app.config['URL_DEFAULT_PREFIX_FOR_API'] - @flask_app.route('upload', methods=['POST']) - def upload(self): + @flask_app.route('/api/attachment/upload', methods=['POST']) + def upload_attachment(self): """ The 3rd party Angular plugin ng6-file-upload makes one POST call per file instead of sending them all at once. @@ -203,7 +203,7 @@ class EmailView(FlaskView): """ route_prefix = flask_app.config['URL_DEFAULT_PREFIX_FOR_API'] - + @flask_app.route('/api/email/server', methods=['POST']) def server_details(self): """ SMTP server URL and credentials @@ -225,7 +225,7 @@ def server_details(self): HTTP_OK, {'ContentType': 'application/json'}) - @flask_app.route('template_to_reality', methods=['POST']) + @flask_app.route('/api/email/template_to_reality', methods=['POST']) def template_to_reality(self): """ Convert an email template (subject or body) by replacing column name placeholders with actual data @@ -240,7 +240,7 @@ def template_to_reality(self): HTTP_OK, {'ContentType': 'application/json'}) - @flask_app.route('metadata_contents', methods=['POST']) + @flask_app.route('/api/email/metadata_contents', methods=['POST']) def metadata_contents(self): """ Soecify email metadata (to, cc etc.) and content templates (subject, body) @@ -265,7 +265,7 @@ def metadata_contents(self): HTTP_OK, {'ContentType': 'application/json'}) - @flask_app.route('send_test', methods=['POST']) + @flask_app.route('/api/email/send_test', methods=['POST']) def send_test(self): """ Send a test email (metadata and actual content in payload) @@ -288,6 +288,7 @@ def send_test(self): except: log.exception("Failed to send test email") + @flask_app.route('/api/email/send', methods=['POST']) def send(self): """ Send a single email (metadata and actual content in payload) @@ -323,6 +324,7 @@ def send(self): SheetView.register(flask_app) AttachmentView.register(flask_app) +EmailView.register(flask_app) @flask_app.route("/api/version", methods=['GET']) def get_version(): @@ -337,7 +339,7 @@ def get_version(): {'ContentType':'application/json'}) -# The below APIs are never called by the GUI, who knows what they are for? +# The below APIs are never called by the GUI, who knows what they are for? ############################################# @flask_app.route("/api/fodder/ingredients", methods=['GET']) def get_fodder_ingredients(): From d7d4829236bad3b593e24a410f05af4b2bb0a7ee Mon Sep 17 00:00:00 2001 From: Omkar Ekbote Date: Sat, 30 Mar 2019 00:21:39 +0530 Subject: [PATCH 04/64] Integrate new URLs with frontend --- .../webserver/wittymail_server/__init__.py | 2 +- .../wittymail_server/default_routes.py | 4 +- .../webserver/wittymail_server/rest_api.py | 27 +++++---- .../wittymail/src/app/wittymail.service.ts | 59 ++++++++++++------- 4 files changed, 55 insertions(+), 37 deletions(-) diff --git a/backend/webserver/wittymail_server/__init__.py b/backend/webserver/wittymail_server/__init__.py index e59df89..032c407 100644 --- a/backend/webserver/wittymail_server/__init__.py +++ b/backend/webserver/wittymail_server/__init__.py @@ -62,7 +62,7 @@ def get_attachments_dir(): flask_app.config['ATTACHMENTS_DIR'] = a flask_app.config['FODDER_DIR'] = f - flask_app.config['URL_DEFAULT_PREFIX_FOR_API'] = '/api/' + flask_app.config['URL_DEFAULT_PREFIX_FOR_API'] = '/api' # Import other Flask sub-modules containing URL handlers import wittymail_server.default_routes diff --git a/backend/webserver/wittymail_server/default_routes.py b/backend/webserver/wittymail_server/default_routes.py index a3bf1e5..ee00f9c 100644 --- a/backend/webserver/wittymail_server/default_routes.py +++ b/backend/webserver/wittymail_server/default_routes.py @@ -28,10 +28,10 @@ def route_static_files(path): ''' return send_from_directory(os.path.join(base_path, "static"), path) -@flask_app.route('/api/fodder/achar/') +@flask_app.route('/attachment/') def route_attachment_files(path): return send_from_directory(flask_app.config['ATTACHMENTS_DIR'], path) -@flask_app.route('/api/fodder/') +@flask_app.route('/sheet/') def route_fodder_file(path): return send_from_directory(flask_app.config['FODDER_DIR'], path) \ No newline at end of file diff --git a/backend/webserver/wittymail_server/rest_api.py b/backend/webserver/wittymail_server/rest_api.py index e4af7e5..ea2bcef 100644 --- a/backend/webserver/wittymail_server/rest_api.py +++ b/backend/webserver/wittymail_server/rest_api.py @@ -7,8 +7,8 @@ import mailer.emailapi_broker as emailapi_broker from wittymail_server import flask_app -from flask import jsonify, request, json -from flask_classy import FlaskView +from flask import jsonify, request, json, url_for +from flask_classy import FlaskView, route import util.version as version import util.logger as logger from flask import send_file @@ -28,14 +28,14 @@ class SheetView(FlaskView): """ route_prefix = flask_app.config['URL_DEFAULT_PREFIX_FOR_API'] - @flask_app.route('/api/sheet/upload', methods=['POST']) - def upload_sheet(self): + @route('upload', methods=['POST']) + def some(self): """ Upload a new Excel sheet as input :return: """ - log.debug("Uploading sheet: ", request.files) + log.debug("Uploading sheet: %s", request.files) fodder_dir = flask_app.config['FODDER_DIR'] f = request.files['fodder'] @@ -67,6 +67,7 @@ def contents(self): :return: """ + log.info("URL: %s", url_for('SheetView:some')) e = emailapi_broker.get_email_fodder_names() if e[0] is not 0: return (jsonify({"err_msg": e[1]}), @@ -100,7 +101,7 @@ def contents(self): for f, e in zip(fodder, extended_fodder): at = [] for a in e[-2]: - at_dict = {"name": a, "url": os.path.join("/api/fodder/achar/", a)} + at_dict = {"name": a, "url": os.path.join("/attachment/", a)} at.append(at_dict) email = { \ "from": emailapi_broker.email_from, @@ -156,7 +157,7 @@ def headers(self): HTTP_OK, {'ContentType': 'application/json'}) - @flask_app.route('/api/sheet/mapping', methods=['POST']) + @route('mapping', methods=['POST']) def mapping(self): """ Specify the mapping of columns in the Excel sheet to targets (eg. attachment names) @@ -176,7 +177,7 @@ class AttachmentView(FlaskView): """ route_prefix = flask_app.config['URL_DEFAULT_PREFIX_FOR_API'] - @flask_app.route('/api/attachment/upload', methods=['POST']) + @route('upload', methods=['POST']) def upload_attachment(self): """ The 3rd party Angular plugin ng6-file-upload makes one POST call per file instead of @@ -203,7 +204,7 @@ class EmailView(FlaskView): """ route_prefix = flask_app.config['URL_DEFAULT_PREFIX_FOR_API'] - @flask_app.route('/api/email/server', methods=['POST']) + @route('server', methods=['POST']) def server_details(self): """ SMTP server URL and credentials @@ -225,7 +226,7 @@ def server_details(self): HTTP_OK, {'ContentType': 'application/json'}) - @flask_app.route('/api/email/template_to_reality', methods=['POST']) + @route('template_to_reality', methods=['POST']) def template_to_reality(self): """ Convert an email template (subject or body) by replacing column name placeholders with actual data @@ -240,7 +241,7 @@ def template_to_reality(self): HTTP_OK, {'ContentType': 'application/json'}) - @flask_app.route('/api/email/metadata_contents', methods=['POST']) + @route('metadata_contents', methods=['POST']) def metadata_contents(self): """ Soecify email metadata (to, cc etc.) and content templates (subject, body) @@ -265,7 +266,7 @@ def metadata_contents(self): HTTP_OK, {'ContentType': 'application/json'}) - @flask_app.route('/api/email/send_test', methods=['POST']) + @route('send_test', methods=['POST']) def send_test(self): """ Send a test email (metadata and actual content in payload) @@ -288,7 +289,7 @@ def send_test(self): except: log.exception("Failed to send test email") - @flask_app.route('/api/email/send', methods=['POST']) + @route('send', methods=['POST']) def send(self): """ Send a single email (metadata and actual content in payload) diff --git a/frontend/wittymail/src/app/wittymail.service.ts b/frontend/wittymail/src/app/wittymail.service.ts index 31f29df..59674aa 100644 --- a/frontend/wittymail/src/app/wittymail.service.ts +++ b/frontend/wittymail/src/app/wittymail.service.ts @@ -69,16 +69,33 @@ export class WittymailService { urls = { version: 'api/version', // GET - fodder: 'api/fodder', // POST, GET - regurgitate: 'api/fodder/regurgitate', // POST - vomit: 'api/vomit', //POST - attachment: 'api/fodder/achar', // POST - attachment_metadata: 'api/fodder/achar/mapping', // POST - email: 'api/burp', // POST - email_server: 'api/burp/server', // POST - email_test: 'api/burp/test', // POST - email_send: 'api/burp/send', // POST - template_resolver: 'api/burp/template' // POST + sheet: { + upload: 'api/sheet/upload', // POST + get_file: 'api/sheet/file', // GET + get_contents: 'api/sheet/contents', //GET + get_headers: 'api/sheet/headers', // GET + set_mapping: 'api/sheet/mapping' // POST + }, + attachment: { + upload: 'api/attachment/upload' // POST + }, + email: { + set_server: 'api/email/server', // POST + convert_template_to_string: 'api/email/template_to_reality', // POST + set_metadata_and_contents: 'api/email/metadata_contents', // POST + send_test: 'api/email/send_test', // POST + send: 'api/email/send' // POST + } + // fodder: 'api/fodder', // POST, GET + // regurgitate: 'api/fodder/regurgitate', // POST + // vomit: 'api/vomit', //POST + // attachment: 'api/fodder/achar', // POST + // attachment_metadata: 'api/fodder/achar/mapping', // POST + // email: 'api/burp', // POST + // email_server: 'api/burp/server', // POST + // email_test: 'api/burp/test', // POST + // email_send: 'api/burp/send', // POST + // template_resolver: 'api/burp/template' // POST } constructor(private log: LoggerService, private http: HttpClient) { @@ -129,26 +146,26 @@ export class WittymailService { } getFodderUploadUrl(): string { - return this.urls.fodder; + return this.urls.sheet.upload; } getFodderDownloadUrl(): string { - return this.urls.fodder; + return this.urls.sheet.get_file; } getAttachmentUploadUrl(): string { - return this.urls.attachment; + return this.urls.attachment.upload; } getColumnHeadersWithSampleRows(): Observable { - return this.http.get(this.urls.regurgitate) + return this.http.get(this.urls.sheet.get_headers) .pipe( catchError(this.handleError('getColumnHeadersWithSampleRows')) ); } getVomit(): Observable { - return this.http.get(this.urls.vomit) + return this.http.get(this.urls.sheet.get_contents) .pipe( catchError(this.handleError('getVomit')) ); @@ -226,7 +243,7 @@ export class WittymailService { resolveTemplate(input: TemplateInput): Observable { this.log.info("POSTing template: ", input); - return this.http.post(this.urls.template_resolver, input) + return this.http.post(this.urls.email.convert_template_to_string, input) .pipe( catchError(this.handleError('resolveTemplate')) ); @@ -234,7 +251,7 @@ export class WittymailService { postEmailMetadata(): Observable { this.log.info("POSTing email metadata: ", this.emailMetadataInstance); - return this.http.post(this.urls.email, this.emailMetadataInstance) + return this.http.post(this.urls.email.set_metadata_and_contents, this.emailMetadataInstance) .pipe( catchError(this.handleError('postEmailMetadata')) ); @@ -242,7 +259,7 @@ export class WittymailService { postAttachmentMetadata(): Observable { this.log.info("POSTing attachment metadata: ", this.attachmentMetadataInstance); - return this.http.post(this.urls.attachment_metadata, this.attachmentMetadataInstance) + return this.http.post(this.urls.sheet.set_mapping, this.attachmentMetadataInstance) .pipe( catchError(this.handleError('postAttachmentMetadata')) ); @@ -250,7 +267,7 @@ export class WittymailService { postEmailServerDetails(payload: EmailServerDetails): Observable { this.log.info("POSTing email server details: ", payload); - return this.http.post(this.urls.email_server, payload) + return this.http.post(this.urls.email.set_server, payload) .pipe( catchError(this.handleError('postEmailServerDetails')) ); @@ -258,7 +275,7 @@ export class WittymailService { postTestEmail(payload: TestEmailDetails): Observable { this.log.info("POSTing test email details: ", payload); - return this.http.post(this.urls.email_test, payload) + return this.http.post(this.urls.email.send_test, payload) .pipe( catchError(this.handleError('postTestEmail')) ); @@ -266,7 +283,7 @@ export class WittymailService { postSendEmail(payload: SendEmailContent): Observable { this.log.info("POSTing email details: ", payload); - return this.http.post(this.urls.email_send, payload) + return this.http.post(this.urls.email.send, payload) .pipe( catchError(this.handleError('postSendEmail')) ); From 4c68bad0133fb5ec6e9361ff4f219bdb6687783f Mon Sep 17 00:00:00 2001 From: Omkar Ekbote Date: Sat, 20 Apr 2019 19:45:30 +0530 Subject: [PATCH 05/64] Create new Angular project for v2 --- frontend/wittymail-v2/.editorconfig | 13 + frontend/wittymail-v2/.gitignore | 46 + frontend/wittymail-v2/README.md | 27 + frontend/wittymail-v2/angular.json | 136 + frontend/wittymail-v2/e2e/protractor.conf.js | 28 + frontend/wittymail-v2/e2e/src/app.e2e-spec.ts | 23 + frontend/wittymail-v2/e2e/src/app.po.ts | 11 + frontend/wittymail-v2/e2e/tsconfig.e2e.json | 13 + frontend/wittymail-v2/package.json | 48 + .../src/app/app-routing.module.ts | 10 + .../wittymail-v2/src/app/app.component.css | 0 .../wittymail-v2/src/app/app.component.html | 21 + .../src/app/app.component.spec.ts | 35 + .../wittymail-v2/src/app/app.component.ts | 10 + frontend/wittymail-v2/src/app/app.module.ts | 18 + frontend/wittymail-v2/src/assets/.gitkeep | 0 frontend/wittymail-v2/src/browserslist | 11 + .../src/environments/environment.prod.ts | 3 + .../src/environments/environment.ts | 16 + frontend/wittymail-v2/src/favicon.ico | Bin 0 -> 5430 bytes frontend/wittymail-v2/src/index.html | 14 + frontend/wittymail-v2/src/karma.conf.js | 32 + frontend/wittymail-v2/src/main.ts | 12 + frontend/wittymail-v2/src/polyfills.ts | 63 + frontend/wittymail-v2/src/styles.css | 1 + frontend/wittymail-v2/src/test.ts | 20 + frontend/wittymail-v2/src/tsconfig.app.json | 11 + frontend/wittymail-v2/src/tsconfig.spec.json | 18 + frontend/wittymail-v2/src/tslint.json | 17 + frontend/wittymail-v2/tsconfig.json | 22 + frontend/wittymail-v2/tslint.json | 75 + frontend/wittymail-v2/yarn.lock | 7236 +++++++++++++++++ 32 files changed, 7990 insertions(+) create mode 100644 frontend/wittymail-v2/.editorconfig create mode 100644 frontend/wittymail-v2/.gitignore create mode 100644 frontend/wittymail-v2/README.md create mode 100644 frontend/wittymail-v2/angular.json create mode 100644 frontend/wittymail-v2/e2e/protractor.conf.js create mode 100644 frontend/wittymail-v2/e2e/src/app.e2e-spec.ts create mode 100644 frontend/wittymail-v2/e2e/src/app.po.ts create mode 100644 frontend/wittymail-v2/e2e/tsconfig.e2e.json create mode 100644 frontend/wittymail-v2/package.json create mode 100644 frontend/wittymail-v2/src/app/app-routing.module.ts create mode 100644 frontend/wittymail-v2/src/app/app.component.css create mode 100644 frontend/wittymail-v2/src/app/app.component.html create mode 100644 frontend/wittymail-v2/src/app/app.component.spec.ts create mode 100644 frontend/wittymail-v2/src/app/app.component.ts create mode 100644 frontend/wittymail-v2/src/app/app.module.ts create mode 100644 frontend/wittymail-v2/src/assets/.gitkeep create mode 100644 frontend/wittymail-v2/src/browserslist create mode 100644 frontend/wittymail-v2/src/environments/environment.prod.ts create mode 100644 frontend/wittymail-v2/src/environments/environment.ts create mode 100644 frontend/wittymail-v2/src/favicon.ico create mode 100644 frontend/wittymail-v2/src/index.html create mode 100644 frontend/wittymail-v2/src/karma.conf.js create mode 100644 frontend/wittymail-v2/src/main.ts create mode 100644 frontend/wittymail-v2/src/polyfills.ts create mode 100644 frontend/wittymail-v2/src/styles.css create mode 100644 frontend/wittymail-v2/src/test.ts create mode 100644 frontend/wittymail-v2/src/tsconfig.app.json create mode 100644 frontend/wittymail-v2/src/tsconfig.spec.json create mode 100644 frontend/wittymail-v2/src/tslint.json create mode 100644 frontend/wittymail-v2/tsconfig.json create mode 100644 frontend/wittymail-v2/tslint.json create mode 100644 frontend/wittymail-v2/yarn.lock diff --git a/frontend/wittymail-v2/.editorconfig b/frontend/wittymail-v2/.editorconfig new file mode 100644 index 0000000..e89330a --- /dev/null +++ b/frontend/wittymail-v2/.editorconfig @@ -0,0 +1,13 @@ +# Editor configuration, see https://editorconfig.org +root = true + +[*] +charset = utf-8 +indent_style = space +indent_size = 2 +insert_final_newline = true +trim_trailing_whitespace = true + +[*.md] +max_line_length = off +trim_trailing_whitespace = false diff --git a/frontend/wittymail-v2/.gitignore b/frontend/wittymail-v2/.gitignore new file mode 100644 index 0000000..f4f46a5 --- /dev/null +++ b/frontend/wittymail-v2/.gitignore @@ -0,0 +1,46 @@ +# See http://help.github.com/ignore-files/ for more about ignoring files. + +# compiled output +/dist +/tmp +/out-tsc +# Only exists if Bazel was run +/bazel-out + +# dependencies +/node_modules + +# profiling files +chrome-profiler-events.json +speed-measure-plugin.json + +# IDEs and editors +/.idea +.project +.classpath +.c9/ +*.launch +.settings/ +*.sublime-workspace + +# IDE - VSCode +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +.history/* + +# misc +/.sass-cache +/connect.lock +/coverage +/libpeerconnection.log +npm-debug.log +yarn-error.log +testem.log +/typings + +# System Files +.DS_Store +Thumbs.db diff --git a/frontend/wittymail-v2/README.md b/frontend/wittymail-v2/README.md new file mode 100644 index 0000000..8ed4935 --- /dev/null +++ b/frontend/wittymail-v2/README.md @@ -0,0 +1,27 @@ +# WittymailV2 + +This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 7.3.8. + +## Development server + +Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The app will automatically reload if you change any of the source files. + +## Code scaffolding + +Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`. + +## Build + +Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory. Use the `--prod` flag for a production build. + +## Running unit tests + +Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io). + +## Running end-to-end tests + +Run `ng e2e` to execute the end-to-end tests via [Protractor](http://www.protractortest.org/). + +## Further help + +To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI README](https://github.com/angular/angular-cli/blob/master/README.md). diff --git a/frontend/wittymail-v2/angular.json b/frontend/wittymail-v2/angular.json new file mode 100644 index 0000000..e82229e --- /dev/null +++ b/frontend/wittymail-v2/angular.json @@ -0,0 +1,136 @@ +{ + "$schema": "./node_modules/@angular/cli/lib/config/schema.json", + "version": 1, + "newProjectRoot": "projects", + "projects": { + "wittymail-v2": { + "root": "", + "sourceRoot": "src", + "projectType": "application", + "prefix": "app", + "schematics": {}, + "architect": { + "build": { + "builder": "@angular-devkit/build-angular:browser", + "options": { + "outputPath": "dist/wittymail-v2", + "index": "src/index.html", + "main": "src/main.ts", + "polyfills": "src/polyfills.ts", + "tsConfig": "src/tsconfig.app.json", + "assets": [ + "src/favicon.ico", + "src/assets" + ], + "styles": [ + "src/styles.css" + ], + "scripts": [], + "es5BrowserSupport": true + }, + "configurations": { + "production": { + "fileReplacements": [ + { + "replace": "src/environments/environment.ts", + "with": "src/environments/environment.prod.ts" + } + ], + "optimization": true, + "outputHashing": "all", + "sourceMap": false, + "extractCss": true, + "namedChunks": false, + "aot": true, + "extractLicenses": true, + "vendorChunk": false, + "buildOptimizer": true, + "budgets": [ + { + "type": "initial", + "maximumWarning": "2mb", + "maximumError": "5mb" + } + ] + } + } + }, + "serve": { + "builder": "@angular-devkit/build-angular:dev-server", + "options": { + "browserTarget": "wittymail-v2:build" + }, + "configurations": { + "production": { + "browserTarget": "wittymail-v2:build:production" + } + } + }, + "extract-i18n": { + "builder": "@angular-devkit/build-angular:extract-i18n", + "options": { + "browserTarget": "wittymail-v2:build" + } + }, + "test": { + "builder": "@angular-devkit/build-angular:karma", + "options": { + "main": "src/test.ts", + "polyfills": "src/polyfills.ts", + "tsConfig": "src/tsconfig.spec.json", + "karmaConfig": "src/karma.conf.js", + "styles": [ + "src/styles.css" + ], + "scripts": [], + "assets": [ + "src/favicon.ico", + "src/assets" + ] + } + }, + "lint": { + "builder": "@angular-devkit/build-angular:tslint", + "options": { + "tsConfig": [ + "src/tsconfig.app.json", + "src/tsconfig.spec.json" + ], + "exclude": [ + "**/node_modules/**" + ] + } + } + } + }, + "wittymail-v2-e2e": { + "root": "e2e/", + "projectType": "application", + "prefix": "", + "architect": { + "e2e": { + "builder": "@angular-devkit/build-angular:protractor", + "options": { + "protractorConfig": "e2e/protractor.conf.js", + "devServerTarget": "wittymail-v2:serve" + }, + "configurations": { + "production": { + "devServerTarget": "wittymail-v2:serve:production" + } + } + }, + "lint": { + "builder": "@angular-devkit/build-angular:tslint", + "options": { + "tsConfig": "e2e/tsconfig.e2e.json", + "exclude": [ + "**/node_modules/**" + ] + } + } + } + } + }, + "defaultProject": "wittymail-v2" +} \ No newline at end of file diff --git a/frontend/wittymail-v2/e2e/protractor.conf.js b/frontend/wittymail-v2/e2e/protractor.conf.js new file mode 100644 index 0000000..86776a3 --- /dev/null +++ b/frontend/wittymail-v2/e2e/protractor.conf.js @@ -0,0 +1,28 @@ +// Protractor configuration file, see link for more information +// https://github.com/angular/protractor/blob/master/lib/config.ts + +const { SpecReporter } = require('jasmine-spec-reporter'); + +exports.config = { + allScriptsTimeout: 11000, + specs: [ + './src/**/*.e2e-spec.ts' + ], + capabilities: { + 'browserName': 'chrome' + }, + directConnect: true, + baseUrl: 'http://localhost:4200/', + framework: 'jasmine', + jasmineNodeOpts: { + showColors: true, + defaultTimeoutInterval: 30000, + print: function() {} + }, + onPrepare() { + require('ts-node').register({ + project: require('path').join(__dirname, './tsconfig.e2e.json') + }); + jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } })); + } +}; \ No newline at end of file diff --git a/frontend/wittymail-v2/e2e/src/app.e2e-spec.ts b/frontend/wittymail-v2/e2e/src/app.e2e-spec.ts new file mode 100644 index 0000000..154da28 --- /dev/null +++ b/frontend/wittymail-v2/e2e/src/app.e2e-spec.ts @@ -0,0 +1,23 @@ +import { AppPage } from './app.po'; +import { browser, logging } from 'protractor'; + +describe('workspace-project App', () => { + let page: AppPage; + + beforeEach(() => { + page = new AppPage(); + }); + + it('should display welcome message', () => { + page.navigateTo(); + expect(page.getTitleText()).toEqual('Welcome to wittymail-v2!'); + }); + + afterEach(async () => { + // Assert that there are no errors emitted from the browser + const logs = await browser.manage().logs().get(logging.Type.BROWSER); + expect(logs).not.toContain(jasmine.objectContaining({ + level: logging.Level.SEVERE, + } as logging.Entry)); + }); +}); diff --git a/frontend/wittymail-v2/e2e/src/app.po.ts b/frontend/wittymail-v2/e2e/src/app.po.ts new file mode 100644 index 0000000..5776aa9 --- /dev/null +++ b/frontend/wittymail-v2/e2e/src/app.po.ts @@ -0,0 +1,11 @@ +import { browser, by, element } from 'protractor'; + +export class AppPage { + navigateTo() { + return browser.get(browser.baseUrl) as Promise; + } + + getTitleText() { + return element(by.css('app-root h1')).getText() as Promise; + } +} diff --git a/frontend/wittymail-v2/e2e/tsconfig.e2e.json b/frontend/wittymail-v2/e2e/tsconfig.e2e.json new file mode 100644 index 0000000..a6dd622 --- /dev/null +++ b/frontend/wittymail-v2/e2e/tsconfig.e2e.json @@ -0,0 +1,13 @@ +{ + "extends": "../tsconfig.json", + "compilerOptions": { + "outDir": "../out-tsc/app", + "module": "commonjs", + "target": "es5", + "types": [ + "jasmine", + "jasminewd2", + "node" + ] + } +} \ No newline at end of file diff --git a/frontend/wittymail-v2/package.json b/frontend/wittymail-v2/package.json new file mode 100644 index 0000000..499420c --- /dev/null +++ b/frontend/wittymail-v2/package.json @@ -0,0 +1,48 @@ +{ + "name": "wittymail-v2", + "version": "0.0.0", + "scripts": { + "ng": "ng", + "start": "ng serve", + "build": "ng build", + "test": "ng test", + "lint": "ng lint", + "e2e": "ng e2e" + }, + "private": true, + "dependencies": { + "@angular/animations": "~7.2.0", + "@angular/common": "~7.2.0", + "@angular/compiler": "~7.2.0", + "@angular/core": "~7.2.0", + "@angular/forms": "~7.2.0", + "@angular/platform-browser": "~7.2.0", + "@angular/platform-browser-dynamic": "~7.2.0", + "@angular/router": "~7.2.0", + "core-js": "^2.5.4", + "rxjs": "~6.3.3", + "tslib": "^1.9.0", + "zone.js": "~0.8.26" + }, + "devDependencies": { + "@angular-devkit/build-angular": "~0.13.0", + "@angular/cli": "~7.3.8", + "@angular/compiler-cli": "~7.2.0", + "@angular/language-service": "~7.2.0", + "@types/node": "~8.9.4", + "@types/jasmine": "~2.8.8", + "@types/jasminewd2": "~2.0.3", + "codelyzer": "~4.5.0", + "jasmine-core": "~2.99.1", + "jasmine-spec-reporter": "~4.2.1", + "karma": "~4.0.0", + "karma-chrome-launcher": "~2.2.0", + "karma-coverage-istanbul-reporter": "~2.0.1", + "karma-jasmine": "~1.1.2", + "karma-jasmine-html-reporter": "^0.2.2", + "protractor": "~5.4.0", + "ts-node": "~7.0.0", + "tslint": "~5.11.0", + "typescript": "~3.2.2" + } +} diff --git a/frontend/wittymail-v2/src/app/app-routing.module.ts b/frontend/wittymail-v2/src/app/app-routing.module.ts new file mode 100644 index 0000000..d425c6f --- /dev/null +++ b/frontend/wittymail-v2/src/app/app-routing.module.ts @@ -0,0 +1,10 @@ +import { NgModule } from '@angular/core'; +import { Routes, RouterModule } from '@angular/router'; + +const routes: Routes = []; + +@NgModule({ + imports: [RouterModule.forRoot(routes)], + exports: [RouterModule] +}) +export class AppRoutingModule { } diff --git a/frontend/wittymail-v2/src/app/app.component.css b/frontend/wittymail-v2/src/app/app.component.css new file mode 100644 index 0000000..e69de29 diff --git a/frontend/wittymail-v2/src/app/app.component.html b/frontend/wittymail-v2/src/app/app.component.html new file mode 100644 index 0000000..0f3d9d8 --- /dev/null +++ b/frontend/wittymail-v2/src/app/app.component.html @@ -0,0 +1,21 @@ + +
+

+ Welcome to {{ title }}! +

+ Angular Logo +
+

Here are some links to help you start:

+ + + diff --git a/frontend/wittymail-v2/src/app/app.component.spec.ts b/frontend/wittymail-v2/src/app/app.component.spec.ts new file mode 100644 index 0000000..33a0690 --- /dev/null +++ b/frontend/wittymail-v2/src/app/app.component.spec.ts @@ -0,0 +1,35 @@ +import { TestBed, async } from '@angular/core/testing'; +import { RouterTestingModule } from '@angular/router/testing'; +import { AppComponent } from './app.component'; + +describe('AppComponent', () => { + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [ + RouterTestingModule + ], + declarations: [ + AppComponent + ], + }).compileComponents(); + })); + + it('should create the app', () => { + const fixture = TestBed.createComponent(AppComponent); + const app = fixture.debugElement.componentInstance; + expect(app).toBeTruthy(); + }); + + it(`should have as title 'wittymail-v2'`, () => { + const fixture = TestBed.createComponent(AppComponent); + const app = fixture.debugElement.componentInstance; + expect(app.title).toEqual('wittymail-v2'); + }); + + it('should render title in a h1 tag', () => { + const fixture = TestBed.createComponent(AppComponent); + fixture.detectChanges(); + const compiled = fixture.debugElement.nativeElement; + expect(compiled.querySelector('h1').textContent).toContain('Welcome to wittymail-v2!'); + }); +}); diff --git a/frontend/wittymail-v2/src/app/app.component.ts b/frontend/wittymail-v2/src/app/app.component.ts new file mode 100644 index 0000000..20ce772 --- /dev/null +++ b/frontend/wittymail-v2/src/app/app.component.ts @@ -0,0 +1,10 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: 'app-root', + templateUrl: './app.component.html', + styleUrls: ['./app.component.css'] +}) +export class AppComponent { + title = 'wittymail-v2'; +} diff --git a/frontend/wittymail-v2/src/app/app.module.ts b/frontend/wittymail-v2/src/app/app.module.ts new file mode 100644 index 0000000..2c3ba29 --- /dev/null +++ b/frontend/wittymail-v2/src/app/app.module.ts @@ -0,0 +1,18 @@ +import { BrowserModule } from '@angular/platform-browser'; +import { NgModule } from '@angular/core'; + +import { AppRoutingModule } from './app-routing.module'; +import { AppComponent } from './app.component'; + +@NgModule({ + declarations: [ + AppComponent + ], + imports: [ + BrowserModule, + AppRoutingModule + ], + providers: [], + bootstrap: [AppComponent] +}) +export class AppModule { } diff --git a/frontend/wittymail-v2/src/assets/.gitkeep b/frontend/wittymail-v2/src/assets/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/frontend/wittymail-v2/src/browserslist b/frontend/wittymail-v2/src/browserslist new file mode 100644 index 0000000..37371cb --- /dev/null +++ b/frontend/wittymail-v2/src/browserslist @@ -0,0 +1,11 @@ +# This file is currently used by autoprefixer to adjust CSS to support the below specified browsers +# For additional information regarding the format and rule options, please see: +# https://github.com/browserslist/browserslist#queries +# +# For IE 9-11 support, please remove 'not' from the last line of the file and adjust as needed + +> 0.5% +last 2 versions +Firefox ESR +not dead +not IE 9-11 \ No newline at end of file diff --git a/frontend/wittymail-v2/src/environments/environment.prod.ts b/frontend/wittymail-v2/src/environments/environment.prod.ts new file mode 100644 index 0000000..3612073 --- /dev/null +++ b/frontend/wittymail-v2/src/environments/environment.prod.ts @@ -0,0 +1,3 @@ +export const environment = { + production: true +}; diff --git a/frontend/wittymail-v2/src/environments/environment.ts b/frontend/wittymail-v2/src/environments/environment.ts new file mode 100644 index 0000000..7b4f817 --- /dev/null +++ b/frontend/wittymail-v2/src/environments/environment.ts @@ -0,0 +1,16 @@ +// This file can be replaced during build by using the `fileReplacements` array. +// `ng build --prod` replaces `environment.ts` with `environment.prod.ts`. +// The list of file replacements can be found in `angular.json`. + +export const environment = { + production: false +}; + +/* + * For easier debugging in development mode, you can import the following file + * to ignore zone related error stack frames such as `zone.run`, `zoneDelegate.invokeTask`. + * + * This import should be commented out in production mode because it will have a negative impact + * on performance if an error is thrown. + */ +// import 'zone.js/dist/zone-error'; // Included with Angular CLI. diff --git a/frontend/wittymail-v2/src/favicon.ico b/frontend/wittymail-v2/src/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..8081c7ceaf2be08bf59010158c586170d9d2d517 GIT binary patch literal 5430 zcmc(je{54#6vvCoAI3i*G5%$U7!sA3wtMZ$fH6V9C`=eXGJb@R1%(I_{vnZtpD{6n z5Pl{DmxzBDbrB>}`90e12m8T*36WoeDLA&SD_hw{H^wM!cl_RWcVA!I+x87ee975; z@4kD^=bYPn&pmG@(+JZ`rqQEKxW<}RzhW}I!|ulN=fmjVi@x{p$cC`)5$a!)X&U+blKNvN5tg=uLvuLnuqRM;Yc*swiexsoh#XPNu{9F#c`G zQLe{yWA(Y6(;>y|-efAy11k<09(@Oo1B2@0`PtZSkqK&${ zgEY}`W@t{%?9u5rF?}Y7OL{338l*JY#P!%MVQY@oqnItpZ}?s z!r?*kwuR{A@jg2Chlf0^{q*>8n5Ir~YWf*wmsh7B5&EpHfd5@xVaj&gqsdui^spyL zB|kUoblGoO7G(MuKTfa9?pGH0@QP^b#!lM1yHWLh*2iq#`C1TdrnO-d#?Oh@XV2HK zKA{`eo{--^K&MW66Lgsktfvn#cCAc*(}qsfhrvOjMGLE?`dHVipu1J3Kgr%g?cNa8 z)pkmC8DGH~fG+dlrp(5^-QBeEvkOvv#q7MBVLtm2oD^$lJZx--_=K&Ttd=-krx(Bb zcEoKJda@S!%%@`P-##$>*u%T*mh+QjV@)Qa=Mk1?#zLk+M4tIt%}wagT{5J%!tXAE;r{@=bb%nNVxvI+C+$t?!VJ@0d@HIyMJTI{vEw0Ul ze(ha!e&qANbTL1ZneNl45t=#Ot??C0MHjjgY8%*mGisN|S6%g3;Hlx#fMNcL<87MW zZ>6moo1YD?P!fJ#Jb(4)_cc50X5n0KoDYfdPoL^iV`k&o{LPyaoqMqk92wVM#_O0l z09$(A-D+gVIlq4TA&{1T@BsUH`Bm=r#l$Z51J-U&F32+hfUP-iLo=jg7Xmy+WLq6_tWv&`wDlz#`&)Jp~iQf zZP)tu>}pIIJKuw+$&t}GQuqMd%Z>0?t%&BM&Wo^4P^Y z)c6h^f2R>X8*}q|bblAF?@;%?2>$y+cMQbN{X$)^R>vtNq_5AB|0N5U*d^T?X9{xQnJYeU{ zoZL#obI;~Pp95f1`%X3D$Mh*4^?O?IT~7HqlWguezmg?Ybq|7>qQ(@pPHbE9V?f|( z+0xo!#m@Np9PljsyxBY-UA*{U*la#8Wz2sO|48_-5t8%_!n?S$zlGe+NA%?vmxjS- zHE5O3ZarU=X}$7>;Okp(UWXJxI%G_J-@IH;%5#Rt$(WUX?6*Ux!IRd$dLP6+SmPn= z8zjm4jGjN772R{FGkXwcNv8GBcZI#@Y2m{RNF_w8(Z%^A*!bS*!}s6sh*NnURytky humW;*g7R+&|Ledvc- + + + + WittymailV2 + + + + + + + + + diff --git a/frontend/wittymail-v2/src/karma.conf.js b/frontend/wittymail-v2/src/karma.conf.js new file mode 100644 index 0000000..2019e95 --- /dev/null +++ b/frontend/wittymail-v2/src/karma.conf.js @@ -0,0 +1,32 @@ +// Karma configuration file, see link for more information +// https://karma-runner.github.io/1.0/config/configuration-file.html + +module.exports = function (config) { + config.set({ + basePath: '', + frameworks: ['jasmine', '@angular-devkit/build-angular'], + plugins: [ + require('karma-jasmine'), + require('karma-chrome-launcher'), + require('karma-jasmine-html-reporter'), + require('karma-coverage-istanbul-reporter'), + require('@angular-devkit/build-angular/plugins/karma') + ], + client: { + clearContext: false // leave Jasmine Spec Runner output visible in browser + }, + coverageIstanbulReporter: { + dir: require('path').join(__dirname, '../coverage/wittymail-v2'), + reports: ['html', 'lcovonly', 'text-summary'], + fixWebpackSourcePaths: true + }, + reporters: ['progress', 'kjhtml'], + port: 9876, + colors: true, + logLevel: config.LOG_INFO, + autoWatch: true, + browsers: ['Chrome'], + singleRun: false, + restartOnFileChange: true + }); +}; diff --git a/frontend/wittymail-v2/src/main.ts b/frontend/wittymail-v2/src/main.ts new file mode 100644 index 0000000..c7b673c --- /dev/null +++ b/frontend/wittymail-v2/src/main.ts @@ -0,0 +1,12 @@ +import { enableProdMode } from '@angular/core'; +import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; + +import { AppModule } from './app/app.module'; +import { environment } from './environments/environment'; + +if (environment.production) { + enableProdMode(); +} + +platformBrowserDynamic().bootstrapModule(AppModule) + .catch(err => console.error(err)); diff --git a/frontend/wittymail-v2/src/polyfills.ts b/frontend/wittymail-v2/src/polyfills.ts new file mode 100644 index 0000000..75d6393 --- /dev/null +++ b/frontend/wittymail-v2/src/polyfills.ts @@ -0,0 +1,63 @@ +/** + * This file includes polyfills needed by Angular and is loaded before the app. + * You can add your own extra polyfills to this file. + * + * This file is divided into 2 sections: + * 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers. + * 2. Application imports. Files imported after ZoneJS that should be loaded before your main + * file. + * + * The current setup is for so-called "evergreen" browsers; the last versions of browsers that + * automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera), + * Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile. + * + * Learn more in https://angular.io/guide/browser-support + */ + +/*************************************************************************************************** + * BROWSER POLYFILLS + */ + +/** IE10 and IE11 requires the following for NgClass support on SVG elements */ +// import 'classlist.js'; // Run `npm install --save classlist.js`. + +/** + * Web Animations `@angular/platform-browser/animations` + * Only required if AnimationBuilder is used within the application and using IE/Edge or Safari. + * Standard animation support in Angular DOES NOT require any polyfills (as of Angular 6.0). + */ +// import 'web-animations-js'; // Run `npm install --save web-animations-js`. + +/** + * By default, zone.js will patch all possible macroTask and DomEvents + * user can disable parts of macroTask/DomEvents patch by setting following flags + * because those flags need to be set before `zone.js` being loaded, and webpack + * will put import in the top of bundle, so user need to create a separate file + * in this directory (for example: zone-flags.ts), and put the following flags + * into that file, and then add the following code before importing zone.js. + * import './zone-flags.ts'; + * + * The flags allowed in zone-flags.ts are listed here. + * + * The following flags will work for all browsers. + * + * (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame + * (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick + * (window as any).__zone_symbol__BLACK_LISTED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames + * + * in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js + * with the following flag, it will bypass `zone.js` patch for IE/Edge + * + * (window as any).__Zone_enable_cross_context_check = true; + * + */ + +/*************************************************************************************************** + * Zone JS is required by default for Angular itself. + */ +import 'zone.js/dist/zone'; // Included with Angular CLI. + + +/*************************************************************************************************** + * APPLICATION IMPORTS + */ diff --git a/frontend/wittymail-v2/src/styles.css b/frontend/wittymail-v2/src/styles.css new file mode 100644 index 0000000..90d4ee0 --- /dev/null +++ b/frontend/wittymail-v2/src/styles.css @@ -0,0 +1 @@ +/* You can add global styles to this file, and also import other style files */ diff --git a/frontend/wittymail-v2/src/test.ts b/frontend/wittymail-v2/src/test.ts new file mode 100644 index 0000000..1631789 --- /dev/null +++ b/frontend/wittymail-v2/src/test.ts @@ -0,0 +1,20 @@ +// This file is required by karma.conf.js and loads recursively all the .spec and framework files + +import 'zone.js/dist/zone-testing'; +import { getTestBed } from '@angular/core/testing'; +import { + BrowserDynamicTestingModule, + platformBrowserDynamicTesting +} from '@angular/platform-browser-dynamic/testing'; + +declare const require: any; + +// First, initialize the Angular testing environment. +getTestBed().initTestEnvironment( + BrowserDynamicTestingModule, + platformBrowserDynamicTesting() +); +// Then we find all the tests. +const context = require.context('./', true, /\.spec\.ts$/); +// And load the modules. +context.keys().map(context); diff --git a/frontend/wittymail-v2/src/tsconfig.app.json b/frontend/wittymail-v2/src/tsconfig.app.json new file mode 100644 index 0000000..190fd30 --- /dev/null +++ b/frontend/wittymail-v2/src/tsconfig.app.json @@ -0,0 +1,11 @@ +{ + "extends": "../tsconfig.json", + "compilerOptions": { + "outDir": "../out-tsc/app", + "types": [] + }, + "exclude": [ + "test.ts", + "**/*.spec.ts" + ] +} diff --git a/frontend/wittymail-v2/src/tsconfig.spec.json b/frontend/wittymail-v2/src/tsconfig.spec.json new file mode 100644 index 0000000..de77336 --- /dev/null +++ b/frontend/wittymail-v2/src/tsconfig.spec.json @@ -0,0 +1,18 @@ +{ + "extends": "../tsconfig.json", + "compilerOptions": { + "outDir": "../out-tsc/spec", + "types": [ + "jasmine", + "node" + ] + }, + "files": [ + "test.ts", + "polyfills.ts" + ], + "include": [ + "**/*.spec.ts", + "**/*.d.ts" + ] +} diff --git a/frontend/wittymail-v2/src/tslint.json b/frontend/wittymail-v2/src/tslint.json new file mode 100644 index 0000000..aa7c3ee --- /dev/null +++ b/frontend/wittymail-v2/src/tslint.json @@ -0,0 +1,17 @@ +{ + "extends": "../tslint.json", + "rules": { + "directive-selector": [ + true, + "attribute", + "app", + "camelCase" + ], + "component-selector": [ + true, + "element", + "app", + "kebab-case" + ] + } +} diff --git a/frontend/wittymail-v2/tsconfig.json b/frontend/wittymail-v2/tsconfig.json new file mode 100644 index 0000000..b271fd9 --- /dev/null +++ b/frontend/wittymail-v2/tsconfig.json @@ -0,0 +1,22 @@ +{ + "compileOnSave": false, + "compilerOptions": { + "baseUrl": "./", + "outDir": "./dist/out-tsc", + "sourceMap": true, + "declaration": false, + "module": "es2015", + "moduleResolution": "node", + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "importHelpers": true, + "target": "es5", + "typeRoots": [ + "node_modules/@types" + ], + "lib": [ + "es2018", + "dom" + ] + } +} diff --git a/frontend/wittymail-v2/tslint.json b/frontend/wittymail-v2/tslint.json new file mode 100644 index 0000000..868ecba --- /dev/null +++ b/frontend/wittymail-v2/tslint.json @@ -0,0 +1,75 @@ +{ + "extends": "tslint:recommended", + "rulesDirectory": [ + "codelyzer" + ], + "rules": { + "array-type": false, + "arrow-parens": false, + "deprecation": { + "severity": "warn" + }, + "import-blacklist": [ + true, + "rxjs/Rx" + ], + "interface-name": false, + "max-classes-per-file": false, + "max-line-length": [ + true, + 140 + ], + "member-access": false, + "member-ordering": [ + true, + { + "order": [ + "static-field", + "instance-field", + "static-method", + "instance-method" + ] + } + ], + "no-consecutive-blank-lines": false, + "no-console": [ + true, + "debug", + "info", + "time", + "timeEnd", + "trace" + ], + "no-empty": false, + "no-inferrable-types": [ + true, + "ignore-params" + ], + "no-non-null-assertion": true, + "no-redundant-jsdoc": true, + "no-switch-case-fall-through": true, + "no-use-before-declare": true, + "no-var-requires": false, + "object-literal-key-quotes": [ + true, + "as-needed" + ], + "object-literal-sort-keys": false, + "ordered-imports": false, + "quotemark": [ + true, + "single" + ], + "trailing-comma": false, + "no-output-on-prefix": true, + "use-input-property-decorator": true, + "use-output-property-decorator": true, + "use-host-property-decorator": true, + "no-input-rename": true, + "no-output-rename": true, + "use-life-cycle-interface": true, + "use-pipe-transform-interface": true, + "component-class-suffix": true, + "directive-class-suffix": true + } +} diff --git a/frontend/wittymail-v2/yarn.lock b/frontend/wittymail-v2/yarn.lock new file mode 100644 index 0000000..4d7bf19 --- /dev/null +++ b/frontend/wittymail-v2/yarn.lock @@ -0,0 +1,7236 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@angular-devkit/architect@0.13.8": + version "0.13.8" + resolved "https://registry.yarnpkg.com/@angular-devkit/architect/-/architect-0.13.8.tgz#c3b7469e15e2710d48b6fe4e54efea26b557bf14" + integrity sha512-gxUs5rhnP576T8ZclKqxlspiChrqRtqaJo54wqNVFvYKEjRZKyMa+1AK6p0oD9zcIToEkcjknj3BbtQa27lLHg== + dependencies: + "@angular-devkit/core" "7.3.8" + rxjs "6.3.3" + +"@angular-devkit/build-angular@~0.13.0": + version "0.13.8" + resolved "https://registry.yarnpkg.com/@angular-devkit/build-angular/-/build-angular-0.13.8.tgz#7ff949db46c78115e0bc45b3a2f9cad64459c016" + integrity sha512-uRb8CKC0hUdcE+Fv2Ov9LJNelyjsiMuddBpo8pdTKCIHVVC6hvip9S/Z18Tvb207kKI3k7Dn+Ji1J63mCqmQzA== + dependencies: + "@angular-devkit/architect" "0.13.8" + "@angular-devkit/build-optimizer" "0.13.8" + "@angular-devkit/build-webpack" "0.13.8" + "@angular-devkit/core" "7.3.8" + "@ngtools/webpack" "7.3.8" + ajv "6.9.1" + autoprefixer "9.4.6" + circular-dependency-plugin "5.0.2" + clean-css "4.2.1" + copy-webpack-plugin "4.6.0" + file-loader "3.0.1" + glob "7.1.3" + istanbul-instrumenter-loader "3.0.1" + karma-source-map-support "1.3.0" + less "3.9.0" + less-loader "4.1.0" + license-webpack-plugin "2.1.0" + loader-utils "1.2.3" + mini-css-extract-plugin "0.5.0" + minimatch "3.0.4" + open "6.0.0" + parse5 "4.0.0" + postcss "7.0.14" + postcss-import "12.0.1" + postcss-loader "3.0.0" + raw-loader "1.0.0" + rxjs "6.3.3" + sass-loader "7.1.0" + semver "5.6.0" + source-map-loader "0.2.4" + source-map-support "0.5.10" + speed-measure-webpack-plugin "1.3.1" + stats-webpack-plugin "0.7.0" + style-loader "0.23.1" + stylus "0.54.5" + stylus-loader "3.0.2" + terser-webpack-plugin "1.2.2" + tree-kill "1.2.1" + webpack "4.29.0" + webpack-dev-middleware "3.5.1" + webpack-dev-server "3.1.14" + webpack-merge "4.2.1" + webpack-sources "1.3.0" + webpack-subresource-integrity "1.1.0-rc.6" + optionalDependencies: + node-sass "4.11.0" + +"@angular-devkit/build-optimizer@0.13.8": + version "0.13.8" + resolved "https://registry.yarnpkg.com/@angular-devkit/build-optimizer/-/build-optimizer-0.13.8.tgz#0bcba1a4ef598c1a01caa60dd3603bac52a57b16" + integrity sha512-RvYxtsdYuvpFb1iivVixylSVN/Q8LsQ449uYuqEe3OsDjQBvUVG2fMLPOQjmKWhi0NC9WSsNiUluxLDNdvd0Vw== + dependencies: + loader-utils "1.2.3" + source-map "0.5.6" + typescript "3.2.4" + webpack-sources "1.3.0" + +"@angular-devkit/build-webpack@0.13.8": + version "0.13.8" + resolved "https://registry.yarnpkg.com/@angular-devkit/build-webpack/-/build-webpack-0.13.8.tgz#81e754442285dd4ece7d16a4d14ed80d7eaa9e27" + integrity sha512-WMyn1vUHyx+VfJKgYuEHrICwQzPMDTaUNB1zlvzZt9gX/9H+XnetrebeWBZCITPXHBw/377oA6wmiHWJ0yaZRw== + dependencies: + "@angular-devkit/architect" "0.13.8" + "@angular-devkit/core" "7.3.8" + rxjs "6.3.3" + +"@angular-devkit/core@7.3.8": + version "7.3.8" + resolved "https://registry.yarnpkg.com/@angular-devkit/core/-/core-7.3.8.tgz#702b0944a69c71cce3a1492e0d62de18df22a993" + integrity sha512-3X9uzaZXFpm5o2TSzhD6wEOtVU32CgeytKjD1Scxj+uMMVo48SWLlKiFh312T+smI9ko7tOT8VqxglwYkWosgg== + dependencies: + ajv "6.9.1" + chokidar "2.0.4" + fast-json-stable-stringify "2.0.0" + rxjs "6.3.3" + source-map "0.7.3" + +"@angular-devkit/schematics@7.3.8": + version "7.3.8" + resolved "https://registry.yarnpkg.com/@angular-devkit/schematics/-/schematics-7.3.8.tgz#70bfc7876f7924ff53ab9310a00b62f20acf2f5c" + integrity sha512-mvaKoORZIaW/h0VNZ3IQWP0qThRCZRX6869FNlzV0jlW0mhn07XbiIGHCGGSCDRxS7qJ0VbuIVnKXntF+iDeWw== + dependencies: + "@angular-devkit/core" "7.3.8" + rxjs "6.3.3" + +"@angular/animations@~7.2.0": + version "7.2.13" + resolved "https://registry.yarnpkg.com/@angular/animations/-/animations-7.2.13.tgz#9a49482ea2e0386a691d5b9d7be422251b66d767" + integrity sha512-Z0g0DthJnxTZ0dUc5BlojMq/0XIikhWzTqq0ym8w3G6jqBJD0OJ0jRCIfV0Leqlgzq6Jzvdrx0/JngBiKi5+uA== + dependencies: + tslib "^1.9.0" + +"@angular/cli@~7.3.8": + version "7.3.8" + resolved "https://registry.yarnpkg.com/@angular/cli/-/cli-7.3.8.tgz#a0891e08bee7d68b9ef2c00a9a7e93c6c5ac75d7" + integrity sha512-5ldU1idvWstmRaavGZen9WRjfjIViERGt8NYuLLI7dgVLYOPF5TyFoTnpT5nxkiCopp4tPIcpbzPV394Bxmdtg== + dependencies: + "@angular-devkit/architect" "0.13.8" + "@angular-devkit/core" "7.3.8" + "@angular-devkit/schematics" "7.3.8" + "@schematics/angular" "7.3.8" + "@schematics/update" "0.13.8" + "@yarnpkg/lockfile" "1.1.0" + ini "1.3.5" + inquirer "6.2.1" + npm-package-arg "6.1.0" + open "6.0.0" + pacote "9.4.0" + semver "5.6.0" + symbol-observable "1.2.0" + +"@angular/common@~7.2.0": + version "7.2.13" + resolved "https://registry.yarnpkg.com/@angular/common/-/common-7.2.13.tgz#187fc1b053957c1654537ff4be6cc286ada76401" + integrity sha512-NYlzUkFVgjLg9VB6/lkd8ZV0ZezSiv9vlg+26wOyw7x+gahRrm5WMAGF7eBLrXoZPEaoOO0uhKWKo7oiA0aufA== + dependencies: + tslib "^1.9.0" + +"@angular/compiler-cli@~7.2.0": + version "7.2.13" + resolved "https://registry.yarnpkg.com/@angular/compiler-cli/-/compiler-cli-7.2.13.tgz#6968310becf152eacc328584650035fa797e1b9f" + integrity sha512-UpA6V+GCY9qKj5j6tvzun2DJNjqRKjCrQgJqD5BIf4FTAKjVgqOvh++d23tbdltdjXlbHqUVRgfeXltbO91fWg== + dependencies: + canonical-path "1.0.0" + chokidar "^2.1.1" + convert-source-map "^1.5.1" + dependency-graph "^0.7.2" + magic-string "^0.25.0" + minimist "^1.2.0" + reflect-metadata "^0.1.2" + shelljs "^0.8.1" + source-map "^0.6.1" + tslib "^1.9.0" + yargs "9.0.1" + +"@angular/compiler@~7.2.0": + version "7.2.13" + resolved "https://registry.yarnpkg.com/@angular/compiler/-/compiler-7.2.13.tgz#30910c2a3e3b4062593c0aa1cdc8d1d5dc1207f0" + integrity sha512-k0IvaozNIlrPKUNF3M/NXMb/jfHBCDO9uRYA6h+84FFY4Y9po40c7YXfsfUxGKwouTWyemaxy9iXlLEnd3ELSQ== + dependencies: + tslib "^1.9.0" + +"@angular/core@~7.2.0": + version "7.2.13" + resolved "https://registry.yarnpkg.com/@angular/core/-/core-7.2.13.tgz#3ec4ca5027d8e259b2a13c9901c86d1dc50fc5b6" + integrity sha512-vHD69xxDDSQaE8KfHeY2STJSd3xgfsz3/meBCAnT+Bpq9LqxL8DuPlrkC0kyBa2vyj/BwPR3CJNTaQrZcszJ/w== + dependencies: + tslib "^1.9.0" + +"@angular/forms@~7.2.0": + version "7.2.13" + resolved "https://registry.yarnpkg.com/@angular/forms/-/forms-7.2.13.tgz#27686331b6501a86fbb6c25904781ec233cdb059" + integrity sha512-dBz7kYa8XoCKxZ+3EvYt6CxHZhM9Qbn3uYkLMsPA+NC6GtIt/tmYn1kNn+YWgVWZtWLvYRaOtYiCuMUJaRNQQw== + dependencies: + tslib "^1.9.0" + +"@angular/language-service@~7.2.0": + version "7.2.13" + resolved "https://registry.yarnpkg.com/@angular/language-service/-/language-service-7.2.13.tgz#941cb098657efdbc386ef8e54d2d893497f68c20" + integrity sha512-1bNWJpwH9wB0JybkbjdQp9J4bGmGxJX6BG7Mz3188Wc4J+aNy696Gc6IaJs7tFK8VXAdJrTJ5jGr9Oiu+ATe8w== + +"@angular/platform-browser-dynamic@~7.2.0": + version "7.2.13" + resolved "https://registry.yarnpkg.com/@angular/platform-browser-dynamic/-/platform-browser-dynamic-7.2.13.tgz#3aee18e422d5ef69ced4d4749031b23647dfad57" + integrity sha512-3+/BzrNLQ/Tn1hoPal3fvIeB3S/P3e00gHcH3oK+hfACYgWxLE1oIHL+w4NE2eTIJbHfphKhuascMaOH5WNlkg== + dependencies: + tslib "^1.9.0" + +"@angular/platform-browser@~7.2.0": + version "7.2.13" + resolved "https://registry.yarnpkg.com/@angular/platform-browser/-/platform-browser-7.2.13.tgz#6e87de07a7938a81981d75da20e2d5d31ec61ca9" + integrity sha512-4n9De4sOwVoYHh6IGO2+UQIjABqGAXk4RdrEGpXqPBHCNO4sF43c2JsXbPTU4kjPVwTwposfLlKEOjTXfwxGow== + dependencies: + tslib "^1.9.0" + +"@angular/router@~7.2.0": + version "7.2.13" + resolved "https://registry.yarnpkg.com/@angular/router/-/router-7.2.13.tgz#9b470e37f57ddf2741e21d1f299974cf48b7e938" + integrity sha512-pTdJT9TXk1A9YMa6C2zRRqLB4GPGMSik838P7n+yGrzhdybiudZU9T3egcxDRCWQMjsobVBRKLEUn405n3Hjgg== + dependencies: + tslib "^1.9.0" + +"@babel/code-frame@^7.0.0": + version "7.0.0" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.0.0.tgz#06e2ab19bdb535385559aabb5ba59729482800f8" + integrity sha512-OfC2uemaknXr87bdLUkWog7nYuliM9Ij5HUcajsVcMCpQrcLmtxRbVFTIqmcSkSeYRBFBRxs2FiUqFJDLdiebA== + dependencies: + "@babel/highlight" "^7.0.0" + +"@babel/generator@^7.0.0", "@babel/generator@^7.4.0": + version "7.4.0" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.4.0.tgz#c230e79589ae7a729fd4631b9ded4dc220418196" + integrity sha512-/v5I+a1jhGSKLgZDcmAUZ4K/VePi43eRkUs3yePW1HB1iANOD5tqJXwGSG4BZhSksP8J9ejSlwGeTiiOFZOrXQ== + dependencies: + "@babel/types" "^7.4.0" + jsesc "^2.5.1" + lodash "^4.17.11" + source-map "^0.5.0" + trim-right "^1.0.1" + +"@babel/helper-function-name@^7.1.0": + version "7.1.0" + resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.1.0.tgz#a0ceb01685f73355d4360c1247f582bfafc8ff53" + integrity sha512-A95XEoCpb3TO+KZzJ4S/5uW5fNe26DjBGqf1o9ucyLyCmi1dXq/B3c8iaWTfBk3VvetUxl16e8tIrd5teOCfGw== + dependencies: + "@babel/helper-get-function-arity" "^7.0.0" + "@babel/template" "^7.1.0" + "@babel/types" "^7.0.0" + +"@babel/helper-get-function-arity@^7.0.0": + version "7.0.0" + resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.0.0.tgz#83572d4320e2a4657263734113c42868b64e49c3" + integrity sha512-r2DbJeg4svYvt3HOS74U4eWKsUAMRH01Z1ds1zx8KNTPtpTL5JAsdFv8BNyOpVqdFhHkkRDIg5B4AsxmkjAlmQ== + dependencies: + "@babel/types" "^7.0.0" + +"@babel/helper-split-export-declaration@^7.4.0": + version "7.4.0" + resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.4.0.tgz#571bfd52701f492920d63b7f735030e9a3e10b55" + integrity sha512-7Cuc6JZiYShaZnybDmfwhY4UYHzI6rlqhWjaIqbsJGsIqPimEYy5uh3akSRLMg65LSdSEnJ8a8/bWQN6u2oMGw== + dependencies: + "@babel/types" "^7.4.0" + +"@babel/highlight@^7.0.0": + version "7.0.0" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.0.0.tgz#f710c38c8d458e6dd9a201afb637fcb781ce99e4" + integrity sha512-UFMC4ZeFC48Tpvj7C8UgLvtkaUuovQX+5xNWrsIoMG8o2z+XFKjKaN9iVmS84dPwVN00W4wPmqvYoZF3EGAsfw== + dependencies: + chalk "^2.0.0" + esutils "^2.0.2" + js-tokens "^4.0.0" + +"@babel/parser@^7.0.0", "@babel/parser@^7.4.0", "@babel/parser@^7.4.3": + version "7.4.3" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.4.3.tgz#eb3ac80f64aa101c907d4ce5406360fe75b7895b" + integrity sha512-gxpEUhTS1sGA63EGQGuA+WESPR/6tz6ng7tSHFCmaTJK/cGK8y37cBTspX+U2xCAue2IQVvF6Z0oigmjwD8YGQ== + +"@babel/template@^7.0.0", "@babel/template@^7.1.0": + version "7.4.0" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.4.0.tgz#12474e9c077bae585c5d835a95c0b0b790c25c8b" + integrity sha512-SOWwxxClTTh5NdbbYZ0BmaBVzxzTh2tO/TeLTbF6MO6EzVhHTnff8CdBXx3mEtazFBoysmEM6GU/wF+SuSx4Fw== + dependencies: + "@babel/code-frame" "^7.0.0" + "@babel/parser" "^7.4.0" + "@babel/types" "^7.4.0" + +"@babel/traverse@^7.0.0": + version "7.4.3" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.4.3.tgz#1a01f078fc575d589ff30c0f71bf3c3d9ccbad84" + integrity sha512-HmA01qrtaCwwJWpSKpA948cBvU5BrmviAief/b3AVw936DtcdsTexlbyzNuDnthwhOQ37xshn7hvQaEQk7ISYQ== + dependencies: + "@babel/code-frame" "^7.0.0" + "@babel/generator" "^7.4.0" + "@babel/helper-function-name" "^7.1.0" + "@babel/helper-split-export-declaration" "^7.4.0" + "@babel/parser" "^7.4.3" + "@babel/types" "^7.4.0" + debug "^4.1.0" + globals "^11.1.0" + lodash "^4.17.11" + +"@babel/types@^7.0.0", "@babel/types@^7.4.0": + version "7.4.0" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.4.0.tgz#670724f77d24cce6cc7d8cf64599d511d164894c" + integrity sha512-aPvkXyU2SPOnztlgo8n9cEiXW755mgyvueUPcpStqdzoSPm0fjO0vQBjLkt3JKJW7ufikfcnMTTPsN1xaTsBPA== + dependencies: + esutils "^2.0.2" + lodash "^4.17.11" + to-fast-properties "^2.0.0" + +"@ngtools/webpack@7.3.8": + version "7.3.8" + resolved "https://registry.yarnpkg.com/@ngtools/webpack/-/webpack-7.3.8.tgz#c8761d0f6959682e03032f8d3de718d1f811410e" + integrity sha512-gfjSKz+F/2T4tZHpnQ1XqelKP/CIfI87XdoHsOI53ceTUrAkVKsOb3ULmEfkcdsdQZ/HhmCiLivcutHcW8xkhQ== + dependencies: + "@angular-devkit/core" "7.3.8" + enhanced-resolve "4.1.0" + rxjs "6.3.3" + tree-kill "1.2.1" + webpack-sources "1.3.0" + +"@schematics/angular@7.3.8": + version "7.3.8" + resolved "https://registry.yarnpkg.com/@schematics/angular/-/angular-7.3.8.tgz#9cded496b79830164acbc2fc382b66e5b5f7cf02" + integrity sha512-7o90bnIxXNpJhWPDY/zCedcG6KMIihz7a4UQe6UdlhEX21MNZLYFiDiR5Vmsx39wjm2EfPh3JTuBIHGmMCXkQQ== + dependencies: + "@angular-devkit/core" "7.3.8" + "@angular-devkit/schematics" "7.3.8" + typescript "3.2.4" + +"@schematics/update@0.13.8": + version "0.13.8" + resolved "https://registry.yarnpkg.com/@schematics/update/-/update-0.13.8.tgz#149c3335f385e94e0593bce4dfac8e91cb4a56c1" + integrity sha512-2jP9w7Nnn24jOdrJtWjoS9LsNPmO9/Eu/+gDxBAVERCqR71mtNW+DopgWDtxleE9jri/pZWrHwShGFCSS7w23g== + dependencies: + "@angular-devkit/core" "7.3.8" + "@angular-devkit/schematics" "7.3.8" + "@yarnpkg/lockfile" "1.1.0" + ini "1.3.5" + pacote "9.4.0" + rxjs "6.3.3" + semver "5.6.0" + semver-intersect "1.4.0" + +"@types/jasmine@*": + version "3.3.12" + resolved "https://registry.yarnpkg.com/@types/jasmine/-/jasmine-3.3.12.tgz#bf282cb540e9ad7a0a04b742082c073b655eab39" + integrity sha512-lXvr2xFQEVQLkIhuGaR3GC1L9lMU1IxeWnAF/wNY5ZWpC4p9dgxkKkzMp7pntpAdv9pZSnYqgsBkCg32MXSZMg== + +"@types/jasmine@~2.8.8": + version "2.8.16" + resolved "https://registry.yarnpkg.com/@types/jasmine/-/jasmine-2.8.16.tgz#a6cb24b1149d65293bd616923500014838e14e7d" + integrity sha512-056oRlBBp7MDzr+HoU5su099s/s7wjZ3KcHxLfv+Byqb9MwdLUvsfLgw1VS97hsh3ddxSPyQu+olHMnoVTUY6g== + +"@types/jasminewd2@~2.0.3": + version "2.0.6" + resolved "https://registry.yarnpkg.com/@types/jasminewd2/-/jasminewd2-2.0.6.tgz#2f57a8d9875a6c9ef328a14bd070ba14a055ac39" + integrity sha512-2ZOKrxb8bKRmP/po5ObYnRDgFE4i+lQiEB27bAMmtMWLgJSqlIDqlLx6S0IRorpOmOPRQ6O80NujTmQAtBkeNw== + dependencies: + "@types/jasmine" "*" + +"@types/node@*": + version "11.13.6" + resolved "https://registry.yarnpkg.com/@types/node/-/node-11.13.6.tgz#37ec75690830acb0d74ce3c6c43caab787081e85" + integrity sha512-Xoo/EBzEe8HxTSwaZNLZjaW6M6tA/+GmD3/DZ6uo8qSaolE/9Oarko0oV1fVfrLqOz0tx0nXJB4rdD5c+vixLw== + +"@types/node@~8.9.4": + version "8.9.5" + resolved "https://registry.yarnpkg.com/@types/node/-/node-8.9.5.tgz#162b864bc70be077e6db212b322754917929e976" + integrity sha512-jRHfWsvyMtXdbhnz5CVHxaBgnV6duZnPlQuRSo/dm/GnmikNcmZhxIES4E9OZjUmQ8C+HCl4KJux+cXN/ErGDQ== + +"@types/q@^0.0.32": + version "0.0.32" + resolved "https://registry.yarnpkg.com/@types/q/-/q-0.0.32.tgz#bd284e57c84f1325da702babfc82a5328190c0c5" + integrity sha1-vShOV8hPEyXacCur/IKlMoGQwMU= + +"@types/selenium-webdriver@^3.0.0": + version "3.0.16" + resolved "https://registry.yarnpkg.com/@types/selenium-webdriver/-/selenium-webdriver-3.0.16.tgz#50a4755f8e33edacd9c406729e9b930d2451902a" + integrity sha512-lMC2G0ItF2xv4UCiwbJGbnJlIuUixHrioOhNGHSCsYCJ8l4t9hMCUimCytvFv7qy6AfSzRxhRHoGa+UqaqwyeA== + +"@types/source-list-map@*": + version "0.1.2" + resolved "https://registry.yarnpkg.com/@types/source-list-map/-/source-list-map-0.1.2.tgz#0078836063ffaf17412349bba364087e0ac02ec9" + integrity sha512-K5K+yml8LTo9bWJI/rECfIPrGgxdpeNbj+d53lwN4QjW1MCwlkhUms+gtdzigTeUyBr09+u8BwOIY3MXvHdcsA== + +"@types/webpack-sources@^0.1.5": + version "0.1.5" + resolved "https://registry.yarnpkg.com/@types/webpack-sources/-/webpack-sources-0.1.5.tgz#be47c10f783d3d6efe1471ff7f042611bd464a92" + integrity sha512-zfvjpp7jiafSmrzJ2/i3LqOyTYTuJ7u1KOXlKgDlvsj9Rr0x7ZiYu5lZbXwobL7lmsRNtPXlBfmaUD8eU2Hu8w== + dependencies: + "@types/node" "*" + "@types/source-list-map" "*" + source-map "^0.6.1" + +"@webassemblyjs/ast@1.7.11": + version "1.7.11" + resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.7.11.tgz#b988582cafbb2b095e8b556526f30c90d057cace" + integrity sha512-ZEzy4vjvTzScC+SH8RBssQUawpaInUdMTYwYYLh54/s8TuT0gBLuyUnppKsVyZEi876VmmStKsUs28UxPgdvrA== + dependencies: + "@webassemblyjs/helper-module-context" "1.7.11" + "@webassemblyjs/helper-wasm-bytecode" "1.7.11" + "@webassemblyjs/wast-parser" "1.7.11" + +"@webassemblyjs/floating-point-hex-parser@1.7.11": + version "1.7.11" + resolved "https://registry.yarnpkg.com/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.7.11.tgz#a69f0af6502eb9a3c045555b1a6129d3d3f2e313" + integrity sha512-zY8dSNyYcgzNRNT666/zOoAyImshm3ycKdoLsyDw/Bwo6+/uktb7p4xyApuef1dwEBo/U/SYQzbGBvV+nru2Xg== + +"@webassemblyjs/helper-api-error@1.7.11": + version "1.7.11" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-api-error/-/helper-api-error-1.7.11.tgz#c7b6bb8105f84039511a2b39ce494f193818a32a" + integrity sha512-7r1qXLmiglC+wPNkGuXCvkmalyEstKVwcueZRP2GNC2PAvxbLYwLLPr14rcdJaE4UtHxQKfFkuDFuv91ipqvXg== + +"@webassemblyjs/helper-buffer@1.7.11": + version "1.7.11" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-buffer/-/helper-buffer-1.7.11.tgz#3122d48dcc6c9456ed982debe16c8f37101df39b" + integrity sha512-MynuervdylPPh3ix+mKZloTcL06P8tenNH3sx6s0qE8SLR6DdwnfgA7Hc9NSYeob2jrW5Vql6GVlsQzKQCa13w== + +"@webassemblyjs/helper-code-frame@1.7.11": + version "1.7.11" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-code-frame/-/helper-code-frame-1.7.11.tgz#cf8f106e746662a0da29bdef635fcd3d1248364b" + integrity sha512-T8ESC9KMXFTXA5urJcyor5cn6qWeZ4/zLPyWeEXZ03hj/x9weSokGNkVCdnhSabKGYWxElSdgJ+sFa9G/RdHNw== + dependencies: + "@webassemblyjs/wast-printer" "1.7.11" + +"@webassemblyjs/helper-fsm@1.7.11": + version "1.7.11" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-fsm/-/helper-fsm-1.7.11.tgz#df38882a624080d03f7503f93e3f17ac5ac01181" + integrity sha512-nsAQWNP1+8Z6tkzdYlXT0kxfa2Z1tRTARd8wYnc/e3Zv3VydVVnaeePgqUzFrpkGUyhUUxOl5ML7f1NuT+gC0A== + +"@webassemblyjs/helper-module-context@1.7.11": + version "1.7.11" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-module-context/-/helper-module-context-1.7.11.tgz#d874d722e51e62ac202476935d649c802fa0e209" + integrity sha512-JxfD5DX8Ygq4PvXDucq0M+sbUFA7BJAv/GGl9ITovqE+idGX+J3QSzJYz+LwQmL7fC3Rs+utvWoJxDb6pmC0qg== + +"@webassemblyjs/helper-wasm-bytecode@1.7.11": + version "1.7.11" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.7.11.tgz#dd9a1e817f1c2eb105b4cf1013093cb9f3c9cb06" + integrity sha512-cMXeVS9rhoXsI9LLL4tJxBgVD/KMOKXuFqYb5oCJ/opScWpkCMEz9EJtkonaNcnLv2R3K5jIeS4TRj/drde1JQ== + +"@webassemblyjs/helper-wasm-section@1.7.11": + version "1.7.11" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.7.11.tgz#9c9ac41ecf9fbcfffc96f6d2675e2de33811e68a" + integrity sha512-8ZRY5iZbZdtNFE5UFunB8mmBEAbSI3guwbrsCl4fWdfRiAcvqQpeqd5KHhSWLL5wuxo53zcaGZDBU64qgn4I4Q== + dependencies: + "@webassemblyjs/ast" "1.7.11" + "@webassemblyjs/helper-buffer" "1.7.11" + "@webassemblyjs/helper-wasm-bytecode" "1.7.11" + "@webassemblyjs/wasm-gen" "1.7.11" + +"@webassemblyjs/ieee754@1.7.11": + version "1.7.11" + resolved "https://registry.yarnpkg.com/@webassemblyjs/ieee754/-/ieee754-1.7.11.tgz#c95839eb63757a31880aaec7b6512d4191ac640b" + integrity sha512-Mmqx/cS68K1tSrvRLtaV/Lp3NZWzXtOHUW2IvDvl2sihAwJh4ACE0eL6A8FvMyDG9abes3saB6dMimLOs+HMoQ== + dependencies: + "@xtuc/ieee754" "^1.2.0" + +"@webassemblyjs/leb128@1.7.11": + version "1.7.11" + resolved "https://registry.yarnpkg.com/@webassemblyjs/leb128/-/leb128-1.7.11.tgz#d7267a1ee9c4594fd3f7e37298818ec65687db63" + integrity sha512-vuGmgZjjp3zjcerQg+JA+tGOncOnJLWVkt8Aze5eWQLwTQGNgVLcyOTqgSCxWTR4J42ijHbBxnuRaL1Rv7XMdw== + dependencies: + "@xtuc/long" "4.2.1" + +"@webassemblyjs/utf8@1.7.11": + version "1.7.11" + resolved "https://registry.yarnpkg.com/@webassemblyjs/utf8/-/utf8-1.7.11.tgz#06d7218ea9fdc94a6793aa92208160db3d26ee82" + integrity sha512-C6GFkc7aErQIAH+BMrIdVSmW+6HSe20wg57HEC1uqJP8E/xpMjXqQUxkQw07MhNDSDcGpxI9G5JSNOQCqJk4sA== + +"@webassemblyjs/wasm-edit@1.7.11": + version "1.7.11" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-edit/-/wasm-edit-1.7.11.tgz#8c74ca474d4f951d01dbae9bd70814ee22a82005" + integrity sha512-FUd97guNGsCZQgeTPKdgxJhBXkUbMTY6hFPf2Y4OedXd48H97J+sOY2Ltaq6WGVpIH8o/TGOVNiVz/SbpEMJGg== + dependencies: + "@webassemblyjs/ast" "1.7.11" + "@webassemblyjs/helper-buffer" "1.7.11" + "@webassemblyjs/helper-wasm-bytecode" "1.7.11" + "@webassemblyjs/helper-wasm-section" "1.7.11" + "@webassemblyjs/wasm-gen" "1.7.11" + "@webassemblyjs/wasm-opt" "1.7.11" + "@webassemblyjs/wasm-parser" "1.7.11" + "@webassemblyjs/wast-printer" "1.7.11" + +"@webassemblyjs/wasm-gen@1.7.11": + version "1.7.11" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-gen/-/wasm-gen-1.7.11.tgz#9bbba942f22375686a6fb759afcd7ac9c45da1a8" + integrity sha512-U/KDYp7fgAZX5KPfq4NOupK/BmhDc5Kjy2GIqstMhvvdJRcER/kUsMThpWeRP8BMn4LXaKhSTggIJPOeYHwISA== + dependencies: + "@webassemblyjs/ast" "1.7.11" + "@webassemblyjs/helper-wasm-bytecode" "1.7.11" + "@webassemblyjs/ieee754" "1.7.11" + "@webassemblyjs/leb128" "1.7.11" + "@webassemblyjs/utf8" "1.7.11" + +"@webassemblyjs/wasm-opt@1.7.11": + version "1.7.11" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-opt/-/wasm-opt-1.7.11.tgz#b331e8e7cef8f8e2f007d42c3a36a0580a7d6ca7" + integrity sha512-XynkOwQyiRidh0GLua7SkeHvAPXQV/RxsUeERILmAInZegApOUAIJfRuPYe2F7RcjOC9tW3Cb9juPvAC/sCqvg== + dependencies: + "@webassemblyjs/ast" "1.7.11" + "@webassemblyjs/helper-buffer" "1.7.11" + "@webassemblyjs/wasm-gen" "1.7.11" + "@webassemblyjs/wasm-parser" "1.7.11" + +"@webassemblyjs/wasm-parser@1.7.11": + version "1.7.11" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-parser/-/wasm-parser-1.7.11.tgz#6e3d20fa6a3519f6b084ef9391ad58211efb0a1a" + integrity sha512-6lmXRTrrZjYD8Ng8xRyvyXQJYUQKYSXhJqXOBLw24rdiXsHAOlvw5PhesjdcaMadU/pyPQOJ5dHreMjBxwnQKg== + dependencies: + "@webassemblyjs/ast" "1.7.11" + "@webassemblyjs/helper-api-error" "1.7.11" + "@webassemblyjs/helper-wasm-bytecode" "1.7.11" + "@webassemblyjs/ieee754" "1.7.11" + "@webassemblyjs/leb128" "1.7.11" + "@webassemblyjs/utf8" "1.7.11" + +"@webassemblyjs/wast-parser@1.7.11": + version "1.7.11" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-parser/-/wast-parser-1.7.11.tgz#25bd117562ca8c002720ff8116ef9072d9ca869c" + integrity sha512-lEyVCg2np15tS+dm7+JJTNhNWq9yTZvi3qEhAIIOaofcYlUp0UR5/tVqOwa/gXYr3gjwSZqw+/lS9dscyLelbQ== + dependencies: + "@webassemblyjs/ast" "1.7.11" + "@webassemblyjs/floating-point-hex-parser" "1.7.11" + "@webassemblyjs/helper-api-error" "1.7.11" + "@webassemblyjs/helper-code-frame" "1.7.11" + "@webassemblyjs/helper-fsm" "1.7.11" + "@xtuc/long" "4.2.1" + +"@webassemblyjs/wast-printer@1.7.11": + version "1.7.11" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-printer/-/wast-printer-1.7.11.tgz#c4245b6de242cb50a2cc950174fdbf65c78d7813" + integrity sha512-m5vkAsuJ32QpkdkDOUPGSltrg8Cuk3KBx4YrmAGQwCZPRdUHXxG4phIOuuycLemHFr74sWL9Wthqss4fzdzSwg== + dependencies: + "@webassemblyjs/ast" "1.7.11" + "@webassemblyjs/wast-parser" "1.7.11" + "@xtuc/long" "4.2.1" + +"@xtuc/ieee754@^1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@xtuc/ieee754/-/ieee754-1.2.0.tgz#eef014a3145ae477a1cbc00cd1e552336dceb790" + integrity sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA== + +"@xtuc/long@4.2.1": + version "4.2.1" + resolved "https://registry.yarnpkg.com/@xtuc/long/-/long-4.2.1.tgz#5c85d662f76fa1d34575766c5dcd6615abcd30d8" + integrity sha512-FZdkNBDqBRHKQ2MEbSC17xnPFOhZxeJ2YGSfr2BKf3sujG49Qe3bB+rGCwQfIaA7WHnGeGkSijX4FuBCdrzW/g== + +"@yarnpkg/lockfile@1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz#e77a97fbd345b76d83245edcd17d393b1b41fb31" + integrity sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ== + +JSONStream@^1.3.4: + version "1.3.5" + resolved "https://registry.yarnpkg.com/JSONStream/-/JSONStream-1.3.5.tgz#3208c1f08d3a4d99261ab64f92302bc15e111ca0" + integrity sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ== + dependencies: + jsonparse "^1.2.0" + through ">=2.2.7 <3" + +abbrev@1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" + integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q== + +accepts@~1.3.4, accepts@~1.3.5: + version "1.3.5" + resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.5.tgz#eb777df6011723a3b14e8a72c0805c8e86746bd2" + integrity sha1-63d99gEXI6OxTopywIBcjoZ0a9I= + dependencies: + mime-types "~2.1.18" + negotiator "0.6.1" + +acorn-dynamic-import@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/acorn-dynamic-import/-/acorn-dynamic-import-4.0.0.tgz#482210140582a36b83c3e342e1cfebcaa9240948" + integrity sha512-d3OEjQV4ROpoflsnUA8HozoIR504TFxNivYEUi6uwz0IYhBkTDXGuWlNdMtybRt3nqVx/L6XqMt0FxkXuWKZhw== + +acorn@^6.0.5: + version "6.1.1" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.1.1.tgz#7d25ae05bb8ad1f9b699108e1094ecd7884adc1f" + integrity sha512-jPTiwtOxaHNaAPg/dmrJ/beuzLRnXtB0kQPQ8JpotKJgTB6rX6c8mlf315941pyjBSaPg8NHXS9fhP4u17DpGA== + +adm-zip@^0.4.9: + version "0.4.13" + resolved "https://registry.yarnpkg.com/adm-zip/-/adm-zip-0.4.13.tgz#597e2f8cc3672151e1307d3e95cddbc75672314a" + integrity sha512-fERNJX8sOXfel6qCBCMPvZLzENBEhZTzKqg6vrOW5pvoEaQuJhRU4ndTAh6lHOxn1I6jnz2NHra56ZODM751uw== + +after@0.8.2: + version "0.8.2" + resolved "https://registry.yarnpkg.com/after/-/after-0.8.2.tgz#fedb394f9f0e02aa9768e702bda23b505fae7e1f" + integrity sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8= + +agent-base@4, agent-base@^4.1.0, agent-base@~4.2.1: + version "4.2.1" + resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-4.2.1.tgz#d89e5999f797875674c07d87f260fc41e83e8ca9" + integrity sha512-JVwXMr9nHYTUXsBFKUqhJwvlcYU/blreOEUkhNR2eXZIvwd+c+o5V4MgDPKWnMS/56awN3TRzIP+KoPn+roQtg== + dependencies: + es6-promisify "^5.0.0" + +agentkeepalive@^3.4.1: + version "3.5.2" + resolved "https://registry.yarnpkg.com/agentkeepalive/-/agentkeepalive-3.5.2.tgz#a113924dd3fa24a0bc3b78108c450c2abee00f67" + integrity sha512-e0L/HNe6qkQ7H19kTlRRqUibEAwDK5AFk6y3PtMsuut2VAH6+Q4xZml1tNDJD7kSAyqmbG/K08K5WEJYtUrSlQ== + dependencies: + humanize-ms "^1.2.1" + +ajv-errors@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/ajv-errors/-/ajv-errors-1.0.1.tgz#f35986aceb91afadec4102fbd85014950cefa64d" + integrity sha512-DCRfO/4nQ+89p/RK43i8Ezd41EqdGIU4ld7nGF8OQ14oc/we5rEntLCUa7+jrn3nn83BosfwZA0wb4pon2o8iQ== + +ajv-keywords@^3.1.0: + version "3.4.0" + resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.4.0.tgz#4b831e7b531415a7cc518cd404e73f6193c6349d" + integrity sha512-aUjdRFISbuFOl0EIZc+9e4FfZp0bDZgAdOOf30bJmw8VM9v84SHyVyxDfbWxpGYbdZD/9XoKxfHVNmxPkhwyGw== + +ajv@6.9.1: + version "6.9.1" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.9.1.tgz#a4d3683d74abc5670e75f0b16520f70a20ea8dc1" + integrity sha512-XDN92U311aINL77ieWHmqCcNlwjoP5cHXDxIxbf2MaPYuCXOHS7gHH8jktxeK5omgd52XbSTX6a4Piwd1pQmzA== + dependencies: + 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@^5.0.0: + version "5.5.2" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-5.5.2.tgz#73b5eeca3fab653e3d3f9422b341ad42205dc965" + integrity sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU= + dependencies: + co "^4.6.0" + fast-deep-equal "^1.0.0" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.3.0" + +ajv@^6.1.0, ajv@^6.5.5: + version "6.10.0" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.10.0.tgz#90d0d54439da587cd7e843bfb7045f50bd22bdf1" + integrity sha512-nffhOpkymDECQyR0mnsUtoCE8RlX38G0rYP+wgLWFyZuUyuuojSSvi/+euOiQBIn63whYwYVIIH1TvE3tu4OEg== + dependencies: + fast-deep-equal "^2.0.1" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.4.1" + uri-js "^4.2.2" + +amdefine@>=0.0.4: + version "1.0.1" + resolved "https://registry.yarnpkg.com/amdefine/-/amdefine-1.0.1.tgz#4a5282ac164729e93619bcfd3ad151f817ce91f5" + integrity sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU= + +ansi-colors@^3.0.0: + version "3.2.4" + resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-3.2.4.tgz#e3a3da4bfbae6c86a9c285625de124a234026fbf" + integrity sha512-hHUXGagefjN2iRrID63xckIvotOXOojhQKWIPUZ4mNUZ9nLZW+7FMNoE1lOkEhNWYsx/7ysGIuJYCiMAA9FnrA== + +ansi-escapes@^3.0.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-3.2.0.tgz#8780b98ff9dbf5638152d1f1fe5c1d7b4442976b" + integrity sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ== + +ansi-html@0.0.7: + version "0.0.7" + resolved "https://registry.yarnpkg.com/ansi-html/-/ansi-html-0.0.7.tgz#813584021962a9e9e6fd039f940d12f56ca7859e" + integrity sha1-gTWEAhliqenm/QOflA0S9WynhZ4= + +ansi-regex@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" + integrity sha1-w7M6te42DYbg5ijwRorn7yfWVN8= + +ansi-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" + integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg= + +ansi-regex@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997" + integrity sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg== + +ansi-styles@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" + integrity sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4= + +ansi-styles@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" + integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== + dependencies: + color-convert "^1.9.0" + +anymatch@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-2.0.0.tgz#bcb24b4f37934d9aa7ac17b4adaf89e7c76ef2eb" + integrity sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw== + dependencies: + micromatch "^3.1.4" + normalize-path "^2.1.1" + +app-root-path@^2.1.0: + version "2.2.1" + resolved "https://registry.yarnpkg.com/app-root-path/-/app-root-path-2.2.1.tgz#d0df4a682ee408273583d43f6f79e9892624bc9a" + integrity sha512-91IFKeKk7FjfmezPKkwtaRvSpnUc4gDwPAjA1YZ9Gn0q0PPeW+vbeUsZuyDwjI7+QTHhcLen2v25fi/AmhvbJA== + +append-transform@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/append-transform/-/append-transform-1.0.0.tgz#046a52ae582a228bd72f58acfbe2967c678759ab" + integrity sha512-P009oYkeHyU742iSZJzZZywj4QRJdnTWffaKuJQLablCZ1uz6/cW4yaRgcDaoQ+uwOxxnt0gRUcwfsNP2ri0gw== + dependencies: + default-require-extensions "^2.0.0" + +aproba@^1.0.3, aproba@^1.1.1: + version "1.2.0" + resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" + integrity sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw== + +are-we-there-yet@~1.1.2: + version "1.1.5" + resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz#4b35c2944f062a8bfcda66410760350fe9ddfc21" + integrity sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w== + dependencies: + delegates "^1.0.0" + readable-stream "^2.0.6" + +argparse@^1.0.7: + version "1.0.10" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" + integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== + dependencies: + sprintf-js "~1.0.2" + +arr-diff@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520" + integrity sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA= + +arr-flatten@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1" + integrity sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg== + +arr-union@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4" + integrity sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ= + +array-find-index@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/array-find-index/-/array-find-index-1.0.2.tgz#df010aa1287e164bbda6f9723b0a96a1ec4187a1" + integrity sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E= + +array-flatten@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" + integrity sha1-ml9pkFGx5wczKPKgCJaLZOopVdI= + +array-flatten@^2.1.0: + version "2.1.2" + resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-2.1.2.tgz#24ef80a28c1a893617e2149b0c6d0d788293b099" + integrity sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ== + +array-union@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39" + integrity sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk= + dependencies: + array-uniq "^1.0.1" + +array-uniq@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6" + integrity sha1-r2rId6Jcx/dOBYiUdThY39sk/bY= + +array-unique@^0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428" + integrity sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg= + +arraybuffer.slice@~0.0.7: + version "0.0.7" + resolved "https://registry.yarnpkg.com/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz#3bbc4275dd584cc1b10809b89d4e8b63a69e7675" + integrity sha512-wGUIVQXuehL5TCqQun8OW81jGzAWycqzFF8lFp+GOM5BXLYj3bKNsYC4daB7n6XjCqxQA/qgTJ+8ANR3acjrog== + +arrify@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" + integrity sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0= + +asap@~2.0.3: + version "2.0.6" + resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46" + integrity sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY= + +asn1.js@^4.0.0: + version "4.10.1" + resolved "https://registry.yarnpkg.com/asn1.js/-/asn1.js-4.10.1.tgz#b9c2bf5805f1e64aadeed6df3a2bfafb5a73f5a0" + integrity sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw== + dependencies: + bn.js "^4.0.0" + inherits "^2.0.1" + minimalistic-assert "^1.0.0" + +asn1@~0.2.3: + version "0.2.4" + resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.4.tgz#8d2475dfab553bb33e77b54e59e880bb8ce23136" + integrity sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg== + dependencies: + safer-buffer "~2.1.0" + +assert-plus@1.0.0, assert-plus@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" + integrity sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU= + +assert@^1.1.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/assert/-/assert-1.4.1.tgz#99912d591836b5a6f5b345c0f07eefc08fc65d91" + integrity sha1-mZEtWRg2tab1s0XA8H7vwI/GXZE= + dependencies: + util "0.10.3" + +assign-symbols@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367" + integrity sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c= + +async-each@^1.0.0, async-each@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.3.tgz#b727dbf87d7651602f06f4d4ac387f47d91b0cbf" + integrity sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ== + +async-foreach@^0.1.3: + version "0.1.3" + resolved "https://registry.yarnpkg.com/async-foreach/-/async-foreach-0.1.3.tgz#36121f845c0578172de419a97dbeb1d16ec34542" + integrity sha1-NhIfhFwFeBct5Bmpfb6x0W7DRUI= + +async-limiter@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.0.tgz#78faed8c3d074ab81f22b4e985d79e8738f720f8" + integrity sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg== + +async@^1.5.2: + version "1.5.2" + resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a" + integrity sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo= + +async@^2.5.0, async@^2.6.1: + version "2.6.2" + resolved "https://registry.yarnpkg.com/async/-/async-2.6.2.tgz#18330ea7e6e313887f5d2f2a904bac6fe4dd5381" + integrity sha512-H1qVYh1MYhEEFLsP97cVKqCGo7KfCyTt6uEWqsTBr9SO84oK9Uwbyd/yCW+6rKJLHksBNUVWZDAjfS+Ccx0Bbg== + dependencies: + lodash "^4.17.11" + +asynckit@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" + integrity sha1-x57Zf380y48robyXkLzDZkdLS3k= + +atob@^2.1.1: + version "2.1.2" + resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9" + integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg== + +autoprefixer@9.4.6: + version "9.4.6" + resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-9.4.6.tgz#0ace275e33b37de16b09a5547dbfe73a98c1d446" + integrity sha512-Yp51mevbOEdxDUy5WjiKtpQaecqYq9OqZSL04rSoCiry7Tc5I9FEyo3bfxiTJc1DfHeKwSFCUYbBAiOQ2VGfiw== + dependencies: + browserslist "^4.4.1" + caniuse-lite "^1.0.30000929" + normalize-range "^0.1.2" + num2fraction "^1.2.2" + postcss "^7.0.13" + postcss-value-parser "^3.3.1" + +aws-sign2@~0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8" + integrity sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg= + +aws4@^1.8.0: + version "1.8.0" + resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.8.0.tgz#f0e003d9ca9e7f59c7a508945d7b2ef9a04a542f" + integrity sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ== + +babel-code-frame@^6.22.0, babel-code-frame@^6.26.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b" + integrity sha1-Y/1D99weO7fONZR9uP42mj9Yx0s= + dependencies: + chalk "^1.1.3" + esutils "^2.0.2" + js-tokens "^3.0.2" + +babel-generator@^6.18.0: + version "6.26.1" + resolved "https://registry.yarnpkg.com/babel-generator/-/babel-generator-6.26.1.tgz#1844408d3b8f0d35a404ea7ac180f087a601bd90" + integrity sha512-HyfwY6ApZj7BYTcJURpM5tznulaBvyio7/0d4zFOeMPUmfxkCjHocCuoLa2SAGzBI8AREcH3eP3758F672DppA== + dependencies: + 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" + +babel-messages@^6.23.0: + version "6.23.0" + resolved "https://registry.yarnpkg.com/babel-messages/-/babel-messages-6.23.0.tgz#f3cdf4703858035b2a2951c6ec5edf6c62f2630e" + integrity sha1-8830cDhYA1sqKVHG7F7fbGLyYw4= + dependencies: + babel-runtime "^6.22.0" + +babel-runtime@^6.22.0, babel-runtime@^6.26.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe" + integrity sha1-llxwWGaOgrVde/4E/yM3vItWR/4= + dependencies: + core-js "^2.4.0" + regenerator-runtime "^0.11.0" + +babel-template@^6.16.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-template/-/babel-template-6.26.0.tgz#de03e2d16396b069f46dd9fff8521fb1a0e35e02" + integrity sha1-3gPi0WOWsGn0bdn/+FIfsaDjXgI= + dependencies: + 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@^6.18.0, babel-traverse@^6.26.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-traverse/-/babel-traverse-6.26.0.tgz#46a9cbd7edcc62c8e5c064e2d2d8d0f4035766ee" + integrity sha1-RqnL1+3MYsjlwGTi0tjQ9ANXZu4= + dependencies: + 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" + +babel-types@^6.18.0, babel-types@^6.26.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-types/-/babel-types-6.26.0.tgz#a3b073f94ab49eb6fa55cd65227a334380632497" + integrity sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc= + dependencies: + babel-runtime "^6.26.0" + esutils "^2.0.2" + lodash "^4.17.4" + to-fast-properties "^1.0.3" + +babylon@^6.18.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.18.0.tgz#af2f3b88fa6f5c1e4c634d1a0f8eac4f55b395e3" + integrity sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ== + +backo2@1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/backo2/-/backo2-1.0.2.tgz#31ab1ac8b129363463e35b3ebb69f4dfcfba7947" + integrity sha1-MasayLEpNjRj41s+u2n038+6eUc= + +balanced-match@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" + integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c= + +base64-arraybuffer@0.1.5: + version "0.1.5" + resolved "https://registry.yarnpkg.com/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz#73926771923b5a19747ad666aa5cd4bf9c6e9ce8" + integrity sha1-c5JncZI7Whl0etZmqlzUv5xunOg= + +base64-js@^1.0.2: + version "1.3.0" + resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.3.0.tgz#cab1e6118f051095e58b5281aea8c1cd22bfc0e3" + integrity sha512-ccav/yGvoa80BQDljCxsmmQ3Xvx60/UpBIij5QN21W3wBi/hhIC9OoO+KLpu9IJTS9j4DRVJ3aDDF9cMSoa2lw== + +base64id@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/base64id/-/base64id-1.0.0.tgz#47688cb99bb6804f0e06d3e763b1c32e57d8e6b6" + integrity sha1-R2iMuZu2gE8OBtPnY7HDLlfY5rY= + +base@^0.11.1: + version "0.11.2" + resolved "https://registry.yarnpkg.com/base/-/base-0.11.2.tgz#7bde5ced145b6d551a90db87f83c558b4eb48a8f" + integrity sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg== + dependencies: + cache-base "^1.0.1" + class-utils "^0.3.5" + component-emitter "^1.2.1" + define-property "^1.0.0" + isobject "^3.0.1" + mixin-deep "^1.2.0" + pascalcase "^0.1.1" + +batch@0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/batch/-/batch-0.6.1.tgz#dc34314f4e679318093fc760272525f94bf25c16" + integrity sha1-3DQxT05nkxgJP8dgJyUl+UvyXBY= + +bcrypt-pbkdf@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz#a4301d389b6a43f9b67ff3ca11a3f6637e360e9e" + integrity sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4= + dependencies: + tweetnacl "^0.14.3" + +better-assert@~1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/better-assert/-/better-assert-1.0.2.tgz#40866b9e1b9e0b55b481894311e68faffaebc522" + integrity sha1-QIZrnhueC1W0gYlDEeaPr/rrxSI= + dependencies: + callsite "1.0.0" + +big.js@^5.2.2: + version "5.2.2" + resolved "https://registry.yarnpkg.com/big.js/-/big.js-5.2.2.tgz#65f0af382f578bcdc742bd9c281e9cb2d7768328" + integrity sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ== + +binary-extensions@^1.0.0: + version "1.13.1" + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.13.1.tgz#598afe54755b2868a5330d2aff9d4ebb53209b65" + integrity sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw== + +blob@0.0.5: + version "0.0.5" + resolved "https://registry.yarnpkg.com/blob/-/blob-0.0.5.tgz#d680eeef25f8cd91ad533f5b01eed48e64caf683" + integrity sha512-gaqbzQPqOoamawKg0LGVd7SzLgXS+JH61oWprSLH+P+abTczqJbhTR8CmJ2u9/bUYNmHTGJx/UEmn6doAvvuig== + +block-stream@*: + version "0.0.9" + resolved "https://registry.yarnpkg.com/block-stream/-/block-stream-0.0.9.tgz#13ebfe778a03205cfe03751481ebb4b3300c126a" + integrity sha1-E+v+d4oDIFz+A3UUgeu0szAMEmo= + dependencies: + inherits "~2.0.0" + +blocking-proxy@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/blocking-proxy/-/blocking-proxy-1.0.1.tgz#81d6fd1fe13a4c0d6957df7f91b75e98dac40cb2" + integrity sha512-KE8NFMZr3mN2E0HcvCgRtX7DjhiIQrwle+nSVJVC/yqFb9+xznHl2ZcoBp2L9qzkI4t4cBFJ1efXF8Dwi132RA== + dependencies: + minimist "^1.2.0" + +bluebird@^3.3.0, bluebird@^3.5.1, bluebird@^3.5.3: + version "3.5.4" + resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.4.tgz#d6cc661595de30d5b3af5fcedd3c0b3ef6ec5714" + integrity sha512-FG+nFEZChJrbQ9tIccIfZJBz3J7mLrAhxakAbnrJWn8d7aKOC+LWifa0G+p4ZqKp4y13T7juYvdhq9NzKdsrjw== + +bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.1.1, bn.js@^4.4.0: + version "4.11.8" + resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.8.tgz#2cde09eb5ee341f484746bb0309b3253b1b1442f" + integrity sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA== + +body-parser@1.18.3, body-parser@^1.16.1: + version "1.18.3" + resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.18.3.tgz#5b292198ffdd553b3a0f20ded0592b956955c8b4" + integrity sha1-WykhmP/dVTs6DyDe0FkrlWlVyLQ= + dependencies: + bytes "3.0.0" + content-type "~1.0.4" + debug "2.6.9" + depd "~1.1.2" + http-errors "~1.6.3" + iconv-lite "0.4.23" + on-finished "~2.3.0" + qs "6.5.2" + raw-body "2.3.3" + type-is "~1.6.16" + +bonjour@^3.5.0: + version "3.5.0" + resolved "https://registry.yarnpkg.com/bonjour/-/bonjour-3.5.0.tgz#8e890a183d8ee9a2393b3844c691a42bcf7bc9f5" + integrity sha1-jokKGD2O6aI5OzhExpGkK897yfU= + dependencies: + array-flatten "^2.1.0" + deep-equal "^1.0.1" + dns-equal "^1.0.0" + dns-txt "^2.0.2" + multicast-dns "^6.0.1" + multicast-dns-service-types "^1.1.0" + +brace-expansion@^1.1.7: + version "1.1.11" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +braces@^2.3.0, braces@^2.3.1, braces@^2.3.2: + version "2.3.2" + resolved "https://registry.yarnpkg.com/braces/-/braces-2.3.2.tgz#5979fd3f14cd531565e5fa2df1abfff1dfaee729" + integrity sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w== + dependencies: + arr-flatten "^1.1.0" + array-unique "^0.3.2" + extend-shallow "^2.0.1" + fill-range "^4.0.0" + isobject "^3.0.1" + repeat-element "^1.1.2" + snapdragon "^0.8.1" + snapdragon-node "^2.0.1" + split-string "^3.0.2" + to-regex "^3.0.1" + +brorand@^1.0.1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f" + integrity sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8= + +browserify-aes@^1.0.0, browserify-aes@^1.0.4: + version "1.2.0" + resolved "https://registry.yarnpkg.com/browserify-aes/-/browserify-aes-1.2.0.tgz#326734642f403dabc3003209853bb70ad428ef48" + integrity sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA== + dependencies: + buffer-xor "^1.0.3" + cipher-base "^1.0.0" + create-hash "^1.1.0" + evp_bytestokey "^1.0.3" + inherits "^2.0.1" + safe-buffer "^5.0.1" + +browserify-cipher@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/browserify-cipher/-/browserify-cipher-1.0.1.tgz#8d6474c1b870bfdabcd3bcfcc1934a10e94f15f0" + integrity sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w== + dependencies: + browserify-aes "^1.0.4" + browserify-des "^1.0.0" + evp_bytestokey "^1.0.0" + +browserify-des@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/browserify-des/-/browserify-des-1.0.2.tgz#3af4f1f59839403572f1c66204375f7a7f703e9c" + integrity sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A== + dependencies: + cipher-base "^1.0.1" + des.js "^1.0.0" + inherits "^2.0.1" + safe-buffer "^5.1.2" + +browserify-rsa@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/browserify-rsa/-/browserify-rsa-4.0.1.tgz#21e0abfaf6f2029cf2fafb133567a701d4135524" + integrity sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ= + dependencies: + bn.js "^4.1.0" + randombytes "^2.0.1" + +browserify-sign@^4.0.0: + version "4.0.4" + resolved "https://registry.yarnpkg.com/browserify-sign/-/browserify-sign-4.0.4.tgz#aa4eb68e5d7b658baa6bf6a57e630cbd7a93d298" + integrity sha1-qk62jl17ZYuqa/alfmMMvXqT0pg= + dependencies: + 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@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/browserify-zlib/-/browserify-zlib-0.2.0.tgz#2869459d9aa3be245fe8fe2ca1f46e2e7f54d73f" + integrity sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA== + dependencies: + pako "~1.0.5" + +browserslist@^4.4.1: + version "4.5.5" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.5.5.tgz#fe1a352330d2490d5735574c149a85bc18ef9b82" + integrity sha512-0QFO1r/2c792Ohkit5XI8Cm8pDtZxgNl2H6HU4mHrpYz7314pEYcsAVVatM0l/YmxPnEzh9VygXouj4gkFUTKA== + dependencies: + caniuse-lite "^1.0.30000960" + electron-to-chromium "^1.3.124" + node-releases "^1.1.14" + +browserstack@^1.5.1: + version "1.5.2" + resolved "https://registry.yarnpkg.com/browserstack/-/browserstack-1.5.2.tgz#17d8bb76127a1cc0ea416424df80d218f803673f" + integrity sha512-+6AFt9HzhKykcPF79W6yjEUJcdvZOV0lIXdkORXMJftGrDl0OKWqRF4GHqpDNkxiceDT/uB7Fb/aDwktvXX7dg== + dependencies: + https-proxy-agent "^2.2.1" + +buffer-alloc-unsafe@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz#bd7dc26ae2972d0eda253be061dba992349c19f0" + integrity sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg== + +buffer-alloc@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/buffer-alloc/-/buffer-alloc-1.2.0.tgz#890dd90d923a873e08e10e5fd51a57e5b7cce0ec" + integrity sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow== + dependencies: + buffer-alloc-unsafe "^1.1.0" + buffer-fill "^1.0.0" + +buffer-fill@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/buffer-fill/-/buffer-fill-1.0.0.tgz#f8f78b76789888ef39f205cd637f68e702122b2c" + integrity sha1-+PeLdniYiO858gXNY39o5wISKyw= + +buffer-from@^1.0.0, buffer-from@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef" + integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A== + +buffer-indexof@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/buffer-indexof/-/buffer-indexof-1.1.1.tgz#52fabcc6a606d1a00302802648ef68f639da268c" + integrity sha512-4/rOEg86jivtPTeOUUT61jJO1Ya1TrR/OkqCSZDyq84WJh3LuuiphBYJN+fm5xufIk4XAFcEwte/8WzC8If/1g== + +buffer-xor@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/buffer-xor/-/buffer-xor-1.0.3.tgz#26e61ed1422fb70dd42e6e36729ed51d855fe8d9" + integrity sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk= + +buffer@^4.3.0: + version "4.9.1" + resolved "https://registry.yarnpkg.com/buffer/-/buffer-4.9.1.tgz#6d1bb601b07a4efced97094132093027c95bc298" + integrity sha1-bRu2AbB6TvztlwlBMgkwJ8lbwpg= + dependencies: + base64-js "^1.0.2" + ieee754 "^1.1.4" + isarray "^1.0.0" + +builtin-modules@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f" + integrity sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8= + +builtin-status-codes@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz#85982878e21b98e1c66425e03d0174788f569ee8" + integrity sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug= + +builtins@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/builtins/-/builtins-1.0.3.tgz#cb94faeb61c8696451db36534e1422f94f0aee88" + integrity sha1-y5T662HIaWRR2zZTThQi+U8K7og= + +bytes@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048" + integrity sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg= + +cacache@^10.0.4: + version "10.0.4" + resolved "https://registry.yarnpkg.com/cacache/-/cacache-10.0.4.tgz#6452367999eff9d4188aefd9a14e9d7c6a263460" + integrity sha512-Dph0MzuH+rTQzGPNT9fAnrPmMmjKfST6trxJeK7NQuHRaVw24VzPRWTmg9MpcwOVQZO0E1FBICUlFeNaKPIfHA== + dependencies: + bluebird "^3.5.1" + chownr "^1.0.1" + glob "^7.1.2" + graceful-fs "^4.1.11" + lru-cache "^4.1.1" + mississippi "^2.0.0" + mkdirp "^0.5.1" + move-concurrently "^1.0.1" + promise-inflight "^1.0.1" + rimraf "^2.6.2" + ssri "^5.2.4" + unique-filename "^1.1.0" + y18n "^4.0.0" + +cacache@^11.0.1, cacache@^11.0.2, cacache@^11.3.2: + version "11.3.2" + resolved "https://registry.yarnpkg.com/cacache/-/cacache-11.3.2.tgz#2d81e308e3d258ca38125b676b98b2ac9ce69bfa" + integrity sha512-E0zP4EPGDOaT2chM08Als91eYnf8Z+eH1awwwVsngUmgppfM5jjJ8l3z5vO5p5w/I3LsiXawb1sW0VY65pQABg== + dependencies: + bluebird "^3.5.3" + chownr "^1.1.1" + figgy-pudding "^3.5.1" + glob "^7.1.3" + graceful-fs "^4.1.15" + lru-cache "^5.1.1" + mississippi "^3.0.0" + mkdirp "^0.5.1" + move-concurrently "^1.0.1" + promise-inflight "^1.0.1" + rimraf "^2.6.2" + ssri "^6.0.1" + unique-filename "^1.1.1" + y18n "^4.0.0" + +cache-base@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/cache-base/-/cache-base-1.0.1.tgz#0a7f46416831c8b662ee36fe4e7c59d76f666ab2" + integrity sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ== + dependencies: + collection-visit "^1.0.0" + component-emitter "^1.2.1" + get-value "^2.0.6" + has-value "^1.0.0" + isobject "^3.0.1" + set-value "^2.0.0" + to-object-path "^0.3.0" + union-value "^1.0.0" + unset-value "^1.0.0" + +callsite@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/callsite/-/callsite-1.0.0.tgz#280398e5d664bd74038b6f0905153e6e8af1bc20" + integrity sha1-KAOY5dZkvXQDi28JBRU+borxvCA= + +camelcase-keys@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/camelcase-keys/-/camelcase-keys-2.1.0.tgz#308beeaffdf28119051efa1d932213c91b8f92e7" + integrity sha1-MIvur/3ygRkFHvodkyITyRuPkuc= + dependencies: + camelcase "^2.0.0" + map-obj "^1.0.0" + +camelcase@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-2.1.1.tgz#7c1d16d679a1bbe59ca02cacecfb011e201f5a1f" + integrity sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8= + +camelcase@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-3.0.0.tgz#32fc4b9fcdaf845fcdf7e73bb97cac2261f0ab0a" + integrity sha1-MvxLn82vhF/N9+c7uXysImHwqwo= + +camelcase@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-4.1.0.tgz#d545635be1e33c542649c69173e5de6acfae34dd" + integrity sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0= + +caniuse-lite@^1.0.30000929, caniuse-lite@^1.0.30000960: + version "1.0.30000962" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000962.tgz#6c10c3ab304b89bea905e66adf98c0905088ee44" + integrity sha512-WXYsW38HK+6eaj5IZR16Rn91TGhU3OhbwjKZvJ4HN/XBIABLKfbij9Mnd3pM0VEwZSlltWjoWg3I8FQ0DGgNOA== + +canonical-path@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/canonical-path/-/canonical-path-1.0.0.tgz#fcb470c23958def85081856be7a86e904f180d1d" + integrity sha512-feylzsbDxi1gPZ1IjystzIQZagYYLvfKrSuygUCgf7z6x790VEzze5QEkdSV1U58RA7Hi0+v6fv4K54atOzATg== + +caseless@~0.12.0: + version "0.12.0" + resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" + integrity sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw= + +chalk@^1.1.1, chalk@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" + integrity sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg= + dependencies: + ansi-styles "^2.2.1" + escape-string-regexp "^1.0.2" + has-ansi "^2.0.0" + strip-ansi "^3.0.0" + supports-color "^2.0.0" + +chalk@^2.0.0, chalk@^2.0.1, chalk@^2.3.0, chalk@^2.4.2: + version "2.4.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" + integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== + dependencies: + ansi-styles "^3.2.1" + escape-string-regexp "^1.0.5" + supports-color "^5.3.0" + +chardet@^0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e" + integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA== + +chokidar@2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.0.4.tgz#356ff4e2b0e8e43e322d18a372460bbcf3accd26" + integrity sha512-z9n7yt9rOvIJrMhvDtDictKrkFHeihkNl6uWMmZlmL6tJtX9Cs+87oK+teBx+JIgzvbX3yZHT3eF8vpbDxHJXQ== + dependencies: + anymatch "^2.0.0" + async-each "^1.0.0" + braces "^2.3.0" + 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" + optionalDependencies: + fsevents "^1.2.2" + +chokidar@^2.0.0, chokidar@^2.0.2, chokidar@^2.0.3, chokidar@^2.1.1: + version "2.1.5" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.1.5.tgz#0ae8434d962281a5f56c72869e79cb6d9d86ad4d" + integrity sha512-i0TprVWp+Kj4WRPtInjexJ8Q+BqTE909VpH8xVhXrJkoc5QC8VO9TryGOqTr+2hljzc1sC62t22h5tZePodM/A== + dependencies: + anymatch "^2.0.0" + async-each "^1.0.1" + braces "^2.3.2" + glob-parent "^3.1.0" + inherits "^2.0.3" + is-binary-path "^1.0.0" + is-glob "^4.0.0" + normalize-path "^3.0.0" + path-is-absolute "^1.0.0" + readdirp "^2.2.1" + upath "^1.1.1" + optionalDependencies: + fsevents "^1.2.7" + +chownr@^1.0.1, chownr@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.1.tgz#54726b8b8fff4df053c42187e801fb4412df1494" + integrity sha512-j38EvO5+LHX84jlo6h4UzmOwi0UgW61WRyPtJz4qaadK5eY3BTS5TY/S1Stc3Uk2lIM6TPevAlULiEJwie860g== + +chrome-trace-event@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-1.0.0.tgz#45a91bd2c20c9411f0963b5aaeb9a1b95e09cc48" + integrity sha512-xDbVgyfDTT2piup/h8dK/y4QZfJRSa73bw1WZ8b4XM1o7fsFubUVGYcE+1ANtOzJJELGpYoG2961z0Z6OAld9A== + dependencies: + tslib "^1.9.0" + +cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.4.tgz#8760e4ecc272f4c363532f926d874aae2c1397de" + integrity sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q== + dependencies: + inherits "^2.0.1" + safe-buffer "^5.0.1" + +circular-dependency-plugin@5.0.2: + version "5.0.2" + resolved "https://registry.yarnpkg.com/circular-dependency-plugin/-/circular-dependency-plugin-5.0.2.tgz#da168c0b37e7b43563fb9f912c1c007c213389ef" + integrity sha512-oC7/DVAyfcY3UWKm0sN/oVoDedQDQiw/vIiAnuTWTpE5s0zWf7l3WY417Xw/Fbi/QbAjctAkxgMiS9P0s3zkmA== + +class-utils@^0.3.5: + version "0.3.6" + resolved "https://registry.yarnpkg.com/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463" + integrity sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg== + dependencies: + arr-union "^3.1.0" + define-property "^0.2.5" + isobject "^3.0.0" + static-extend "^0.1.1" + +clean-css@4.2.1: + version "4.2.1" + resolved "https://registry.yarnpkg.com/clean-css/-/clean-css-4.2.1.tgz#2d411ef76b8569b6d0c84068dabe85b0aa5e5c17" + integrity sha512-4ZxI6dy4lrY6FHzfiy1aEOXgu4LIsW2MhwG0VBKdcoGoH/XLFgaHSdLTGr4O8Be6A8r3MOphEiI8Gc1n0ecf3g== + dependencies: + source-map "~0.6.0" + +cli-cursor@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-2.1.0.tgz#b35dac376479facc3e94747d41d0d0f5238ffcb5" + integrity sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU= + dependencies: + restore-cursor "^2.0.0" + +cli-width@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.2.0.tgz#ff19ede8a9a5e579324147b0c11f0fbcbabed639" + integrity sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk= + +cliui@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-3.2.0.tgz#120601537a916d29940f934da3b48d585a39213d" + integrity sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0= + dependencies: + string-width "^1.0.1" + strip-ansi "^3.0.1" + wrap-ansi "^2.0.0" + +cliui@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-4.1.0.tgz#348422dbe82d800b3022eef4f6ac10bf2e4d1b49" + integrity sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ== + dependencies: + string-width "^2.1.1" + strip-ansi "^4.0.0" + wrap-ansi "^2.0.0" + +clone-deep@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/clone-deep/-/clone-deep-2.0.2.tgz#00db3a1e173656730d1188c3d6aced6d7ea97713" + integrity sha512-SZegPTKjCgpQH63E+eN6mVEEPdQBOUzjyJm5Pora4lrwWRFS8I0QAxV/KD6vV/i0WuijHZWQC1fMsPEdxfdVCQ== + dependencies: + for-own "^1.0.0" + is-plain-object "^2.0.4" + kind-of "^6.0.0" + shallow-clone "^1.0.0" + +clone@^2.1.1, clone@^2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/clone/-/clone-2.1.2.tgz#1b7f4b9f591f1e8f83670401600345a02887435f" + integrity sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18= + +co@^4.6.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" + integrity sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ= + +code-point-at@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" + integrity sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c= + +codelyzer@~4.5.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/codelyzer/-/codelyzer-4.5.0.tgz#a65ddeeeca2894653253a89bfa229118ff9f59b1" + integrity sha512-oO6vCkjqsVrEsmh58oNlnJkRXuA30hF8cdNAQV9DytEalDwyOFRvHMnlKFzmOStNerOmPGZU9GAHnBo4tGvtiQ== + dependencies: + app-root-path "^2.1.0" + css-selector-tokenizer "^0.7.0" + cssauron "^1.4.0" + semver-dsl "^1.0.1" + source-map "^0.5.7" + sprintf-js "^1.1.1" + +collection-visit@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/collection-visit/-/collection-visit-1.0.0.tgz#4bc0373c164bc3291b4d368c829cf1a80a59dca0" + integrity sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA= + dependencies: + map-visit "^1.0.0" + object-visit "^1.0.0" + +color-convert@^1.9.0: + version "1.9.3" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" + integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== + dependencies: + color-name "1.1.3" + +color-name@1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" + integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= + +colors@1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/colors/-/colors-1.1.2.tgz#168a4701756b6a7f51a12ce0c97bfa28c084ed63" + integrity sha1-FopHAXVran9RoSzgyXv6KMCE7WM= + +colors@^1.1.0: + version "1.3.3" + resolved "https://registry.yarnpkg.com/colors/-/colors-1.3.3.tgz#39e005d546afe01e01f9c4ca8fa50f686a01205d" + integrity sha512-mmGt/1pZqYRjMxB1axhTo16/snVZ5krrKkcmMeVKxzECMMXoCgnvTPp10QgHfcbQZw8Dq2jMNG6je4JlWU0gWg== + +combined-stream@^1.0.6, combined-stream@~1.0.6: + version "1.0.7" + resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.7.tgz#2d1d24317afb8abe95d6d2c0b07b57813539d828" + integrity sha512-brWl9y6vOB1xYPZcpZde3N9zDByXTosAeMDo4p1wzo6UMOX4vumB+TP1RZ76sfE6Md68Q0NJSrE/gbezd4Ul+w== + dependencies: + delayed-stream "~1.0.0" + +commander@^2.12.1, commander@^2.19.0, commander@~2.20.0: + version "2.20.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.0.tgz#d58bb2b5c1ee8f87b0d340027e9e94e222c5a422" + integrity sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ== + +commondir@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b" + integrity sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs= + +compare-versions@^3.2.1: + version "3.4.0" + resolved "https://registry.yarnpkg.com/compare-versions/-/compare-versions-3.4.0.tgz#e0747df5c9cb7f054d6d3dc3e1dbc444f9e92b26" + integrity sha512-tK69D7oNXXqUW3ZNo/z7NXTEz22TCF0pTE+YF9cxvaAM9XnkLo1fV621xCLrRR6aevJlKxExkss0vWqUCUpqdg== + +component-bind@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/component-bind/-/component-bind-1.0.0.tgz#00c608ab7dcd93897c0009651b1d3a8e1e73bbd1" + integrity sha1-AMYIq33Nk4l8AAllGx06jh5zu9E= + +component-emitter@1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.2.1.tgz#137918d6d78283f7df7a6b7c5a63e140e69425e6" + integrity sha1-E3kY1teCg/ffemt8WmPhQOaUJeY= + +component-emitter@^1.2.1: + version "1.3.0" + resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0" + integrity sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg== + +component-inherit@0.0.3: + version "0.0.3" + resolved "https://registry.yarnpkg.com/component-inherit/-/component-inherit-0.0.3.tgz#645fc4adf58b72b649d5cae65135619db26ff143" + integrity sha1-ZF/ErfWLcrZJ1crmUTVhnbJv8UM= + +compressible@~2.0.16: + version "2.0.16" + resolved "https://registry.yarnpkg.com/compressible/-/compressible-2.0.16.tgz#a49bf9858f3821b64ce1be0296afc7380466a77f" + integrity sha512-JQfEOdnI7dASwCuSPWIeVYwc/zMsu/+tRhoUvEfXz2gxOA2DNjmG5vhtFdBlhWPPGo+RdT9S3tgc/uH5qgDiiA== + dependencies: + mime-db ">= 1.38.0 < 2" + +compression@^1.5.2: + version "1.7.4" + resolved "https://registry.yarnpkg.com/compression/-/compression-1.7.4.tgz#95523eff170ca57c29a0ca41e6fe131f41e5bb8f" + integrity sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ== + dependencies: + accepts "~1.3.5" + bytes "3.0.0" + compressible "~2.0.16" + debug "2.6.9" + on-headers "~1.0.2" + safe-buffer "5.1.2" + vary "~1.1.2" + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= + +concat-stream@^1.5.0: + version "1.6.2" + resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34" + integrity sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw== + dependencies: + buffer-from "^1.0.0" + inherits "^2.0.3" + readable-stream "^2.2.2" + typedarray "^0.0.6" + +connect-history-api-fallback@^1.3.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/connect-history-api-fallback/-/connect-history-api-fallback-1.6.0.tgz#8b32089359308d111115d81cad3fceab888f97bc" + integrity sha512-e54B99q/OUoH64zYYRf3HBP5z24G38h5D3qXu23JGRoigpX5Ss4r9ZnDk3g0Z8uQC2x2lPaJ+UlWBc1ZWBWdLg== + +connect@^3.6.0: + version "3.6.6" + resolved "https://registry.yarnpkg.com/connect/-/connect-3.6.6.tgz#09eff6c55af7236e137135a72574858b6786f524" + integrity sha1-Ce/2xVr3I24TcTWnJXSFi2eG9SQ= + dependencies: + debug "2.6.9" + finalhandler "1.1.0" + parseurl "~1.3.2" + utils-merge "1.0.1" + +console-browserify@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/console-browserify/-/console-browserify-1.1.0.tgz#f0241c45730a9fc6323b206dbf38edc741d0bb10" + integrity sha1-8CQcRXMKn8YyOyBtvzjtx0HQuxA= + dependencies: + date-now "^0.1.4" + +console-control-strings@^1.0.0, console-control-strings@~1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" + integrity sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4= + +constants-browserify@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/constants-browserify/-/constants-browserify-1.0.0.tgz#c20b96d8c617748aaf1c16021760cd27fcb8cb75" + integrity sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U= + +content-disposition@0.5.2: + version "0.5.2" + resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.2.tgz#0cf68bb9ddf5f2be7961c3a85178cb85dba78cb4" + integrity sha1-DPaLud318r55YcOoUXjLhdunjLQ= + +content-type@~1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" + integrity sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA== + +convert-source-map@^1.5.0, convert-source-map@^1.5.1: + version "1.6.0" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.6.0.tgz#51b537a8c43e0f04dec1993bffcdd504e758ac20" + integrity sha512-eFu7XigvxdZ1ETfbgPBohgyQ/Z++C0eEhTor0qRwBw9unw+L0/6V8wkSuGgzdThkiS5lSpdptOQPD8Ak40a+7A== + dependencies: + safe-buffer "~5.1.1" + +cookie-signature@1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" + integrity sha1-4wOogrNCzD7oylE6eZmXNNqzriw= + +cookie@0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.3.1.tgz#e7e0a1f9ef43b4c8ba925c5c5a96e806d16873bb" + integrity sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s= + +copy-concurrently@^1.0.0: + version "1.0.5" + resolved "https://registry.yarnpkg.com/copy-concurrently/-/copy-concurrently-1.0.5.tgz#92297398cae34937fcafd6ec8139c18051f0b5e0" + integrity sha512-f2domd9fsVDFtaFcbaRZuYXwtdmnzqbADSwhSWYxYB/Q8zsdUUFMXVRwXGDMWmbEzAn1kdRrtI1T/KTFOL4X2A== + dependencies: + aproba "^1.1.1" + fs-write-stream-atomic "^1.0.8" + iferr "^0.1.5" + mkdirp "^0.5.1" + rimraf "^2.5.4" + run-queue "^1.0.0" + +copy-descriptor@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" + integrity sha1-Z29us8OZl8LuGsOpJP1hJHSPV40= + +copy-webpack-plugin@4.6.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/copy-webpack-plugin/-/copy-webpack-plugin-4.6.0.tgz#e7f40dd8a68477d405dd1b7a854aae324b158bae" + integrity sha512-Y+SQCF+0NoWQryez2zXn5J5knmr9z/9qSQt7fbL78u83rxmigOy8X5+BFn8CFSuX+nKT8gpYwJX68ekqtQt6ZA== + dependencies: + cacache "^10.0.4" + find-cache-dir "^1.0.0" + globby "^7.1.1" + is-glob "^4.0.0" + loader-utils "^1.1.0" + minimatch "^3.0.4" + p-limit "^1.0.0" + serialize-javascript "^1.4.0" + +core-js@^2.2.0, core-js@^2.4.0, core-js@^2.5.4: + version "2.6.5" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.5.tgz#44bc8d249e7fb2ff5d00e0341a7ffb94fbf67895" + integrity sha512-klh/kDpwX8hryYL14M9w/xei6vrv6sE8gTHDG7/T/+SEovB/G4ejwcfE/CBzO6Edsu+OETZMZ3wcX/EjUkrl5A== + +core-util-is@1.0.2, core-util-is@~1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" + integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac= + +cosmiconfig@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-4.0.0.tgz#760391549580bbd2df1e562bc177b13c290972dc" + integrity sha512-6e5vDdrXZD+t5v0L8CrurPeybg4Fmf+FCSYxXKYVAqLUtyCSbuyqE059d0kDthTNRzKVjL7QMgNpEUlsoYH3iQ== + dependencies: + is-directory "^0.3.1" + js-yaml "^3.9.0" + parse-json "^4.0.0" + require-from-string "^2.0.1" + +create-ecdh@^4.0.0: + version "4.0.3" + resolved "https://registry.yarnpkg.com/create-ecdh/-/create-ecdh-4.0.3.tgz#c9111b6f33045c4697f144787f9254cdc77c45ff" + integrity sha512-GbEHQPMOswGpKXM9kCWVrremUcBmjteUaQ01T9rkKCPDXfUHX0IoP9LpHYo2NPFampa4e+/pFDc3jQdxrxQLaw== + dependencies: + bn.js "^4.1.0" + elliptic "^6.0.0" + +create-hash@^1.1.0, create-hash@^1.1.2: + version "1.2.0" + resolved "https://registry.yarnpkg.com/create-hash/-/create-hash-1.2.0.tgz#889078af11a63756bcfb59bd221996be3a9ef196" + integrity sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg== + dependencies: + cipher-base "^1.0.1" + inherits "^2.0.1" + md5.js "^1.3.4" + ripemd160 "^2.0.1" + sha.js "^2.4.0" + +create-hmac@^1.1.0, create-hmac@^1.1.2, create-hmac@^1.1.4: + version "1.1.7" + resolved "https://registry.yarnpkg.com/create-hmac/-/create-hmac-1.1.7.tgz#69170c78b3ab957147b2b8b04572e47ead2243ff" + integrity sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg== + dependencies: + cipher-base "^1.0.3" + create-hash "^1.1.0" + inherits "^2.0.1" + ripemd160 "^2.0.0" + safe-buffer "^5.0.1" + sha.js "^2.4.8" + +cross-spawn@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-3.0.1.tgz#1256037ecb9f0c5f79e3d6ef135e30770184b982" + integrity sha1-ElYDfsufDF9549bvE14wdwGEuYI= + dependencies: + lru-cache "^4.0.1" + which "^1.2.9" + +cross-spawn@^5.0.1: + version "5.1.0" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449" + integrity sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk= + dependencies: + lru-cache "^4.0.1" + shebang-command "^1.2.0" + which "^1.2.9" + +cross-spawn@^6.0.0: + version "6.0.5" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" + integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ== + dependencies: + nice-try "^1.0.4" + path-key "^2.0.1" + semver "^5.5.0" + shebang-command "^1.2.0" + which "^1.2.9" + +crypto-browserify@^3.11.0: + version "3.12.0" + resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.12.0.tgz#396cf9f3137f03e4b8e532c58f698254e00f80ec" + integrity sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg== + dependencies: + browserify-cipher "^1.0.0" + browserify-sign "^4.0.0" + create-ecdh "^4.0.0" + create-hash "^1.1.0" + create-hmac "^1.1.0" + diffie-hellman "^5.0.0" + inherits "^2.0.1" + pbkdf2 "^3.0.3" + public-encrypt "^4.0.0" + randombytes "^2.0.0" + randomfill "^1.0.3" + +css-parse@1.7.x: + version "1.7.0" + resolved "https://registry.yarnpkg.com/css-parse/-/css-parse-1.7.0.tgz#321f6cf73782a6ff751111390fc05e2c657d8c9b" + integrity sha1-Mh9s9zeCpv91ERE5D8BeLGV9jJs= + +css-selector-tokenizer@^0.7.0: + version "0.7.1" + resolved "https://registry.yarnpkg.com/css-selector-tokenizer/-/css-selector-tokenizer-0.7.1.tgz#a177271a8bca5019172f4f891fc6eed9cbf68d5d" + integrity sha512-xYL0AMZJ4gFzJQsHUKa5jiWWi2vH77WVNg7JYRyewwj6oPh4yb/y6Y9ZCw9dsj/9UauMhtuxR+ogQd//EdEVNA== + dependencies: + cssesc "^0.1.0" + fastparse "^1.1.1" + regexpu-core "^1.0.0" + +cssauron@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/cssauron/-/cssauron-1.4.0.tgz#a6602dff7e04a8306dc0db9a551e92e8b5662ad8" + integrity sha1-pmAt/34EqDBtwNuaVR6S6LVmKtg= + dependencies: + through X.X.X + +cssesc@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-0.1.0.tgz#c814903e45623371a0477b40109aaafbeeaddbb4" + integrity sha1-yBSQPkViM3GgR3tAEJqq++6t27Q= + +currently-unhandled@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/currently-unhandled/-/currently-unhandled-0.4.1.tgz#988df33feab191ef799a61369dd76c17adf957ea" + integrity sha1-mI3zP+qxke95mmE2nddsF635V+o= + dependencies: + array-find-index "^1.0.1" + +custom-event@~1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/custom-event/-/custom-event-1.0.1.tgz#5d02a46850adf1b4a317946a3928fccb5bfd0425" + integrity sha1-XQKkaFCt8bSjF5RqOSj8y1v9BCU= + +cyclist@~0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/cyclist/-/cyclist-0.2.2.tgz#1b33792e11e914a2fd6d6ed6447464444e5fa640" + integrity sha1-GzN5LhHpFKL9bW7WRHRkRE5fpkA= + +dashdash@^1.12.0: + version "1.14.1" + resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" + integrity sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA= + dependencies: + assert-plus "^1.0.0" + +date-format@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/date-format/-/date-format-2.0.0.tgz#7cf7b172f1ec564f0003b39ea302c5498fb98c8f" + integrity sha512-M6UqVvZVgFYqZL1SfHsRGIQSz3ZL+qgbsV5Lp1Vj61LZVYuEwcMXYay7DRDtYs2HQQBK5hQtQ0fD9aEJ89V0LA== + +date-now@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/date-now/-/date-now-0.1.4.tgz#eaf439fd4d4848ad74e5cc7dbef200672b9e345b" + integrity sha1-6vQ5/U1ISK105cx9vvIAZyueNFs= + +debug@*, debug@^4.1.0, debug@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791" + integrity sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw== + dependencies: + ms "^2.1.1" + +debug@2.6.9, debug@^2.2.0, debug@^2.3.3, debug@^2.6.8: + version "2.6.9" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" + integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== + dependencies: + ms "2.0.0" + +debug@3.1.0, debug@~3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" + integrity sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g== + dependencies: + ms "2.0.0" + +debug@^3.1.0, debug@^3.2.5, debug@^3.2.6: + version "3.2.6" + resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b" + integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ== + dependencies: + ms "^2.1.1" + +decamelize@^1.1.1, decamelize@^1.1.2: + version "1.2.0" + resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" + integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA= + +decamelize@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-2.0.0.tgz#656d7bbc8094c4c788ea53c5840908c9c7d063c7" + integrity sha512-Ikpp5scV3MSYxY39ymh45ZLEecsTdv/Xj2CaQfI8RLMuwi7XvjX9H/fhraiSuU+C5w5NTDu4ZU72xNiZnurBPg== + dependencies: + xregexp "4.0.0" + +decode-uri-component@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545" + integrity sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU= + +deep-equal@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-1.0.1.tgz#f5d260292b660e084eff4cdbc9f08ad3247448b5" + integrity sha1-9dJgKStmDghO/0zbyfCK0yR0SLU= + +deep-extend@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" + integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA== + +default-gateway@^2.6.0: + version "2.7.2" + resolved "https://registry.yarnpkg.com/default-gateway/-/default-gateway-2.7.2.tgz#b7ef339e5e024b045467af403d50348db4642d0f" + integrity sha512-lAc4i9QJR0YHSDFdzeBQKfZ1SRDG3hsJNEkrpcZa8QhBfidLAilT60BDEIVUUGqosFp425KOgB3uYqcnQrWafQ== + dependencies: + execa "^0.10.0" + ip-regex "^2.1.0" + +default-require-extensions@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/default-require-extensions/-/default-require-extensions-2.0.0.tgz#f5f8fbb18a7d6d50b21f641f649ebb522cfe24f7" + integrity sha1-9fj7sYp9bVCyH2QfZJ67Uiz+JPc= + dependencies: + strip-bom "^3.0.0" + +define-property@^0.2.5: + version "0.2.5" + resolved "https://registry.yarnpkg.com/define-property/-/define-property-0.2.5.tgz#c35b1ef918ec3c990f9a5bc57be04aacec5c8116" + integrity sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY= + dependencies: + is-descriptor "^0.1.0" + +define-property@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/define-property/-/define-property-1.0.0.tgz#769ebaaf3f4a63aad3af9e8d304c9bbe79bfb0e6" + integrity sha1-dp66rz9KY6rTr56NMEybvnm/sOY= + dependencies: + is-descriptor "^1.0.0" + +define-property@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/define-property/-/define-property-2.0.2.tgz#d459689e8d654ba77e02a817f8710d702cb16e9d" + integrity sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ== + dependencies: + is-descriptor "^1.0.2" + isobject "^3.0.1" + +del@^2.2.0: + version "2.2.2" + resolved "https://registry.yarnpkg.com/del/-/del-2.2.2.tgz#c12c981d067846c84bcaf862cff930d907ffd1a8" + integrity sha1-wSyYHQZ4RshLyvhiz/kw2Qf/0ag= + dependencies: + globby "^5.0.0" + is-path-cwd "^1.0.0" + is-path-in-cwd "^1.0.0" + object-assign "^4.0.1" + pify "^2.0.0" + pinkie-promise "^2.0.0" + rimraf "^2.2.8" + +del@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/del/-/del-3.0.0.tgz#53ecf699ffcbcb39637691ab13baf160819766e5" + integrity sha1-U+z2mf/LyzljdpGrE7rxYIGXZuU= + dependencies: + 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" + +delayed-stream@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" + integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk= + +delegates@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" + integrity sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o= + +depd@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" + integrity sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak= + +dependency-graph@^0.7.2: + version "0.7.2" + resolved "https://registry.yarnpkg.com/dependency-graph/-/dependency-graph-0.7.2.tgz#91db9de6eb72699209d88aea4c1fd5221cac1c49" + integrity sha512-KqtH4/EZdtdfWX0p6MGP9jljvxSY6msy/pRUD4jgNwVpv3v1QmNLlsB3LDSSUg79BRVSn7jI1QPRtArGABovAQ== + +des.js@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/des.js/-/des.js-1.0.0.tgz#c074d2e2aa6a8a9a07dbd61f9a15c2cd83ec8ecc" + integrity sha1-wHTS4qpqipoH29YfmhXCzYPsjsw= + dependencies: + inherits "^2.0.1" + minimalistic-assert "^1.0.0" + +destroy@~1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" + integrity sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA= + +detect-indent@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-4.0.0.tgz#f76d064352cdf43a1cb6ce619c4ee3a9475de208" + integrity sha1-920GQ1LN9Docts5hnE7jqUdd4gg= + dependencies: + repeating "^2.0.0" + +detect-libc@^1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" + integrity sha1-+hN8S9aY7fVc1c0CrFWfkaTEups= + +detect-node@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.0.4.tgz#014ee8f8f669c5c58023da64b8179c083a28c46c" + integrity sha512-ZIzRpLJrOj7jjP2miAtgqIfmzbxa4ZOr5jJc601zklsfEx9oTzmmj2nVpIPRpNlRTIh8lc1kyViIY7BWSGNmKw== + +di@^0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/di/-/di-0.0.1.tgz#806649326ceaa7caa3306d75d985ea2748ba913c" + integrity sha1-gGZJMmzqp8qjMG112YXqJ0i6kTw= + +diff@^3.1.0, diff@^3.2.0: + version "3.5.0" + resolved "https://registry.yarnpkg.com/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12" + integrity sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA== + +diffie-hellman@^5.0.0: + version "5.0.3" + resolved "https://registry.yarnpkg.com/diffie-hellman/-/diffie-hellman-5.0.3.tgz#40e8ee98f55a2149607146921c63e1ae5f3d2875" + integrity sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg== + dependencies: + bn.js "^4.1.0" + miller-rabin "^4.0.0" + randombytes "^2.0.0" + +dir-glob@^2.0.0: + version "2.2.2" + resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-2.2.2.tgz#fa09f0694153c8918b18ba0deafae94769fc50c4" + integrity sha512-f9LBi5QWzIW3I6e//uxZoLBlUt9kcp66qo0sSCxL6YZKc75R1c4MFCoe/LaZiBGmgujvQdxc5Bn3QhfyvK5Hsw== + dependencies: + path-type "^3.0.0" + +dns-equal@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/dns-equal/-/dns-equal-1.0.0.tgz#b39e7f1da6eb0a75ba9c17324b34753c47e0654d" + integrity sha1-s55/HabrCnW6nBcySzR1PEfgZU0= + +dns-packet@^1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/dns-packet/-/dns-packet-1.3.1.tgz#12aa426981075be500b910eedcd0b47dd7deda5a" + integrity sha512-0UxfQkMhYAUaZI+xrNZOz/as5KgDU0M/fQ9b6SpkyLbk3GEswDi6PADJVaYJradtRVsRIlF1zLyOodbcTCDzUg== + dependencies: + ip "^1.1.0" + safe-buffer "^5.0.1" + +dns-txt@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/dns-txt/-/dns-txt-2.0.2.tgz#b91d806f5d27188e4ab3e7d107d881a1cc4642b6" + integrity sha1-uR2Ab10nGI5Ks+fRB9iBocxGQrY= + dependencies: + buffer-indexof "^1.0.0" + +dom-serialize@^2.2.0: + version "2.2.1" + resolved "https://registry.yarnpkg.com/dom-serialize/-/dom-serialize-2.2.1.tgz#562ae8999f44be5ea3076f5419dcd59eb43ac95b" + integrity sha1-ViromZ9Evl6jB29UGdzVnrQ6yVs= + dependencies: + custom-event "~1.0.0" + ent "~2.2.0" + extend "^3.0.0" + void-elements "^2.0.0" + +domain-browser@^1.1.1: + version "1.2.0" + resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-1.2.0.tgz#3d31f50191a6749dd1375a7f522e823d42e54eda" + integrity sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA== + +duplexify@^3.4.2, duplexify@^3.6.0: + version "3.7.1" + resolved "https://registry.yarnpkg.com/duplexify/-/duplexify-3.7.1.tgz#2a4df5317f6ccfd91f86d6fd25d8d8a103b88309" + integrity sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g== + dependencies: + end-of-stream "^1.0.0" + inherits "^2.0.1" + readable-stream "^2.0.0" + stream-shift "^1.0.0" + +ecc-jsbn@~0.1.1: + version "0.1.2" + resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9" + integrity sha1-OoOpBOVDUyh4dMVkt1SThoSamMk= + dependencies: + jsbn "~0.1.0" + safer-buffer "^2.1.0" + +ee-first@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" + integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0= + +electron-to-chromium@^1.3.124: + version "1.3.125" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.125.tgz#dbde0e95e64ebe322db0eca764d951f885a5aff2" + integrity sha512-XxowpqQxJ4nDwUXHtVtmEhRqBpm2OnjBomZmZtHD0d2Eo0244+Ojezhk3sD/MBSSe2nxCdGQFRXHIsf/LUTL9A== + +elliptic@^6.0.0: + version "6.4.1" + resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.4.1.tgz#c2d0b7776911b86722c632c3c06c60f2f819939a" + integrity sha512-BsXLz5sqX8OHcsh7CqBMztyXARmGQ3LWPtGjJi6DiJHq5C/qvi9P3OqgswKSDftbu8+IoI/QDTAm2fFnQ9SZSQ== + dependencies: + bn.js "^4.4.0" + brorand "^1.0.1" + hash.js "^1.0.0" + hmac-drbg "^1.0.0" + inherits "^2.0.1" + minimalistic-assert "^1.0.0" + minimalistic-crypto-utils "^1.0.0" + +emojis-list@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-2.1.0.tgz#4daa4d9db00f9819880c79fa457ae5b09a1fd389" + integrity sha1-TapNnbAPmBmIDHn6RXrlsJof04k= + +encodeurl@~1.0.1, encodeurl@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" + integrity sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k= + +encoding@^0.1.11: + version "0.1.12" + resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.12.tgz#538b66f3ee62cd1ab51ec323829d1f9480c74beb" + integrity sha1-U4tm8+5izRq1HsMjgp0flIDHS+s= + dependencies: + iconv-lite "~0.4.13" + +end-of-stream@^1.0.0, end-of-stream@^1.1.0: + version "1.4.1" + resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.1.tgz#ed29634d19baba463b6ce6b80a37213eab71ec43" + integrity sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q== + dependencies: + once "^1.4.0" + +engine.io-client@~3.2.0: + version "3.2.1" + resolved "https://registry.yarnpkg.com/engine.io-client/-/engine.io-client-3.2.1.tgz#6f54c0475de487158a1a7c77d10178708b6add36" + integrity sha512-y5AbkytWeM4jQr7m/koQLc5AxpRKC1hEVUb/s1FUAWEJq5AzJJ4NLvzuKPuxtDi5Mq755WuDvZ6Iv2rXj4PTzw== + dependencies: + 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 "~3.3.1" + xmlhttprequest-ssl "~1.5.4" + yeast "0.1.2" + +engine.io-parser@~2.1.0, engine.io-parser@~2.1.1: + version "2.1.3" + resolved "https://registry.yarnpkg.com/engine.io-parser/-/engine.io-parser-2.1.3.tgz#757ab970fbf2dfb32c7b74b033216d5739ef79a6" + integrity sha512-6HXPre2O4Houl7c4g7Ic/XzPnHBvaEmN90vtRO9uLmwtRqQmTOw0QMevL1TOfL2Cpu1VzsaTmMotQgMdkzGkVA== + dependencies: + after "0.8.2" + arraybuffer.slice "~0.0.7" + base64-arraybuffer "0.1.5" + blob "0.0.5" + has-binary2 "~1.0.2" + +engine.io@~3.2.0: + version "3.2.1" + resolved "https://registry.yarnpkg.com/engine.io/-/engine.io-3.2.1.tgz#b60281c35484a70ee0351ea0ebff83ec8c9522a2" + integrity sha512-+VlKzHzMhaU+GsCIg4AoXF1UdDFjHHwMmMKqMJNDNLlUlejz58FCy4LBqB2YVJskHGYl06BatYWKP2TVdVXE5w== + dependencies: + accepts "~1.3.4" + base64id "1.0.0" + cookie "0.3.1" + debug "~3.1.0" + engine.io-parser "~2.1.0" + ws "~3.3.1" + +enhanced-resolve@4.1.0, enhanced-resolve@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-4.1.0.tgz#41c7e0bfdfe74ac1ffe1e57ad6a5c6c9f3742a7f" + integrity sha512-F/7vkyTtyc/llOIn8oWclcB25KdRaiPBpZYDgJHgh/UHtpgT2p2eldQgtQnLtUvfMKPKxbRaQM/hHkvLHt1Vng== + dependencies: + graceful-fs "^4.1.2" + memory-fs "^0.4.0" + tapable "^1.0.0" + +ent@~2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/ent/-/ent-2.2.0.tgz#e964219325a21d05f44466a2f686ed6ce5f5dd1d" + integrity sha1-6WQhkyWiHQX0RGai9obtbOX13R0= + +err-code@^1.0.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/err-code/-/err-code-1.1.2.tgz#06e0116d3028f6aef4806849eb0ea6a748ae6960" + integrity sha1-BuARbTAo9q70gGhJ6w6mp0iuaWA= + +errno@^0.1.1, errno@^0.1.3, errno@~0.1.7: + version "0.1.7" + resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.7.tgz#4684d71779ad39af177e3f007996f7c67c852618" + integrity sha512-MfrRBDWzIWifgq6tJj60gkAwtLNb6sQPlcFrSOflcP1aFmmruKQ2wRnze/8V6kgyz7H3FF8Npzv78mZ7XLLflg== + dependencies: + prr "~1.0.1" + +error-ex@^1.2.0, error-ex@^1.3.1: + version "1.3.2" + resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" + integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g== + dependencies: + is-arrayish "^0.2.1" + +es6-promise@^4.0.3: + version "4.2.6" + resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.6.tgz#b685edd8258886365ea62b57d30de28fadcd974f" + integrity sha512-aRVgGdnmW2OiySVPUC9e6m+plolMAJKjZnQlCwNSuK5yQ0JN61DZSO1X1Ufd1foqWRAlig0rhduTCHe7sVtK5Q== + +es6-promisify@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/es6-promisify/-/es6-promisify-5.0.0.tgz#5109d62f3e56ea967c4b63505aef08291c8a5203" + integrity sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM= + dependencies: + es6-promise "^4.0.3" + +escape-html@~1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" + integrity sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg= + +escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= + +eslint-scope@^4.0.0: + version "4.0.3" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-4.0.3.tgz#ca03833310f6889a3264781aa82e63eb9cfe7848" + integrity sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg== + dependencies: + esrecurse "^4.1.0" + estraverse "^4.1.1" + +esprima@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" + integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== + +esrecurse@^4.1.0: + version "4.2.1" + resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.2.1.tgz#007a3b9fdbc2b3bb87e4879ea19c92fdbd3942cf" + integrity sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ== + dependencies: + estraverse "^4.1.0" + +estraverse@^4.1.0, estraverse@^4.1.1: + version "4.2.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.2.0.tgz#0dee3fed31fcd469618ce7342099fc1afa0bdb13" + integrity sha1-De4/7TH81GlhjOc0IJn8GvoL2xM= + +esutils@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b" + integrity sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs= + +etag@~1.8.1: + version "1.8.1" + resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" + integrity sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc= + +eventemitter3@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-3.1.0.tgz#090b4d6cdbd645ed10bf750d4b5407942d7ba163" + integrity sha512-ivIvhpq/Y0uSjcHDcOIccjmYjGLcP09MFGE7ysAwkAvkXfpZlC985pH2/ui64DKazbTW/4kN3yqozUxlXzI6cA== + +events@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/events/-/events-3.0.0.tgz#9a0a0dfaf62893d92b875b8f2698ca4114973e88" + integrity sha512-Dc381HFWJzEOhQ+d8pkNon++bk9h6cdAoAj4iE6Q4y6xgTzySWXlKn05/TVNpjnfRqi/X0EpJEJohPjNI3zpVA== + +eventsource@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/eventsource/-/eventsource-1.0.7.tgz#8fbc72c93fcd34088090bc0a4e64f4b5cee6d8d0" + integrity sha512-4Ln17+vVT0k8aWq+t/bF5arcS3EpT9gYtW66EPacdj/mAFevznsnyoHLPy2BA8gbIQeIHoPsvwmfBftfcG//BQ== + dependencies: + original "^1.0.0" + +evp_bytestokey@^1.0.0, evp_bytestokey@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz#7fcbdb198dc71959432efe13842684e0525acb02" + integrity sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA== + dependencies: + md5.js "^1.3.4" + safe-buffer "^5.1.1" + +execa@^0.10.0: + version "0.10.0" + resolved "https://registry.yarnpkg.com/execa/-/execa-0.10.0.tgz#ff456a8f53f90f8eccc71a96d11bdfc7f082cb50" + integrity sha512-7XOMnz8Ynx1gGo/3hyV9loYNPWM94jG3+3T3Y8tsfSstFmETmENCMU/A/zj8Lyaj1lkgEepKepvd6240tBRvlw== + dependencies: + 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" + +execa@^0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/execa/-/execa-0.7.0.tgz#944becd34cc41ee32a63a9faf27ad5a65fc59777" + integrity sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c= + dependencies: + cross-spawn "^5.0.1" + get-stream "^3.0.0" + is-stream "^1.1.0" + npm-run-path "^2.0.0" + p-finally "^1.0.0" + signal-exit "^3.0.0" + strip-eof "^1.0.0" + +execa@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/execa/-/execa-1.0.0.tgz#c6236a5bb4df6d6f15e88e7f017798216749ddd8" + integrity sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA== + dependencies: + cross-spawn "^6.0.0" + get-stream "^4.0.0" + is-stream "^1.1.0" + npm-run-path "^2.0.0" + p-finally "^1.0.0" + signal-exit "^3.0.0" + strip-eof "^1.0.0" + +exit@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" + integrity sha1-BjJjj42HfMghB9MKD/8aF8uhzQw= + +expand-brackets@^2.1.4: + version "2.1.4" + resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-2.1.4.tgz#b77735e315ce30f6b6eff0f83b04151a22449622" + integrity sha1-t3c14xXOMPa27/D4OwQVGiJEliI= + dependencies: + debug "^2.3.3" + define-property "^0.2.5" + extend-shallow "^2.0.1" + posix-character-classes "^0.1.0" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" + +express@^4.16.2: + version "4.16.4" + resolved "https://registry.yarnpkg.com/express/-/express-4.16.4.tgz#fddef61926109e24c515ea97fd2f1bdbf62df12e" + integrity sha512-j12Uuyb4FMrd/qQAm6uCHAkPtO8FDTRJZBDd5D2KOL2eLaz1yUNdUB/NOIyq0iU4q4cFarsUCrnFDPBcnksuOg== + dependencies: + accepts "~1.3.5" + array-flatten "1.1.1" + body-parser "1.18.3" + content-disposition "0.5.2" + 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" + 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" + path-to-regexp "0.1.7" + proxy-addr "~2.0.4" + qs "6.5.2" + 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" + utils-merge "1.0.1" + vary "~1.1.2" + +extend-shallow@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f" + integrity sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8= + dependencies: + is-extendable "^0.1.0" + +extend-shallow@^3.0.0, extend-shallow@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-3.0.2.tgz#26a71aaf073b39fb2127172746131c2704028db8" + integrity sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg= + dependencies: + assign-symbols "^1.0.0" + is-extendable "^1.0.1" + +extend@^3.0.0, extend@~3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" + integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== + +external-editor@^3.0.0: + version "3.0.3" + resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-3.0.3.tgz#5866db29a97826dbe4bf3afd24070ead9ea43a27" + integrity sha512-bn71H9+qWoOQKyZDo25mOMVpSmXROAsTJVVVYzrrtol3d4y+AsKjf4Iwl2Q+IuT0kFSQ1qo166UuIwqYq7mGnA== + dependencies: + chardet "^0.7.0" + iconv-lite "^0.4.24" + tmp "^0.0.33" + +extglob@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/extglob/-/extglob-2.0.4.tgz#ad00fe4dc612a9232e8718711dc5cb5ab0285543" + integrity sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw== + dependencies: + array-unique "^0.3.2" + define-property "^1.0.0" + expand-brackets "^2.1.4" + extend-shallow "^2.0.1" + fragment-cache "^0.2.1" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" + +extsprintf@1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05" + integrity sha1-lpGEQOMEGnpBT4xS48V06zw+HgU= + +extsprintf@^1.2.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f" + integrity sha1-4mifjzVvrWLMplo6kcXfX5VRaS8= + +fast-deep-equal@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz#c053477817c86b51daa853c81e059b733d023614" + integrity sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ= + +fast-deep-equal@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz#7b05218ddf9667bf7f370bf7fdb2cb15fdd0aa49" + integrity sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk= + +fast-json-stable-stringify@2.0.0, fast-json-stable-stringify@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2" + integrity sha1-1RQsDK7msRifh9OnYREGT4bIu/I= + +fastparse@^1.1.1: + version "1.1.2" + resolved "https://registry.yarnpkg.com/fastparse/-/fastparse-1.1.2.tgz#91728c5a5942eced8531283c79441ee4122c35a9" + integrity sha512-483XLLxTVIwWK3QTrMGRqUfUpoOs/0hbQrl2oz4J0pAcm3A3bu84wxTFqGqkJzewCLdME38xJLJAxBABfQT8sQ== + +faye-websocket@^0.10.0: + version "0.10.0" + resolved "https://registry.yarnpkg.com/faye-websocket/-/faye-websocket-0.10.0.tgz#4e492f8d04dfb6f89003507f6edbf2d501e7c6f4" + integrity sha1-TkkvjQTftviQA1B/btvy1QHnxvQ= + dependencies: + websocket-driver ">=0.5.1" + +faye-websocket@~0.11.1: + version "0.11.1" + resolved "https://registry.yarnpkg.com/faye-websocket/-/faye-websocket-0.11.1.tgz#f0efe18c4f56e4f40afc7e06c719fd5ee6188f38" + integrity sha1-8O/hjE9W5PQK/H4Gxxn9XuYYjzg= + dependencies: + websocket-driver ">=0.5.1" + +figgy-pudding@^3.4.1, figgy-pudding@^3.5.1: + version "3.5.1" + resolved "https://registry.yarnpkg.com/figgy-pudding/-/figgy-pudding-3.5.1.tgz#862470112901c727a0e495a80744bd5baa1d6790" + integrity sha512-vNKxJHTEKNThjfrdJwHc7brvM6eVevuO5nTj6ez8ZQ1qbXTvGthucRF7S4vf2cr71QVnT70V34v0S1DyQsti0w== + +figures@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/figures/-/figures-2.0.0.tgz#3ab1a2d2a62c8bfb431a0c94cb797a2fce27c962" + integrity sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI= + dependencies: + escape-string-regexp "^1.0.5" + +file-loader@3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/file-loader/-/file-loader-3.0.1.tgz#f8e0ba0b599918b51adfe45d66d1e771ad560faa" + integrity sha512-4sNIOXgtH/9WZq4NvlfU3Opn5ynUsqBwSLyM+I7UOwdGigTBYfVVQEwe/msZNX/j4pCJTIM14Fsw66Svo1oVrw== + dependencies: + loader-utils "^1.0.2" + schema-utils "^1.0.0" + +fileset@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/fileset/-/fileset-2.0.3.tgz#8e7548a96d3cc2327ee5e674168723a333bba2a0" + integrity sha1-jnVIqW08wjJ+5eZ0FocjozO7oqA= + dependencies: + glob "^7.0.3" + minimatch "^3.0.3" + +fill-range@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-4.0.0.tgz#d544811d428f98eb06a63dc402d2403c328c38f7" + integrity sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc= + dependencies: + extend-shallow "^2.0.1" + is-number "^3.0.0" + repeat-string "^1.6.1" + to-regex-range "^2.1.0" + +finalhandler@1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.0.tgz#ce0b6855b45853e791b2fcc680046d88253dd7f5" + integrity sha1-zgtoVbRYU+eRsvzGgARtiCU91/U= + dependencies: + debug "2.6.9" + encodeurl "~1.0.1" + escape-html "~1.0.3" + on-finished "~2.3.0" + parseurl "~1.3.2" + statuses "~1.3.1" + unpipe "~1.0.0" + +finalhandler@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.1.tgz#eebf4ed840079c83f4249038c9d703008301b105" + integrity sha512-Y1GUDo39ez4aHAw7MysnUD5JzYX+WaIj8I57kO3aEPT1fFRL4sr7mjei97FgnwhAyyzRYmQZaTHb2+9uZ1dPtg== + dependencies: + 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" + +find-cache-dir@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-1.0.0.tgz#9288e3e9e3cc3748717d39eade17cf71fc30ee6f" + integrity sha1-kojj6ePMN0hxfTnq3hfPcfww7m8= + dependencies: + commondir "^1.0.1" + make-dir "^1.0.0" + pkg-dir "^2.0.0" + +find-cache-dir@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-2.1.0.tgz#8d0f94cd13fe43c6c7c261a0d86115ca918c05f7" + integrity sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ== + dependencies: + commondir "^1.0.1" + make-dir "^2.0.0" + pkg-dir "^3.0.0" + +find-up@^1.0.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-1.1.2.tgz#6b2e9822b1a2ce0a60ab64d610eccad53cb24d0f" + integrity sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8= + dependencies: + path-exists "^2.0.0" + pinkie-promise "^2.0.0" + +find-up@^2.0.0, find-up@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7" + integrity sha1-RdG35QbHF93UgndaK3eSCjwMV6c= + dependencies: + locate-path "^2.0.0" + +find-up@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-3.0.0.tgz#49169f1d7993430646da61ecc5ae355c21c97b73" + integrity sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg== + dependencies: + locate-path "^3.0.0" + +flatted@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/flatted/-/flatted-2.0.0.tgz#55122b6536ea496b4b44893ee2608141d10d9916" + integrity sha512-R+H8IZclI8AAkSBRQJLVOsxwAoHd6WC40b4QTNWIjzAa6BXOBfQcM587MXDTVPeYaopFNWHUFLx7eNmHDSxMWg== + +flush-write-stream@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/flush-write-stream/-/flush-write-stream-1.1.1.tgz#8dd7d873a1babc207d94ead0c2e0e44276ebf2e8" + integrity sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w== + dependencies: + inherits "^2.0.3" + readable-stream "^2.3.6" + +follow-redirects@^1.0.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.7.0.tgz#489ebc198dc0e7f64167bd23b03c4c19b5784c76" + integrity sha512-m/pZQy4Gj287eNy94nivy5wchN3Kp+Q5WgUPNy5lJSZ3sgkVKSYV/ZChMAQVIgx1SqfZ2zBZtPA2YlXIWxxJOQ== + dependencies: + debug "^3.2.6" + +for-in@^0.1.3: + version "0.1.8" + resolved "https://registry.yarnpkg.com/for-in/-/for-in-0.1.8.tgz#d8773908e31256109952b1fdb9b3fa867d2775e1" + integrity sha1-2Hc5COMSVhCZUrH9ubP6hn0ndeE= + +for-in@^1.0.1, for-in@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" + integrity sha1-gQaNKVqBQuwKxybG4iAMMPttXoA= + +for-own@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/for-own/-/for-own-1.0.0.tgz#c63332f415cedc4b04dbfe70cf836494c53cb44b" + integrity sha1-xjMy9BXO3EsE2/5wz4NklMU8tEs= + dependencies: + for-in "^1.0.1" + +forever-agent@~0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" + integrity sha1-+8cfDEGt6zf5bFd60e1C2P2sypE= + +form-data@~2.3.2: + version "2.3.3" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6" + integrity sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ== + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.6" + mime-types "^2.1.12" + +forwarded@~0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.1.2.tgz#98c23dab1175657b8c0573e8ceccd91b0ff18c84" + integrity sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ= + +fragment-cache@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/fragment-cache/-/fragment-cache-0.2.1.tgz#4290fad27f13e89be7f33799c6bc5a0abfff0d19" + integrity sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk= + dependencies: + map-cache "^0.2.2" + +fresh@0.5.2: + version "0.5.2" + resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" + integrity sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac= + +from2@^2.1.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/from2/-/from2-2.3.0.tgz#8bfb5502bde4a4d36cfdeea007fcca21d7e382af" + integrity sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8= + dependencies: + inherits "^2.0.1" + readable-stream "^2.0.0" + +fs-access@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/fs-access/-/fs-access-1.0.1.tgz#d6a87f262271cefebec30c553407fb995da8777a" + integrity sha1-1qh/JiJxzv6+wwxVNAf7mV2od3o= + dependencies: + null-check "^1.0.0" + +fs-extra@^7.0.0: + version "7.0.1" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-7.0.1.tgz#4f189c44aa123b895f722804f55ea23eadc348e9" + integrity sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw== + dependencies: + graceful-fs "^4.1.2" + jsonfile "^4.0.0" + universalify "^0.1.0" + +fs-minipass@^1.2.5: + version "1.2.5" + resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-1.2.5.tgz#06c277218454ec288df77ada54a03b8702aacb9d" + integrity sha512-JhBl0skXjUPCFH7x6x61gQxrKyXsxB5gcgePLZCwfyCGGsTISMoIeObbrvVeP6Xmyaudw4TT43qV2Gz+iyd2oQ== + dependencies: + minipass "^2.2.1" + +fs-write-stream-atomic@^1.0.8: + version "1.0.10" + resolved "https://registry.yarnpkg.com/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz#b47df53493ef911df75731e70a9ded0189db40c9" + integrity sha1-tH31NJPvkR33VzHnCp3tAYnbQMk= + dependencies: + graceful-fs "^4.1.2" + iferr "^0.1.5" + imurmurhash "^0.1.4" + readable-stream "1 || 2" + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= + +fsevents@^1.2.2, fsevents@^1.2.7: + version "1.2.8" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.2.8.tgz#57ea5320f762cd4696e5e8e87120eccc8b11cacf" + integrity sha512-tPvHgPGB7m40CZ68xqFGkKuzN+RnpGmSV+hgeKxhRpbxdqKXUFJGC3yonBOLzQBcJyGpdZFDfCsdOC2KFsXzeA== + dependencies: + nan "^2.12.1" + node-pre-gyp "^0.12.0" + +fstream@^1.0.0, fstream@^1.0.2: + version "1.0.11" + resolved "https://registry.yarnpkg.com/fstream/-/fstream-1.0.11.tgz#5c1fb1f117477114f0632a0eb4b71b3cb0fd3171" + integrity sha1-XB+x8RdHcRTwYyoOtLcbPLD9MXE= + dependencies: + graceful-fs "^4.1.2" + inherits "~2.0.0" + mkdirp ">=0.5 0" + rimraf "2" + +gauge@~2.7.3: + version "2.7.4" + resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7" + integrity sha1-LANAXHU4w51+s3sxcCLjJfsBi/c= + dependencies: + 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" + +gaze@^1.0.0: + version "1.1.3" + resolved "https://registry.yarnpkg.com/gaze/-/gaze-1.1.3.tgz#c441733e13b927ac8c0ff0b4c3b033f28812924a" + integrity sha512-BRdNm8hbWzFzWHERTrejLqwHDfS4GibPoq5wjTPIoJHoBtKGPg3xAFfxmM+9ztbXelxcf2hwQcaz1PtmFeue8g== + dependencies: + globule "^1.0.0" + +genfun@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/genfun/-/genfun-5.0.0.tgz#9dd9710a06900a5c4a5bf57aca5da4e52fe76537" + integrity sha512-KGDOARWVga7+rnB3z9Sd2Letx515owfk0hSxHGuqjANb1M+x2bGZGqHLiozPsYMdM2OubeMni/Hpwmjq6qIUhA== + +get-caller-file@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.3.tgz#f978fa4c90d1dfe7ff2d6beda2a515e713bdcf4a" + integrity sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w== + +get-stdin@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-4.0.1.tgz#b968c6b0a04384324902e8bf1a5df32579a450fe" + integrity sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4= + +get-stream@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14" + integrity sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ= + +get-stream@^4.0.0, get-stream@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5" + integrity sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w== + dependencies: + pump "^3.0.0" + +get-value@^2.0.3, get-value@^2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28" + integrity sha1-3BXKHGcjh8p2vTesCjlbogQqLCg= + +getpass@^0.1.1: + version "0.1.7" + resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa" + integrity sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo= + dependencies: + assert-plus "^1.0.0" + +glob-parent@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-3.1.0.tgz#9e6af6299d8d3bd2bd40430832bd113df906c5ae" + integrity sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4= + dependencies: + is-glob "^3.1.0" + path-dirname "^1.0.0" + +glob@7.0.x: + version "7.0.6" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.0.6.tgz#211bafaf49e525b8cd93260d14ab136152b3f57a" + integrity sha1-IRuvr0nlJbjNkyYNFKsTYVKz9Xo= + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.2" + once "^1.3.0" + path-is-absolute "^1.0.0" + +glob@7.1.3, glob@^7.0.0, glob@^7.0.3, glob@^7.0.6, glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@~7.1.1: + version "7.1.3" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.3.tgz#3960832d3f1574108342dafd3a67b332c0969df1" + integrity sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" + +globals@^11.1.0: + version "11.11.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-11.11.0.tgz#dcf93757fa2de5486fbeed7118538adf789e9c2e" + integrity sha512-WHq43gS+6ufNOEqlrDBxVEbb8ntfXrfAUU2ZOpCxrBdGKW3gyv8mCxAfIBD0DroPKGrJ2eSsXsLtY9MPntsyTw== + +globals@^9.18.0: + version "9.18.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-9.18.0.tgz#aa3896b3e69b487f17e31ed2143d69a8e30c2d8a" + integrity sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ== + +globby@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/globby/-/globby-5.0.0.tgz#ebd84667ca0dbb330b99bcfc68eac2bc54370e0d" + integrity sha1-69hGZ8oNuzMLmbz8aOrCvFQ3Dg0= + dependencies: + array-union "^1.0.1" + arrify "^1.0.0" + glob "^7.0.3" + object-assign "^4.0.1" + pify "^2.0.0" + pinkie-promise "^2.0.0" + +globby@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/globby/-/globby-6.1.0.tgz#f5a6d70e8395e21c858fb0489d64df02424d506c" + integrity sha1-9abXDoOV4hyFj7BInWTfAkJNUGw= + dependencies: + array-union "^1.0.1" + glob "^7.0.3" + object-assign "^4.0.1" + pify "^2.0.0" + pinkie-promise "^2.0.0" + +globby@^7.1.1: + version "7.1.1" + resolved "https://registry.yarnpkg.com/globby/-/globby-7.1.1.tgz#fb2ccff9401f8600945dfada97440cca972b8680" + integrity sha1-+yzP+UAfhgCUXfral0QMypcrhoA= + dependencies: + array-union "^1.0.1" + dir-glob "^2.0.0" + glob "^7.1.2" + ignore "^3.3.5" + pify "^3.0.0" + slash "^1.0.0" + +globule@^1.0.0: + version "1.2.1" + resolved "https://registry.yarnpkg.com/globule/-/globule-1.2.1.tgz#5dffb1b191f22d20797a9369b49eab4e9839696d" + integrity sha512-g7QtgWF4uYSL5/dn71WxubOrS7JVGCnFPEnoeChJmBnyR9Mw8nGoEwOgJL/RC2Te0WhbsEUCejfH8SZNJ+adYQ== + dependencies: + glob "~7.1.1" + lodash "~4.17.10" + minimatch "~3.0.2" + +graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6: + version "4.1.15" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.15.tgz#ffb703e1066e8a0eeaa4c8b80ba9253eeefbfb00" + integrity sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA== + +handle-thing@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/handle-thing/-/handle-thing-2.0.0.tgz#0e039695ff50c93fc288557d696f3c1dc6776754" + integrity sha512-d4sze1JNC454Wdo2fkuyzCr6aHcbL6PGGuFAz0Li/NcOm1tCHGnWDRmJP85dh9IhQErTc2svWFEX5xHIOo//kQ== + +handlebars@^4.1.0: + version "4.1.2" + resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.1.2.tgz#b6b37c1ced0306b221e094fc7aca3ec23b131b67" + integrity sha512-nvfrjqvt9xQ8Z/w0ijewdD/vvWDTOweBUm96NTr66Wfvo1mJenBLwcYmPs3TIBP5ruzYGD7Hx/DaM9RmhroGPw== + dependencies: + neo-async "^2.6.0" + optimist "^0.6.1" + source-map "^0.6.1" + optionalDependencies: + uglify-js "^3.1.4" + +har-schema@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92" + integrity sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI= + +har-validator@~5.1.0: + version "5.1.3" + resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.1.3.tgz#1ef89ebd3e4996557675eed9893110dc350fa080" + integrity sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g== + dependencies: + ajv "^6.5.5" + har-schema "^2.0.0" + +has-ansi@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" + integrity sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE= + dependencies: + ansi-regex "^2.0.0" + +has-binary2@~1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has-binary2/-/has-binary2-1.0.3.tgz#7776ac627f3ea77250cfc332dab7ddf5e4f5d11d" + integrity sha512-G1LWKhDSvhGeAQ8mPVQlqNcOB2sJdwATtZKl2pDKKHfpf/rYj24lkinxf69blJbnsvtqqNU+L3SL50vzZhXOnw== + dependencies: + isarray "2.0.1" + +has-cors@1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/has-cors/-/has-cors-1.1.0.tgz#5e474793f7ea9843d1bb99c23eef49ff126fff39" + integrity sha1-XkdHk/fqmEPRu5nCPu9J/xJv/zk= + +has-flag@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" + integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= + +has-unicode@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" + integrity sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk= + +has-value@^0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/has-value/-/has-value-0.3.1.tgz#7b1f58bada62ca827ec0a2078025654845995e1f" + integrity sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8= + dependencies: + get-value "^2.0.3" + has-values "^0.1.4" + isobject "^2.0.0" + +has-value@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-value/-/has-value-1.0.0.tgz#18b281da585b1c5c51def24c930ed29a0be6b177" + integrity sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc= + dependencies: + get-value "^2.0.6" + has-values "^1.0.0" + isobject "^3.0.0" + +has-values@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/has-values/-/has-values-0.1.4.tgz#6d61de95d91dfca9b9a02089ad384bff8f62b771" + integrity sha1-bWHeldkd/Km5oCCJrThL/49it3E= + +has-values@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-values/-/has-values-1.0.0.tgz#95b0b63fec2146619a6fe57fe75628d5a39efe4f" + integrity sha1-lbC2P+whRmGab+V/51Yo1aOe/k8= + dependencies: + is-number "^3.0.0" + kind-of "^4.0.0" + +hash-base@^3.0.0: + version "3.0.4" + resolved "https://registry.yarnpkg.com/hash-base/-/hash-base-3.0.4.tgz#5fc8686847ecd73499403319a6b0a3f3f6ae4918" + integrity sha1-X8hoaEfs1zSZQDMZprCj8/auSRg= + dependencies: + inherits "^2.0.1" + safe-buffer "^5.0.1" + +hash.js@^1.0.0, hash.js@^1.0.3: + version "1.1.7" + resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.1.7.tgz#0babca538e8d4ee4a0f8988d68866537a003cf42" + integrity sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA== + dependencies: + inherits "^2.0.3" + minimalistic-assert "^1.0.1" + +hmac-drbg@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1" + integrity sha1-0nRXAQJabHdabFRXk+1QL8DGSaE= + dependencies: + hash.js "^1.0.3" + minimalistic-assert "^1.0.0" + minimalistic-crypto-utils "^1.0.1" + +hosted-git-info@^2.1.4, hosted-git-info@^2.6.0: + version "2.7.1" + resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.7.1.tgz#97f236977bd6e125408930ff6de3eec6281ec047" + integrity sha512-7T/BxH19zbcCTa8XkMlbK5lTo1WtgkFi3GvdWEyNuc4Vex7/9Dqbnpsf4JMydcfj9HCg4zUWFTL3Za6lapg5/w== + +hpack.js@^2.1.6: + version "2.1.6" + resolved "https://registry.yarnpkg.com/hpack.js/-/hpack.js-2.1.6.tgz#87774c0949e513f42e84575b3c45681fade2a0b2" + integrity sha1-h3dMCUnlE/QuhFdbPEVoH63ioLI= + dependencies: + inherits "^2.0.1" + obuf "^1.0.0" + readable-stream "^2.0.1" + wbuf "^1.1.0" + +html-entities@^1.2.0: + version "1.2.1" + resolved "https://registry.yarnpkg.com/html-entities/-/html-entities-1.2.1.tgz#0df29351f0721163515dfb9e5543e5f6eed5162f" + integrity sha1-DfKTUfByEWNRXfueVUPl9u7VFi8= + +http-cache-semantics@^3.8.1: + version "3.8.1" + resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-3.8.1.tgz#39b0e16add9b605bf0a9ef3d9daaf4843b4cacd2" + integrity sha512-5ai2iksyV8ZXmnZhHH4rWPoxxistEexSi5936zIQ1bnNTW5VnA85B6P/VpXiRM017IgRvb2kKo1a//y+0wSp3w== + +http-deceiver@^1.2.7: + version "1.2.7" + resolved "https://registry.yarnpkg.com/http-deceiver/-/http-deceiver-1.2.7.tgz#fa7168944ab9a519d337cb0bec7284dc3e723d87" + integrity sha1-+nFolEq5pRnTN8sL7HKE3D5yPYc= + +http-errors@1.6.3, http-errors@~1.6.2, http-errors@~1.6.3: + version "1.6.3" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.3.tgz#8b55680bb4be283a0b5bf4ea2e38580be1d9320d" + integrity sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0= + dependencies: + depd "~1.1.2" + inherits "2.0.3" + setprototypeof "1.1.0" + statuses ">= 1.4.0 < 2" + +http-parser-js@>=0.4.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/http-parser-js/-/http-parser-js-0.5.0.tgz#d65edbede84349d0dc30320815a15d39cc3cbbd8" + integrity sha512-cZdEF7r4gfRIq7ezX9J0T+kQmJNOub71dWbgAXVHDct80TKP4MCETtZQ31xyv38UwgzkWPYF/Xc0ge55dW9Z9w== + +http-proxy-agent@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-2.1.0.tgz#e4821beef5b2142a2026bd73926fe537631c5405" + integrity sha512-qwHbBLV7WviBl0rQsOzH6o5lwyOIvwp/BdFnvVxXORldu5TmjFfjzBcWUWS5kWAZhmv+JtiDhSuQCp4sBfbIgg== + dependencies: + agent-base "4" + debug "3.1.0" + +http-proxy-middleware@~0.18.0: + version "0.18.0" + resolved "https://registry.yarnpkg.com/http-proxy-middleware/-/http-proxy-middleware-0.18.0.tgz#0987e6bb5a5606e5a69168d8f967a87f15dd8aab" + integrity sha512-Fs25KVMPAIIcgjMZkVHJoKg9VcXcC1C8yb9JUgeDvVXY0S/zgVIhMb+qVswDIgtJe2DfckMSY2d6TuTEutlk6Q== + dependencies: + http-proxy "^1.16.2" + is-glob "^4.0.0" + lodash "^4.17.5" + micromatch "^3.1.9" + +http-proxy@^1.13.0, http-proxy@^1.16.2: + version "1.17.0" + resolved "https://registry.yarnpkg.com/http-proxy/-/http-proxy-1.17.0.tgz#7ad38494658f84605e2f6db4436df410f4e5be9a" + integrity sha512-Taqn+3nNvYRfJ3bGvKfBSRwy1v6eePlm3oc/aWVxZp57DQr5Eq3xhKJi7Z4hZpS8PC3H4qI+Yly5EmFacGuA/g== + dependencies: + eventemitter3 "^3.0.0" + follow-redirects "^1.0.0" + requires-port "^1.0.0" + +http-signature@~1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1" + integrity sha1-muzZJRFHcvPZW2WmCruPfBj7rOE= + dependencies: + assert-plus "^1.0.0" + jsprim "^1.2.2" + sshpk "^1.7.0" + +https-browserify@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-1.0.0.tgz#ec06c10e0a34c0f2faf199f7fd7fc78fffd03c73" + integrity sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM= + +https-proxy-agent@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-2.2.1.tgz#51552970fa04d723e04c56d04178c3f92592bbc0" + integrity sha512-HPCTS1LW51bcyMYbxUIOO4HEOlQ1/1qRaFWcyxvwaqUS9TY88aoEuHUY33kuAh1YhVVaDQhLZsnPd+XNARWZlQ== + dependencies: + agent-base "^4.1.0" + debug "^3.1.0" + +humanize-ms@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/humanize-ms/-/humanize-ms-1.2.1.tgz#c46e3159a293f6b896da29316d8b6fe8bb79bbed" + integrity sha1-xG4xWaKT9riW2ikxbYtv6Lt5u+0= + dependencies: + ms "^2.0.0" + +iconv-lite@0.4.23: + version "0.4.23" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.23.tgz#297871f63be507adcfbfca715d0cd0eed84e9a63" + integrity sha512-neyTUVFtahjf0mB3dZT77u+8O0QB89jFdnBkd5P1JgYPbPaia3gXXOVL2fq8VyU2gMMD7SaN7QukTB/pmXYvDA== + dependencies: + safer-buffer ">= 2.1.2 < 3" + +iconv-lite@^0.4.24, iconv-lite@^0.4.4, iconv-lite@~0.4.13: + version "0.4.24" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" + integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== + dependencies: + safer-buffer ">= 2.1.2 < 3" + +ieee754@^1.1.4: + version "1.1.13" + resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.13.tgz#ec168558e95aa181fd87d37f55c32bbcb6708b84" + integrity sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg== + +iferr@^0.1.5: + version "0.1.5" + resolved "https://registry.yarnpkg.com/iferr/-/iferr-0.1.5.tgz#c60eed69e6d8fdb6b3104a1fcbca1c192dc5b501" + integrity sha1-xg7taebY/bazEEofy8ocGS3FtQE= + +ignore-walk@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/ignore-walk/-/ignore-walk-3.0.1.tgz#a83e62e7d272ac0e3b551aaa82831a19b69f82f8" + integrity sha512-DTVlMx3IYPe0/JJcYP7Gxg7ttZZu3IInhuEhbchuqneY9wWe5Ojy2mXLBaQFUQmo0AW2r3qG7m1mg86js+gnlQ== + dependencies: + minimatch "^3.0.4" + +ignore@^3.3.5: + version "3.3.10" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.3.10.tgz#0a97fb876986e8081c631160f8f9f389157f0043" + integrity sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug== + +image-size@~0.5.0: + version "0.5.5" + resolved "https://registry.yarnpkg.com/image-size/-/image-size-0.5.5.tgz#09dfd4ab9d20e29eb1c3e80b8990378df9e3cb9c" + integrity sha1-Cd/Uq50g4p6xw+gLiZA3jfnjy5w= + +immediate@~3.0.5: + version "3.0.6" + resolved "https://registry.yarnpkg.com/immediate/-/immediate-3.0.6.tgz#9db1dbd0faf8de6fbe0f5dd5e56bb606280de69b" + integrity sha1-nbHb0Pr43m++D13V5Wu2BigN5ps= + +import-cwd@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/import-cwd/-/import-cwd-2.1.0.tgz#aa6cf36e722761285cb371ec6519f53e2435b0a9" + integrity sha1-qmzzbnInYShcs3HsZRn1PiQ1sKk= + dependencies: + import-from "^2.1.0" + +import-from@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/import-from/-/import-from-2.1.0.tgz#335db7f2a7affd53aaa471d4b8021dee36b7f3b1" + integrity sha1-M1238qev/VOqpHHUuAId7ja387E= + dependencies: + resolve-from "^3.0.0" + +import-local@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/import-local/-/import-local-2.0.0.tgz#55070be38a5993cf18ef6db7e961f5bee5c5a09d" + integrity sha512-b6s04m3O+s3CGSbqDIyP4R6aAwAeYlVq9+WUWep6iHa8ETRf9yei1U48C5MmfJmV9AiLYYBKPMq/W+/WRpQmCQ== + dependencies: + pkg-dir "^3.0.0" + resolve-cwd "^2.0.0" + +imurmurhash@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" + integrity sha1-khi5srkoojixPcT7a21XbyMUU+o= + +in-publish@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/in-publish/-/in-publish-2.0.0.tgz#e20ff5e3a2afc2690320b6dc552682a9c7fadf51" + integrity sha1-4g/146KvwmkDILbcVSaCqcf631E= + +indent-string@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-2.1.0.tgz#8e2d48348742121b4a8218b7a137e9a52049dc80" + integrity sha1-ji1INIdCEhtKghi3oTfppSBJ3IA= + dependencies: + repeating "^2.0.0" + +indexof@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/indexof/-/indexof-0.0.1.tgz#82dc336d232b9062179d05ab3293a66059fd435d" + integrity sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10= + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2, inherits@2.0.3, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.0, inherits@~2.0.1, inherits@~2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" + integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= + +inherits@2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.1.tgz#b17d08d326b4423e568eff719f91b0b1cbdf69f1" + integrity sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE= + +ini@1.3.5, ini@^1.3.4, ini@~1.3.0: + version "1.3.5" + resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927" + integrity sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw== + +inquirer@6.2.1: + version "6.2.1" + resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-6.2.1.tgz#9943fc4882161bdb0b0c9276769c75b32dbfcd52" + integrity sha512-088kl3DRT2dLU5riVMKKr1DlImd6X7smDhpXUCkJDCKvTEJeRiXh0G132HG9u5a+6Ylw9plFRY7RuTnwohYSpg== + dependencies: + 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.2.0" + rxjs "^6.1.0" + string-width "^2.1.0" + strip-ansi "^5.0.0" + through "^2.3.6" + +internal-ip@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/internal-ip/-/internal-ip-3.0.1.tgz#df5c99876e1d2eb2ea2d74f520e3f669a00ece27" + integrity sha512-NXXgESC2nNVtU+pqmC9e6R8B1GpKxzsAQhffvh5AL79qKnodd+L7tnEQmTiUAVngqLalPbSqRA7XGIEL5nCd0Q== + dependencies: + default-gateway "^2.6.0" + ipaddr.js "^1.5.2" + +interpret@^1.0.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.2.0.tgz#d5061a6224be58e8083985f5014d844359576296" + integrity sha512-mT34yGKMNceBQUoVn7iCDKDntA7SC6gycMAWzGx1z/CMCTV7b2AAtXlo3nRyHZ1FelRkQbQjprHSYGwzLtkVbw== + +invariant@^2.2.2: + version "2.2.4" + resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6" + integrity sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA== + dependencies: + loose-envify "^1.0.0" + +invert-kv@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6" + integrity sha1-EEqOSqym09jNFXqO+L+rLXo//bY= + +invert-kv@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-2.0.0.tgz#7393f5afa59ec9ff5f67a27620d11c226e3eec02" + integrity sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA== + +ip-regex@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/ip-regex/-/ip-regex-2.1.0.tgz#fa78bf5d2e6913c911ce9f819ee5146bb6d844e9" + integrity sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk= + +ip@^1.1.0, ip@^1.1.5: + version "1.1.5" + resolved "https://registry.yarnpkg.com/ip/-/ip-1.1.5.tgz#bdded70114290828c0a039e72ef25f5aaec4354a" + integrity sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo= + +ipaddr.js@1.9.0, ipaddr.js@^1.5.2: + version "1.9.0" + resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.0.tgz#37df74e430a0e47550fe54a2defe30d8acd95f65" + integrity sha512-M4Sjn6N/+O6/IXSJseKqHoFc+5FdGJ22sXqnjTpdZweHK64MzEPAyQZyEU3R/KRv2GLoa7nNtg/C2Ev6m7z+eA== + +is-accessor-descriptor@^0.1.6: + version "0.1.6" + resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz#a9e12cb3ae8d876727eeef3843f8a0897b5c98d6" + integrity sha1-qeEss66Nh2cn7u84Q/igiXtcmNY= + dependencies: + kind-of "^3.0.2" + +is-accessor-descriptor@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz#169c2f6d3df1f992618072365c9b0ea1f6878656" + integrity sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ== + dependencies: + kind-of "^6.0.0" + +is-arrayish@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" + integrity sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0= + +is-binary-path@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-1.0.1.tgz#75f16642b480f187a711c814161fd3a4a7655898" + integrity sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg= + dependencies: + binary-extensions "^1.0.0" + +is-buffer@^1.1.5: + version "1.1.6" + resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" + integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== + +is-data-descriptor@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56" + integrity sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y= + dependencies: + kind-of "^3.0.2" + +is-data-descriptor@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz#d84876321d0e7add03990406abbbbd36ba9268c7" + integrity sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ== + dependencies: + kind-of "^6.0.0" + +is-descriptor@^0.1.0: + version "0.1.6" + resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-0.1.6.tgz#366d8240dde487ca51823b1ab9f07a10a78251ca" + integrity sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg== + dependencies: + is-accessor-descriptor "^0.1.6" + is-data-descriptor "^0.1.4" + kind-of "^5.0.0" + +is-descriptor@^1.0.0, is-descriptor@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-1.0.2.tgz#3b159746a66604b04f8c81524ba365c5f14d86ec" + integrity sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg== + dependencies: + is-accessor-descriptor "^1.0.0" + is-data-descriptor "^1.0.0" + kind-of "^6.0.2" + +is-directory@^0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/is-directory/-/is-directory-0.3.1.tgz#61339b6f2475fc772fd9c9d83f5c8575dc154ae1" + integrity sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE= + +is-extendable@^0.1.0, is-extendable@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" + integrity sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik= + +is-extendable@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-1.0.1.tgz#a7470f9e426733d81bd81e1155264e3a3507cab4" + integrity sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA== + dependencies: + is-plain-object "^2.0.4" + +is-extglob@^2.1.0, is-extglob@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" + integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= + +is-finite@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-finite/-/is-finite-1.0.2.tgz#cc6677695602be550ef11e8b4aa6305342b6d0aa" + integrity sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko= + dependencies: + number-is-nan "^1.0.0" + +is-fullwidth-code-point@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" + integrity sha1-754xOG8DGn8NZDr4L95QxFfvAMs= + dependencies: + number-is-nan "^1.0.0" + +is-fullwidth-code-point@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" + integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8= + +is-glob@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-3.1.0.tgz#7ba5ae24217804ac70707b96922567486cc3e84a" + integrity sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo= + dependencies: + is-extglob "^2.1.0" + +is-glob@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.1.tgz#7567dbe9f2f5e2467bc77ab83c4a29482407a5dc" + integrity sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg== + dependencies: + is-extglob "^2.1.1" + +is-number@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195" + integrity sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU= + dependencies: + kind-of "^3.0.2" + +is-path-cwd@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-path-cwd/-/is-path-cwd-1.0.0.tgz#d225ec23132e89edd38fda767472e62e65f1106d" + integrity sha1-0iXsIxMuie3Tj9p2dHLmLmXxEG0= + +is-path-in-cwd@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-path-in-cwd/-/is-path-in-cwd-1.0.1.tgz#5ac48b345ef675339bd6c7a48a912110b241cf52" + integrity sha512-FjV1RTW48E7CWM7eE/J2NJvAEEVektecDBVBE5Hh3nM1Jd0kvhHtX68Pr3xsDf857xt3Y4AkwVULK1Vku62aaQ== + dependencies: + is-path-inside "^1.0.0" + +is-path-inside@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-1.0.1.tgz#8ef5b7de50437a3fdca6b4e865ef7aa55cb48036" + integrity sha1-jvW33lBDej/cprToZe96pVy0gDY= + dependencies: + path-is-inside "^1.0.1" + +is-plain-object@^2.0.1, is-plain-object@^2.0.3, is-plain-object@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677" + integrity sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og== + dependencies: + isobject "^3.0.1" + +is-promise@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-2.1.0.tgz#79a2a9ece7f096e80f36d2b2f3bc16c1ff4bf3fa" + integrity sha1-eaKp7OfwlugPNtKy87wWwf9L8/o= + +is-stream@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" + integrity sha1-EtSj3U5o4Lec6428hBc66A2RykQ= + +is-typedarray@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" + integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo= + +is-utf8@^0.2.0: + version "0.2.1" + resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72" + integrity sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI= + +is-windows@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" + integrity sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA== + +is-wsl@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-1.1.0.tgz#1f16e4aa22b04d1336b66188a66af3c600c3a66d" + integrity sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0= + +isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" + integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= + +isarray@2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-2.0.1.tgz#a37d94ed9cda2d59865c9f76fe596ee1f338741e" + integrity sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4= + +isbinaryfile@^3.0.0: + version "3.0.3" + resolved "https://registry.yarnpkg.com/isbinaryfile/-/isbinaryfile-3.0.3.tgz#5d6def3edebf6e8ca8cae9c30183a804b5f8be80" + integrity sha512-8cJBL5tTd2OS0dM4jz07wQd5g0dCCqIhUxPIGtZfa5L6hWlvV5MHTITy/DBAsF+Oe2LS1X3krBUhNwaGUWpWxw== + dependencies: + buffer-alloc "^1.2.0" + +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= + +isobject@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" + integrity sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk= + dependencies: + isarray "1.0.0" + +isobject@^3.0.0, isobject@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" + integrity sha1-TkMekrEalzFjaqH5yNHMvP2reN8= + +isstream@~0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" + integrity sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo= + +istanbul-api@^2.1.1: + version "2.1.5" + resolved "https://registry.yarnpkg.com/istanbul-api/-/istanbul-api-2.1.5.tgz#697b95ec69856c278aacafc0f86ee7392338d5b5" + integrity sha512-meYk1BwDp59Pfse1TvPrkKYgVqAufbdBLEVoqvu/hLLKSaQ054ZTksbNepyc223tMnWdm6AdK2URIJJRqdP87g== + dependencies: + async "^2.6.1" + compare-versions "^3.2.1" + fileset "^2.0.3" + istanbul-lib-coverage "^2.0.4" + istanbul-lib-hook "^2.0.6" + istanbul-lib-instrument "^3.2.0" + istanbul-lib-report "^2.0.7" + istanbul-lib-source-maps "^3.0.5" + istanbul-reports "^2.2.3" + js-yaml "^3.13.0" + make-dir "^2.1.0" + minimatch "^3.0.4" + once "^1.4.0" + +istanbul-instrumenter-loader@3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/istanbul-instrumenter-loader/-/istanbul-instrumenter-loader-3.0.1.tgz#9957bd59252b373fae5c52b7b5188e6fde2a0949" + integrity sha512-a5SPObZgS0jB/ixaKSMdn6n/gXSrK2S6q/UfRJBT3e6gQmVjwZROTODQsYW5ZNwOu78hG62Y3fWlebaVOL0C+w== + dependencies: + convert-source-map "^1.5.0" + istanbul-lib-instrument "^1.7.3" + loader-utils "^1.1.0" + schema-utils "^0.3.0" + +istanbul-lib-coverage@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-1.2.1.tgz#ccf7edcd0a0bb9b8f729feeb0930470f9af664f0" + integrity sha512-PzITeunAgyGbtY1ibVIUiV679EFChHjoMNRibEIobvmrCRaIgwLxNucOSimtNWUhEib/oO7QY2imD75JVgCJWQ== + +istanbul-lib-coverage@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz#927a354005d99dd43a24607bb8b33fd4e9aca1ad" + integrity sha512-LXTBICkMARVgo579kWDm8SqfB6nvSDKNqIOBEjmJRnL04JvoMHCYGWaMddQnseJYtkEuEvO/sIcOxPLk9gERug== + +istanbul-lib-hook@^2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/istanbul-lib-hook/-/istanbul-lib-hook-2.0.6.tgz#5baa6067860a38290aef038b389068b225b01b7d" + integrity sha512-829DKONApZ7UCiPXcOYWSgkFXa4+vNYoNOt3F+4uDJLKL1OotAoVwvThoEj1i8jmOj7odbYcR3rnaHu+QroaXg== + dependencies: + append-transform "^1.0.0" + +istanbul-lib-instrument@^1.7.3: + version "1.10.2" + resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-1.10.2.tgz#1f55ed10ac3c47f2bdddd5307935126754d0a9ca" + integrity sha512-aWHxfxDqvh/ZlxR8BBaEPVSWDPUkGD63VjGQn3jcw8jCp7sHEMKcrj4xfJn/ABzdMEHiQNyvDQhqm5o8+SQg7A== + dependencies: + 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-instrument@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-3.2.0.tgz#c549208da8a793f6622257a2da83e0ea96ae6a93" + integrity sha512-06IM3xShbNW4NgZv5AP4QH0oHqf1/ivFo8eFys0ZjPXHGldHJQWb3riYOKXqmOqfxXBfxu4B+g/iuhOPZH0RJg== + dependencies: + "@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.4" + semver "^6.0.0" + +istanbul-lib-report@^2.0.7: + version "2.0.7" + resolved "https://registry.yarnpkg.com/istanbul-lib-report/-/istanbul-lib-report-2.0.7.tgz#370d80d433c4dbc7f58de63618f49599c74bd954" + integrity sha512-wLH6beJBFbRBLiTlMOBxmb85cnVM1Vyl36N48e4e/aTKSM3WbOx7zbVIH1SQ537fhhsPbX0/C5JB4qsmyRXXyA== + dependencies: + istanbul-lib-coverage "^2.0.4" + make-dir "^2.1.0" + supports-color "^6.0.0" + +istanbul-lib-source-maps@^3.0.5: + version "3.0.5" + resolved "https://registry.yarnpkg.com/istanbul-lib-source-maps/-/istanbul-lib-source-maps-3.0.5.tgz#1d9ee9d94d2633f15611ee7aae28f9cac6d1aeb9" + integrity sha512-eDhZ7r6r1d1zQPVZehLc3D0K14vRba/eBYkz3rw16DLOrrTzve9RmnkcwrrkWVgO1FL3EK5knujVe5S8QHE9xw== + dependencies: + debug "^4.1.1" + istanbul-lib-coverage "^2.0.4" + make-dir "^2.1.0" + rimraf "^2.6.2" + source-map "^0.6.1" + +istanbul-reports@^2.2.3: + version "2.2.3" + resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-2.2.3.tgz#14e0d00ecbfa9387757999cf36599b88e9f2176e" + integrity sha512-T6EbPuc8Cb620LWAYyZ4D8SSn06dY9i1+IgUX2lTH8gbwflMc9Obd33zHTyNX653ybjpamAHS9toKS3E6cGhTw== + dependencies: + handlebars "^4.1.0" + +jasmine-core@~2.8.0: + version "2.8.0" + resolved "https://registry.yarnpkg.com/jasmine-core/-/jasmine-core-2.8.0.tgz#bcc979ae1f9fd05701e45e52e65d3a5d63f1a24e" + integrity sha1-vMl5rh+f0FcB5F5S5l06XWPxok4= + +jasmine-core@~2.99.1: + version "2.99.1" + resolved "https://registry.yarnpkg.com/jasmine-core/-/jasmine-core-2.99.1.tgz#e6400df1e6b56e130b61c4bcd093daa7f6e8ca15" + integrity sha1-5kAN8ea1bhMLYcS80JPap/boyhU= + +jasmine-spec-reporter@~4.2.1: + version "4.2.1" + resolved "https://registry.yarnpkg.com/jasmine-spec-reporter/-/jasmine-spec-reporter-4.2.1.tgz#1d632aec0341670ad324f92ba84b4b32b35e9e22" + integrity sha512-FZBoZu7VE5nR7Nilzy+Np8KuVIOxF4oXDPDknehCYBDE080EnlPu0afdZNmpGDBRCUBv3mj5qgqCRmk6W/K8vg== + dependencies: + colors "1.1.2" + +jasmine@2.8.0: + version "2.8.0" + resolved "https://registry.yarnpkg.com/jasmine/-/jasmine-2.8.0.tgz#6b089c0a11576b1f16df11b80146d91d4e8b8a3e" + integrity sha1-awicChFXax8W3xG4AUbZHU6Lij4= + dependencies: + exit "^0.1.2" + glob "^7.0.6" + jasmine-core "~2.8.0" + +jasminewd2@^2.1.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/jasminewd2/-/jasminewd2-2.2.0.tgz#e37cf0b17f199cce23bea71b2039395246b4ec4e" + integrity sha1-43zwsX8ZnM4jvqcbIDk5Uka07E4= + +js-base64@^2.1.8: + version "2.5.1" + resolved "https://registry.yarnpkg.com/js-base64/-/js-base64-2.5.1.tgz#1efa39ef2c5f7980bb1784ade4a8af2de3291121" + integrity sha512-M7kLczedRMYX4L8Mdh4MzyAMM9O5osx+4FcOQuTvr3A9F2D9S5JXheN0ewNbrvK2UatkTRhL5ejGmGSjNMiZuw== + +"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" + integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== + +js-tokens@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b" + integrity sha1-mGbfOVECEw449/mWvOtlRDIJwls= + +js-yaml@^3.13.0, js-yaml@^3.7.0, js-yaml@^3.9.0: + version "3.13.1" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.13.1.tgz#aff151b30bfdfa8e49e05da22e7415e9dfa37847" + integrity sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw== + dependencies: + argparse "^1.0.7" + esprima "^4.0.0" + +jsbn@~0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" + integrity sha1-peZUwuWi3rXyAdls77yoDA7y9RM= + +jsesc@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-1.3.0.tgz#46c3fec8c1892b12b0833db9bc7622176dbab34b" + integrity sha1-RsP+yMGJKxKwgz25vHYiF226s0s= + +jsesc@^2.5.1: + version "2.5.2" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" + integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== + +jsesc@~0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" + integrity sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0= + +json-parse-better-errors@^1.0.0, json-parse-better-errors@^1.0.1, json-parse-better-errors@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9" + integrity sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw== + +json-schema-traverse@^0.3.0: + version "0.3.1" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz#349a6d44c53a51de89b40805c5d5e59b417d3340" + integrity sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A= + +json-schema-traverse@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" + integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== + +json-schema@0.2.3: + version "0.2.3" + resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" + integrity sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM= + +json-stringify-safe@~5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" + integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus= + +json3@^3.3.2: + version "3.3.2" + resolved "https://registry.yarnpkg.com/json3/-/json3-3.3.2.tgz#3c0434743df93e2f5c42aee7b19bcb483575f4e1" + integrity sha1-PAQ0dD35Pi9cQq7nsZvLSDV19OE= + +json5@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.1.tgz#779fb0018604fa854eacbf6252180d83543e3dbe" + integrity sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow== + dependencies: + minimist "^1.2.0" + +jsonfile@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb" + integrity sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss= + optionalDependencies: + graceful-fs "^4.1.6" + +jsonparse@^1.2.0: + version "1.3.1" + resolved "https://registry.yarnpkg.com/jsonparse/-/jsonparse-1.3.1.tgz#3f4dae4a91fac315f71062f8521cc239f1366280" + integrity sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA= + +jsprim@^1.2.2: + version "1.4.1" + resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2" + integrity sha1-MT5mvB5cwG5Di8G3SZwuXFastqI= + dependencies: + assert-plus "1.0.0" + extsprintf "1.3.0" + json-schema "0.2.3" + verror "1.10.0" + +jszip@^3.1.3: + version "3.2.1" + resolved "https://registry.yarnpkg.com/jszip/-/jszip-3.2.1.tgz#c5d32df7274042282b157efb16e522b43435e01a" + integrity sha512-iCMBbo4eE5rb1VCpm5qXOAaUiRKRUKiItn8ah2YQQx9qymmSAY98eyQfioChEYcVQLh0zxJ3wS4A0mh90AVPvw== + dependencies: + lie "~3.3.0" + pako "~1.0.2" + readable-stream "~2.3.6" + set-immediate-shim "~1.0.1" + +karma-chrome-launcher@~2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/karma-chrome-launcher/-/karma-chrome-launcher-2.2.0.tgz#cf1b9d07136cc18fe239327d24654c3dbc368acf" + integrity sha512-uf/ZVpAabDBPvdPdveyk1EPgbnloPvFFGgmRhYLTDH7gEB4nZdSBk8yTU47w1g/drLSx5uMOkjKk7IWKfWg/+w== + dependencies: + fs-access "^1.0.0" + which "^1.2.1" + +karma-coverage-istanbul-reporter@~2.0.1: + version "2.0.5" + resolved "https://registry.yarnpkg.com/karma-coverage-istanbul-reporter/-/karma-coverage-istanbul-reporter-2.0.5.tgz#ca5899d4905e44a5984dd4f963adfc1a74dce767" + integrity sha512-yPvAlKtY3y+rKKWbOo0CzBMVTvJEeMOgbMXuVv3yWvS8YtYKC98AU9vFF0mVBZ2RP1E9SgS90+PT6Kf14P3S4w== + dependencies: + istanbul-api "^2.1.1" + minimatch "^3.0.4" + +karma-jasmine-html-reporter@^0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/karma-jasmine-html-reporter/-/karma-jasmine-html-reporter-0.2.2.tgz#48a8e5ef18807617ee2b5e33c1194c35b439524c" + integrity sha1-SKjl7xiAdhfuK14zwRlMNbQ5Ukw= + dependencies: + karma-jasmine "^1.0.2" + +karma-jasmine@^1.0.2, karma-jasmine@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/karma-jasmine/-/karma-jasmine-1.1.2.tgz#394f2b25ffb4a644b9ada6f22d443e2fd08886c3" + integrity sha1-OU8rJf+0pkS5rabyLUQ+L9CIhsM= + +karma-source-map-support@1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/karma-source-map-support/-/karma-source-map-support-1.3.0.tgz#36dd4d8ca154b62ace95696236fae37caf0a7dde" + integrity sha512-HcPqdAusNez/ywa+biN4EphGz62MmQyPggUsDfsHqa7tSe4jdsxgvTKuDfIazjL+IOxpVWyT7Pr4dhAV+sxX5Q== + dependencies: + source-map-support "^0.5.5" + +karma@~4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/karma/-/karma-4.0.1.tgz#2581d6caa0d4cd28b65131561b47bad6d5478773" + integrity sha512-ind+4s03BqIXas7ZmraV3/kc5+mnqwCd+VDX1FndS6jxbt03kQKX2vXrWxNLuCjVYmhMwOZosAEKMM0a2q7w7A== + dependencies: + bluebird "^3.3.0" + body-parser "^1.16.1" + braces "^2.3.2" + chokidar "^2.0.3" + colors "^1.1.0" + connect "^3.6.0" + core-js "^2.2.0" + di "^0.0.1" + dom-serialize "^2.2.0" + flatted "^2.0.0" + glob "^7.1.1" + graceful-fs "^4.1.2" + http-proxy "^1.13.0" + isbinaryfile "^3.0.0" + lodash "^4.17.11" + log4js "^4.0.0" + mime "^2.3.1" + minimatch "^3.0.2" + optimist "^0.6.1" + qjobs "^1.1.4" + range-parser "^1.2.0" + rimraf "^2.6.0" + safe-buffer "^5.0.1" + socket.io "2.1.1" + source-map "^0.6.1" + tmp "0.0.33" + useragent "2.3.0" + +killable@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/killable/-/killable-1.0.1.tgz#4c8ce441187a061c7474fb87ca08e2a638194892" + integrity sha512-LzqtLKlUwirEUyl/nicirVmNiPvYs7l5n8wOPP7fyJVpUPkvCnW/vuiXGpylGUlnPDnB7311rARzAt3Mhswpjg== + +kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0: + version "3.2.2" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" + integrity sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ= + dependencies: + is-buffer "^1.1.5" + +kind-of@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-4.0.0.tgz#20813df3d712928b207378691a45066fae72dd57" + integrity sha1-IIE989cSkosgc3hpGkUGb65y3Vc= + dependencies: + is-buffer "^1.1.5" + +kind-of@^5.0.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-5.1.0.tgz#729c91e2d857b7a419a1f9aa65685c4c33f5845d" + integrity sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw== + +kind-of@^6.0.0, kind-of@^6.0.2: + version "6.0.2" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.2.tgz#01146b36a6218e64e58f3a8d66de5d7fc6f6d051" + integrity sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA== + +lcid@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/lcid/-/lcid-1.0.0.tgz#308accafa0bc483a3867b4b6f2b9506251d1b835" + integrity sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU= + dependencies: + invert-kv "^1.0.0" + +lcid@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/lcid/-/lcid-2.0.0.tgz#6ef5d2df60e52f82eb228a4c373e8d1f397253cf" + integrity sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA== + dependencies: + invert-kv "^2.0.0" + +less-loader@4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/less-loader/-/less-loader-4.1.0.tgz#2c1352c5b09a4f84101490274fd51674de41363e" + integrity sha512-KNTsgCE9tMOM70+ddxp9yyt9iHqgmSs0yTZc5XH5Wo+g80RWRIYNqE58QJKm/yMud5wZEvz50ugRDuzVIkyahg== + dependencies: + clone "^2.1.1" + loader-utils "^1.1.0" + pify "^3.0.0" + +less@3.9.0: + version "3.9.0" + resolved "https://registry.yarnpkg.com/less/-/less-3.9.0.tgz#b7511c43f37cf57dc87dffd9883ec121289b1474" + integrity sha512-31CmtPEZraNUtuUREYjSqRkeETFdyEHSEPAGq4erDlUXtda7pzNmctdljdIagSb589d/qXGWiiP31R5JVf+v0w== + dependencies: + clone "^2.1.2" + optionalDependencies: + errno "^0.1.1" + graceful-fs "^4.1.2" + image-size "~0.5.0" + mime "^1.4.1" + mkdirp "^0.5.0" + promise "^7.1.1" + request "^2.83.0" + source-map "~0.6.0" + +license-webpack-plugin@2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/license-webpack-plugin/-/license-webpack-plugin-2.1.0.tgz#83acaa6e89c3c5316effdd80cb4ec9c5cd8efc2f" + integrity sha512-vDiBeMWxjE9n6TabQ9J4FH8urFdsRK0Nvxn1cit9biCiR9aq1zBR0X2BlAkEiIG6qPamLeU0GzvIgLkrFc398A== + dependencies: + "@types/webpack-sources" "^0.1.5" + webpack-sources "^1.2.0" + +lie@~3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/lie/-/lie-3.3.0.tgz#dcf82dee545f46074daf200c7c1c5a08e0f40f6a" + integrity sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ== + dependencies: + immediate "~3.0.5" + +load-json-file@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-1.1.0.tgz#956905708d58b4bab4c2261b04f59f31c99374c0" + integrity sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA= + dependencies: + graceful-fs "^4.1.2" + parse-json "^2.2.0" + pify "^2.0.0" + pinkie-promise "^2.0.0" + strip-bom "^2.0.0" + +load-json-file@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-2.0.0.tgz#7947e42149af80d696cbf797bcaabcfe1fe29ca8" + integrity sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg= + dependencies: + graceful-fs "^4.1.2" + parse-json "^2.2.0" + pify "^2.0.0" + strip-bom "^3.0.0" + +loader-runner@^2.3.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-2.4.0.tgz#ed47066bfe534d7e84c4c7b9998c2a75607d9357" + integrity sha512-Jsmr89RcXGIwivFY21FcRrisYZfvLMTWx5kOLc+JTxtpBOG6xML0vzbc6SEQG2FO9/4Fc3wW4LVcB5DmGflaRw== + +loader-utils@1.2.3, loader-utils@^1.0.1, loader-utils@^1.0.2, loader-utils@^1.1.0: + version "1.2.3" + resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-1.2.3.tgz#1ff5dc6911c9f0a062531a4c04b609406108c2c7" + integrity sha512-fkpz8ejdnEMG3s37wGL07iSBDg99O9D5yflE9RGNH3hRdx9SOwYfnGYdZOUIZitN8E+E2vkq3MUMYMvPYl5ZZA== + dependencies: + big.js "^5.2.2" + emojis-list "^2.0.0" + json5 "^1.0.1" + +locate-path@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e" + integrity sha1-K1aLJl7slExtnA3pw9u7ygNUzY4= + dependencies: + p-locate "^2.0.0" + path-exists "^3.0.0" + +locate-path@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e" + integrity sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A== + dependencies: + p-locate "^3.0.0" + path-exists "^3.0.0" + +lodash.assign@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/lodash.assign/-/lodash.assign-4.2.0.tgz#0d99f3ccd7a6d261d19bdaeb9245005d285808e7" + integrity sha1-DZnzzNem0mHRm9rrkkUAXShYCOc= + +lodash.clonedeep@^4.3.2, lodash.clonedeep@^4.5.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef" + integrity sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8= + +lodash.debounce@^4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af" + integrity sha1-gteb/zCmfEAF/9XiUVMArZyk168= + +lodash.mergewith@^4.6.0: + version "4.6.1" + resolved "https://registry.yarnpkg.com/lodash.mergewith/-/lodash.mergewith-4.6.1.tgz#639057e726c3afbdb3e7d42741caa8d6e4335927" + integrity sha512-eWw5r+PYICtEBgrBE5hhlT6aAa75f411bgDz/ZL2KZqYV03USvucsxcHUIlGTDTECs1eunpI7HOV7U+WLDvNdQ== + +lodash.tail@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/lodash.tail/-/lodash.tail-4.1.1.tgz#d2333a36d9e7717c8ad2f7cacafec7c32b444664" + integrity sha1-0jM6NtnncXyK0vfKyv7HwytERmQ= + +lodash@^4.0.0, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.4, lodash@^4.17.5, lodash@~4.17.10: + version "4.17.11" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.11.tgz#b39ea6229ef607ecd89e2c8df12536891cac9b8d" + integrity sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg== + +log4js@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/log4js/-/log4js-4.1.0.tgz#57983c6a443546a8c8607e9cb045d2a117c27644" + integrity sha512-eDa+zZPeVEeK6QGJAePyXM6pg4P3n3TO5rX9iZMVY48JshsTyLJZLIL5HipI1kQ2qLsSyOpUqNND/C5H4WhhiA== + dependencies: + date-format "^2.0.0" + debug "^4.1.1" + flatted "^2.0.0" + rfdc "^1.1.2" + streamroller "^1.0.4" + +loglevel@^1.4.1: + version "1.6.1" + resolved "https://registry.yarnpkg.com/loglevel/-/loglevel-1.6.1.tgz#e0fc95133b6ef276cdc8887cdaf24aa6f156f8fa" + integrity sha1-4PyVEztu8nbNyIh82vJKpvFW+Po= + +loose-envify@^1.0.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" + integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== + dependencies: + js-tokens "^3.0.0 || ^4.0.0" + +loud-rejection@^1.0.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/loud-rejection/-/loud-rejection-1.6.0.tgz#5b46f80147edee578870f086d04821cf998e551f" + integrity sha1-W0b4AUft7leIcPCG0Eghz5mOVR8= + dependencies: + currently-unhandled "^0.4.1" + signal-exit "^3.0.0" + +lru-cache@4.1.x, lru-cache@^4.0.1, lru-cache@^4.1.1, lru-cache@^4.1.2, lru-cache@^4.1.3: + version "4.1.5" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.5.tgz#8bbe50ea85bed59bc9e33dcab8235ee9bcf443cd" + integrity sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g== + dependencies: + pseudomap "^1.0.2" + yallist "^2.1.2" + +lru-cache@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" + integrity sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w== + dependencies: + yallist "^3.0.2" + +magic-string@^0.25.0: + version "0.25.2" + resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.25.2.tgz#139c3a729515ec55e96e69e82a11fe890a293ad9" + integrity sha512-iLs9mPjh9IuTtRsqqhNGYcZXGei0Nh/A4xirrsqW7c+QhKVFL2vm7U09ru6cHRD22azaP/wMDgI+HCqbETMTtg== + dependencies: + sourcemap-codec "^1.4.4" + +make-dir@^1.0.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-1.3.0.tgz#79c1033b80515bd6d24ec9933e860ca75ee27f0c" + integrity sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ== + dependencies: + pify "^3.0.0" + +make-dir@^2.0.0, make-dir@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-2.1.0.tgz#5f0310e18b8be898cc07009295a30ae41e91e6f5" + integrity sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA== + dependencies: + pify "^4.0.1" + semver "^5.6.0" + +make-error@^1.1.1: + version "1.3.5" + resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.5.tgz#efe4e81f6db28cadd605c70f29c831b58ef776c8" + integrity sha512-c3sIjNUow0+8swNwVpqoH4YCShKNFkMaw6oH1mNS2haDZQqkeZFlHS3dhoeEbKKmJB4vXpJucU6oH75aDYeE9g== + +make-fetch-happen@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/make-fetch-happen/-/make-fetch-happen-4.0.1.tgz#141497cb878f243ba93136c83d8aba12c216c083" + integrity sha512-7R5ivfy9ilRJ1EMKIOziwrns9fGeAD4bAha8EB7BIiBBLHm2KeTUGCrICFt2rbHfzheTLynv50GnNTK1zDTrcQ== + dependencies: + agentkeepalive "^3.4.1" + cacache "^11.0.1" + http-cache-semantics "^3.8.1" + http-proxy-agent "^2.1.0" + https-proxy-agent "^2.2.1" + lru-cache "^4.1.2" + mississippi "^3.0.0" + node-fetch-npm "^2.0.2" + promise-retry "^1.1.1" + socks-proxy-agent "^4.0.0" + ssri "^6.0.0" + +map-age-cleaner@^0.1.1: + version "0.1.3" + resolved "https://registry.yarnpkg.com/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz#7d583a7306434c055fe474b0f45078e6e1b4b92a" + integrity sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w== + dependencies: + p-defer "^1.0.0" + +map-cache@^0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf" + integrity sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8= + +map-obj@^1.0.0, map-obj@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-1.0.1.tgz#d933ceb9205d82bdcf4886f6742bdc2b4dea146d" + integrity sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0= + +map-visit@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/map-visit/-/map-visit-1.0.0.tgz#ecdca8f13144e660f1b5bd41f12f3479d98dfb8f" + integrity sha1-7Nyo8TFE5mDxtb1B8S80edmN+48= + dependencies: + object-visit "^1.0.0" + +md5.js@^1.3.4: + version "1.3.5" + resolved "https://registry.yarnpkg.com/md5.js/-/md5.js-1.3.5.tgz#b5d07b8e3216e3e27cd728d72f70d1e6a342005f" + integrity sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg== + dependencies: + hash-base "^3.0.0" + inherits "^2.0.1" + safe-buffer "^5.1.2" + +media-typer@0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" + integrity sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g= + +mem@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/mem/-/mem-1.1.0.tgz#5edd52b485ca1d900fe64895505399a0dfa45f76" + integrity sha1-Xt1StIXKHZAP5kiVUFOZoN+kX3Y= + dependencies: + mimic-fn "^1.0.0" + +mem@^4.0.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/mem/-/mem-4.3.0.tgz#461af497bc4ae09608cdb2e60eefb69bff744178" + integrity sha512-qX2bG48pTqYRVmDB37rn/6PT7LcR8T7oAX3bf99u1Tt1nzxYfxkgqDwUwolPlXweM0XzBOBFzSx4kfp7KP1s/w== + dependencies: + map-age-cleaner "^0.1.1" + mimic-fn "^2.0.0" + p-is-promise "^2.0.0" + +memory-fs@^0.4.0, memory-fs@~0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.4.1.tgz#3a9a20b8462523e447cfbc7e8bb80ed667bfc552" + integrity sha1-OpoguEYlI+RHz7x+i7gO1me/xVI= + dependencies: + errno "^0.1.3" + readable-stream "^2.0.1" + +meow@^3.7.0: + version "3.7.0" + resolved "https://registry.yarnpkg.com/meow/-/meow-3.7.0.tgz#72cb668b425228290abbfa856892587308a801fb" + integrity sha1-cstmi0JSKCkKu/qFaJJYcwioAfs= + dependencies: + camelcase-keys "^2.0.0" + decamelize "^1.1.2" + loud-rejection "^1.0.0" + map-obj "^1.0.1" + minimist "^1.1.3" + normalize-package-data "^2.3.4" + object-assign "^4.0.1" + read-pkg-up "^1.0.1" + redent "^1.0.0" + trim-newlines "^1.0.0" + +merge-descriptors@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" + integrity sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E= + +methods@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" + integrity sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4= + +micromatch@^3.1.10, micromatch@^3.1.4, micromatch@^3.1.8, micromatch@^3.1.9: + version "3.1.10" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23" + integrity sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg== + dependencies: + arr-diff "^4.0.0" + array-unique "^0.3.2" + braces "^2.3.1" + define-property "^2.0.2" + extend-shallow "^3.0.2" + extglob "^2.0.4" + fragment-cache "^0.2.1" + kind-of "^6.0.2" + nanomatch "^1.2.9" + object.pick "^1.3.0" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.2" + +miller-rabin@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/miller-rabin/-/miller-rabin-4.0.1.tgz#f080351c865b0dc562a8462966daa53543c78a4d" + integrity sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA== + dependencies: + bn.js "^4.0.0" + brorand "^1.0.1" + +"mime-db@>= 1.38.0 < 2", mime-db@~1.39.0: + version "1.39.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.39.0.tgz#f95a20275742f7d2ad0429acfe40f4233543780e" + integrity sha512-DTsrw/iWVvwHH+9Otxccdyy0Tgiil6TWK/xhfARJZF/QFhwOgZgOIvA2/VIGpM8U7Q8z5nDmdDWC6tuVMJNibw== + +mime-types@^2.1.12, mime-types@~2.1.17, mime-types@~2.1.18, mime-types@~2.1.19: + version "2.1.23" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.23.tgz#d4eacd87de99348a6858fe1e479aad877388d977" + integrity sha512-ROk/m+gMVSrRxTkMlaQOvFmFmYDc7sZgrjjM76abqmd2Cc5fCV7jAMA5XUccEtJ3cYiYdgixUVI+fApc2LkXlw== + dependencies: + mime-db "~1.39.0" + +mime@1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/mime/-/mime-1.4.1.tgz#121f9ebc49e3766f311a76e1fa1c8003c4b03aa6" + integrity sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ== + +mime@^1.4.1: + version "1.6.0" + resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" + integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== + +mime@^2.3.1: + version "2.4.2" + resolved "https://registry.yarnpkg.com/mime/-/mime-2.4.2.tgz#ce5229a5e99ffc313abac806b482c10e7ba6ac78" + integrity sha512-zJBfZDkwRu+j3Pdd2aHsR5GfH2jIWhmL1ZzBoc+X+3JEti2hbArWcyJ+1laC1D2/U/W1a/+Cegj0/OnEU2ybjg== + +mimic-fn@^1.0.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.2.0.tgz#820c86a39334640e99516928bd03fca88057d022" + integrity sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ== + +mimic-fn@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" + integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== + +mini-css-extract-plugin@0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/mini-css-extract-plugin/-/mini-css-extract-plugin-0.5.0.tgz#ac0059b02b9692515a637115b0cc9fed3a35c7b0" + integrity sha512-IuaLjruM0vMKhUUT51fQdQzBYTX49dLj8w68ALEAe2A4iYNpIC4eMac67mt3NzycvjOlf07/kYxJDc0RTl1Wqw== + dependencies: + loader-utils "^1.1.0" + schema-utils "^1.0.0" + webpack-sources "^1.1.0" + +minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7" + integrity sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A== + +minimalistic-crypto-utils@^1.0.0, minimalistic-crypto-utils@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a" + integrity sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo= + +minimatch@3.0.4, minimatch@^3.0.2, minimatch@^3.0.3, minimatch@^3.0.4, minimatch@~3.0.2: + version "3.0.4" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" + integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== + dependencies: + brace-expansion "^1.1.7" + +minimist@0.0.8: + version "0.0.8" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" + integrity sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0= + +minimist@^1.1.3, minimist@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" + integrity sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ= + +minimist@~0.0.1: + version "0.0.10" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.10.tgz#de3f98543dbf96082be48ad1a0c7cda836301dcf" + integrity sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8= + +minipass@^2.2.1, minipass@^2.3.4, minipass@^2.3.5: + version "2.3.5" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-2.3.5.tgz#cacebe492022497f656b0f0f51e2682a9ed2d848" + integrity sha512-Gi1W4k059gyRbyVUZQ4mEqLm0YIUiGYfvxhF6SIlk3ui1WVxMTGfGdQ2SInh3PDrRTVvPKgULkpJtT4RH10+VA== + dependencies: + safe-buffer "^5.1.2" + yallist "^3.0.0" + +minizlib@^1.1.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-1.2.1.tgz#dd27ea6136243c7c880684e8672bb3a45fd9b614" + integrity sha512-7+4oTUOWKg7AuL3vloEWekXY2/D20cevzsrNT2kGWm+39J9hGTCBv8VI5Pm5lXZ/o3/mdR4f8rflAPhnQb8mPA== + dependencies: + minipass "^2.2.1" + +mississippi@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/mississippi/-/mississippi-2.0.0.tgz#3442a508fafc28500486feea99409676e4ee5a6f" + integrity sha512-zHo8v+otD1J10j/tC+VNoGK9keCuByhKovAvdn74dmxJl9+mWHnx6EMsDN4lgRoMI/eYo2nchAxniIbUPb5onw== + dependencies: + concat-stream "^1.5.0" + duplexify "^3.4.2" + end-of-stream "^1.1.0" + flush-write-stream "^1.0.0" + from2 "^2.1.0" + parallel-transform "^1.1.0" + pump "^2.0.1" + pumpify "^1.3.3" + stream-each "^1.1.0" + through2 "^2.0.0" + +mississippi@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/mississippi/-/mississippi-3.0.0.tgz#ea0a3291f97e0b5e8776b363d5f0a12d94c67022" + integrity sha512-x471SsVjUtBRtcvd4BzKE9kFC+/2TeWgKCgw0bZcw1b9l2X3QX5vCWgF+KaZaYm87Ss//rHnWryupDrgLvmSkA== + dependencies: + concat-stream "^1.5.0" + duplexify "^3.4.2" + end-of-stream "^1.1.0" + flush-write-stream "^1.0.0" + from2 "^2.1.0" + parallel-transform "^1.1.0" + pump "^3.0.0" + pumpify "^1.3.3" + stream-each "^1.1.0" + through2 "^2.0.0" + +mixin-deep@^1.2.0: + version "1.3.1" + resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.1.tgz#a49e7268dce1a0d9698e45326c5626df3543d0fe" + integrity sha512-8ZItLHeEgaqEvd5lYBXfm4EZSFCX29Jb9K+lAHhDKzReKBQKj3R+7NOF6tjqYi9t4oI8VUfaWITJQm86wnXGNQ== + dependencies: + for-in "^1.0.2" + is-extendable "^1.0.1" + +mixin-object@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/mixin-object/-/mixin-object-2.0.1.tgz#4fb949441dab182540f1fe035ba60e1947a5e57e" + integrity sha1-T7lJRB2rGCVA8f4DW6YOGUel5X4= + dependencies: + for-in "^0.1.3" + is-extendable "^0.1.1" + +mkdirp@0.5.x, "mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.0: + version "0.5.1" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" + integrity sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM= + dependencies: + minimist "0.0.8" + +move-concurrently@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/move-concurrently/-/move-concurrently-1.0.1.tgz#be2c005fda32e0b29af1f05d7c4b33214c701f92" + integrity sha1-viwAX9oy4LKa8fBdfEszIUxwH5I= + dependencies: + aproba "^1.1.1" + copy-concurrently "^1.0.0" + fs-write-stream-atomic "^1.0.8" + mkdirp "^0.5.1" + rimraf "^2.5.4" + run-queue "^1.0.3" + +ms@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" + integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= + +ms@^2.0.0, ms@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a" + integrity sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg== + +multicast-dns-service-types@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/multicast-dns-service-types/-/multicast-dns-service-types-1.1.0.tgz#899f11d9686e5e05cb91b35d5f0e63b773cfc901" + integrity sha1-iZ8R2WhuXgXLkbNdXw5jt3PPyQE= + +multicast-dns@^6.0.1: + version "6.2.3" + resolved "https://registry.yarnpkg.com/multicast-dns/-/multicast-dns-6.2.3.tgz#a0ec7bd9055c4282f790c3c82f4e28db3b31b229" + integrity sha512-ji6J5enbMyGRHIAkAOu3WdV8nggqviKCEKtXcOqfphZZtQrmHKycfynJ2V7eVPUA4NhJ6V7Wf4TmGbTwKE9B6g== + dependencies: + dns-packet "^1.3.1" + thunky "^1.0.2" + +mute-stream@0.0.7: + version "0.0.7" + resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab" + integrity sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s= + +nan@^2.10.0, nan@^2.12.1: + version "2.13.2" + resolved "https://registry.yarnpkg.com/nan/-/nan-2.13.2.tgz#f51dc7ae66ba7d5d55e1e6d4d8092e802c9aefe7" + integrity sha512-TghvYc72wlMGMVMluVo9WRJc0mB8KxxF/gZ4YYFy7V2ZQX9l7rgbPg7vjS9mt6U5HXODVFVI2bOduCzwOMv/lw== + +nanomatch@^1.2.9: + version "1.2.13" + resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119" + integrity sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA== + dependencies: + arr-diff "^4.0.0" + array-unique "^0.3.2" + define-property "^2.0.2" + extend-shallow "^3.0.2" + fragment-cache "^0.2.1" + is-windows "^1.0.2" + kind-of "^6.0.2" + object.pick "^1.3.0" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" + +needle@^2.2.1: + version "2.3.0" + resolved "https://registry.yarnpkg.com/needle/-/needle-2.3.0.tgz#ce3fea21197267bacb310705a7bbe24f2a3a3492" + integrity sha512-QBZu7aAFR0522EyaXZM0FZ9GLpq6lvQ3uq8gteiDUp7wKdy0lSd2hPlgFwVuW1CBkfEs9PfDQsQzZghLs/psdg== + dependencies: + debug "^4.1.0" + iconv-lite "^0.4.4" + sax "^1.2.4" + +negotiator@0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.1.tgz#2b327184e8992101177b28563fb5e7102acd0ca9" + integrity sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk= + +neo-async@^2.5.0, neo-async@^2.6.0: + version "2.6.0" + resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.0.tgz#b9d15e4d71c6762908654b5183ed38b753340835" + integrity sha512-MFh0d/Wa7vkKO3Y3LlacqAEeHK0mckVqzDieUKTT+KGxi+zIpeVsFxymkIiRpbpDziHc290Xr9A1O4Om7otoRA== + +nice-try@^1.0.4: + version "1.0.5" + resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" + integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ== + +node-fetch-npm@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/node-fetch-npm/-/node-fetch-npm-2.0.2.tgz#7258c9046182dca345b4208eda918daf33697ff7" + integrity sha512-nJIxm1QmAj4v3nfCvEeCrYSoVwXyxLnaPBK5W1W5DGEJwjlKuC2VEUycGw5oxk+4zZahRrB84PUJJgEmhFTDFw== + dependencies: + encoding "^0.1.11" + json-parse-better-errors "^1.0.0" + safe-buffer "^5.1.1" + +node-forge@0.7.5: + version "0.7.5" + resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-0.7.5.tgz#6c152c345ce11c52f465c2abd957e8639cd674df" + integrity sha512-MmbQJ2MTESTjt3Gi/3yG1wGpIMhUfcIypUCGtTizFR9IiccFwxSpfp0vtIZlkFclEqERemxfnSdZEMR9VqqEFQ== + +node-gyp@^3.8.0: + version "3.8.0" + resolved "https://registry.yarnpkg.com/node-gyp/-/node-gyp-3.8.0.tgz#540304261c330e80d0d5edce253a68cb3964218c" + integrity sha512-3g8lYefrRRzvGeSowdJKAKyks8oUpLEd/DyPV4eMhVlhJ0aNaZqIrNUIPuEWWTAoPqyFkfGrM67MC69baqn6vA== + dependencies: + fstream "^1.0.0" + glob "^7.0.3" + graceful-fs "^4.1.2" + mkdirp "^0.5.0" + nopt "2 || 3" + npmlog "0 || 1 || 2 || 3 || 4" + osenv "0" + request "^2.87.0" + rimraf "2" + semver "~5.3.0" + tar "^2.0.0" + which "1" + +node-libs-browser@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/node-libs-browser/-/node-libs-browser-2.2.0.tgz#c72f60d9d46de08a940dedbb25f3ffa2f9bbaa77" + integrity sha512-5MQunG/oyOaBdttrL40dA7bUfPORLRWMUJLQtMg7nluxUvk5XwnLdL9twQHFAjRx/y7mIMkLKT9++qPbbk6BZA== + dependencies: + assert "^1.1.1" + browserify-zlib "^0.2.0" + buffer "^4.3.0" + console-browserify "^1.1.0" + constants-browserify "^1.0.0" + crypto-browserify "^3.11.0" + domain-browser "^1.1.1" + events "^3.0.0" + https-browserify "^1.0.0" + os-browserify "^0.3.0" + path-browserify "0.0.0" + process "^0.11.10" + punycode "^1.2.4" + querystring-es3 "^0.2.0" + readable-stream "^2.3.3" + stream-browserify "^2.0.1" + stream-http "^2.7.2" + string_decoder "^1.0.0" + timers-browserify "^2.0.4" + tty-browserify "0.0.0" + url "^0.11.0" + util "^0.11.0" + vm-browserify "0.0.4" + +node-pre-gyp@^0.12.0: + version "0.12.0" + resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.12.0.tgz#39ba4bb1439da030295f899e3b520b7785766149" + integrity sha512-4KghwV8vH5k+g2ylT+sLTjy5wmUOb9vPhnM8NHvRf9dHmnW/CndrFXy2aRPaPST6dugXSdHXfeaHQm77PIz/1A== + dependencies: + detect-libc "^1.0.2" + mkdirp "^0.5.1" + needle "^2.2.1" + nopt "^4.0.1" + npm-packlist "^1.1.6" + npmlog "^4.0.2" + rc "^1.2.7" + rimraf "^2.6.1" + semver "^5.3.0" + tar "^4" + +node-releases@^1.1.14: + version "1.1.15" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.15.tgz#9e76a73b0eca3bf7801addaa0e6ce90c795f2b9a" + integrity sha512-cKV097BQaZr8LTSRUa2+oc/aX5L8UkZtPQrMSTgiJEeaW7ymTDCoRaGCoaTqk0lqnalcoSHu4wjSl0Cmj2+bMw== + dependencies: + semver "^5.3.0" + +node-sass@4.11.0: + version "4.11.0" + resolved "https://registry.yarnpkg.com/node-sass/-/node-sass-4.11.0.tgz#183faec398e9cbe93ba43362e2768ca988a6369a" + integrity sha512-bHUdHTphgQJZaF1LASx0kAviPH7sGlcyNhWade4eVIpFp6tsn7SV8xNMTbsQFpEV9VXpnwTTnNYlfsZXgGgmkA== + dependencies: + async-foreach "^0.1.3" + chalk "^1.1.1" + cross-spawn "^3.0.0" + gaze "^1.0.0" + get-stdin "^4.0.1" + glob "^7.0.3" + in-publish "^2.0.0" + lodash.assign "^4.2.0" + lodash.clonedeep "^4.3.2" + lodash.mergewith "^4.6.0" + meow "^3.7.0" + mkdirp "^0.5.1" + nan "^2.10.0" + node-gyp "^3.8.0" + npmlog "^4.0.0" + request "^2.88.0" + sass-graph "^2.2.4" + stdout-stream "^1.4.0" + "true-case-path" "^1.0.2" + +"nopt@2 || 3": + version "3.0.6" + resolved "https://registry.yarnpkg.com/nopt/-/nopt-3.0.6.tgz#c6465dbf08abcd4db359317f79ac68a646b28ff9" + integrity sha1-xkZdvwirzU2zWTF/eaxopkayj/k= + dependencies: + abbrev "1" + +nopt@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.1.tgz#d0d4685afd5415193c8c7505602d0d17cd64474d" + integrity sha1-0NRoWv1UFRk8jHUFYC0NF81kR00= + dependencies: + abbrev "1" + osenv "^0.1.4" + +normalize-package-data@^2.3.2, normalize-package-data@^2.3.4, normalize-package-data@^2.4.0: + version "2.5.0" + resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8" + integrity sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA== + dependencies: + hosted-git-info "^2.1.4" + resolve "^1.10.0" + semver "2 || 3 || 4 || 5" + validate-npm-package-license "^3.0.1" + +normalize-path@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9" + integrity sha1-GrKLVW4Zg2Oowab35vogE3/mrtk= + dependencies: + remove-trailing-separator "^1.0.1" + +normalize-path@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" + integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== + +normalize-range@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/normalize-range/-/normalize-range-0.1.2.tgz#2d10c06bdfd312ea9777695a4d28439456b75942" + integrity sha1-LRDAa9/TEuqXd2laTShDlFa3WUI= + +npm-bundled@^1.0.1: + version "1.0.6" + resolved "https://registry.yarnpkg.com/npm-bundled/-/npm-bundled-1.0.6.tgz#e7ba9aadcef962bb61248f91721cd932b3fe6bdd" + integrity sha512-8/JCaftHwbd//k6y2rEWp6k1wxVfpFzB6t1p825+cUb7Ym2XQfhwIC5KwhrvzZRJu+LtDE585zVaS32+CGtf0g== + +npm-package-arg@6.1.0, npm-package-arg@^6.0.0, npm-package-arg@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/npm-package-arg/-/npm-package-arg-6.1.0.tgz#15ae1e2758a5027efb4c250554b85a737db7fcc1" + integrity sha512-zYbhP2k9DbJhA0Z3HKUePUgdB1x7MfIfKssC+WLPFMKTBZKpZh5m13PgexJjCq6KW7j17r0jHWcCpxEqnnncSA== + dependencies: + hosted-git-info "^2.6.0" + osenv "^0.1.5" + semver "^5.5.0" + validate-npm-package-name "^3.0.0" + +npm-packlist@^1.1.12, npm-packlist@^1.1.6: + version "1.4.1" + resolved "https://registry.yarnpkg.com/npm-packlist/-/npm-packlist-1.4.1.tgz#19064cdf988da80ea3cee45533879d90192bbfbc" + integrity sha512-+TcdO7HJJ8peiiYhvPxsEDhF3PJFGUGRcFsGve3vxvxdcpO2Z4Z7rkosRM0kWj6LfbK/P0gu3dzk5RU1ffvFcw== + dependencies: + ignore-walk "^3.0.1" + npm-bundled "^1.0.1" + +npm-pick-manifest@^2.2.3: + version "2.2.3" + resolved "https://registry.yarnpkg.com/npm-pick-manifest/-/npm-pick-manifest-2.2.3.tgz#32111d2a9562638bb2c8f2bf27f7f3092c8fae40" + integrity sha512-+IluBC5K201+gRU85vFlUwX3PFShZAbAgDNp2ewJdWMVSppdo/Zih0ul2Ecky/X7b51J7LrrUAP+XOmOCvYZqA== + dependencies: + figgy-pudding "^3.5.1" + npm-package-arg "^6.0.0" + semver "^5.4.1" + +npm-registry-fetch@^3.8.0: + version "3.9.0" + resolved "https://registry.yarnpkg.com/npm-registry-fetch/-/npm-registry-fetch-3.9.0.tgz#44d841780e2833f06accb34488f8c7450d1a6856" + integrity sha512-srwmt8YhNajAoSAaDWndmZgx89lJwIZ1GWxOuckH4Coek4uHv5S+o/l9FLQe/awA+JwTnj4FJHldxhlXdZEBmw== + dependencies: + JSONStream "^1.3.4" + bluebird "^3.5.1" + figgy-pudding "^3.4.1" + lru-cache "^4.1.3" + make-fetch-happen "^4.0.1" + npm-package-arg "^6.1.0" + +npm-run-path@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f" + integrity sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8= + dependencies: + path-key "^2.0.0" + +"npmlog@0 || 1 || 2 || 3 || 4", npmlog@^4.0.0, npmlog@^4.0.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b" + integrity sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg== + dependencies: + are-we-there-yet "~1.1.2" + console-control-strings "~1.1.0" + gauge "~2.7.3" + set-blocking "~2.0.0" + +null-check@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/null-check/-/null-check-1.0.0.tgz#977dffd7176012b9ec30d2a39db5cf72a0439edd" + integrity sha1-l33/1xdgErnsMNKjnbXPcqBDnt0= + +num2fraction@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/num2fraction/-/num2fraction-1.2.2.tgz#6f682b6a027a4e9ddfa4564cd2589d1d4e669ede" + integrity sha1-b2gragJ6Tp3fpFZM0lidHU5mnt4= + +number-is-nan@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" + integrity sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0= + +oauth-sign@~0.9.0: + version "0.9.0" + resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455" + integrity sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ== + +object-assign@^4.0.1, object-assign@^4.1.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" + integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= + +object-component@0.0.3: + version "0.0.3" + resolved "https://registry.yarnpkg.com/object-component/-/object-component-0.0.3.tgz#f0c69aa50efc95b866c186f400a33769cb2f1291" + integrity sha1-8MaapQ78lbhmwYb0AKM3acsvEpE= + +object-copy@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/object-copy/-/object-copy-0.1.0.tgz#7e7d858b781bd7c991a41ba975ed3812754e998c" + integrity sha1-fn2Fi3gb18mRpBupde04EnVOmYw= + dependencies: + copy-descriptor "^0.1.0" + define-property "^0.2.5" + kind-of "^3.0.3" + +object-visit@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/object-visit/-/object-visit-1.0.1.tgz#f79c4493af0c5377b59fe39d395e41042dd045bb" + integrity sha1-95xEk68MU3e1n+OdOV5BBC3QRbs= + dependencies: + isobject "^3.0.0" + +object.pick@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/object.pick/-/object.pick-1.3.0.tgz#87a10ac4c1694bd2e1cbf53591a66141fb5dd747" + integrity sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c= + dependencies: + isobject "^3.0.1" + +obuf@^1.0.0, obuf@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/obuf/-/obuf-1.1.2.tgz#09bea3343d41859ebd446292d11c9d4db619084e" + integrity sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg== + +on-finished@~2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" + integrity sha1-IPEzZIGwg811M3mSoWlxqi2QaUc= + dependencies: + ee-first "1.1.1" + +on-headers@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/on-headers/-/on-headers-1.0.2.tgz#772b0ae6aaa525c399e489adfad90c403eb3c28f" + integrity sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA== + +once@^1.3.0, once@^1.3.1, once@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= + dependencies: + wrappy "1" + +onetime@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/onetime/-/onetime-2.0.1.tgz#067428230fd67443b2794b22bba528b6867962d4" + integrity sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ= + dependencies: + mimic-fn "^1.0.0" + +open@6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/open/-/open-6.0.0.tgz#cae5e2c1a3a1bfaee0d0acc8c4b7609374750346" + integrity sha512-/yb5mVZBz7mHLySMiSj2DcLtMBbFPJk5JBKEkHVZFxZAPzeg3L026O0T+lbdz1B2nyDnkClRSwRQJdeVUIF7zw== + dependencies: + is-wsl "^1.1.0" + +opn@^5.1.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/opn/-/opn-5.5.0.tgz#fc7164fab56d235904c51c3b27da6758ca3b9bfc" + integrity sha512-PqHpggC9bLV0VeWcdKhkpxY+3JTzetLSqTCWL/z/tFIbI6G8JCjondXklT1JinczLz2Xib62sSp0T/gKT4KksA== + dependencies: + is-wsl "^1.1.0" + +optimist@^0.6.1, optimist@~0.6.0: + version "0.6.1" + resolved "https://registry.yarnpkg.com/optimist/-/optimist-0.6.1.tgz#da3ea74686fa21a19a111c326e90eb15a0196686" + integrity sha1-2j6nRob6IaGaERwybpDrFaAZZoY= + dependencies: + minimist "~0.0.1" + wordwrap "~0.0.2" + +original@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/original/-/original-1.0.2.tgz#e442a61cffe1c5fd20a65f3261c26663b303f25f" + integrity sha512-hyBVl6iqqUOJ8FqRe+l/gS8H+kKYjrEndd5Pm1MfBtsEKA038HkkdbAl/72EAXGyonD/PFsvmVG+EvcIpliMBg== + dependencies: + url-parse "^1.4.3" + +os-browserify@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/os-browserify/-/os-browserify-0.3.0.tgz#854373c7f5c2315914fc9bfc6bd8238fdda1ec27" + integrity sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc= + +os-homedir@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" + integrity sha1-/7xJiDNuDoM94MFox+8VISGqf7M= + +os-locale@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-1.4.0.tgz#20f9f17ae29ed345e8bde583b13d2009803c14d9" + integrity sha1-IPnxeuKe00XoveWDsT0gCYA8FNk= + dependencies: + lcid "^1.0.0" + +os-locale@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-2.1.0.tgz#42bc2900a6b5b8bd17376c8e882b65afccf24bf2" + integrity sha512-3sslG3zJbEYcaC4YVAvDorjGxc7tv6KVATnLPZONiljsUncvihe9BQoVCEs0RZ1kmf4Hk9OBqlZfJZWI4GanKA== + dependencies: + execa "^0.7.0" + lcid "^1.0.0" + mem "^1.1.0" + +os-locale@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-3.1.0.tgz#a802a6ee17f24c10483ab9935719cef4ed16bf1a" + integrity sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q== + dependencies: + execa "^1.0.0" + lcid "^2.0.0" + mem "^4.0.0" + +os-tmpdir@^1.0.0, os-tmpdir@~1.0.1, os-tmpdir@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" + integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ= + +osenv@0, osenv@^0.1.4, osenv@^0.1.5: + version "0.1.5" + resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.5.tgz#85cdfafaeb28e8677f416e287592b5f3f49ea410" + integrity sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g== + dependencies: + os-homedir "^1.0.0" + os-tmpdir "^1.0.0" + +p-defer@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/p-defer/-/p-defer-1.0.0.tgz#9f6eb182f6c9aa8cd743004a7d4f96b196b0fb0c" + integrity sha1-n26xgvbJqozXQwBKfU+WsZaw+ww= + +p-finally@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" + integrity sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4= + +p-is-promise@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/p-is-promise/-/p-is-promise-2.1.0.tgz#918cebaea248a62cf7ffab8e3bca8c5f882fc42e" + integrity sha512-Y3W0wlRPK8ZMRbNq97l4M5otioeA5lm1z7bkNkxCka8HSPjR0xRWmpCmc9utiaLP9Jb1eD8BgeIxTW4AIF45Pg== + +p-limit@^1.0.0, p-limit@^1.1.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.3.0.tgz#b86bd5f0c25690911c7590fcbfc2010d54b3ccb8" + integrity sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q== + dependencies: + p-try "^1.0.0" + +p-limit@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.2.0.tgz#417c9941e6027a9abcba5092dd2904e255b5fbc2" + integrity sha512-pZbTJpoUsCzV48Mc9Nh51VbwO0X9cuPFE8gYwx9BTCt9SF8/b7Zljd2fVgOxhIF/HDTKgpVzs+GPhyKfjLLFRQ== + dependencies: + p-try "^2.0.0" + +p-locate@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43" + integrity sha1-IKAQOyIqcMj9OcwuWAaA893l7EM= + dependencies: + p-limit "^1.1.0" + +p-locate@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-3.0.0.tgz#322d69a05c0264b25997d9f40cd8a891ab0064a4" + integrity sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ== + dependencies: + p-limit "^2.0.0" + +p-map@^1.1.1: + version "1.2.0" + resolved "https://registry.yarnpkg.com/p-map/-/p-map-1.2.0.tgz#e4e94f311eabbc8633a1e79908165fca26241b6b" + integrity sha512-r6zKACMNhjPJMTl8KcFH4li//gkrXWfbD6feV8l6doRHlzljFWGJ2AP6iKaCJXyZmAUMOPtvbW7EXkbWO/pLEA== + +p-try@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3" + integrity sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M= + +p-try@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" + integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== + +pacote@9.4.0: + version "9.4.0" + resolved "https://registry.yarnpkg.com/pacote/-/pacote-9.4.0.tgz#af979abdeb175cd347c3e33be3241af1ed254807" + integrity sha512-WQ1KL/phGMkedYEQx9ODsjj7xvwLSpdFJJdEXrLyw5SILMxcTNt5DTxT2Z93fXuLFYJBlZJdnwdalrQdB/rX5w== + dependencies: + bluebird "^3.5.3" + cacache "^11.3.2" + figgy-pudding "^3.5.1" + get-stream "^4.1.0" + glob "^7.1.3" + lru-cache "^5.1.1" + make-fetch-happen "^4.0.1" + minimatch "^3.0.4" + minipass "^2.3.5" + mississippi "^3.0.0" + mkdirp "^0.5.1" + normalize-package-data "^2.4.0" + npm-package-arg "^6.1.0" + npm-packlist "^1.1.12" + npm-pick-manifest "^2.2.3" + npm-registry-fetch "^3.8.0" + osenv "^0.1.5" + promise-inflight "^1.0.1" + promise-retry "^1.1.1" + protoduck "^5.0.1" + rimraf "^2.6.2" + safe-buffer "^5.1.2" + semver "^5.6.0" + ssri "^6.0.1" + tar "^4.4.8" + unique-filename "^1.1.1" + which "^1.3.1" + +pako@~1.0.2, pako@~1.0.5: + version "1.0.10" + resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.10.tgz#4328badb5086a426aa90f541977d4955da5c9732" + integrity sha512-0DTvPVU3ed8+HNXOu5Bs+o//Mbdj9VNQMUOe9oKCwh8l0GNwpTDMKCWbRjgtD291AWnkAgkqA/LOnQS8AmS1tw== + +parallel-transform@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/parallel-transform/-/parallel-transform-1.1.0.tgz#d410f065b05da23081fcd10f28854c29bda33b06" + integrity sha1-1BDwZbBdojCB/NEPKIVMKb2jOwY= + dependencies: + cyclist "~0.2.2" + inherits "^2.0.3" + readable-stream "^2.1.5" + +parse-asn1@^5.0.0: + version "5.1.4" + resolved "https://registry.yarnpkg.com/parse-asn1/-/parse-asn1-5.1.4.tgz#37f6628f823fbdeb2273b4d540434a22f3ef1fcc" + integrity sha512-Qs5duJcuvNExRfFZ99HDD3z4mAi3r9Wl/FOjEOijlxwCZs7E7mW2vjTpgQ4J8LpTF8x5v+1Vn5UQFejmWT11aw== + dependencies: + asn1.js "^4.0.0" + browserify-aes "^1.0.0" + create-hash "^1.1.0" + evp_bytestokey "^1.0.0" + pbkdf2 "^3.0.3" + safe-buffer "^5.1.1" + +parse-json@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9" + integrity sha1-9ID0BDTvgHQfhGkJn43qGPVaTck= + dependencies: + error-ex "^1.2.0" + +parse-json@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-4.0.0.tgz#be35f5425be1f7f6c747184f98a788cb99477ee0" + integrity sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA= + dependencies: + error-ex "^1.3.1" + json-parse-better-errors "^1.0.1" + +parse5@4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/parse5/-/parse5-4.0.0.tgz#6d78656e3da8d78b4ec0b906f7c08ef1dfe3f608" + integrity sha512-VrZ7eOd3T1Fk4XWNXMgiGBK/z0MG48BWG2uQNU4I72fkQuKUTZpl+u9k+CxEG0twMVzSmXEEz12z5Fnw1jIQFA== + +parseqs@0.0.5: + version "0.0.5" + resolved "https://registry.yarnpkg.com/parseqs/-/parseqs-0.0.5.tgz#d5208a3738e46766e291ba2ea173684921a8b89d" + integrity sha1-1SCKNzjkZ2bikbouoXNoSSGouJ0= + dependencies: + better-assert "~1.0.0" + +parseuri@0.0.5: + version "0.0.5" + resolved "https://registry.yarnpkg.com/parseuri/-/parseuri-0.0.5.tgz#80204a50d4dbb779bfdc6ebe2778d90e4bce320a" + integrity sha1-gCBKUNTbt3m/3G6+J3jZDkvOMgo= + dependencies: + better-assert "~1.0.0" + +parseurl@~1.3.2: + version "1.3.3" + resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" + integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== + +pascalcase@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14" + integrity sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ= + +path-browserify@0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-0.0.0.tgz#a0b870729aae214005b7d5032ec2cbbb0fb4451a" + integrity sha1-oLhwcpquIUAFt9UDLsLLuw+0RRo= + +path-dirname@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/path-dirname/-/path-dirname-1.0.2.tgz#cc33d24d525e099a5388c0336c6e32b9160609e0" + integrity sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA= + +path-exists@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-2.1.0.tgz#0feb6c64f0fc518d9a754dd5efb62c7022761f4b" + integrity sha1-D+tsZPD8UY2adU3V77YscCJ2H0s= + dependencies: + pinkie-promise "^2.0.0" + +path-exists@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" + integrity sha1-zg6+ql94yxiSXqfYENe1mwEP1RU= + +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= + +path-is-inside@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53" + integrity sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM= + +path-key@^2.0.0, path-key@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" + integrity sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A= + +path-parse@^1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c" + integrity sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw== + +path-to-regexp@0.1.7: + version "0.1.7" + resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" + integrity sha1-32BBeABfUi8V60SQ5yR6G/qmf4w= + +path-type@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-1.1.0.tgz#59c44f7ee491da704da415da5a4070ba4f8fe441" + integrity sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE= + dependencies: + graceful-fs "^4.1.2" + pify "^2.0.0" + pinkie-promise "^2.0.0" + +path-type@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-2.0.0.tgz#f012ccb8415b7096fc2daa1054c3d72389594c73" + integrity sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM= + dependencies: + pify "^2.0.0" + +path-type@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-3.0.0.tgz#cef31dc8e0a1a3bb0d105c0cd97cf3bf47f4e36f" + integrity sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg== + dependencies: + pify "^3.0.0" + +pbkdf2@^3.0.3: + version "3.0.17" + resolved "https://registry.yarnpkg.com/pbkdf2/-/pbkdf2-3.0.17.tgz#976c206530617b14ebb32114239f7b09336e93a6" + integrity sha512-U/il5MsrZp7mGg3mSQfn742na2T+1/vHDCG5/iTI3X9MKUuYUZVLQhyRsg06mCgDBTd57TxzgZt7P+fYfjRLtA== + dependencies: + create-hash "^1.1.2" + create-hmac "^1.1.4" + ripemd160 "^2.0.1" + safe-buffer "^5.0.1" + sha.js "^2.4.8" + +performance-now@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" + integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns= + +pify@^2.0.0, pify@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" + integrity sha1-7RQaasBDqEnqWISY59yosVMw6Qw= + +pify@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176" + integrity sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY= + +pify@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/pify/-/pify-4.0.1.tgz#4b2cd25c50d598735c50292224fd8c6df41e3231" + integrity sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g== + +pinkie-promise@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa" + integrity sha1-ITXW36ejWMBprJsXh3YogihFD/o= + dependencies: + pinkie "^2.0.0" + +pinkie@^2.0.0: + version "2.0.4" + resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" + integrity sha1-clVrgM+g1IqXToDnckjoDtT3+HA= + +pkg-dir@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-2.0.0.tgz#f6d5d1109e19d63edf428e0bd57e12777615334b" + integrity sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s= + dependencies: + find-up "^2.1.0" + +pkg-dir@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-3.0.0.tgz#2749020f239ed990881b1f71210d51eb6523bea3" + integrity sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw== + dependencies: + find-up "^3.0.0" + +portfinder@^1.0.9: + version "1.0.20" + resolved "https://registry.yarnpkg.com/portfinder/-/portfinder-1.0.20.tgz#bea68632e54b2e13ab7b0c4775e9b41bf270e44a" + integrity sha512-Yxe4mTyDzTd59PZJY4ojZR8F+E5e97iq2ZOHPz3HDgSvYC5siNad2tLooQ5y5QHyQhc3xVqvyk/eNA3wuoa7Sw== + dependencies: + async "^1.5.2" + debug "^2.2.0" + mkdirp "0.5.x" + +posix-character-classes@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" + integrity sha1-AerA/jta9xoqbAL+q7jB/vfgDqs= + +postcss-import@12.0.1: + version "12.0.1" + resolved "https://registry.yarnpkg.com/postcss-import/-/postcss-import-12.0.1.tgz#cf8c7ab0b5ccab5649024536e565f841928b7153" + integrity sha512-3Gti33dmCjyKBgimqGxL3vcV8w9+bsHwO5UrBawp796+jdardbcFl4RP5w/76BwNL7aGzpKstIfF9I+kdE8pTw== + dependencies: + postcss "^7.0.1" + postcss-value-parser "^3.2.3" + read-cache "^1.0.0" + resolve "^1.1.7" + +postcss-load-config@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/postcss-load-config/-/postcss-load-config-2.0.0.tgz#f1312ddbf5912cd747177083c5ef7a19d62ee484" + integrity sha512-V5JBLzw406BB8UIfsAWSK2KSwIJ5yoEIVFb4gVkXci0QdKgA24jLmHZ/ghe/GgX0lJ0/D1uUK1ejhzEY94MChQ== + dependencies: + cosmiconfig "^4.0.0" + import-cwd "^2.0.0" + +postcss-loader@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/postcss-loader/-/postcss-loader-3.0.0.tgz#6b97943e47c72d845fa9e03f273773d4e8dd6c2d" + integrity sha512-cLWoDEY5OwHcAjDnkyRQzAXfs2jrKjXpO/HQFcc5b5u/r7aa471wdmChmwfnv7x2u840iat/wi0lQ5nbRgSkUA== + dependencies: + loader-utils "^1.1.0" + postcss "^7.0.0" + postcss-load-config "^2.0.0" + schema-utils "^1.0.0" + +postcss-value-parser@^3.2.3, postcss-value-parser@^3.3.1: + version "3.3.1" + resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz#9ff822547e2893213cf1c30efa51ac5fd1ba8281" + integrity sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ== + +postcss@7.0.14, postcss@^7.0.0, postcss@^7.0.1, postcss@^7.0.13: + version "7.0.14" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.14.tgz#4527ed6b1ca0d82c53ce5ec1a2041c2346bbd6e5" + integrity sha512-NsbD6XUUMZvBxtQAJuWDJeeC4QFsmWsfozWxCJPWf3M55K9iu2iMDaKqyoOdTJ1R4usBXuxlVFAIo8rZPQD4Bg== + dependencies: + chalk "^2.4.2" + source-map "^0.6.1" + supports-color "^6.1.0" + +process-nextick-args@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.0.tgz#a37d732f4271b4ab1ad070d35508e8290788ffaa" + integrity sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw== + +process@^0.11.10: + version "0.11.10" + resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" + integrity sha1-czIwDoQBYb2j5podHZGn1LwW8YI= + +promise-inflight@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/promise-inflight/-/promise-inflight-1.0.1.tgz#98472870bf228132fcbdd868129bad12c3c029e3" + integrity sha1-mEcocL8igTL8vdhoEputEsPAKeM= + +promise-retry@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/promise-retry/-/promise-retry-1.1.1.tgz#6739e968e3051da20ce6497fb2b50f6911df3d6d" + integrity sha1-ZznpaOMFHaIM5kl/srUPaRHfPW0= + dependencies: + err-code "^1.0.0" + retry "^0.10.0" + +promise@^7.1.1: + version "7.3.1" + resolved "https://registry.yarnpkg.com/promise/-/promise-7.3.1.tgz#064b72602b18f90f29192b8b1bc418ffd1ebd3bf" + integrity sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg== + dependencies: + asap "~2.0.3" + +protoduck@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/protoduck/-/protoduck-5.0.1.tgz#03c3659ca18007b69a50fd82a7ebcc516261151f" + integrity sha512-WxoCeDCoCBY55BMvj4cAEjdVUFGRWed9ZxPlqTKYyw1nDDTQ4pqmnIMAGfJlg7Dx35uB/M+PHJPTmGOvaCaPTg== + dependencies: + genfun "^5.0.0" + +protractor@~5.4.0: + version "5.4.2" + resolved "https://registry.yarnpkg.com/protractor/-/protractor-5.4.2.tgz#329efe37f48b2141ab9467799be2d4d12eb48c13" + integrity sha512-zlIj64Cr6IOWP7RwxVeD8O4UskLYPoyIcg0HboWJL9T79F1F0VWtKkGTr/9GN6BKL+/Q/GmM7C9kFVCfDbP5sA== + dependencies: + "@types/q" "^0.0.32" + "@types/selenium-webdriver" "^3.0.0" + blocking-proxy "^1.0.0" + browserstack "^1.5.1" + chalk "^1.1.3" + glob "^7.0.3" + jasmine "2.8.0" + jasminewd2 "^2.1.0" + optimist "~0.6.0" + q "1.4.1" + saucelabs "^1.5.0" + selenium-webdriver "3.6.0" + source-map-support "~0.4.0" + webdriver-js-extender "2.1.0" + webdriver-manager "^12.0.6" + +proxy-addr@~2.0.4: + version "2.0.5" + resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.5.tgz#34cbd64a2d81f4b1fd21e76f9f06c8a45299ee34" + integrity sha512-t/7RxHXPH6cJtP0pRG6smSr9QJidhB+3kXu0KgXnbGYMgzEnUxRQ4/LDdfOwZEMyIh3/xHb8PX3t+lfL9z+YVQ== + dependencies: + forwarded "~0.1.2" + ipaddr.js "1.9.0" + +prr@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/prr/-/prr-1.0.1.tgz#d3fc114ba06995a45ec6893f484ceb1d78f5f476" + integrity sha1-0/wRS6BplaRexok/SEzrHXj19HY= + +pseudomap@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3" + integrity sha1-8FKijacOYYkX7wqKw0wa5aaChrM= + +psl@^1.1.24: + version "1.1.31" + resolved "https://registry.yarnpkg.com/psl/-/psl-1.1.31.tgz#e9aa86d0101b5b105cbe93ac6b784cd547276184" + integrity sha512-/6pt4+C+T+wZUieKR620OpzN/LlnNKuWjy1iFLQ/UG35JqHlR/89MP1d96dUfkf6Dne3TuLQzOYEYshJ+Hx8mw== + +public-encrypt@^4.0.0: + version "4.0.3" + resolved "https://registry.yarnpkg.com/public-encrypt/-/public-encrypt-4.0.3.tgz#4fcc9d77a07e48ba7527e7cbe0de33d0701331e0" + integrity sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q== + dependencies: + bn.js "^4.1.0" + browserify-rsa "^4.0.0" + create-hash "^1.1.0" + parse-asn1 "^5.0.0" + randombytes "^2.0.1" + safe-buffer "^5.1.2" + +pump@^2.0.0, pump@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/pump/-/pump-2.0.1.tgz#12399add6e4cf7526d973cbc8b5ce2e2908b3909" + integrity sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA== + dependencies: + end-of-stream "^1.1.0" + once "^1.3.1" + +pump@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64" + integrity sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww== + dependencies: + end-of-stream "^1.1.0" + once "^1.3.1" + +pumpify@^1.3.3: + version "1.5.1" + resolved "https://registry.yarnpkg.com/pumpify/-/pumpify-1.5.1.tgz#36513be246ab27570b1a374a5ce278bfd74370ce" + integrity sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ== + dependencies: + duplexify "^3.6.0" + inherits "^2.0.3" + pump "^2.0.0" + +punycode@1.3.2: + version "1.3.2" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d" + integrity sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0= + +punycode@^1.2.4, punycode@^1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" + integrity sha1-wNWmOycYgArY4esPpSachN1BhF4= + +punycode@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" + integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== + +q@1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/q/-/q-1.4.1.tgz#55705bcd93c5f3673530c2c2cbc0c2b3addc286e" + integrity sha1-VXBbzZPF82c1MMLCy8DCs63cKG4= + +q@^1.4.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7" + integrity sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc= + +qjobs@^1.1.4: + version "1.2.0" + resolved "https://registry.yarnpkg.com/qjobs/-/qjobs-1.2.0.tgz#c45e9c61800bd087ef88d7e256423bdd49e5d071" + integrity sha512-8YOJEHtxpySA3fFDyCRxA+UUV+fA+rTWnuWvylOK/NCjhY+b4ocCtmu8TtsWb+mYeU+GCHf/S66KZF/AsteKHg== + +qs@6.5.2, qs@~6.5.2: + version "6.5.2" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36" + integrity sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA== + +querystring-es3@^0.2.0: + version "0.2.1" + resolved "https://registry.yarnpkg.com/querystring-es3/-/querystring-es3-0.2.1.tgz#9ec61f79049875707d69414596fd907a4d711e73" + integrity sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM= + +querystring@0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620" + integrity sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA= + +querystringify@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-2.1.1.tgz#60e5a5fd64a7f8bfa4d2ab2ed6fdf4c85bad154e" + integrity sha512-w7fLxIRCRT7U8Qu53jQnJyPkYZIaR4n5151KMfcJlO/A9397Wxb1amJvROTK6TOnp7PfoAmg/qXiNHI+08jRfA== + +randombytes@^2.0.0, randombytes@^2.0.1, randombytes@^2.0.5: + version "2.1.0" + resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" + integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ== + dependencies: + safe-buffer "^5.1.0" + +randomfill@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/randomfill/-/randomfill-1.0.4.tgz#c92196fc86ab42be983f1bf31778224931d61458" + integrity sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw== + dependencies: + randombytes "^2.0.5" + safe-buffer "^5.1.0" + +range-parser@^1.0.3, range-parser@^1.2.0, range-parser@~1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.0.tgz#f49be6b487894ddc40dcc94a322f611092e00d5e" + integrity sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4= + +raw-body@2.3.3: + version "2.3.3" + resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.3.3.tgz#1b324ece6b5706e153855bc1148c65bb7f6ea0c3" + integrity sha512-9esiElv1BrZoI3rCDuOuKCBRbuApGGaDPQfjSflGxdy4oyzqghxu6klEkkVIvBje+FF0BX9coEv8KqW6X/7njw== + dependencies: + bytes "3.0.0" + http-errors "1.6.3" + iconv-lite "0.4.23" + unpipe "1.0.0" + +raw-loader@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/raw-loader/-/raw-loader-1.0.0.tgz#3f9889e73dadbda9a424bce79809b4133ad46405" + integrity sha512-Uqy5AqELpytJTRxYT4fhltcKPj0TyaEpzJDcGz7DFJi+pQOOi3GjR/DOdxTkTsF+NzhnldIoG6TORaBlInUuqA== + dependencies: + loader-utils "^1.1.0" + schema-utils "^1.0.0" + +rc@^1.2.7: + version "1.2.8" + resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed" + integrity sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw== + dependencies: + deep-extend "^0.6.0" + ini "~1.3.0" + minimist "^1.2.0" + strip-json-comments "~2.0.1" + +read-cache@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/read-cache/-/read-cache-1.0.0.tgz#e664ef31161166c9751cdbe8dbcf86b5fb58f774" + integrity sha1-5mTvMRYRZsl1HNvo28+GtftY93Q= + dependencies: + pify "^2.3.0" + +read-pkg-up@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-1.0.1.tgz#9d63c13276c065918d57f002a57f40a1b643fb02" + integrity sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI= + dependencies: + find-up "^1.0.0" + read-pkg "^1.0.0" + +read-pkg-up@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-2.0.0.tgz#6b72a8048984e0c41e79510fd5e9fa99b3b549be" + integrity sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4= + dependencies: + find-up "^2.0.0" + read-pkg "^2.0.0" + +read-pkg@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-1.1.0.tgz#f5ffaa5ecd29cb31c0474bca7d756b6bb29e3f28" + integrity sha1-9f+qXs0pyzHAR0vKfXVra7KePyg= + dependencies: + load-json-file "^1.0.0" + normalize-package-data "^2.3.2" + path-type "^1.0.0" + +read-pkg@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-2.0.0.tgz#8ef1c0623c6a6db0dc6713c4bfac46332b2368f8" + integrity sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg= + dependencies: + load-json-file "^2.0.0" + normalize-package-data "^2.3.2" + path-type "^2.0.0" + +"readable-stream@1 || 2", readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.6, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.3.3, readable-stream@^2.3.6, readable-stream@~2.3.6: + version "2.3.6" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf" + integrity sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw== + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.3" + isarray "~1.0.0" + process-nextick-args "~2.0.0" + safe-buffer "~5.1.1" + string_decoder "~1.1.1" + util-deprecate "~1.0.1" + +readable-stream@^3.0.6: + version "3.3.0" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.3.0.tgz#cb8011aad002eb717bf040291feba8569c986fb9" + integrity sha512-EsI+s3k3XsW+fU8fQACLN59ky34AZ14LoeVZpYwmZvldCFo0r0gnelwF2TcMjLor/BTL5aDJVBMkss0dthToPw== + dependencies: + inherits "^2.0.3" + string_decoder "^1.1.1" + util-deprecate "^1.0.1" + +readdirp@^2.0.0, readdirp@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.2.1.tgz#0e87622a3325aa33e892285caf8b4e846529a525" + integrity sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ== + dependencies: + graceful-fs "^4.1.11" + micromatch "^3.1.10" + readable-stream "^2.0.2" + +rechoir@^0.6.2: + version "0.6.2" + resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.6.2.tgz#85204b54dba82d5742e28c96756ef43af50e3384" + integrity sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q= + dependencies: + resolve "^1.1.6" + +redent@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/redent/-/redent-1.0.0.tgz#cf916ab1fd5f1f16dfb20822dd6ec7f730c2afde" + integrity sha1-z5Fqsf1fHxbfsggi3W7H9zDCr94= + dependencies: + indent-string "^2.1.0" + strip-indent "^1.0.1" + +reflect-metadata@^0.1.2: + version "0.1.13" + resolved "https://registry.yarnpkg.com/reflect-metadata/-/reflect-metadata-0.1.13.tgz#67ae3ca57c972a2aa1642b10fe363fe32d49dc08" + integrity sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg== + +regenerate@^1.2.1: + version "1.4.0" + resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.0.tgz#4a856ec4b56e4077c557589cae85e7a4c8869a11" + integrity sha512-1G6jJVDWrt0rK99kBjvEtziZNCICAuvIPkSiUFIQxVP06RCVpq3dmDo2oi6ABpYaDYaTRr67BEhL8r1wgEZZKg== + +regenerator-runtime@^0.11.0: + version "0.11.1" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9" + integrity sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg== + +regex-not@^1.0.0, regex-not@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/regex-not/-/regex-not-1.0.2.tgz#1f4ece27e00b0b65e0247a6810e6a85d83a5752c" + integrity sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A== + dependencies: + extend-shallow "^3.0.2" + safe-regex "^1.1.0" + +regexpu-core@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-1.0.0.tgz#86a763f58ee4d7c2f6b102e4764050de7ed90c6b" + integrity sha1-hqdj9Y7k18L2sQLkdkBQ3n7ZDGs= + dependencies: + regenerate "^1.2.1" + regjsgen "^0.2.0" + regjsparser "^0.1.4" + +regjsgen@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.2.0.tgz#6c016adeac554f75823fe37ac05b92d5a4edb1f7" + integrity sha1-bAFq3qxVT3WCP+N6wFuS1aTtsfc= + +regjsparser@^0.1.4: + version "0.1.5" + resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.1.5.tgz#7ee8f84dc6fa792d3fd0ae228d24bd949ead205c" + integrity sha1-fuj4Tcb6eS0/0K4ijSS9lJ6tIFw= + dependencies: + jsesc "~0.5.0" + +remove-trailing-separator@^1.0.1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef" + integrity sha1-wkvOKig62tW8P1jg1IJJuSN52O8= + +repeat-element@^1.1.2: + version "1.1.3" + resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.3.tgz#782e0d825c0c5a3bb39731f84efee6b742e6b1ce" + integrity sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g== + +repeat-string@^1.6.1: + version "1.6.1" + resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" + integrity sha1-jcrkcOHIirwtYA//Sndihtp15jc= + +repeating@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/repeating/-/repeating-2.0.1.tgz#5214c53a926d3552707527fbab415dbc08d06dda" + integrity sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo= + dependencies: + is-finite "^1.0.0" + +request@^2.83.0, request@^2.87.0, request@^2.88.0: + version "2.88.0" + resolved "https://registry.yarnpkg.com/request/-/request-2.88.0.tgz#9c2fca4f7d35b592efe57c7f0a55e81052124fef" + integrity sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg== + dependencies: + aws-sign2 "~0.7.0" + aws4 "^1.8.0" + caseless "~0.12.0" + combined-stream "~1.0.6" + extend "~3.0.2" + forever-agent "~0.6.1" + form-data "~2.3.2" + har-validator "~5.1.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" + +require-directory@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" + integrity sha1-jGStX9MNqxyXbiNE/+f3kqam30I= + +require-from-string@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909" + integrity sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw== + +require-main-filename@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1" + integrity sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE= + +requires-port@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" + integrity sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8= + +resolve-cwd@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-2.0.0.tgz#00a9f7387556e27038eae232caa372a6a59b665a" + integrity sha1-AKn3OHVW4nA46uIyyqNypqWbZlo= + dependencies: + resolve-from "^3.0.0" + +resolve-from@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-3.0.0.tgz#b22c7af7d9d6881bc8b6e653335eebcb0a188748" + integrity sha1-six699nWiBvItuZTM17rywoYh0g= + +resolve-url@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" + integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo= + +resolve@^1.1.6, resolve@^1.1.7, resolve@^1.10.0, resolve@^1.3.2: + version "1.10.0" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.10.0.tgz#3bdaaeaf45cc07f375656dfd2e54ed0810b101ba" + integrity sha512-3sUr9aq5OfSg2S9pNtPA9hL1FVEAjvfOC4leW0SNf/mpnaakz2a9femSd6LqAww2RaFctwyf1lCqnTHuF1rxDg== + dependencies: + path-parse "^1.0.6" + +restore-cursor@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-2.0.0.tgz#9f7ee287f82fd326d4fd162923d62129eee0dfaf" + integrity sha1-n37ih/gv0ybU/RYpI9YhKe7g368= + dependencies: + onetime "^2.0.0" + signal-exit "^3.0.2" + +ret@~0.1.10: + version "0.1.15" + resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc" + integrity sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg== + +retry@^0.10.0: + version "0.10.1" + resolved "https://registry.yarnpkg.com/retry/-/retry-0.10.1.tgz#e76388d217992c252750241d3d3956fed98d8ff4" + integrity sha1-52OI0heZLCUnUCQdPTlW/tmNj/Q= + +rfdc@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/rfdc/-/rfdc-1.1.2.tgz#e6e72d74f5dc39de8f538f65e00c36c18018e349" + integrity sha512-92ktAgvZhBzYTIK0Mja9uen5q5J3NRVMoDkJL2VMwq6SXjVCgqvQeVP2XAaUY6HT+XpQYeLSjb3UoitBryKmdA== + +rimraf@2, rimraf@^2.2.8, rimraf@^2.5.2, rimraf@^2.5.4, rimraf@^2.6.0, rimraf@^2.6.1, rimraf@^2.6.2: + version "2.6.3" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab" + integrity sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA== + dependencies: + glob "^7.1.3" + +ripemd160@^2.0.0, ripemd160@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-2.0.2.tgz#a1c1a6f624751577ba5d07914cbc92850585890c" + integrity sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA== + dependencies: + hash-base "^3.0.0" + inherits "^2.0.1" + +run-async@^2.2.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.3.0.tgz#0371ab4ae0bdd720d4166d7dfda64ff7a445a6c0" + integrity sha1-A3GrSuC91yDUFm19/aZP96RFpsA= + dependencies: + is-promise "^2.1.0" + +run-queue@^1.0.0, run-queue@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/run-queue/-/run-queue-1.0.3.tgz#e848396f057d223f24386924618e25694161ec47" + integrity sha1-6Eg5bwV9Ij8kOGkkYY4laUFh7Ec= + dependencies: + aproba "^1.1.1" + +rxjs@6.3.3, rxjs@~6.3.3: + version "6.3.3" + resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.3.3.tgz#3c6a7fa420e844a81390fb1158a9ec614f4bad55" + integrity sha512-JTWmoY9tWCs7zvIk/CvRjhjGaOd+OVBM987mxFo+OW66cGpdKjZcpmc74ES1sB//7Kl/PAe8+wEakuhG4pcgOw== + dependencies: + tslib "^1.9.0" + +rxjs@^6.1.0: + version "6.4.0" + resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.4.0.tgz#f3bb0fe7bda7fb69deac0c16f17b50b0b8790504" + integrity sha512-Z9Yfa11F6B9Sg/BK9MnqnQ+aQYicPLtilXBp2yUtDt2JRCE0h26d33EnfO3ZxoNxG0T92OUucP3Ct7cpfkdFfw== + dependencies: + tslib "^1.9.0" + +safe-buffer@5.1.2, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: + version "5.1.2" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" + integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== + +safe-regex@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/safe-regex/-/safe-regex-1.1.0.tgz#40a3669f3b077d1e943d44629e157dd48023bf2e" + integrity sha1-QKNmnzsHfR6UPURinhV91IAjvy4= + dependencies: + ret "~0.1.10" + +"safer-buffer@>= 2.1.2 < 3", safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0: + version "2.1.2" + resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" + integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== + +sass-graph@^2.2.4: + version "2.2.4" + resolved "https://registry.yarnpkg.com/sass-graph/-/sass-graph-2.2.4.tgz#13fbd63cd1caf0908b9fd93476ad43a51d1e0b49" + integrity sha1-E/vWPNHK8JCLn9k0dq1DpR0eC0k= + dependencies: + glob "^7.0.0" + lodash "^4.0.0" + scss-tokenizer "^0.2.3" + yargs "^7.0.0" + +sass-loader@7.1.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/sass-loader/-/sass-loader-7.1.0.tgz#16fd5138cb8b424bf8a759528a1972d72aad069d" + integrity sha512-+G+BKGglmZM2GUSfT9TLuEp6tzehHPjAMoRRItOojWIqIGPloVCMhNIQuG639eJ+y033PaGTSjLaTHts8Kw79w== + dependencies: + clone-deep "^2.0.1" + loader-utils "^1.0.1" + lodash.tail "^4.1.1" + neo-async "^2.5.0" + pify "^3.0.0" + semver "^5.5.0" + +saucelabs@^1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/saucelabs/-/saucelabs-1.5.0.tgz#9405a73c360d449b232839919a86c396d379fd9d" + integrity sha512-jlX3FGdWvYf4Q3LFfFWS1QvPg3IGCGWxIc8QBFdPTbpTJnt/v17FHXYVAn7C8sHf1yUXo2c7yIM0isDryfYtHQ== + dependencies: + https-proxy-agent "^2.2.1" + +sax@0.5.x: + version "0.5.8" + resolved "https://registry.yarnpkg.com/sax/-/sax-0.5.8.tgz#d472db228eb331c2506b0e8c15524adb939d12c1" + integrity sha1-1HLbIo6zMcJQaw6MFVJK25OdEsE= + +sax@>=0.6.0, sax@^1.2.4: + version "1.2.4" + resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" + integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== + +schema-utils@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-0.3.0.tgz#f5877222ce3e931edae039f17eb3716e7137f8cf" + integrity sha1-9YdyIs4+kx7a4DnxfrNxbnE3+M8= + dependencies: + ajv "^5.0.0" + +schema-utils@^0.4.4: + version "0.4.7" + resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-0.4.7.tgz#ba74f597d2be2ea880131746ee17d0a093c68187" + integrity sha512-v/iwU6wvwGK8HbU9yi3/nhGzP0yGSuhQMzL6ySiec1FSrZZDkhm4noOSWzrNFo/jEc+SJY6jRTwuwbSXJPDUnQ== + dependencies: + ajv "^6.1.0" + ajv-keywords "^3.1.0" + +schema-utils@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-1.0.0.tgz#0b79a93204d7b600d4b2850d1f66c2a34951c770" + integrity sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g== + dependencies: + ajv "^6.1.0" + ajv-errors "^1.0.0" + ajv-keywords "^3.1.0" + +scss-tokenizer@^0.2.3: + version "0.2.3" + resolved "https://registry.yarnpkg.com/scss-tokenizer/-/scss-tokenizer-0.2.3.tgz#8eb06db9a9723333824d3f5530641149847ce5d1" + integrity sha1-jrBtualyMzOCTT9VMGQRSYR85dE= + dependencies: + js-base64 "^2.1.8" + source-map "^0.4.2" + +select-hose@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/select-hose/-/select-hose-2.0.0.tgz#625d8658f865af43ec962bfc376a37359a4994ca" + integrity sha1-Yl2GWPhlr0Psliv8N2o3NZpJlMo= + +selenium-webdriver@3.6.0, selenium-webdriver@^3.0.1: + version "3.6.0" + resolved "https://registry.yarnpkg.com/selenium-webdriver/-/selenium-webdriver-3.6.0.tgz#2ba87a1662c020b8988c981ae62cb2a01298eafc" + integrity sha512-WH7Aldse+2P5bbFBO4Gle/nuQOdVwpHMTL6raL3uuBj/vPG07k6uzt3aiahu352ONBr5xXh0hDlM3LhtXPOC4Q== + dependencies: + jszip "^3.1.3" + rimraf "^2.5.4" + tmp "0.0.30" + xml2js "^0.4.17" + +selfsigned@^1.9.1: + version "1.10.4" + resolved "https://registry.yarnpkg.com/selfsigned/-/selfsigned-1.10.4.tgz#cdd7eccfca4ed7635d47a08bf2d5d3074092e2cd" + integrity sha512-9AukTiDmHXGXWtWjembZ5NDmVvP2695EtpgbCsxCa68w3c88B+alqbmZ4O3hZ4VWGXeGWzEVdvqgAJD8DQPCDw== + dependencies: + node-forge "0.7.5" + +semver-dsl@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/semver-dsl/-/semver-dsl-1.0.1.tgz#d3678de5555e8a61f629eed025366ae5f27340a0" + integrity sha1-02eN5VVeimH2Ke7QJTZq5fJzQKA= + dependencies: + semver "^5.3.0" + +semver-intersect@1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/semver-intersect/-/semver-intersect-1.4.0.tgz#bdd9c06bedcdd2fedb8cd352c3c43ee8c61321f3" + integrity sha512-d8fvGg5ycKAq0+I6nfWeCx6ffaWJCsBYU0H2Rq56+/zFePYfT8mXkB3tWBSjR5BerkHNZ5eTPIk1/LBYas35xQ== + dependencies: + semver "^5.0.0" + +"semver@2 || 3 || 4 || 5", semver@^5.0.0, semver@^5.3.0, semver@^5.4.1, semver@^5.5.0, semver@^5.6.0: + version "5.7.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.0.tgz#790a7cf6fea5459bac96110b29b60412dc8ff96b" + integrity sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA== + +semver@5.6.0: + version "5.6.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.6.0.tgz#7e74256fbaa49c75aa7c7a205cc22799cac80004" + integrity sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg== + +semver@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-6.0.0.tgz#05e359ee571e5ad7ed641a6eec1e547ba52dea65" + integrity sha512-0UewU+9rFapKFnlbirLi3byoOuhrSsli/z/ihNnvM24vgF+8sNBiI1LZPBSH9wJKUwaUbw+s3hToDLCXkrghrQ== + +semver@~5.3.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.3.0.tgz#9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f" + integrity sha1-myzl094C0XxgEq0yaqa00M9U+U8= + +send@0.16.2: + version "0.16.2" + resolved "https://registry.yarnpkg.com/send/-/send-0.16.2.tgz#6ecca1e0f8c156d141597559848df64730a6bbc1" + integrity sha512-E64YFPUssFHEFBvpbbjr44NCLtI1AohxQ8ZSiJjQLskAdKuriYEP6VyGEsRDH8ScozGpkaX1BGvhanqCwkcEZw== + dependencies: + debug "2.6.9" + depd "~1.1.2" + destroy "~1.0.4" + encodeurl "~1.0.2" + escape-html "~1.0.3" + etag "~1.8.1" + fresh "0.5.2" + http-errors "~1.6.2" + mime "1.4.1" + ms "2.0.0" + on-finished "~2.3.0" + range-parser "~1.2.0" + statuses "~1.4.0" + +serialize-javascript@^1.4.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-1.7.0.tgz#d6e0dfb2a3832a8c94468e6eb1db97e55a192a65" + integrity sha512-ke8UG8ulpFOxO8f8gRYabHQe/ZntKlcig2Mp+8+URDP1D8vJZ0KUt7LYo07q25Z/+JVSgpr/cui9PIp5H6/+nA== + +serve-index@^1.7.2: + version "1.9.1" + resolved "https://registry.yarnpkg.com/serve-index/-/serve-index-1.9.1.tgz#d3768d69b1e7d82e5ce050fff5b453bea12a9239" + integrity sha1-03aNabHn2C5c4FD/9bRTvqEqkjk= + dependencies: + accepts "~1.3.4" + batch "0.6.1" + debug "2.6.9" + escape-html "~1.0.3" + http-errors "~1.6.2" + mime-types "~2.1.17" + parseurl "~1.3.2" + +serve-static@1.13.2: + version "1.13.2" + resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.13.2.tgz#095e8472fd5b46237db50ce486a43f4b86c6cec1" + integrity sha512-p/tdJrO4U387R9oMjb1oj7qSMaMfmOyd4j9hOFoxZe2baQszgHcSWjuya/CiT5kgZZKRudHNOA0pYXOl8rQ5nw== + dependencies: + encodeurl "~1.0.2" + escape-html "~1.0.3" + parseurl "~1.3.2" + send "0.16.2" + +set-blocking@^2.0.0, set-blocking@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" + integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc= + +set-immediate-shim@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz#4b2b1b27eb808a9f8dcc481a58e5e56f599f3f61" + integrity sha1-SysbJ+uAip+NzEgaWOXlb1mfP2E= + +set-value@^0.4.3: + version "0.4.3" + resolved "https://registry.yarnpkg.com/set-value/-/set-value-0.4.3.tgz#7db08f9d3d22dc7f78e53af3c3bf4666ecdfccf1" + integrity sha1-fbCPnT0i3H945Trzw79GZuzfzPE= + dependencies: + extend-shallow "^2.0.1" + is-extendable "^0.1.1" + is-plain-object "^2.0.1" + to-object-path "^0.3.0" + +set-value@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/set-value/-/set-value-2.0.0.tgz#71ae4a88f0feefbbf52d1ea604f3fb315ebb6274" + integrity sha512-hw0yxk9GT/Hr5yJEYnHNKYXkIA8mVJgd9ditYZCe16ZczcaELYYcfvaXesNACk2O8O0nTiPQcQhGUQj8JLzeeg== + dependencies: + extend-shallow "^2.0.1" + is-extendable "^0.1.1" + is-plain-object "^2.0.3" + split-string "^3.0.1" + +setimmediate@^1.0.4: + version "1.0.5" + resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" + integrity sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU= + +setprototypeof@1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.0.tgz#d0bd85536887b6fe7c0d818cb962d9d91c54e656" + integrity sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ== + +sha.js@^2.4.0, sha.js@^2.4.8: + version "2.4.11" + resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.4.11.tgz#37a5cf0b81ecbc6943de109ba2960d1b26584ae7" + integrity sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ== + dependencies: + inherits "^2.0.1" + safe-buffer "^5.0.1" + +shallow-clone@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/shallow-clone/-/shallow-clone-1.0.0.tgz#4480cd06e882ef68b2ad88a3ea54832e2c48b571" + integrity sha512-oeXreoKR/SyNJtRJMAKPDSvd28OqEwG4eR/xc856cRGBII7gX9lvAqDxusPm0846z/w/hWYjI1NpKwJ00NHzRA== + dependencies: + is-extendable "^0.1.1" + kind-of "^5.0.0" + mixin-object "^2.0.1" + +shebang-command@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" + integrity sha1-RKrGW2lbAzmJaMOfNj/uXer98eo= + dependencies: + shebang-regex "^1.0.0" + +shebang-regex@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" + integrity sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM= + +shelljs@^0.8.1: + version "0.8.3" + resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.8.3.tgz#a7f3319520ebf09ee81275b2368adb286659b097" + integrity sha512-fc0BKlAWiLpwZljmOvAOTE/gXawtCoNrP5oaY7KIaQbbyHeQVg01pSEuEGvGh3HEdBU4baCD7wQBwADmM/7f7A== + dependencies: + glob "^7.0.0" + interpret "^1.0.0" + rechoir "^0.6.2" + +signal-exit@^3.0.0, signal-exit@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" + integrity sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0= + +slash@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55" + integrity sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU= + +smart-buffer@4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/smart-buffer/-/smart-buffer-4.0.2.tgz#5207858c3815cc69110703c6b94e46c15634395d" + integrity sha512-JDhEpTKzXusOqXZ0BUIdH+CjFdO/CR3tLlf5CN34IypI+xMmXW1uB16OOY8z3cICbJlDAVJzNbwBhNO0wt9OAw== + +snapdragon-node@^2.0.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b" + integrity sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw== + dependencies: + define-property "^1.0.0" + isobject "^3.0.0" + snapdragon-util "^3.0.1" + +snapdragon-util@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/snapdragon-util/-/snapdragon-util-3.0.1.tgz#f956479486f2acd79700693f6f7b805e45ab56e2" + integrity sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ== + dependencies: + kind-of "^3.2.0" + +snapdragon@^0.8.1: + version "0.8.2" + resolved "https://registry.yarnpkg.com/snapdragon/-/snapdragon-0.8.2.tgz#64922e7c565b0e14204ba1aa7d6964278d25182d" + integrity sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg== + dependencies: + base "^0.11.1" + debug "^2.2.0" + define-property "^0.2.5" + extend-shallow "^2.0.1" + map-cache "^0.2.2" + source-map "^0.5.6" + source-map-resolve "^0.5.0" + use "^3.1.0" + +socket.io-adapter@~1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/socket.io-adapter/-/socket.io-adapter-1.1.1.tgz#2a805e8a14d6372124dd9159ad4502f8cb07f06b" + integrity sha1-KoBeihTWNyEk3ZFZrUUC+MsH8Gs= + +socket.io-client@2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/socket.io-client/-/socket.io-client-2.1.1.tgz#dcb38103436ab4578ddb026638ae2f21b623671f" + integrity sha512-jxnFyhAuFxYfjqIgduQlhzqTcOEQSn+OHKVfAxWaNWa7ecP7xSNk2Dx/3UEsDcY7NcFafxvNvKPmmO7HTwTxGQ== + dependencies: + 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.2.0" + 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.2.0" + to-array "0.1.4" + +socket.io-parser@~3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/socket.io-parser/-/socket.io-parser-3.2.0.tgz#e7c6228b6aa1f814e6148aea325b51aa9499e077" + integrity sha512-FYiBx7rc/KORMJlgsXysflWx/RIvtqZbyGLlHZvjfmPTPeuD/I8MaW7cfFrj5tRltICJdgwflhfZ3NVVbVLFQA== + dependencies: + component-emitter "1.2.1" + debug "~3.1.0" + isarray "2.0.1" + +socket.io@2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/socket.io/-/socket.io-2.1.1.tgz#a069c5feabee3e6b214a75b40ce0652e1cfb9980" + integrity sha512-rORqq9c+7W0DAK3cleWNSyfv/qKXV99hV4tZe+gGLfBECw3XEhBy7x85F3wypA9688LKjtwO9pX9L33/xQI8yA== + dependencies: + debug "~3.1.0" + engine.io "~3.2.0" + has-binary2 "~1.0.2" + socket.io-adapter "~1.1.0" + socket.io-client "2.1.1" + socket.io-parser "~3.2.0" + +sockjs-client@1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/sockjs-client/-/sockjs-client-1.3.0.tgz#12fc9d6cb663da5739d3dc5fb6e8687da95cb177" + integrity sha512-R9jxEzhnnrdxLCNln0xg5uGHqMnkhPSTzUZH2eXcR03S/On9Yvoq2wyUZILRUhZCNVu2PmwWVoyuiPz8th8zbg== + dependencies: + 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" + +sockjs@0.3.19: + version "0.3.19" + resolved "https://registry.yarnpkg.com/sockjs/-/sockjs-0.3.19.tgz#d976bbe800af7bd20ae08598d582393508993c0d" + integrity sha512-V48klKZl8T6MzatbLlzzRNhMepEys9Y4oGFpypBFFn1gLI/QQ9HtLLyWJNbPlwGLelOVOEijUbTTJeLLI59jLw== + dependencies: + faye-websocket "^0.10.0" + uuid "^3.0.1" + +socks-proxy-agent@^4.0.0: + version "4.0.2" + resolved "https://registry.yarnpkg.com/socks-proxy-agent/-/socks-proxy-agent-4.0.2.tgz#3c8991f3145b2799e70e11bd5fbc8b1963116386" + integrity sha512-NT6syHhI9LmuEMSK6Kd2V7gNv5KFZoLE7V5udWmn0de+3Mkj3UMA/AJPLyeNUVmElCurSHtUdM3ETpR3z770Wg== + dependencies: + agent-base "~4.2.1" + socks "~2.3.2" + +socks@~2.3.2: + version "2.3.2" + resolved "https://registry.yarnpkg.com/socks/-/socks-2.3.2.tgz#ade388e9e6d87fdb11649c15746c578922a5883e" + integrity sha512-pCpjxQgOByDHLlNqlnh/mNSAxIUkyBBuwwhTcV+enZGbDaClPvHdvm6uvOwZfFJkam7cGhBNbb4JxiP8UZkRvQ== + dependencies: + ip "^1.1.5" + smart-buffer "4.0.2" + +source-list-map@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-2.0.1.tgz#3993bd873bfc48479cca9ea3a547835c7c154b34" + integrity sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw== + +source-list-map@~0.1.7: + version "0.1.8" + resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-0.1.8.tgz#c550b2ab5427f6b3f21f5afead88c4f5587b2106" + integrity sha1-xVCyq1Qn9rPyH1r+rYjE9Vh7IQY= + +source-map-loader@0.2.4: + version "0.2.4" + resolved "https://registry.yarnpkg.com/source-map-loader/-/source-map-loader-0.2.4.tgz#c18b0dc6e23bf66f6792437557c569a11e072271" + integrity sha512-OU6UJUty+i2JDpTItnizPrlpOIBLmQbWMuBg9q5bVtnHACqw1tn9nNwqJLbv0/00JjnJb/Ee5g5WS5vrRv7zIQ== + dependencies: + async "^2.5.0" + loader-utils "^1.1.0" + +source-map-resolve@^0.5.0: + version "0.5.2" + resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.2.tgz#72e2cc34095543e43b2c62b2c4c10d4a9054f259" + integrity sha512-MjqsvNwyz1s0k81Goz/9vRBe9SZdB09Bdw+/zYyO+3CuPk6fouTaxscHkgtE8jKvf01kVfl8riHzERQ/kefaSA== + dependencies: + 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@0.5.10: + version "0.5.10" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.10.tgz#2214080bc9d51832511ee2bab96e3c2f9353120c" + integrity sha512-YfQ3tQFTK/yzlGJuX8pTwa4tifQj4QS2Mj7UegOu8jAz59MqIiMGPXxQhVQiIMNzayuUSF/jEuVnfFF5JqybmQ== + dependencies: + buffer-from "^1.0.0" + source-map "^0.6.0" + +source-map-support@^0.5.5, source-map-support@^0.5.6, source-map-support@~0.5.10: + version "0.5.12" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.12.tgz#b4f3b10d51857a5af0138d3ce8003b201613d599" + integrity sha512-4h2Pbvyy15EE02G+JOZpUCmqWJuqrs+sEkzewTm++BPi7Hvn/HwcqLAcNxYAyI0x13CpPPn+kMjl+hplXMHITQ== + dependencies: + buffer-from "^1.0.0" + source-map "^0.6.0" + +source-map-support@~0.4.0: + version "0.4.18" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.4.18.tgz#0286a6de8be42641338594e97ccea75f0a2c585f" + integrity sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA== + dependencies: + source-map "^0.5.6" + +source-map-url@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3" + integrity sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM= + +source-map@0.1.x: + version "0.1.43" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.1.43.tgz#c24bc146ca517c1471f5dacbe2571b2b7f9e3346" + integrity sha1-wkvBRspRfBRx9drL4lcbK3+eM0Y= + dependencies: + amdefine ">=0.0.4" + +source-map@0.5.6: + version "0.5.6" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.6.tgz#75ce38f52bf0733c5a7f0c118d81334a2bb5f412" + integrity sha1-dc449SvwczxafwwRjYEzSiu19BI= + +source-map@0.7.3: + version "0.7.3" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.3.tgz#5302f8169031735226544092e64981f751750383" + integrity sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ== + +source-map@^0.4.2, source-map@~0.4.1: + version "0.4.4" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.4.4.tgz#eba4f5da9c0dc999de68032d8b4f76173652036b" + integrity sha1-66T12pwNyZneaAMti092FzZSA2s= + dependencies: + amdefine ">=0.0.4" + +source-map@^0.5.0, source-map@^0.5.6, source-map@^0.5.7: + version "0.5.7" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" + integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= + +source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.0, source-map@~0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" + integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== + +sourcemap-codec@^1.4.4: + version "1.4.4" + resolved "https://registry.yarnpkg.com/sourcemap-codec/-/sourcemap-codec-1.4.4.tgz#c63ea927c029dd6bd9a2b7fa03b3fec02ad56e9f" + integrity sha512-CYAPYdBu34781kLHkaW3m6b/uUSyMOC2R61gcYMWooeuaGtjof86ZA/8T+qVPPt7np1085CR9hmMGrySwEc8Xg== + +spdx-correct@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.1.0.tgz#fb83e504445268f154b074e218c87c003cd31df4" + integrity sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q== + dependencies: + spdx-expression-parse "^3.0.0" + spdx-license-ids "^3.0.0" + +spdx-exceptions@^2.1.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/spdx-exceptions/-/spdx-exceptions-2.2.0.tgz#2ea450aee74f2a89bfb94519c07fcd6f41322977" + integrity sha512-2XQACfElKi9SlVb1CYadKDXvoajPgBVPn/gOQLrTvHdElaVhr7ZEbqJaRnJLVNeaI4cMEAgVCeBMKF6MWRDCRA== + +spdx-expression-parse@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz#99e119b7a5da00e05491c9fa338b7904823b41d0" + integrity sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg== + dependencies: + spdx-exceptions "^2.1.0" + spdx-license-ids "^3.0.0" + +spdx-license-ids@^3.0.0: + version "3.0.4" + resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.4.tgz#75ecd1a88de8c184ef015eafb51b5b48bfd11bb1" + integrity sha512-7j8LYJLeY/Yb6ACbQ7F76qy5jHkp0U6jgBfJsk97bwWlVUnUWsAgpyaCvo17h0/RQGnQ036tVDomiwoI4pDkQA== + +spdy-transport@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/spdy-transport/-/spdy-transport-3.0.0.tgz#00d4863a6400ad75df93361a1608605e5dcdcf31" + integrity sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw== + dependencies: + debug "^4.1.0" + detect-node "^2.0.4" + hpack.js "^2.1.6" + obuf "^1.1.2" + readable-stream "^3.0.6" + wbuf "^1.7.3" + +spdy@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/spdy/-/spdy-4.0.0.tgz#81f222b5a743a329aa12cea6a390e60e9b613c52" + integrity sha512-ot0oEGT/PGUpzf/6uk4AWLqkq+irlqHXkrdbk51oWONh3bxQmBuljxPNl66zlRRcIJStWq0QkLUCPOPjgjvU0Q== + dependencies: + debug "^4.1.0" + handle-thing "^2.0.0" + http-deceiver "^1.2.7" + select-hose "^2.0.0" + spdy-transport "^3.0.0" + +speed-measure-webpack-plugin@1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/speed-measure-webpack-plugin/-/speed-measure-webpack-plugin-1.3.1.tgz#69840a5cdc08b4638697dac7db037f595d7f36a0" + integrity sha512-qVIkJvbtS9j/UeZumbdfz0vg+QfG/zxonAjzefZrqzkr7xOncLVXkeGbTpzd1gjCBM4PmVNkWlkeTVhgskAGSQ== + dependencies: + chalk "^2.0.1" + +split-string@^3.0.1, split-string@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2" + integrity sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw== + dependencies: + extend-shallow "^3.0.0" + +sprintf-js@^1.1.1: + version "1.1.2" + resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.1.2.tgz#da1765262bf8c0f571749f2ad6c26300207ae673" + integrity sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug== + +sprintf-js@~1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" + integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= + +sshpk@^1.7.0: + version "1.16.1" + resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.16.1.tgz#fb661c0bef29b39db40769ee39fa70093d6f6877" + integrity sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg== + dependencies: + asn1 "~0.2.3" + assert-plus "^1.0.0" + bcrypt-pbkdf "^1.0.0" + dashdash "^1.12.0" + ecc-jsbn "~0.1.1" + getpass "^0.1.1" + jsbn "~0.1.0" + safer-buffer "^2.0.2" + tweetnacl "~0.14.0" + +ssri@^5.2.4: + version "5.3.0" + resolved "https://registry.yarnpkg.com/ssri/-/ssri-5.3.0.tgz#ba3872c9c6d33a0704a7d71ff045e5ec48999d06" + integrity sha512-XRSIPqLij52MtgoQavH/x/dU1qVKtWUAAZeOHsR9c2Ddi4XerFy3mc1alf+dLJKl9EUIm/Ht+EowFkTUOA6GAQ== + dependencies: + safe-buffer "^5.1.1" + +ssri@^6.0.0, ssri@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/ssri/-/ssri-6.0.1.tgz#2a3c41b28dd45b62b63676ecb74001265ae9edd8" + integrity sha512-3Wge10hNcT1Kur4PDFwEieXSCMCJs/7WvSACcrMYrNp+b8kDL1/0wJch5Ni2WrtwEa2IO8OsVfeKIciKCDx/QA== + dependencies: + figgy-pudding "^3.5.1" + +static-extend@^0.1.1: + version "0.1.2" + resolved "https://registry.yarnpkg.com/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6" + integrity sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY= + dependencies: + define-property "^0.2.5" + object-copy "^0.1.0" + +stats-webpack-plugin@0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/stats-webpack-plugin/-/stats-webpack-plugin-0.7.0.tgz#ccffe9b745de8bbb155571e063f8263fc0e2bc06" + integrity sha512-NT0YGhwuQ0EOX+uPhhUcI6/+1Sq/pMzNuSCBVT4GbFl/ac6I/JZefBcjlECNfAb1t3GOx5dEj1Z7x0cAxeeVLQ== + dependencies: + lodash "^4.17.4" + +"statuses@>= 1.4.0 < 2": + version "1.5.0" + resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" + integrity sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow= + +statuses@~1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.3.1.tgz#faf51b9eb74aaef3b3acf4ad5f61abf24cb7b93e" + integrity sha1-+vUbnrdKrvOzrPStX2Gr8ky3uT4= + +statuses@~1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.4.0.tgz#bb73d446da2796106efcc1b601a253d6c46bd087" + integrity sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew== + +stdout-stream@^1.4.0: + version "1.4.1" + resolved "https://registry.yarnpkg.com/stdout-stream/-/stdout-stream-1.4.1.tgz#5ac174cdd5cd726104aa0c0b2bd83815d8d535de" + integrity sha512-j4emi03KXqJWcIeF8eIXkjMFN1Cmb8gUlDYGeBALLPo5qdyTfA9bOtl8m33lRoC+vFMkP3gl0WsDr6+gzxbbTA== + dependencies: + readable-stream "^2.0.1" + +stream-browserify@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/stream-browserify/-/stream-browserify-2.0.2.tgz#87521d38a44aa7ee91ce1cd2a47df0cb49dd660b" + integrity sha512-nX6hmklHs/gr2FuxYDltq8fJA1GDlxKQCz8O/IM4atRqBH8OORmBNgfvW5gG10GT/qQ9u0CzIvr2X5Pkt6ntqg== + dependencies: + inherits "~2.0.1" + readable-stream "^2.0.2" + +stream-each@^1.1.0: + version "1.2.3" + resolved "https://registry.yarnpkg.com/stream-each/-/stream-each-1.2.3.tgz#ebe27a0c389b04fbcc233642952e10731afa9bae" + integrity sha512-vlMC2f8I2u/bZGqkdfLQW/13Zihpej/7PmSiMQsbYddxuTsJp8vRe2x2FvVExZg7FaOds43ROAuFJwPR4MTZLw== + dependencies: + end-of-stream "^1.1.0" + stream-shift "^1.0.0" + +stream-http@^2.7.2: + version "2.8.3" + resolved "https://registry.yarnpkg.com/stream-http/-/stream-http-2.8.3.tgz#b2d242469288a5a27ec4fe8933acf623de6514fc" + integrity sha512-+TSkfINHDo4J+ZobQLWiMouQYB+UVYFttRA94FpEzzJ7ZdqcL4uUUQ7WkdkI4DSozGmgBUE/a47L+38PenXhUw== + dependencies: + builtin-status-codes "^3.0.0" + inherits "^2.0.1" + readable-stream "^2.3.6" + to-arraybuffer "^1.0.0" + xtend "^4.0.0" + +stream-shift@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/stream-shift/-/stream-shift-1.0.0.tgz#d5c752825e5367e786f78e18e445ea223a155952" + integrity sha1-1cdSgl5TZ+eG944Y5EXqIjoVWVI= + +streamroller@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/streamroller/-/streamroller-1.0.4.tgz#d485c7624796d5e2eb34190c79afcbf006afb5e6" + integrity sha512-Wc2Gm5ygjSX8ZpW9J7Y9FwiSzTlKSvcl0FTTMd3rn7RoxDXpBW+xD9TY5sWL2n0UR61COB0LG1BQvN6nTUQbLQ== + dependencies: + async "^2.6.1" + date-format "^2.0.0" + debug "^3.1.0" + fs-extra "^7.0.0" + lodash "^4.17.10" + +string-width@^1.0.1, string-width@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" + integrity sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M= + dependencies: + code-point-at "^1.0.0" + is-fullwidth-code-point "^1.0.0" + strip-ansi "^3.0.0" + +"string-width@^1.0.2 || 2", string-width@^2.0.0, string-width@^2.1.0, string-width@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" + integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw== + dependencies: + is-fullwidth-code-point "^2.0.0" + strip-ansi "^4.0.0" + +string_decoder@^1.0.0, string_decoder@^1.1.1: + version "1.2.0" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.2.0.tgz#fe86e738b19544afe70469243b2a1ee9240eae8d" + integrity sha512-6YqyX6ZWEYguAxgZzHGL7SsCeGx3V2TtOTqZz1xSTSWnqsbWwbptafNyvf/ACquZUXV3DANr5BDIwNYe1mN42w== + dependencies: + safe-buffer "~5.1.0" + +string_decoder@~1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" + integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== + dependencies: + safe-buffer "~5.1.0" + +strip-ansi@^3.0.0, strip-ansi@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" + integrity sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8= + dependencies: + ansi-regex "^2.0.0" + +strip-ansi@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" + integrity sha1-qEeQIusaw2iocTibY1JixQXuNo8= + dependencies: + ansi-regex "^3.0.0" + +strip-ansi@^5.0.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae" + integrity sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA== + dependencies: + ansi-regex "^4.1.0" + +strip-bom@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-2.0.0.tgz#6219a85616520491f35788bdbf1447a99c7e6b0e" + integrity sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4= + dependencies: + is-utf8 "^0.2.0" + +strip-bom@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" + integrity sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM= + +strip-eof@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" + integrity sha1-u0P/VZim6wXYm1n80SnJgzE2Br8= + +strip-indent@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-1.0.1.tgz#0c7962a6adefa7bbd4ac366460a638552ae1a0a2" + integrity sha1-DHlipq3vp7vUrDZkYKY4VSrhoKI= + dependencies: + get-stdin "^4.0.1" + +strip-json-comments@~2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" + integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo= + +style-loader@0.23.1: + version "0.23.1" + resolved "https://registry.yarnpkg.com/style-loader/-/style-loader-0.23.1.tgz#cb9154606f3e771ab6c4ab637026a1049174d925" + integrity sha512-XK+uv9kWwhZMZ1y7mysB+zoihsEj4wneFWAS5qoiLwzW0WzSqMrrsIy+a3zkQJq0ipFtBpX5W3MqyRIBF/WFGg== + dependencies: + loader-utils "^1.1.0" + schema-utils "^1.0.0" + +stylus-loader@3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/stylus-loader/-/stylus-loader-3.0.2.tgz#27a706420b05a38e038e7cacb153578d450513c6" + integrity sha512-+VomPdZ6a0razP+zinir61yZgpw2NfljeSsdUF5kJuEzlo3khXhY19Fn6l8QQz1GRJGtMCo8nG5C04ePyV7SUA== + dependencies: + loader-utils "^1.0.2" + lodash.clonedeep "^4.5.0" + when "~3.6.x" + +stylus@0.54.5: + version "0.54.5" + resolved "https://registry.yarnpkg.com/stylus/-/stylus-0.54.5.tgz#42b9560931ca7090ce8515a798ba9e6aa3d6dc79" + integrity sha1-QrlWCTHKcJDOhRWnmLqeaqPW3Hk= + dependencies: + css-parse "1.7.x" + debug "*" + glob "7.0.x" + mkdirp "0.5.x" + sax "0.5.x" + source-map "0.1.x" + +supports-color@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" + integrity sha1-U10EXOa2Nj+kARcIRimZXp3zJMc= + +supports-color@^5.1.0, supports-color@^5.3.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" + integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== + dependencies: + has-flag "^3.0.0" + +supports-color@^6.0.0, supports-color@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-6.1.0.tgz#0764abc69c63d5ac842dd4867e8d025e880df8f3" + integrity sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ== + dependencies: + has-flag "^3.0.0" + +symbol-observable@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.2.0.tgz#c22688aed4eab3cdc2dfeacbb561660560a00804" + integrity sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ== + +tapable@^1.0.0, tapable@^1.1.0: + version "1.1.3" + resolved "https://registry.yarnpkg.com/tapable/-/tapable-1.1.3.tgz#a1fccc06b58db61fd7a45da2da44f5f3a3e67ba2" + integrity sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA== + +tar@^2.0.0: + version "2.2.1" + resolved "https://registry.yarnpkg.com/tar/-/tar-2.2.1.tgz#8e4d2a256c0e2185c6b18ad694aec968b83cb1d1" + integrity sha1-jk0qJWwOIYXGsYrWlK7JaLg8sdE= + dependencies: + block-stream "*" + fstream "^1.0.2" + inherits "2" + +tar@^4, tar@^4.4.8: + version "4.4.8" + resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.8.tgz#b19eec3fde2a96e64666df9fdb40c5ca1bc3747d" + integrity sha512-LzHF64s5chPQQS0IYBn9IN5h3i98c12bo4NCO7e0sGM2llXQ3p2FGC5sdENN4cTW48O915Sh+x+EXx7XW96xYQ== + dependencies: + chownr "^1.1.1" + fs-minipass "^1.2.5" + minipass "^2.3.4" + minizlib "^1.1.1" + mkdirp "^0.5.0" + safe-buffer "^5.1.2" + yallist "^3.0.2" + +terser-webpack-plugin@1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-1.2.2.tgz#9bff3a891ad614855a7dde0d707f7db5a927e3d9" + integrity sha512-1DMkTk286BzmfylAvLXwpJrI7dWa5BnFmscV/2dCr8+c56egFcbaeFAl7+sujAjdmpLam21XRdhA4oifLyiWWg== + dependencies: + 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.16.1" + webpack-sources "^1.1.0" + worker-farm "^1.5.2" + +terser-webpack-plugin@^1.1.0: + version "1.2.3" + resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-1.2.3.tgz#3f98bc902fac3e5d0de730869f50668561262ec8" + integrity sha512-GOK7q85oAb/5kE12fMuLdn2btOS9OBZn4VsecpHDywoUC/jLhSAKOiYo0ezx7ss2EXPMzyEWFoE0s1WLE+4+oA== + dependencies: + 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.16.1" + webpack-sources "^1.1.0" + worker-farm "^1.5.2" + +terser@^3.16.1: + version "3.17.0" + resolved "https://registry.yarnpkg.com/terser/-/terser-3.17.0.tgz#f88ffbeda0deb5637f9d24b0da66f4e15ab10cb2" + integrity sha512-/FQzzPJmCpjAH9Xvk2paiWrFq+5M6aVOf+2KRbwhByISDX/EujxsK+BAvrhb6H+2rtrLCHK9N01wO014vrIwVQ== + dependencies: + commander "^2.19.0" + source-map "~0.6.1" + source-map-support "~0.5.10" + +through2@^2.0.0: + version "2.0.5" + resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.5.tgz#01c1e39eb31d07cb7d03a96a70823260b23132cd" + integrity sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ== + dependencies: + readable-stream "~2.3.6" + xtend "~4.0.1" + +"through@>=2.2.7 <3", through@X.X.X, through@^2.3.6: + version "2.3.8" + resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" + integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU= + +thunky@^1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/thunky/-/thunky-1.0.3.tgz#f5df732453407b09191dae73e2a8cc73f381a826" + integrity sha512-YwT8pjmNcAXBZqrubu22P4FYsh2D4dxRmnWBOL8Jk8bUcRUtc5326kx32tuTmFDAZtLOGEVNl8POAR8j896Iow== + +timers-browserify@^2.0.4: + version "2.0.10" + resolved "https://registry.yarnpkg.com/timers-browserify/-/timers-browserify-2.0.10.tgz#1d28e3d2aadf1d5a5996c4e9f95601cd053480ae" + integrity sha512-YvC1SV1XdOUaL6gx5CoGroT3Gu49pK9+TZ38ErPldOWW4j49GI1HKs9DV+KGq/w6y+LZ72W1c8cKz2vzY+qpzg== + dependencies: + setimmediate "^1.0.4" + +tmp@0.0.30: + version "0.0.30" + resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.30.tgz#72419d4a8be7d6ce75148fd8b324e593a711c2ed" + integrity sha1-ckGdSovn1s51FI/YsyTlk6cRwu0= + dependencies: + os-tmpdir "~1.0.1" + +tmp@0.0.33, tmp@0.0.x, tmp@^0.0.33: + version "0.0.33" + resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" + integrity sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw== + dependencies: + os-tmpdir "~1.0.2" + +to-array@0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/to-array/-/to-array-0.1.4.tgz#17e6c11f73dd4f3d74cda7a4ff3238e9ad9bf890" + integrity sha1-F+bBH3PdTz10zaek/zI46a2b+JA= + +to-arraybuffer@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz#7d229b1fcc637e466ca081180836a7aabff83f43" + integrity sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M= + +to-fast-properties@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-1.0.3.tgz#b83571fa4d8c25b82e231b06e3a3055de4ca1a47" + integrity sha1-uDVx+k2MJbguIxsG46MFXeTKGkc= + +to-fast-properties@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" + integrity sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4= + +to-object-path@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/to-object-path/-/to-object-path-0.3.0.tgz#297588b7b0e7e0ac08e04e672f85c1f4999e17af" + integrity sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68= + dependencies: + kind-of "^3.0.2" + +to-regex-range@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-2.1.1.tgz#7c80c17b9dfebe599e27367e0d4dd5590141db38" + integrity sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg= + dependencies: + is-number "^3.0.0" + repeat-string "^1.6.1" + +to-regex@^3.0.1, to-regex@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/to-regex/-/to-regex-3.0.2.tgz#13cfdd9b336552f30b51f33a8ae1b42a7a7599ce" + integrity sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw== + dependencies: + define-property "^2.0.2" + extend-shallow "^3.0.2" + regex-not "^1.0.2" + safe-regex "^1.1.0" + +tough-cookie@~2.4.3: + version "2.4.3" + resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.4.3.tgz#53f36da3f47783b0925afa06ff9f3b165280f781" + integrity sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ== + dependencies: + psl "^1.1.24" + punycode "^1.4.1" + +tree-kill@1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/tree-kill/-/tree-kill-1.2.1.tgz#5398f374e2f292b9dcc7b2e71e30a5c3bb6c743a" + integrity sha512-4hjqbObwlh2dLyW4tcz0Ymw0ggoaVDMveUB9w8kFSQScdRLo0gxO9J7WFcUBo+W3C1TLdFIEwNOWebgZZ0RH9Q== + +trim-newlines@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-1.0.0.tgz#5887966bb582a4503a41eb524f7d35011815a613" + integrity sha1-WIeWa7WCpFA6QetST301ARgVphM= + +trim-right@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003" + integrity sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM= + +"true-case-path@^1.0.2": + version "1.0.3" + resolved "https://registry.yarnpkg.com/true-case-path/-/true-case-path-1.0.3.tgz#f813b5a8c86b40da59606722b144e3225799f47d" + integrity sha512-m6s2OdQe5wgpFMC+pAJ+q9djG82O2jcHPOI6RNg1yy9rCYR+WD6Nbpl32fDpfC56nirdRy+opFa/Vk7HYhqaew== + dependencies: + glob "^7.1.2" + +ts-node@~7.0.0: + version "7.0.1" + resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-7.0.1.tgz#9562dc2d1e6d248d24bc55f773e3f614337d9baf" + integrity sha512-BVwVbPJRspzNh2yfslyT1PSbl5uIk03EZlb493RKHN4qej/D06n1cEhjlOJG69oFsE7OT8XjpTUcYf6pKTLMhw== + dependencies: + arrify "^1.0.0" + buffer-from "^1.1.0" + diff "^3.1.0" + make-error "^1.1.1" + minimist "^1.2.0" + mkdirp "^0.5.1" + source-map-support "^0.5.6" + yn "^2.0.0" + +tslib@^1.8.0, tslib@^1.8.1, tslib@^1.9.0: + version "1.9.3" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.9.3.tgz#d7e4dd79245d85428c4d7e4822a79917954ca286" + integrity sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ== + +tslint@~5.11.0: + version "5.11.0" + resolved "https://registry.yarnpkg.com/tslint/-/tslint-5.11.0.tgz#98f30c02eae3cde7006201e4c33cb08b48581eed" + integrity sha1-mPMMAurjzecAYgHkwzywi0hYHu0= + dependencies: + babel-code-frame "^6.22.0" + builtin-modules "^1.1.1" + chalk "^2.3.0" + commander "^2.12.1" + diff "^3.2.0" + glob "^7.1.1" + js-yaml "^3.7.0" + minimatch "^3.0.4" + resolve "^1.3.2" + semver "^5.3.0" + tslib "^1.8.0" + tsutils "^2.27.2" + +tsutils@^2.27.2: + version "2.29.0" + resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-2.29.0.tgz#32b488501467acbedd4b85498673a0812aca0b99" + integrity sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA== + dependencies: + tslib "^1.8.1" + +tty-browserify@0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.0.tgz#a157ba402da24e9bf957f9aa69d524eed42901a6" + integrity sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY= + +tunnel-agent@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" + integrity sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0= + dependencies: + safe-buffer "^5.0.1" + +tweetnacl@^0.14.3, tweetnacl@~0.14.0: + version "0.14.5" + resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" + integrity sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q= + +type-is@~1.6.16: + version "1.6.16" + resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.16.tgz#f89ce341541c672b25ee7ae3c73dee3b2be50194" + integrity sha512-HRkVv/5qY2G6I8iab9cI7v1bOIdhm94dVjQCPFElW9W+3GeDOSHmy2EBYe4VTApuzolPcmgFTN3ftVJRKR2J9Q== + dependencies: + media-typer "0.3.0" + mime-types "~2.1.18" + +typedarray@^0.0.6: + version "0.0.6" + resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" + integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= + +typescript@3.2.4, typescript@~3.2.2: + version "3.2.4" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.2.4.tgz#c585cb952912263d915b462726ce244ba510ef3d" + integrity sha512-0RNDbSdEokBeEAkgNbxJ+BLwSManFy9TeXz8uW+48j/xhEXv1ePME60olyzw2XzUqUBNAYFeJadIqAgNqIACwg== + +uglify-js@^3.1.4: + version "3.5.5" + resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.5.5.tgz#9c5aaaf3a7586fbf559df31fa6d3bca1b3ba7e9b" + integrity sha512-e58FqZzPwaLODQetDQKlvErZaGkh1UmzP8YwU0aG65NLourKNtwVyDG8tkIyUU0vqWzxaikSvTaxrCSscmvqvQ== + dependencies: + commander "~2.20.0" + source-map "~0.6.1" + +ultron@~1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/ultron/-/ultron-1.1.1.tgz#9fe1536a10a664a65266a1e3ccf85fd36302bc9c" + integrity sha512-UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og== + +union-value@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.0.tgz#5c71c34cb5bad5dcebe3ea0cd08207ba5aa1aea4" + integrity sha1-XHHDTLW61dzr4+oM0IIHulqhrqQ= + dependencies: + arr-union "^3.1.0" + get-value "^2.0.6" + is-extendable "^0.1.1" + set-value "^0.4.3" + +unique-filename@^1.1.0, unique-filename@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/unique-filename/-/unique-filename-1.1.1.tgz#1d69769369ada0583103a1e6ae87681b56573230" + integrity sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ== + dependencies: + unique-slug "^2.0.0" + +unique-slug@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/unique-slug/-/unique-slug-2.0.1.tgz#5e9edc6d1ce8fb264db18a507ef9bd8544451ca6" + integrity sha512-n9cU6+gITaVu7VGj1Z8feKMmfAjEAQGhwD9fE3zvpRRa0wEIx8ODYkVGfSc94M2OX00tUFV8wH3zYbm1I8mxFg== + dependencies: + imurmurhash "^0.1.4" + +universalify@^0.1.0: + version "0.1.2" + resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" + integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg== + +unpipe@1.0.0, unpipe@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" + integrity sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw= + +unset-value@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/unset-value/-/unset-value-1.0.0.tgz#8376873f7d2335179ffb1e6fc3a8ed0dfc8ab559" + integrity sha1-g3aHP30jNRef+x5vw6jtDfyKtVk= + dependencies: + has-value "^0.3.1" + isobject "^3.0.0" + +upath@^1.0.5, upath@^1.1.1: + version "1.1.2" + resolved "https://registry.yarnpkg.com/upath/-/upath-1.1.2.tgz#3db658600edaeeccbe6db5e684d67ee8c2acd068" + integrity sha512-kXpym8nmDmlCBr7nKdIx8P2jNBa+pBpIUFRnKJ4dr8htyYGJFokkr2ZvERRtUN+9SY+JqXouNgUPtv6JQva/2Q== + +uri-js@^4.2.2: + version "4.2.2" + resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.2.2.tgz#94c540e1ff772956e2299507c010aea6c8838eb0" + integrity sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ== + dependencies: + punycode "^2.1.0" + +urix@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72" + integrity sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI= + +url-parse@^1.4.3: + version "1.4.6" + resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.4.6.tgz#baf91d6e6783c8a795eb476892ffef2737fc0456" + integrity sha512-/B8AD9iQ01seoXmXf9z/MjLZQIdOoYl/+gvsQF6+mpnxaTfG9P7srYaiqaDMyKkR36XMXfhqSHss5MyFAO8lew== + dependencies: + querystringify "^2.0.0" + requires-port "^1.0.0" + +url@^0.11.0: + version "0.11.0" + resolved "https://registry.yarnpkg.com/url/-/url-0.11.0.tgz#3838e97cfc60521eb73c525a8e55bfdd9e2e28f1" + integrity sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE= + dependencies: + punycode "1.3.2" + querystring "0.2.0" + +use@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f" + integrity sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ== + +useragent@2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/useragent/-/useragent-2.3.0.tgz#217f943ad540cb2128658ab23fc960f6a88c9972" + integrity sha512-4AoH4pxuSvHCjqLO04sU6U/uE65BYza8l/KKBS0b0hnUPWi+cQ2BpeTEwejCSx9SPV5/U03nniDTrWx5NrmKdw== + dependencies: + lru-cache "4.1.x" + tmp "0.0.x" + +util-deprecate@^1.0.1, util-deprecate@~1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= + +util@0.10.3: + version "0.10.3" + resolved "https://registry.yarnpkg.com/util/-/util-0.10.3.tgz#7afb1afe50805246489e3db7fe0ed379336ac0f9" + integrity sha1-evsa/lCAUkZInj23/g7TeTNqwPk= + dependencies: + inherits "2.0.1" + +util@^0.11.0: + version "0.11.1" + resolved "https://registry.yarnpkg.com/util/-/util-0.11.1.tgz#3236733720ec64bb27f6e26f421aaa2e1b588d61" + integrity sha512-HShAsny+zS2TZfaXxD9tYj4HQGlBezXZMZuM/S5PKLLoZkShZiGk9o5CzukI1LVHZvjdvZ2Sj1aW/Ndn2NB/HQ== + dependencies: + inherits "2.0.3" + +utils-merge@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" + integrity sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM= + +uuid@^3.0.1, uuid@^3.3.2: + version "3.3.2" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.2.tgz#1b4af4955eb3077c501c23872fc6513811587131" + integrity sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA== + +validate-npm-package-license@^3.0.1: + version "3.0.4" + resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a" + integrity sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew== + dependencies: + spdx-correct "^3.0.0" + spdx-expression-parse "^3.0.0" + +validate-npm-package-name@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/validate-npm-package-name/-/validate-npm-package-name-3.0.0.tgz#5fa912d81eb7d0c74afc140de7317f0ca7df437e" + integrity sha1-X6kS2B630MdK/BQN5zF/DKffQ34= + dependencies: + builtins "^1.0.3" + +vary@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" + integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw= + +verror@1.10.0: + version "1.10.0" + resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400" + integrity sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA= + dependencies: + assert-plus "^1.0.0" + core-util-is "1.0.2" + extsprintf "^1.2.0" + +vm-browserify@0.0.4: + version "0.0.4" + resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-0.0.4.tgz#5d7ea45bbef9e4a6ff65f95438e0a87c357d5a73" + integrity sha1-XX6kW7755Kb/ZflUOOCofDV9WnM= + dependencies: + indexof "0.0.1" + +void-elements@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/void-elements/-/void-elements-2.0.1.tgz#c066afb582bb1cb4128d60ea92392e94d5e9dbec" + integrity sha1-wGavtYK7HLQSjWDqkjkulNXp2+w= + +watchpack@^1.5.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-1.6.0.tgz#4bc12c2ebe8aa277a71f1d3f14d685c7b446cd00" + integrity sha512-i6dHe3EyLjMmDlU1/bGQpEw25XSjkJULPuAVKCbNRefQVq48yXKUpwg538F7AZTf9kyr57zj++pQFltUa5H7yA== + dependencies: + chokidar "^2.0.2" + graceful-fs "^4.1.2" + neo-async "^2.5.0" + +wbuf@^1.1.0, wbuf@^1.7.3: + version "1.7.3" + resolved "https://registry.yarnpkg.com/wbuf/-/wbuf-1.7.3.tgz#c1d8d149316d3ea852848895cb6a0bfe887b87df" + integrity sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA== + dependencies: + minimalistic-assert "^1.0.0" + +webdriver-js-extender@2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/webdriver-js-extender/-/webdriver-js-extender-2.1.0.tgz#57d7a93c00db4cc8d556e4d3db4b5db0a80c3bb7" + integrity sha512-lcUKrjbBfCK6MNsh7xaY2UAUmZwe+/ib03AjVOpFobX4O7+83BUveSrLfU0Qsyb1DaKJdQRbuU+kM9aZ6QUhiQ== + dependencies: + "@types/selenium-webdriver" "^3.0.0" + selenium-webdriver "^3.0.1" + +webdriver-manager@^12.0.6: + version "12.1.1" + resolved "https://registry.yarnpkg.com/webdriver-manager/-/webdriver-manager-12.1.1.tgz#66c3271f69cefdaa9fdfca617ae95afae41c3c62" + integrity sha512-L9TEQmZs6JbMMRQI1w60mfps265/NCr0toYJl7p/R2OAk6oXAfwI6jqYP7EWae+d7Ad2S2Aj4+rzxoSjqk3ZuA== + dependencies: + adm-zip "^0.4.9" + chalk "^1.1.1" + del "^2.2.0" + glob "^7.0.3" + ini "^1.3.4" + minimist "^1.2.0" + q "^1.4.1" + request "^2.87.0" + rimraf "^2.5.2" + semver "^5.3.0" + xml2js "^0.4.17" + +webpack-core@^0.6.8: + version "0.6.9" + resolved "https://registry.yarnpkg.com/webpack-core/-/webpack-core-0.6.9.tgz#fc571588c8558da77be9efb6debdc5a3b172bdc2" + integrity sha1-/FcViMhVjad76e+23r3Fo7FyvcI= + dependencies: + source-list-map "~0.1.7" + source-map "~0.4.1" + +webpack-dev-middleware@3.4.0: + version "3.4.0" + resolved "https://registry.yarnpkg.com/webpack-dev-middleware/-/webpack-dev-middleware-3.4.0.tgz#1132fecc9026fd90f0ecedac5cbff75d1fb45890" + integrity sha512-Q9Iyc0X9dP9bAsYskAVJ/hmIZZQwf/3Sy4xCAZgL5cUkjZmUZLt4l5HpbST/Pdgjn3u6pE7u5OdGd1apgzRujA== + dependencies: + memory-fs "~0.4.1" + mime "^2.3.1" + range-parser "^1.0.3" + webpack-log "^2.0.0" + +webpack-dev-middleware@3.5.1: + version "3.5.1" + resolved "https://registry.yarnpkg.com/webpack-dev-middleware/-/webpack-dev-middleware-3.5.1.tgz#9265b7742ef50f54f54c1d9af022fc17c1be9b88" + integrity sha512-4dwCh/AyMOYAybggUr8fiCkRnjVDp+Cqlr9c+aaNB3GJYgRGYQWJ1YX/WAKUNA9dPNHZ6QSN2lYDKqjKSI8Vqw== + dependencies: + memory-fs "~0.4.1" + mime "^2.3.1" + range-parser "^1.0.3" + webpack-log "^2.0.0" + +webpack-dev-server@3.1.14: + version "3.1.14" + resolved "https://registry.yarnpkg.com/webpack-dev-server/-/webpack-dev-server-3.1.14.tgz#60fb229b997fc5a0a1fc6237421030180959d469" + integrity sha512-mGXDgz5SlTxcF3hUpfC8hrQ11yhAttuUQWf1Wmb+6zo3x6rb7b9mIfuQvAPLdfDRCGRGvakBWHdHOa0I9p/EVQ== + dependencies: + ansi-html "0.0.7" + 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.0" + supports-color "^5.1.0" + url "^0.11.0" + webpack-dev-middleware "3.4.0" + webpack-log "^2.0.0" + yargs "12.0.2" + +webpack-log@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/webpack-log/-/webpack-log-2.0.0.tgz#5b7928e0637593f119d32f6227c1e0ac31e1b47f" + integrity sha512-cX8G2vR/85UYG59FgkoMamwHUIkSSlV3bBMRsbxVXVUk2j6NleCKjQ/WE9eYg9WY4w25O9w8wKP4rzNZFmUcUg== + dependencies: + ansi-colors "^3.0.0" + uuid "^3.3.2" + +webpack-merge@4.2.1: + version "4.2.1" + resolved "https://registry.yarnpkg.com/webpack-merge/-/webpack-merge-4.2.1.tgz#5e923cf802ea2ace4fd5af1d3247368a633489b4" + integrity sha512-4p8WQyS98bUJcCvFMbdGZyZmsKuWjWVnVHnAS3FFg0HDaRVrPbkivx2RYCre8UiemD67RsiFFLfn4JhLAin8Vw== + dependencies: + lodash "^4.17.5" + +webpack-sources@1.3.0, webpack-sources@^1.1.0, webpack-sources@^1.2.0, webpack-sources@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-1.3.0.tgz#2a28dcb9f1f45fe960d8f1493252b5ee6530fa85" + integrity sha512-OiVgSrbGu7NEnEvQJJgdSFPl2qWKkWq5lHMhgiToIiN9w34EBnjYzSYs+VbL5KoYiLNtFFa7BZIKxRED3I32pA== + dependencies: + source-list-map "^2.0.0" + source-map "~0.6.1" + +webpack-subresource-integrity@1.1.0-rc.6: + version "1.1.0-rc.6" + resolved "https://registry.yarnpkg.com/webpack-subresource-integrity/-/webpack-subresource-integrity-1.1.0-rc.6.tgz#37f6f1264e1eb378e41465a98da80fad76ab8886" + integrity sha512-Az7y8xTniNhaA0620AV1KPwWOqawurVVDzQSpPAeR5RwNbL91GoBSJAAo9cfd+GiFHwsS5bbHepBw1e6Hzxy4w== + dependencies: + webpack-core "^0.6.8" + +webpack@4.29.0: + version "4.29.0" + resolved "https://registry.yarnpkg.com/webpack/-/webpack-4.29.0.tgz#f2cfef83f7ae404ba889ff5d43efd285ca26e750" + integrity sha512-pxdGG0keDBtamE1mNvT5zyBdx+7wkh6mh7uzMOo/uRQ/fhsdj5FXkh/j5mapzs060forql1oXqXN9HJGju+y7w== + dependencies: + "@webassemblyjs/ast" "1.7.11" + "@webassemblyjs/helper-module-context" "1.7.11" + "@webassemblyjs/wasm-edit" "1.7.11" + "@webassemblyjs/wasm-parser" "1.7.11" + acorn "^6.0.5" + acorn-dynamic-import "^4.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" + terser-webpack-plugin "^1.1.0" + watchpack "^1.5.0" + webpack-sources "^1.3.0" + +websocket-driver@>=0.5.1: + version "0.7.0" + resolved "https://registry.yarnpkg.com/websocket-driver/-/websocket-driver-0.7.0.tgz#0caf9d2d755d93aee049d4bdd0d3fe2cca2a24eb" + integrity sha1-DK+dLXVdk67gSdS90NP+LMoqJOs= + dependencies: + http-parser-js ">=0.4.0" + websocket-extensions ">=0.1.1" + +websocket-extensions@>=0.1.1: + version "0.1.3" + resolved "https://registry.yarnpkg.com/websocket-extensions/-/websocket-extensions-0.1.3.tgz#5d2ff22977003ec687a4b87073dfbbac146ccf29" + integrity sha512-nqHUnMXmBzT0w570r2JpJxfiSD1IzoI+HGVdd3aZ0yNi3ngvQ4jv1dtHt5VGxfI2yj5yqImPhOK4vmIh2xMbGg== + +when@~3.6.x: + version "3.6.4" + resolved "https://registry.yarnpkg.com/when/-/when-3.6.4.tgz#473b517ec159e2b85005497a13983f095412e34e" + integrity sha1-RztRfsFZ4rhQBUl6E5g/CVQS404= + +which-module@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/which-module/-/which-module-1.0.0.tgz#bba63ca861948994ff307736089e3b96026c2a4f" + integrity sha1-u6Y8qGGUiZT/MHc2CJ47lgJsKk8= + +which-module@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" + integrity sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho= + +which@1, which@^1.2.1, which@^1.2.9, which@^1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" + integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== + dependencies: + isexe "^2.0.0" + +wide-align@^1.1.0: + version "1.1.3" + resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457" + integrity sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA== + dependencies: + string-width "^1.0.2 || 2" + +wordwrap@~0.0.2: + version "0.0.3" + resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.3.tgz#a3d5da6cd5c0bc0008d37234bbaf1bed63059107" + integrity sha1-o9XabNXAvAAI03I0u68b7WMFkQc= + +worker-farm@^1.5.2: + version "1.6.0" + resolved "https://registry.yarnpkg.com/worker-farm/-/worker-farm-1.6.0.tgz#aecc405976fab5a95526180846f0dba288f3a4a0" + integrity sha512-6w+3tHbM87WnSWnENBUvA2pxJPLhQUg5LKwUQHq3r+XPhIM+Gh2R5ycbwPCyuGbNg+lPgdcnQUhuC02kJCvffQ== + dependencies: + errno "~0.1.7" + +wrap-ansi@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85" + integrity sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU= + dependencies: + string-width "^1.0.1" + strip-ansi "^3.0.1" + +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= + +ws@~3.3.1: + version "3.3.3" + resolved "https://registry.yarnpkg.com/ws/-/ws-3.3.3.tgz#f1cf84fe2d5e901ebce94efaece785f187a228f2" + integrity sha512-nnWLa/NwZSt4KQJu51MYlCcSQ5g7INpOrOMt4XV8j4dqTXdmlUmSHQ8/oLC069ckre0fRsgfvsKwbTdtKLCDkA== + dependencies: + async-limiter "~1.0.0" + safe-buffer "~5.1.0" + ultron "~1.1.0" + +xml2js@^0.4.17: + version "0.4.19" + resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.4.19.tgz#686c20f213209e94abf0d1bcf1efaa291c7827a7" + integrity sha512-esZnJZJOiJR9wWKMyuvSE1y6Dq5LCuJanqhxslH2bxM6duahNZ+HMpCLhBQGZkbX6xRf8x1Y2eJlgt2q3qo49Q== + dependencies: + sax ">=0.6.0" + xmlbuilder "~9.0.1" + +xmlbuilder@~9.0.1: + version "9.0.7" + resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-9.0.7.tgz#132ee63d2ec5565c557e20f4c22df9aca686b10d" + integrity sha1-Ey7mPS7FVlxVfiD0wi35rKaGsQ0= + +xmlhttprequest-ssl@~1.5.4: + version "1.5.5" + resolved "https://registry.yarnpkg.com/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.5.tgz#c2876b06168aadc40e57d97e81191ac8f4398b3e" + integrity sha1-wodrBhaKrcQOV9l+gRkayPQ5iz4= + +xregexp@4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/xregexp/-/xregexp-4.0.0.tgz#e698189de49dd2a18cc5687b05e17c8e43943020" + integrity sha512-PHyM+sQouu7xspQQwELlGwwd05mXUFqwFYfqPO0cC7x4fxyHnnuetmQr6CjJiafIDoH4MogHb9dOoJzR/Y4rFg== + +xtend@^4.0.0, xtend@~4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af" + integrity sha1-pcbVMr5lbiPbgg77lDofBJmNY68= + +y18n@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-3.2.1.tgz#6d15fba884c08679c0d77e88e7759e811e07fa41" + integrity sha1-bRX7qITAhnnA136I53WegR4H+kE= + +"y18n@^3.2.1 || ^4.0.0", y18n@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.0.tgz#95ef94f85ecc81d007c264e190a120f0a3c8566b" + integrity sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w== + +yallist@^2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52" + integrity sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI= + +yallist@^3.0.0, yallist@^3.0.2: + version "3.0.3" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.0.3.tgz#b4b049e314be545e3ce802236d6cd22cd91c3de9" + integrity sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A== + +yargs-parser@^10.1.0: + version "10.1.0" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-10.1.0.tgz#7202265b89f7e9e9f2e5765e0fe735a905edbaa8" + integrity sha512-VCIyR1wJoEBZUqk5PA+oOBF6ypbwh5aNB3I50guxAL/quggdfs4TtNHQrSazFA3fYZ+tEqfs0zIGlv0c/rgjbQ== + dependencies: + camelcase "^4.1.0" + +yargs-parser@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-5.0.0.tgz#275ecf0d7ffe05c77e64e7c86e4cd94bf0e1228a" + integrity sha1-J17PDX/+Bcd+ZOfIbkzZS/DhIoo= + dependencies: + camelcase "^3.0.0" + +yargs-parser@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-7.0.0.tgz#8d0ac42f16ea55debd332caf4c4038b3e3f5dfd9" + integrity sha1-jQrELxbqVd69MyyvTEA4s+P139k= + dependencies: + camelcase "^4.1.0" + +yargs@12.0.2: + version "12.0.2" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-12.0.2.tgz#fe58234369392af33ecbef53819171eff0f5aadc" + integrity sha512-e7SkEx6N6SIZ5c5H22RTZae61qtn3PYUE8JYbBFlK9sYmh3DMQ6E5ygtaG/2BW0JZi4WGgTR2IV5ChqlqrDGVQ== + dependencies: + 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" + +yargs@9.0.1: + version "9.0.1" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-9.0.1.tgz#52acc23feecac34042078ee78c0c007f5085db4c" + integrity sha1-UqzCP+7Kw0BCB47njAwAf1CF20w= + dependencies: + camelcase "^4.1.0" + cliui "^3.2.0" + decamelize "^1.1.1" + get-caller-file "^1.0.1" + os-locale "^2.0.0" + read-pkg-up "^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 "^7.0.0" + +yargs@^7.0.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-7.1.0.tgz#6ba318eb16961727f5d284f8ea003e8d6154d0c8" + integrity sha1-a6MY6xaWFyf10oT46gA+jWFU0Mg= + dependencies: + camelcase "^3.0.0" + cliui "^3.2.0" + decamelize "^1.1.1" + get-caller-file "^1.0.1" + os-locale "^1.4.0" + read-pkg-up "^1.0.1" + require-directory "^2.1.1" + require-main-filename "^1.0.1" + set-blocking "^2.0.0" + string-width "^1.0.2" + which-module "^1.0.0" + y18n "^3.2.1" + yargs-parser "^5.0.0" + +yeast@0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/yeast/-/yeast-0.1.2.tgz#008e06d8094320c372dbc2f8ed76a0ca6c8ac419" + integrity sha1-AI4G2AlDIMNy28L47XagymyKxBk= + +yn@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/yn/-/yn-2.0.0.tgz#e5adabc8acf408f6385fc76495684c88e6af689a" + integrity sha1-5a2ryKz0CPY4X8dklWhMiOavaJo= + +zone.js@~0.8.26: + version "0.8.29" + resolved "https://registry.yarnpkg.com/zone.js/-/zone.js-0.8.29.tgz#8dce92aa0dd553b50bc5bfbb90af9986ad845a12" + integrity sha512-mla2acNCMkWXBD+c+yeUrBUrzOxYMNFdQ6FGfigGGtEVBPJx07BQeJekjt9DmH1FtZek4E9rE1eRR9qQpxACOQ== From 0f6d43c5ac896814cd2609d70f78840ee4a6a6ec Mon Sep 17 00:00:00 2001 From: Omkar Ekbote Date: Sat, 20 Apr 2019 20:11:21 +0530 Subject: [PATCH 06/64] Add MaterialUI components --- frontend/wittymail-v2/package.json | 7 +++-- .../wittymail-v2/src/app/app.component.css | 3 ++ .../wittymail-v2/src/app/app.component.html | 27 +++++------------ frontend/wittymail-v2/src/app/app.module.ts | 7 ++++- frontend/wittymail-v2/src/index.html | 3 +- frontend/wittymail-v2/src/main.ts | 1 + frontend/wittymail-v2/src/styles.css | 6 +++- frontend/wittymail-v2/yarn.lock | 30 +++++++++++++++++-- 8 files changed, 57 insertions(+), 27 deletions(-) diff --git a/frontend/wittymail-v2/package.json b/frontend/wittymail-v2/package.json index 499420c..229cd8e 100644 --- a/frontend/wittymail-v2/package.json +++ b/frontend/wittymail-v2/package.json @@ -11,15 +11,18 @@ }, "private": true, "dependencies": { - "@angular/animations": "~7.2.0", + "@angular/animations": "^7.2.13", + "@angular/cdk": "^7.3.7", "@angular/common": "~7.2.0", "@angular/compiler": "~7.2.0", "@angular/core": "~7.2.0", "@angular/forms": "~7.2.0", + "@angular/material": "^7.3.7", "@angular/platform-browser": "~7.2.0", "@angular/platform-browser-dynamic": "~7.2.0", "@angular/router": "~7.2.0", "core-js": "^2.5.4", + "hammerjs": "^2.0.8", "rxjs": "~6.3.3", "tslib": "^1.9.0", "zone.js": "~0.8.26" @@ -29,9 +32,9 @@ "@angular/cli": "~7.3.8", "@angular/compiler-cli": "~7.2.0", "@angular/language-service": "~7.2.0", - "@types/node": "~8.9.4", "@types/jasmine": "~2.8.8", "@types/jasminewd2": "~2.0.3", + "@types/node": "~8.9.4", "codelyzer": "~4.5.0", "jasmine-core": "~2.99.1", "jasmine-spec-reporter": "~4.2.1", diff --git a/frontend/wittymail-v2/src/app/app.component.css b/frontend/wittymail-v2/src/app/app.component.css index e69de29..4c733fe 100644 --- a/frontend/wittymail-v2/src/app/app.component.css +++ b/frontend/wittymail-v2/src/app/app.component.css @@ -0,0 +1,3 @@ +.top-banner-logo { + margin-right: 0.5rem; +} \ No newline at end of file diff --git a/frontend/wittymail-v2/src/app/app.component.html b/frontend/wittymail-v2/src/app/app.component.html index 0f3d9d8..cec31cc 100644 --- a/frontend/wittymail-v2/src/app/app.component.html +++ b/frontend/wittymail-v2/src/app/app.component.html @@ -1,21 +1,8 @@ - -
-

- Welcome to {{ title }}! -

- Angular Logo -
-

Here are some links to help you start:

- + + + WittyMail + - + \ No newline at end of file diff --git a/frontend/wittymail-v2/src/app/app.module.ts b/frontend/wittymail-v2/src/app/app.module.ts index 2c3ba29..837463f 100644 --- a/frontend/wittymail-v2/src/app/app.module.ts +++ b/frontend/wittymail-v2/src/app/app.module.ts @@ -1,5 +1,7 @@ import { BrowserModule } from '@angular/platform-browser'; import { NgModule } from '@angular/core'; +import {BrowserAnimationsModule} from '@angular/platform-browser/animations'; +import {MatToolbarModule} from '@angular/material/toolbar'; import { AppRoutingModule } from './app-routing.module'; import { AppComponent } from './app.component'; @@ -10,7 +12,10 @@ import { AppComponent } from './app.component'; ], imports: [ BrowserModule, - AppRoutingModule + AppRoutingModule, + BrowserAnimationsModule, + + MatToolbarModule ], providers: [], bootstrap: [AppComponent] diff --git a/frontend/wittymail-v2/src/index.html b/frontend/wittymail-v2/src/index.html index c052a6a..59e8278 100644 --- a/frontend/wittymail-v2/src/index.html +++ b/frontend/wittymail-v2/src/index.html @@ -2,11 +2,12 @@ - WittymailV2 + WittyMail v2 + diff --git a/frontend/wittymail-v2/src/main.ts b/frontend/wittymail-v2/src/main.ts index c7b673c..1299fac 100644 --- a/frontend/wittymail-v2/src/main.ts +++ b/frontend/wittymail-v2/src/main.ts @@ -1,5 +1,6 @@ import { enableProdMode } from '@angular/core'; import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; +import 'hammerjs'; import { AppModule } from './app/app.module'; import { environment } from './environments/environment'; diff --git a/frontend/wittymail-v2/src/styles.css b/frontend/wittymail-v2/src/styles.css index 90d4ee0..32c1ecd 100644 --- a/frontend/wittymail-v2/src/styles.css +++ b/frontend/wittymail-v2/src/styles.css @@ -1 +1,5 @@ -/* You can add global styles to this file, and also import other style files */ +@import "~@angular/material/prebuilt-themes/indigo-pink.css"; + +body { + margin: 0; +} \ No newline at end of file diff --git a/frontend/wittymail-v2/yarn.lock b/frontend/wittymail-v2/yarn.lock index 4d7bf19..88ba4d7 100644 --- a/frontend/wittymail-v2/yarn.lock +++ b/frontend/wittymail-v2/yarn.lock @@ -100,13 +100,22 @@ "@angular-devkit/core" "7.3.8" rxjs "6.3.3" -"@angular/animations@~7.2.0": +"@angular/animations@^7.2.13": version "7.2.13" resolved "https://registry.yarnpkg.com/@angular/animations/-/animations-7.2.13.tgz#9a49482ea2e0386a691d5b9d7be422251b66d767" integrity sha512-Z0g0DthJnxTZ0dUc5BlojMq/0XIikhWzTqq0ym8w3G6jqBJD0OJ0jRCIfV0Leqlgzq6Jzvdrx0/JngBiKi5+uA== dependencies: tslib "^1.9.0" +"@angular/cdk@^7.3.7": + version "7.3.7" + resolved "https://registry.yarnpkg.com/@angular/cdk/-/cdk-7.3.7.tgz#ce1ad53ba04beb9c8e950acc5691ea0143753764" + integrity sha512-xbXxhHHKGkVuW6K7pzPmvpJXIwpl0ykBnvA2g+/7Sgy5Pd35wCC+UtHD9RYczDM/mkygNxMQtagyCErwFnDtQA== + dependencies: + tslib "^1.7.1" + optionalDependencies: + parse5 "^5.0.0" + "@angular/cli@~7.3.8": version "7.3.8" resolved "https://registry.yarnpkg.com/@angular/cli/-/cli-7.3.8.tgz#a0891e08bee7d68b9ef2c00a9a7e93c6c5ac75d7" @@ -176,6 +185,13 @@ resolved "https://registry.yarnpkg.com/@angular/language-service/-/language-service-7.2.13.tgz#941cb098657efdbc386ef8e54d2d893497f68c20" integrity sha512-1bNWJpwH9wB0JybkbjdQp9J4bGmGxJX6BG7Mz3188Wc4J+aNy696Gc6IaJs7tFK8VXAdJrTJ5jGr9Oiu+ATe8w== +"@angular/material@^7.3.7": + version "7.3.7" + resolved "https://registry.yarnpkg.com/@angular/material/-/material-7.3.7.tgz#dcd95e6618ba6254c5880efee1aad349cf5b9140" + integrity sha512-Eq+7frkeNGkLOfEtmkmJgR+AgoWajOipXZWWfCSamNfpCcPof82DwvGOpAmgGni9FuN2XFQdqP5MoaffQzIvUA== + dependencies: + tslib "^1.7.1" + "@angular/platform-browser-dynamic@~7.2.0": version "7.2.13" resolved "https://registry.yarnpkg.com/@angular/platform-browser-dynamic/-/platform-browser-dynamic-7.2.13.tgz#3aee18e422d5ef69ced4d4749031b23647dfad57" @@ -2871,6 +2887,11 @@ graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6 resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.15.tgz#ffb703e1066e8a0eeaa4c8b80ba9253eeefbfb00" integrity sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA== +hammerjs@^2.0.8: + version "2.0.8" + resolved "https://registry.yarnpkg.com/hammerjs/-/hammerjs-2.0.8.tgz#04ef77862cff2bb79d30f7692095930222bf60f1" + integrity sha1-BO93hiz/K7edMPdpIJWTAiK/YPE= + handle-thing@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/handle-thing/-/handle-thing-2.0.0.tgz#0e039695ff50c93fc288557d696f3c1dc6776754" @@ -4906,6 +4927,11 @@ parse5@4.0.0: resolved "https://registry.yarnpkg.com/parse5/-/parse5-4.0.0.tgz#6d78656e3da8d78b4ec0b906f7c08ef1dfe3f608" integrity sha512-VrZ7eOd3T1Fk4XWNXMgiGBK/z0MG48BWG2uQNU4I72fkQuKUTZpl+u9k+CxEG0twMVzSmXEEz12z5Fnw1jIQFA== +parse5@^5.0.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/parse5/-/parse5-5.1.0.tgz#c59341c9723f414c452975564c7c00a68d58acd2" + integrity sha512-fxNG2sQjHvlVAYmzBZS9YlDp6PTSSDwa98vkD4QgVDDCAo84z5X1t5XyJQ62ImdLXx5NdIIfihey6xpum9/gRQ== + parseqs@0.0.5: version "0.0.5" resolved "https://registry.yarnpkg.com/parseqs/-/parseqs-0.0.5.tgz#d5208a3738e46766e291ba2ea173684921a8b89d" @@ -6618,7 +6644,7 @@ ts-node@~7.0.0: source-map-support "^0.5.6" yn "^2.0.0" -tslib@^1.8.0, tslib@^1.8.1, tslib@^1.9.0: +tslib@^1.7.1, tslib@^1.8.0, tslib@^1.8.1, tslib@^1.9.0: version "1.9.3" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.9.3.tgz#d7e4dd79245d85428c4d7e4822a79917954ca286" integrity sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ== From bc98ac1a5525218e8d6c278a8ec9679eaed1540d Mon Sep 17 00:00:00 2001 From: Omkar Ekbote Date: Sat, 20 Apr 2019 20:49:23 +0530 Subject: [PATCH 07/64] Add top-level stepper --- .../wittymail-v2/src/app/app.component.html | 2 +- frontend/wittymail-v2/src/app/app.module.ts | 8 ++++-- .../steps-slider/steps-slider.component.css | 0 .../steps-slider/steps-slider.component.html | 17 +++++++++++++ .../steps-slider.component.spec.ts | 25 +++++++++++++++++++ .../steps-slider/steps-slider.component.ts | 15 +++++++++++ 6 files changed, 64 insertions(+), 3 deletions(-) create mode 100644 frontend/wittymail-v2/src/app/steps-slider/steps-slider.component.css create mode 100644 frontend/wittymail-v2/src/app/steps-slider/steps-slider.component.html create mode 100644 frontend/wittymail-v2/src/app/steps-slider/steps-slider.component.spec.ts create mode 100644 frontend/wittymail-v2/src/app/steps-slider/steps-slider.component.ts diff --git a/frontend/wittymail-v2/src/app/app.component.html b/frontend/wittymail-v2/src/app/app.component.html index cec31cc..4a24a2a 100644 --- a/frontend/wittymail-v2/src/app/app.component.html +++ b/frontend/wittymail-v2/src/app/app.component.html @@ -4,5 +4,5 @@ WittyMail - + \ No newline at end of file diff --git a/frontend/wittymail-v2/src/app/app.module.ts b/frontend/wittymail-v2/src/app/app.module.ts index 837463f..782fbdc 100644 --- a/frontend/wittymail-v2/src/app/app.module.ts +++ b/frontend/wittymail-v2/src/app/app.module.ts @@ -2,20 +2,24 @@ import { BrowserModule } from '@angular/platform-browser'; import { NgModule } from '@angular/core'; import {BrowserAnimationsModule} from '@angular/platform-browser/animations'; import {MatToolbarModule} from '@angular/material/toolbar'; +import {MatStepperModule} from '@angular/material/stepper'; import { AppRoutingModule } from './app-routing.module'; import { AppComponent } from './app.component'; +import { StepsSliderComponent } from './steps-slider/steps-slider.component'; @NgModule({ declarations: [ - AppComponent + AppComponent, + StepsSliderComponent ], imports: [ BrowserModule, AppRoutingModule, BrowserAnimationsModule, - MatToolbarModule + MatToolbarModule, + MatStepperModule ], providers: [], bootstrap: [AppComponent] diff --git a/frontend/wittymail-v2/src/app/steps-slider/steps-slider.component.css b/frontend/wittymail-v2/src/app/steps-slider/steps-slider.component.css new file mode 100644 index 0000000..e69de29 diff --git a/frontend/wittymail-v2/src/app/steps-slider/steps-slider.component.html b/frontend/wittymail-v2/src/app/steps-slider/steps-slider.component.html new file mode 100644 index 0000000..1fc2fc6 --- /dev/null +++ b/frontend/wittymail-v2/src/app/steps-slider/steps-slider.component.html @@ -0,0 +1,17 @@ + + + This is step 1 + + + + This is step 2 + + + + This is step 3 + + + + This is step 4 + + \ No newline at end of file diff --git a/frontend/wittymail-v2/src/app/steps-slider/steps-slider.component.spec.ts b/frontend/wittymail-v2/src/app/steps-slider/steps-slider.component.spec.ts new file mode 100644 index 0000000..f2d3b68 --- /dev/null +++ b/frontend/wittymail-v2/src/app/steps-slider/steps-slider.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { StepsSliderComponent } from './steps-slider.component'; + +describe('StepsSliderComponent', () => { + let component: StepsSliderComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ StepsSliderComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(StepsSliderComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/frontend/wittymail-v2/src/app/steps-slider/steps-slider.component.ts b/frontend/wittymail-v2/src/app/steps-slider/steps-slider.component.ts new file mode 100644 index 0000000..c1e610c --- /dev/null +++ b/frontend/wittymail-v2/src/app/steps-slider/steps-slider.component.ts @@ -0,0 +1,15 @@ +import { Component, OnInit } from '@angular/core'; + +@Component({ + selector: 'app-steps-slider', + templateUrl: './steps-slider.component.html', + styleUrls: ['./steps-slider.component.css'] +}) +export class StepsSliderComponent implements OnInit { + + constructor() { } + + ngOnInit() { + } + +} From f0546c79fffc89f7e94b9f7a00234f51712bd7a7 Mon Sep 17 00:00:00 2001 From: Omkar Ekbote Date: Sun, 21 Apr 2019 02:43:53 +0530 Subject: [PATCH 08/64] Create attachments page --- frontend/wittymail-v2/package.json | 1 + frontend/wittymail-v2/src/app/app.module.ts | 14 ++++- .../app/attachments/attachments.component.css | 17 ++++++ .../attachments/attachments.component.html | 45 ++++++++++++++ .../attachments/attachments.component.spec.ts | 25 ++++++++ .../app/attachments/attachments.component.ts | 58 +++++++++++++++++++ .../steps-slider/steps-slider.component.html | 2 +- frontend/wittymail-v2/yarn.lock | 7 +++ 8 files changed, 166 insertions(+), 3 deletions(-) create mode 100644 frontend/wittymail-v2/src/app/attachments/attachments.component.css create mode 100644 frontend/wittymail-v2/src/app/attachments/attachments.component.html create mode 100644 frontend/wittymail-v2/src/app/attachments/attachments.component.spec.ts create mode 100644 frontend/wittymail-v2/src/app/attachments/attachments.component.ts diff --git a/frontend/wittymail-v2/package.json b/frontend/wittymail-v2/package.json index 229cd8e..0300c55 100644 --- a/frontend/wittymail-v2/package.json +++ b/frontend/wittymail-v2/package.json @@ -16,6 +16,7 @@ "@angular/common": "~7.2.0", "@angular/compiler": "~7.2.0", "@angular/core": "~7.2.0", + "@angular/flex-layout": "^7.0.0-beta.24", "@angular/forms": "~7.2.0", "@angular/material": "^7.3.7", "@angular/platform-browser": "~7.2.0", diff --git a/frontend/wittymail-v2/src/app/app.module.ts b/frontend/wittymail-v2/src/app/app.module.ts index 782fbdc..b453e31 100644 --- a/frontend/wittymail-v2/src/app/app.module.ts +++ b/frontend/wittymail-v2/src/app/app.module.ts @@ -1,25 +1,35 @@ import { BrowserModule } from '@angular/platform-browser'; import { NgModule } from '@angular/core'; import {BrowserAnimationsModule} from '@angular/platform-browser/animations'; +import { FormsModule } from '@angular/forms'; import {MatToolbarModule} from '@angular/material/toolbar'; import {MatStepperModule} from '@angular/material/stepper'; +import { FlexLayoutModule } from '@angular/flex-layout'; +import {MatTableModule} from '@angular/material/table'; +import {MatRadioModule} from '@angular/material/radio'; import { AppRoutingModule } from './app-routing.module'; import { AppComponent } from './app.component'; import { StepsSliderComponent } from './steps-slider/steps-slider.component'; +import { AttachmentsComponent } from './attachments/attachments.component'; @NgModule({ declarations: [ AppComponent, - StepsSliderComponent + StepsSliderComponent, + AttachmentsComponent ], imports: [ BrowserModule, AppRoutingModule, BrowserAnimationsModule, + FlexLayoutModule, + FormsModule, MatToolbarModule, - MatStepperModule + MatStepperModule, + MatTableModule, + MatRadioModule ], providers: [], bootstrap: [AppComponent] diff --git a/frontend/wittymail-v2/src/app/attachments/attachments.component.css b/frontend/wittymail-v2/src/app/attachments/attachments.component.css new file mode 100644 index 0000000..5358824 --- /dev/null +++ b/frontend/wittymail-v2/src/app/attachments/attachments.component.css @@ -0,0 +1,17 @@ +table { + width: 100%; +} + +.highlight-table-row { + background: #42A948; /* green */ +} + +.attachment-candidate-list { + display: flex; + flex-direction: column; + margin: 15px 0; +} + +.attachment-candidate-list-item { + margin: 5px; +} \ No newline at end of file diff --git a/frontend/wittymail-v2/src/app/attachments/attachments.component.html b/frontend/wittymail-v2/src/app/attachments/attachments.component.html new file mode 100644 index 0000000..30c66eb --- /dev/null +++ b/frontend/wittymail-v2/src/app/attachments/attachments.component.html @@ -0,0 +1,45 @@ +
+
+ +
+ +
+ + + + + +
{{header}} {{element[header]}}
+
+
+
+
+
+

+ Select a row +

+
+
+ Pick the correct attachment for {{selectedRow[attachmentSubjectHeaderName]}}: +
+ + + {{candidate.displayName}} + + +
+
+
+
+
+ PDF Viewer for {{selectedAttachmentCandidate}} +
+
+
+
+
+
+
\ No newline at end of file diff --git a/frontend/wittymail-v2/src/app/attachments/attachments.component.spec.ts b/frontend/wittymail-v2/src/app/attachments/attachments.component.spec.ts new file mode 100644 index 0000000..3a6f046 --- /dev/null +++ b/frontend/wittymail-v2/src/app/attachments/attachments.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { AttachmentsComponent } from './attachments.component'; + +describe('AttachmentsComponent', () => { + let component: AttachmentsComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ AttachmentsComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(AttachmentsComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/frontend/wittymail-v2/src/app/attachments/attachments.component.ts b/frontend/wittymail-v2/src/app/attachments/attachments.component.ts new file mode 100644 index 0000000..77d0f11 --- /dev/null +++ b/frontend/wittymail-v2/src/app/attachments/attachments.component.ts @@ -0,0 +1,58 @@ +import { Component, OnInit } from '@angular/core'; + +@Component({ + selector: 'app-attachments', + templateUrl: './attachments.component.html', + styleUrls: ['./attachments.component.css'] +}) +export class AttachmentsComponent implements OnInit { + + headers = ['Sr No.', 'Name of Child', 'Class'] + attachmentSubjectHeaderName = 'Name of Child' + sheetContents = [ + { + 'Sr No.': "1", + 'Name of Child': "Aradhya Karche", + 'Class': "Nursery-kalewadi" + }, + { + 'Sr No.': "2", + 'Name of Child': "Vedika Shirgire", + 'Class': "Nursery-kalewadi" + } + ]; + selectedRow: any = null; + + attachmentCandidatesForSelectedRow = [ + { + 'id': 12345, + 'displayName': "Aradhya Karche.pdf" + }, + { + 'id': 12346, + 'displayName': "Aaradhya Karche.pdf" + }, + { + 'id': 12347, + 'displayName': "Aradhya Kachre.pdf" + } + ] + selectedAttachmentCandidate: any = null; + + + constructor() { } + + ngOnInit() { + } + + onClickRow(row) { + console.log(row) + console.log(row[this.attachmentSubjectHeaderName]) + this.selectedRow = row; + } + + onSelectCandidatePDF(candidate) { + console.log(candidate); + } + +} diff --git a/frontend/wittymail-v2/src/app/steps-slider/steps-slider.component.html b/frontend/wittymail-v2/src/app/steps-slider/steps-slider.component.html index 1fc2fc6..f095e4d 100644 --- a/frontend/wittymail-v2/src/app/steps-slider/steps-slider.component.html +++ b/frontend/wittymail-v2/src/app/steps-slider/steps-slider.component.html @@ -4,7 +4,7 @@ - This is step 2 + diff --git a/frontend/wittymail-v2/yarn.lock b/frontend/wittymail-v2/yarn.lock index 88ba4d7..fef226a 100644 --- a/frontend/wittymail-v2/yarn.lock +++ b/frontend/wittymail-v2/yarn.lock @@ -173,6 +173,13 @@ dependencies: tslib "^1.9.0" +"@angular/flex-layout@^7.0.0-beta.24": + version "7.0.0-beta.24" + resolved "https://registry.yarnpkg.com/@angular/flex-layout/-/flex-layout-7.0.0-beta.24.tgz#ad2fd2b0ff5e49119a6e0bc2052256967ad749af" + integrity sha512-ll6sK0nLGxqI/f5+z4jbd+pve1QITzgehv2AuGvfSDgIjPMeqUDB5YZqQmIGM/dQRk/vIio5KCW5LQPJWzMMYQ== + dependencies: + tslib "^1.7.1" + "@angular/forms@~7.2.0": version "7.2.13" resolved "https://registry.yarnpkg.com/@angular/forms/-/forms-7.2.13.tgz#27686331b6501a86fbb6c25904781ec233cdb059" From eac1caef918256f4b4754a36b48bd321d9da1f95 Mon Sep 17 00:00:00 2001 From: Omkar Ekbote Date: Sun, 21 Apr 2019 03:06:17 +0530 Subject: [PATCH 09/64] Added PDF viewer --- .../app/attachments/attachments.component.css | 5 ++ .../attachments/attachments.component.html | 76 ++++++++++--------- .../app/attachments/attachments.component.ts | 12 ++- 3 files changed, 54 insertions(+), 39 deletions(-) diff --git a/frontend/wittymail-v2/src/app/attachments/attachments.component.css b/frontend/wittymail-v2/src/app/attachments/attachments.component.css index 5358824..8cf7fb7 100644 --- a/frontend/wittymail-v2/src/app/attachments/attachments.component.css +++ b/frontend/wittymail-v2/src/app/attachments/attachments.component.css @@ -14,4 +14,9 @@ table { .attachment-candidate-list-item { margin: 5px; +} + +.embedded-pdf-viewer { + width: 100%; + height: 100%; } \ No newline at end of file diff --git a/frontend/wittymail-v2/src/app/attachments/attachments.component.html b/frontend/wittymail-v2/src/app/attachments/attachments.component.html index 30c66eb..ced7800 100644 --- a/frontend/wittymail-v2/src/app/attachments/attachments.component.html +++ b/frontend/wittymail-v2/src/app/attachments/attachments.component.html @@ -1,43 +1,45 @@ -
-
- -
- -
- - - - - -
{{header}} {{element[header]}}
-
-
-
-
-
-

- Select a row -

+
+
+
+ +
+ +
+ + -
- Pick the correct attachment for {{selectedRow[attachmentSubjectHeaderName]}}: -
- - - {{candidate.displayName}} - - +
+ +
{{header}} {{element[header]}}
+
+
+
+
+
+

+ Select a row +

+
+
+ Pick the correct attachment for {{selectedRow[attachmentSubjectHeaderName]}}: +
+ + + {{candidate.displayName}} + + +
-
-
-
- PDF Viewer for {{selectedAttachmentCandidate}} -
-
+
+
+ PDF Viewer for {{selectedAttachmentCandidate}} +
+
+
diff --git a/frontend/wittymail-v2/src/app/attachments/attachments.component.ts b/frontend/wittymail-v2/src/app/attachments/attachments.component.ts index 77d0f11..63aa792 100644 --- a/frontend/wittymail-v2/src/app/attachments/attachments.component.ts +++ b/frontend/wittymail-v2/src/app/attachments/attachments.component.ts @@ -1,4 +1,5 @@ import { Component, OnInit } from '@angular/core'; +import { SafeHtml, DomSanitizer } from '@angular/platform-browser'; @Component({ selector: 'app-attachments', @@ -38,9 +39,9 @@ export class AttachmentsComponent implements OnInit { } ] selectedAttachmentCandidate: any = null; + selectedPDFViewerHTML: SafeHtml = null; - - constructor() { } + constructor(private sanitizer: DomSanitizer) { } ngOnInit() { } @@ -53,6 +54,13 @@ export class AttachmentsComponent implements OnInit { onSelectCandidatePDF(candidate) { console.log(candidate); + + let pdfurl = "https://pdfobject.com/pdf/sample-3pp.pdf"; + + this.selectedPDFViewerHTML = this.sanitizer.bypassSecurityTrustHtml( + "" + + "Object " + pdfurl + " failed" + + ""); } } From 693e1c905b2ae0aee7c4877c1a3b4eef402e6a8f Mon Sep 17 00:00:00 2001 From: Omkar Ekbote Date: Sun, 21 Apr 2019 03:28:53 +0530 Subject: [PATCH 10/64] Add PDF rotation buttons --- frontend/wittymail-v2/src/app/app.module.ts | 4 +++- .../app/attachments/attachments.component.css | 16 ++++++++++++++++ .../app/attachments/attachments.component.html | 17 ++++++++++++++--- 3 files changed, 33 insertions(+), 4 deletions(-) diff --git a/frontend/wittymail-v2/src/app/app.module.ts b/frontend/wittymail-v2/src/app/app.module.ts index b453e31..5298331 100644 --- a/frontend/wittymail-v2/src/app/app.module.ts +++ b/frontend/wittymail-v2/src/app/app.module.ts @@ -12,6 +12,7 @@ import { AppRoutingModule } from './app-routing.module'; import { AppComponent } from './app.component'; import { StepsSliderComponent } from './steps-slider/steps-slider.component'; import { AttachmentsComponent } from './attachments/attachments.component'; +import {MatButtonModule} from '@angular/material/button'; @NgModule({ declarations: [ @@ -29,7 +30,8 @@ import { AttachmentsComponent } from './attachments/attachments.component'; MatToolbarModule, MatStepperModule, MatTableModule, - MatRadioModule + MatRadioModule, + MatButtonModule ], providers: [], bootstrap: [AppComponent] diff --git a/frontend/wittymail-v2/src/app/attachments/attachments.component.css b/frontend/wittymail-v2/src/app/attachments/attachments.component.css index 8cf7fb7..0334fe6 100644 --- a/frontend/wittymail-v2/src/app/attachments/attachments.component.css +++ b/frontend/wittymail-v2/src/app/attachments/attachments.component.css @@ -19,4 +19,20 @@ table { .embedded-pdf-viewer { width: 100%; height: 100%; +} + +.step-container { + height: 70vh; +} + +button { + margin: 5px; +} + +.btn-icon { + margin-right: 5px; +} + +.pdf-btn-group { + text-align: center; } \ No newline at end of file diff --git a/frontend/wittymail-v2/src/app/attachments/attachments.component.html b/frontend/wittymail-v2/src/app/attachments/attachments.component.html index ced7800..bd100de 100644 --- a/frontend/wittymail-v2/src/app/attachments/attachments.component.html +++ b/frontend/wittymail-v2/src/app/attachments/attachments.component.html @@ -1,4 +1,4 @@ -
+
@@ -34,9 +34,20 @@ -
+
- PDF Viewer for {{selectedAttachmentCandidate}} +
+ + + +

From a78904b70310d3290426961019fe571f318b0b07 Mon Sep 17 00:00:00 2001 From: Omkar Ekbote Date: Mon, 22 Apr 2019 18:09:10 +0530 Subject: [PATCH 11/64] Added WittyMail_ClassDiagram.drawio --- docs/WittyMail_ClassDiagram.drawio | 1 + 1 file changed, 1 insertion(+) create mode 100644 docs/WittyMail_ClassDiagram.drawio diff --git a/docs/WittyMail_ClassDiagram.drawio b/docs/WittyMail_ClassDiagram.drawio new file mode 100644 index 0000000..ed45caa --- /dev/null +++ b/docs/WittyMail_ClassDiagram.drawio @@ -0,0 +1 @@ +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 \ No newline at end of file From c5588945fc89fe7399cb0ea8500af7dc958d9883 Mon Sep 17 00:00:00 2001 From: Omkar Ekbote Date: Mon, 22 Apr 2019 18:11:13 +0530 Subject: [PATCH 12/64] Added PNG for WittyMail_ClassDiagram.png --- docs/WittyMail_ClassDiagram.png | Bin 0 -> 29452 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 docs/WittyMail_ClassDiagram.png diff --git a/docs/WittyMail_ClassDiagram.png b/docs/WittyMail_ClassDiagram.png new file mode 100644 index 0000000000000000000000000000000000000000..400398cb7c0fde440c4bd53cd18de13ad061e1d4 GIT binary patch literal 29452 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 z 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 Date: Mon, 22 Apr 2019 18:13:33 +0530 Subject: [PATCH 13/64] Update WittyMail_ClassDiagram.drawio --- docs/WittyMail_ClassDiagram.drawio | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/WittyMail_ClassDiagram.drawio b/docs/WittyMail_ClassDiagram.drawio index ed45caa..4116ce2 100644 --- a/docs/WittyMail_ClassDiagram.drawio +++ b/docs/WittyMail_ClassDiagram.drawio @@ -1 +1 @@ -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 \ No newline at end of file +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 \ No newline at end of file From b1ced4586b87e20f7754130eaed5a568da5fc46a Mon Sep 17 00:00:00 2001 From: Omkar Ekbote Date: Mon, 22 Apr 2019 18:58:19 +0530 Subject: [PATCH 14/64] Add attachment upload step --- frontend/wittymail-v2/package.json | 1 + frontend/wittymail-v2/src/app/app.module.ts | 9 +- .../app/attachments/attachments.component.css | 2 +- .../attachments/attachments.component.html | 123 +++++++++++------- .../app/attachments/attachments.component.ts | 60 +++++++++ frontend/wittymail-v2/yarn.lock | 5 + 6 files changed, 149 insertions(+), 51 deletions(-) diff --git a/frontend/wittymail-v2/package.json b/frontend/wittymail-v2/package.json index 0300c55..b18d2ff 100644 --- a/frontend/wittymail-v2/package.json +++ b/frontend/wittymail-v2/package.json @@ -24,6 +24,7 @@ "@angular/router": "~7.2.0", "core-js": "^2.5.4", "hammerjs": "^2.0.8", + "ng2-file-upload": "^1.3.0", "rxjs": "~6.3.3", "tslib": "^1.9.0", "zone.js": "~0.8.26" diff --git a/frontend/wittymail-v2/src/app/app.module.ts b/frontend/wittymail-v2/src/app/app.module.ts index 5298331..30f5ffb 100644 --- a/frontend/wittymail-v2/src/app/app.module.ts +++ b/frontend/wittymail-v2/src/app/app.module.ts @@ -2,6 +2,8 @@ import { BrowserModule } from '@angular/platform-browser'; import { NgModule } from '@angular/core'; import {BrowserAnimationsModule} from '@angular/platform-browser/animations'; import { FormsModule } from '@angular/forms'; +import { FileUploadModule } from 'ng2-file-upload'; + import {MatToolbarModule} from '@angular/material/toolbar'; import {MatStepperModule} from '@angular/material/stepper'; import { FlexLayoutModule } from '@angular/flex-layout'; @@ -13,6 +15,8 @@ import { AppComponent } from './app.component'; import { StepsSliderComponent } from './steps-slider/steps-slider.component'; import { AttachmentsComponent } from './attachments/attachments.component'; import {MatButtonModule} from '@angular/material/button'; +import {MatFormFieldModule} from '@angular/material/form-field'; +import {MatInputModule} from '@angular/material'; @NgModule({ declarations: [ @@ -26,12 +30,15 @@ import {MatButtonModule} from '@angular/material/button'; BrowserAnimationsModule, FlexLayoutModule, + FileUploadModule, FormsModule, MatToolbarModule, MatStepperModule, MatTableModule, MatRadioModule, - MatButtonModule + MatButtonModule, + MatFormFieldModule, + MatInputModule ], providers: [], bootstrap: [AppComponent] diff --git a/frontend/wittymail-v2/src/app/attachments/attachments.component.css b/frontend/wittymail-v2/src/app/attachments/attachments.component.css index 0334fe6..512f7a8 100644 --- a/frontend/wittymail-v2/src/app/attachments/attachments.component.css +++ b/frontend/wittymail-v2/src/app/attachments/attachments.component.css @@ -22,7 +22,7 @@ table { } .step-container { - height: 70vh; + height: 100%; } button { diff --git a/frontend/wittymail-v2/src/app/attachments/attachments.component.html b/frontend/wittymail-v2/src/app/attachments/attachments.component.html index bd100de..e5e01b0 100644 --- a/frontend/wittymail-v2/src/app/attachments/attachments.component.html +++ b/frontend/wittymail-v2/src/app/attachments/attachments.component.html @@ -1,58 +1,83 @@
-
-
-
-
- -
- - + + +
+
+ Common Attachments
-
- -
{{header}} {{element[header]}}
-
-
-
-
-
-

- Select a row -

-
-
- Pick the correct attachment for {{selectedRow[attachmentSubjectHeaderName]}}: -
- - - {{candidate.displayName}} - - -
+
+ +
+
+ Individual Attachments +
+
+
-
-
-
- - - + + + + + +
+
+ +
+ +
+ + + + + +
{{header}} {{element[header]}}
+
+
+
+
+
+

+ Select a row +

+
+
+ Pick the correct attachment for {{selectedRow[attachmentSubjectHeaderName]}}: +
+ + + {{candidate.displayName}} + + +
+
-
-
+
+
+
+ + + +
+
+
+
+
-
-
+ +
\ No newline at end of file diff --git a/frontend/wittymail-v2/src/app/attachments/attachments.component.ts b/frontend/wittymail-v2/src/app/attachments/attachments.component.ts index 63aa792..da4fa80 100644 --- a/frontend/wittymail-v2/src/app/attachments/attachments.component.ts +++ b/frontend/wittymail-v2/src/app/attachments/attachments.component.ts @@ -16,6 +16,66 @@ export class AttachmentsComponent implements OnInit { 'Name of Child': "Aradhya Karche", 'Class': "Nursery-kalewadi" }, + { + 'Sr No.': "2", + 'Name of Child': "Vedika Shirgire", + 'Class': "Nursery-kalewadi" + }, + { + 'Sr No.': "2", + 'Name of Child': "Vedika Shirgire", + 'Class': "Nursery-kalewadi" + }, + { + 'Sr No.': "2", + 'Name of Child': "Vedika Shirgire", + 'Class': "Nursery-kalewadi" + }, + { + 'Sr No.': "2", + 'Name of Child': "Vedika Shirgire", + 'Class': "Nursery-kalewadi" + }, + { + 'Sr No.': "2", + 'Name of Child': "Vedika Shirgire", + 'Class': "Nursery-kalewadi" + }, + { + 'Sr No.': "2", + 'Name of Child': "Vedika Shirgire", + 'Class': "Nursery-kalewadi" + }, + { + 'Sr No.': "2", + 'Name of Child': "Vedika Shirgire", + 'Class': "Nursery-kalewadi" + }, + { + 'Sr No.': "2", + 'Name of Child': "Vedika Shirgire", + 'Class': "Nursery-kalewadi" + }, + { + 'Sr No.': "2", + 'Name of Child': "Vedika Shirgire", + 'Class': "Nursery-kalewadi" + }, + { + 'Sr No.': "2", + 'Name of Child': "Vedika Shirgire", + 'Class': "Nursery-kalewadi" + }, + { + 'Sr No.': "2", + 'Name of Child': "Vedika Shirgire", + 'Class': "Nursery-kalewadi" + }, + { + 'Sr No.': "2", + 'Name of Child': "Vedika Shirgire", + 'Class': "Nursery-kalewadi" + }, { 'Sr No.': "2", 'Name of Child': "Vedika Shirgire", diff --git a/frontend/wittymail-v2/yarn.lock b/frontend/wittymail-v2/yarn.lock index fef226a..0c62909 100644 --- a/frontend/wittymail-v2/yarn.lock +++ b/frontend/wittymail-v2/yarn.lock @@ -4419,6 +4419,11 @@ neo-async@^2.5.0, neo-async@^2.6.0: resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.0.tgz#b9d15e4d71c6762908654b5183ed38b753340835" integrity sha512-MFh0d/Wa7vkKO3Y3LlacqAEeHK0mckVqzDieUKTT+KGxi+zIpeVsFxymkIiRpbpDziHc290Xr9A1O4Om7otoRA== +ng2-file-upload@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/ng2-file-upload/-/ng2-file-upload-1.3.0.tgz#d90f8f568f62383462175f8bdfa0096b131f277a" + integrity sha512-Pudxik6LWYsT8hNiEW7RfjgGWAnvfQywxwJYMdt1snTUe+KnlRc/QqPv3QEQW6plXTanuLkYz/TbqilSfSHOsw== + nice-try@^1.0.4: version "1.0.5" resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" From cc09540efa5aee3d31cc6da6c2d812e6d384186c Mon Sep 17 00:00:00 2001 From: Omkar Ekbote Date: Mon, 22 Apr 2019 19:07:41 +0530 Subject: [PATCH 15/64] Add summary step --- .../app/attachments/attachments.component.css | 9 ++ .../attachments/attachments.component.html | 127 ++++++++++-------- 2 files changed, 81 insertions(+), 55 deletions(-) diff --git a/frontend/wittymail-v2/src/app/attachments/attachments.component.css b/frontend/wittymail-v2/src/app/attachments/attachments.component.css index 512f7a8..1715cf1 100644 --- a/frontend/wittymail-v2/src/app/attachments/attachments.component.css +++ b/frontend/wittymail-v2/src/app/attachments/attachments.component.css @@ -25,6 +25,10 @@ table { height: 100%; } +.attachment-selector-container { + height: 100vh; +} + button { margin: 5px; } @@ -35,4 +39,9 @@ button { .pdf-btn-group { text-align: center; +} + +.summary-table-container { + height: 100vh; + overflow: auto; } \ No newline at end of file diff --git a/frontend/wittymail-v2/src/app/attachments/attachments.component.html b/frontend/wittymail-v2/src/app/attachments/attachments.component.html index e5e01b0..9737152 100644 --- a/frontend/wittymail-v2/src/app/attachments/attachments.component.html +++ b/frontend/wittymail-v2/src/app/attachments/attachments.component.html @@ -1,83 +1,100 @@
- +
Common Attachments
- +
Individual Attachments
- +
- - + -
-
- -
- -
- - - - - -
{{header}} {{element[header]}}
-
-
-
-
-
-

- Select a row -

-
-
- Pick the correct attachment for {{selectedRow[attachmentSubjectHeaderName]}}: -
- - - {{candidate.displayName}} - - +
+
+
+ +
+ +
+ + - + + +
{{header}} {{element[header]}}
-
-
-
- - - +
+
+
+
+

+ Select a row +

+
+
+ Pick the correct attachment for {{selectedRow[attachmentSubjectHeaderName]}}: +
+ + + {{candidate.displayName}} + + +
-
-
+
+
+
+
+ + + +
+
+
+
+ + +
+ +
+ +
+ + + + + +
{{header}} {{element[header]}}
+
+
\ No newline at end of file From 954efb36fa877d5b79888e1b31387de270976a68 Mon Sep 17 00:00:00 2001 From: Omkar Ekbote Date: Tue, 23 Apr 2019 07:28:06 +0530 Subject: [PATCH 16/64] Add logger service --- frontend/wittymail-v2/angular.json | 9 +++- .../src/app/app.component.spec.ts | 35 ---------------- .../attachments/attachments.component.spec.ts | 25 ----------- .../app/attachments/attachments.component.ts | 9 ++-- .../steps-slider.component.spec.ts | 25 ----------- .../src/app/util/console-logger.service.ts | 42 +++++++++++++++++++ .../src/app/util/logger.service.ts | 16 +++++++ 7 files changed, 71 insertions(+), 90 deletions(-) delete mode 100644 frontend/wittymail-v2/src/app/app.component.spec.ts delete mode 100644 frontend/wittymail-v2/src/app/attachments/attachments.component.spec.ts delete mode 100644 frontend/wittymail-v2/src/app/steps-slider/steps-slider.component.spec.ts create mode 100644 frontend/wittymail-v2/src/app/util/console-logger.service.ts create mode 100644 frontend/wittymail-v2/src/app/util/logger.service.ts diff --git a/frontend/wittymail-v2/angular.json b/frontend/wittymail-v2/angular.json index e82229e..b5de8a1 100644 --- a/frontend/wittymail-v2/angular.json +++ b/frontend/wittymail-v2/angular.json @@ -132,5 +132,12 @@ } } }, - "defaultProject": "wittymail-v2" + "defaultProject": "wittymail-v2", + "schematics": { + "@schematics/angular": { + "component": { + "spec": false + } + } + } } \ No newline at end of file diff --git a/frontend/wittymail-v2/src/app/app.component.spec.ts b/frontend/wittymail-v2/src/app/app.component.spec.ts deleted file mode 100644 index 33a0690..0000000 --- a/frontend/wittymail-v2/src/app/app.component.spec.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { TestBed, async } from '@angular/core/testing'; -import { RouterTestingModule } from '@angular/router/testing'; -import { AppComponent } from './app.component'; - -describe('AppComponent', () => { - beforeEach(async(() => { - TestBed.configureTestingModule({ - imports: [ - RouterTestingModule - ], - declarations: [ - AppComponent - ], - }).compileComponents(); - })); - - it('should create the app', () => { - const fixture = TestBed.createComponent(AppComponent); - const app = fixture.debugElement.componentInstance; - expect(app).toBeTruthy(); - }); - - it(`should have as title 'wittymail-v2'`, () => { - const fixture = TestBed.createComponent(AppComponent); - const app = fixture.debugElement.componentInstance; - expect(app.title).toEqual('wittymail-v2'); - }); - - it('should render title in a h1 tag', () => { - const fixture = TestBed.createComponent(AppComponent); - fixture.detectChanges(); - const compiled = fixture.debugElement.nativeElement; - expect(compiled.querySelector('h1').textContent).toContain('Welcome to wittymail-v2!'); - }); -}); diff --git a/frontend/wittymail-v2/src/app/attachments/attachments.component.spec.ts b/frontend/wittymail-v2/src/app/attachments/attachments.component.spec.ts deleted file mode 100644 index 3a6f046..0000000 --- a/frontend/wittymail-v2/src/app/attachments/attachments.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; - -import { AttachmentsComponent } from './attachments.component'; - -describe('AttachmentsComponent', () => { - let component: AttachmentsComponent; - let fixture: ComponentFixture; - - beforeEach(async(() => { - TestBed.configureTestingModule({ - declarations: [ AttachmentsComponent ] - }) - .compileComponents(); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(AttachmentsComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/frontend/wittymail-v2/src/app/attachments/attachments.component.ts b/frontend/wittymail-v2/src/app/attachments/attachments.component.ts index da4fa80..bb1f15a 100644 --- a/frontend/wittymail-v2/src/app/attachments/attachments.component.ts +++ b/frontend/wittymail-v2/src/app/attachments/attachments.component.ts @@ -1,5 +1,6 @@ import { Component, OnInit } from '@angular/core'; import { SafeHtml, DomSanitizer } from '@angular/platform-browser'; +import { LoggerService } from '../util/logger.service'; @Component({ selector: 'app-attachments', @@ -101,19 +102,19 @@ export class AttachmentsComponent implements OnInit { selectedAttachmentCandidate: any = null; selectedPDFViewerHTML: SafeHtml = null; - constructor(private sanitizer: DomSanitizer) { } + constructor(private sanitizer: DomSanitizer, private log: LoggerService) { } ngOnInit() { } onClickRow(row) { - console.log(row) - console.log(row[this.attachmentSubjectHeaderName]) + this.log.info(row) + this.log.info(row[this.attachmentSubjectHeaderName]) this.selectedRow = row; } onSelectCandidatePDF(candidate) { - console.log(candidate); + this.log.info(candidate); let pdfurl = "https://pdfobject.com/pdf/sample-3pp.pdf"; diff --git a/frontend/wittymail-v2/src/app/steps-slider/steps-slider.component.spec.ts b/frontend/wittymail-v2/src/app/steps-slider/steps-slider.component.spec.ts deleted file mode 100644 index f2d3b68..0000000 --- a/frontend/wittymail-v2/src/app/steps-slider/steps-slider.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; - -import { StepsSliderComponent } from './steps-slider.component'; - -describe('StepsSliderComponent', () => { - let component: StepsSliderComponent; - let fixture: ComponentFixture; - - beforeEach(async(() => { - TestBed.configureTestingModule({ - declarations: [ StepsSliderComponent ] - }) - .compileComponents(); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(StepsSliderComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/frontend/wittymail-v2/src/app/util/console-logger.service.ts b/frontend/wittymail-v2/src/app/util/console-logger.service.ts new file mode 100644 index 0000000..d521aca --- /dev/null +++ b/frontend/wittymail-v2/src/app/util/console-logger.service.ts @@ -0,0 +1,42 @@ +import { Injectable } from '@angular/core'; +import { Logger } from './logger.service'; + +// Change this to enable/disable logging globally on the console +export let isLoggingEnabled = true; + +const noop = (): any => undefined; + +@Injectable({ + providedIn: 'root' +}) +export class ConsoleLoggerService implements Logger { + + get info() { + if (isLoggingEnabled) { + return console.info.bind(console); + } else { + return noop; + } + } + + get warn() { + if (isLoggingEnabled) { + return console.warn.bind(console); + } else { + return noop; + } + } + + get error() { + if (isLoggingEnabled) { + return console.error.bind(console); + } else { + return noop; + } + } + + invokeConsoleMethod(type: string, args?: any): void { + const logFn: Function = (console)[type] || console.log || noop; + logFn.apply(console, [args]); + } +} \ No newline at end of file diff --git a/frontend/wittymail-v2/src/app/util/logger.service.ts b/frontend/wittymail-v2/src/app/util/logger.service.ts new file mode 100644 index 0000000..ba3ed20 --- /dev/null +++ b/frontend/wittymail-v2/src/app/util/logger.service.ts @@ -0,0 +1,16 @@ +import { Injectable } from '@angular/core'; + +export abstract class Logger { + info: any; + warn: any; + error: any; +} + +@Injectable() +export class LoggerService implements Logger { + info: any; + warn: any; + error: any; + + invokeConsoleMethod(type: string, args?: any): void {} +} \ No newline at end of file From 9bbce7775a30d9b8f05a9f2dfc7681f73d1ace2f Mon Sep 17 00:00:00 2001 From: Omkar Ekbote Date: Tue, 23 Apr 2019 07:30:24 +0530 Subject: [PATCH 17/64] Create sleletons for other components --- frontend/wittymail-v2/src/app/app.module.ts | 12 +++++++++++- .../src/app/common/about/about.component.css | 0 .../src/app/common/about/about.component.html | 3 +++ .../src/app/common/about/about.component.ts | 15 +++++++++++++++ .../error-dialog/error-dialog.component.css | 0 .../error-dialog/error-dialog.component.html | 3 +++ .../common/error-dialog/error-dialog.component.ts | 15 +++++++++++++++ .../app/email-design/email-design.component.css | 0 .../app/email-design/email-design.component.html | 3 +++ .../app/email-design/email-design.component.ts | 15 +++++++++++++++ .../app/sponsor-list/sponsor-list.component.css | 0 .../app/sponsor-list/sponsor-list.component.html | 3 +++ .../app/sponsor-list/sponsor-list.component.ts | 15 +++++++++++++++ .../src/app/summary/summary.component.css | 0 .../src/app/summary/summary.component.html | 3 +++ .../src/app/summary/summary.component.ts | 15 +++++++++++++++ 16 files changed, 101 insertions(+), 1 deletion(-) create mode 100644 frontend/wittymail-v2/src/app/common/about/about.component.css create mode 100644 frontend/wittymail-v2/src/app/common/about/about.component.html create mode 100644 frontend/wittymail-v2/src/app/common/about/about.component.ts create mode 100644 frontend/wittymail-v2/src/app/common/error-dialog/error-dialog.component.css create mode 100644 frontend/wittymail-v2/src/app/common/error-dialog/error-dialog.component.html create mode 100644 frontend/wittymail-v2/src/app/common/error-dialog/error-dialog.component.ts create mode 100644 frontend/wittymail-v2/src/app/email-design/email-design.component.css create mode 100644 frontend/wittymail-v2/src/app/email-design/email-design.component.html create mode 100644 frontend/wittymail-v2/src/app/email-design/email-design.component.ts create mode 100644 frontend/wittymail-v2/src/app/sponsor-list/sponsor-list.component.css create mode 100644 frontend/wittymail-v2/src/app/sponsor-list/sponsor-list.component.html create mode 100644 frontend/wittymail-v2/src/app/sponsor-list/sponsor-list.component.ts create mode 100644 frontend/wittymail-v2/src/app/summary/summary.component.css create mode 100644 frontend/wittymail-v2/src/app/summary/summary.component.html create mode 100644 frontend/wittymail-v2/src/app/summary/summary.component.ts diff --git a/frontend/wittymail-v2/src/app/app.module.ts b/frontend/wittymail-v2/src/app/app.module.ts index 30f5ffb..b3e17c8 100644 --- a/frontend/wittymail-v2/src/app/app.module.ts +++ b/frontend/wittymail-v2/src/app/app.module.ts @@ -17,12 +17,22 @@ import { AttachmentsComponent } from './attachments/attachments.component'; import {MatButtonModule} from '@angular/material/button'; import {MatFormFieldModule} from '@angular/material/form-field'; import {MatInputModule} from '@angular/material'; +import { SponsorListComponent } from './sponsor-list/sponsor-list.component'; +import { EmailDesignComponent } from './email-design/email-design.component'; +import { SummaryComponent } from './summary/summary.component'; +import { AboutComponent } from './common/about/about.component'; +import { ErrorDialogComponent } from './common/error-dialog/error-dialog.component'; @NgModule({ declarations: [ AppComponent, StepsSliderComponent, - AttachmentsComponent + AttachmentsComponent, + SponsorListComponent, + EmailDesignComponent, + SummaryComponent, + AboutComponent, + ErrorDialogComponent ], imports: [ BrowserModule, diff --git a/frontend/wittymail-v2/src/app/common/about/about.component.css b/frontend/wittymail-v2/src/app/common/about/about.component.css new file mode 100644 index 0000000..e69de29 diff --git a/frontend/wittymail-v2/src/app/common/about/about.component.html b/frontend/wittymail-v2/src/app/common/about/about.component.html new file mode 100644 index 0000000..17e2a33 --- /dev/null +++ b/frontend/wittymail-v2/src/app/common/about/about.component.html @@ -0,0 +1,3 @@ +

+ about works! +

diff --git a/frontend/wittymail-v2/src/app/common/about/about.component.ts b/frontend/wittymail-v2/src/app/common/about/about.component.ts new file mode 100644 index 0000000..d8a4231 --- /dev/null +++ b/frontend/wittymail-v2/src/app/common/about/about.component.ts @@ -0,0 +1,15 @@ +import { Component, OnInit } from '@angular/core'; + +@Component({ + selector: 'app-about', + templateUrl: './about.component.html', + styleUrls: ['./about.component.css'] +}) +export class AboutComponent implements OnInit { + + constructor() { } + + ngOnInit() { + } + +} diff --git a/frontend/wittymail-v2/src/app/common/error-dialog/error-dialog.component.css b/frontend/wittymail-v2/src/app/common/error-dialog/error-dialog.component.css new file mode 100644 index 0000000..e69de29 diff --git a/frontend/wittymail-v2/src/app/common/error-dialog/error-dialog.component.html b/frontend/wittymail-v2/src/app/common/error-dialog/error-dialog.component.html new file mode 100644 index 0000000..17d57ef --- /dev/null +++ b/frontend/wittymail-v2/src/app/common/error-dialog/error-dialog.component.html @@ -0,0 +1,3 @@ +

+ error-dialog works! +

diff --git a/frontend/wittymail-v2/src/app/common/error-dialog/error-dialog.component.ts b/frontend/wittymail-v2/src/app/common/error-dialog/error-dialog.component.ts new file mode 100644 index 0000000..9ffb819 --- /dev/null +++ b/frontend/wittymail-v2/src/app/common/error-dialog/error-dialog.component.ts @@ -0,0 +1,15 @@ +import { Component, OnInit } from '@angular/core'; + +@Component({ + selector: 'app-error-dialog', + templateUrl: './error-dialog.component.html', + styleUrls: ['./error-dialog.component.css'] +}) +export class ErrorDialogComponent implements OnInit { + + constructor() { } + + ngOnInit() { + } + +} diff --git a/frontend/wittymail-v2/src/app/email-design/email-design.component.css b/frontend/wittymail-v2/src/app/email-design/email-design.component.css new file mode 100644 index 0000000..e69de29 diff --git a/frontend/wittymail-v2/src/app/email-design/email-design.component.html b/frontend/wittymail-v2/src/app/email-design/email-design.component.html new file mode 100644 index 0000000..762c1c4 --- /dev/null +++ b/frontend/wittymail-v2/src/app/email-design/email-design.component.html @@ -0,0 +1,3 @@ +

+ email-design works! +

diff --git a/frontend/wittymail-v2/src/app/email-design/email-design.component.ts b/frontend/wittymail-v2/src/app/email-design/email-design.component.ts new file mode 100644 index 0000000..0ddffa2 --- /dev/null +++ b/frontend/wittymail-v2/src/app/email-design/email-design.component.ts @@ -0,0 +1,15 @@ +import { Component, OnInit } from '@angular/core'; + +@Component({ + selector: 'app-email-design', + templateUrl: './email-design.component.html', + styleUrls: ['./email-design.component.css'] +}) +export class EmailDesignComponent implements OnInit { + + constructor() { } + + ngOnInit() { + } + +} diff --git a/frontend/wittymail-v2/src/app/sponsor-list/sponsor-list.component.css b/frontend/wittymail-v2/src/app/sponsor-list/sponsor-list.component.css new file mode 100644 index 0000000..e69de29 diff --git a/frontend/wittymail-v2/src/app/sponsor-list/sponsor-list.component.html b/frontend/wittymail-v2/src/app/sponsor-list/sponsor-list.component.html new file mode 100644 index 0000000..bce2eb9 --- /dev/null +++ b/frontend/wittymail-v2/src/app/sponsor-list/sponsor-list.component.html @@ -0,0 +1,3 @@ +

+ sponsor-list works! +

diff --git a/frontend/wittymail-v2/src/app/sponsor-list/sponsor-list.component.ts b/frontend/wittymail-v2/src/app/sponsor-list/sponsor-list.component.ts new file mode 100644 index 0000000..9fe4d14 --- /dev/null +++ b/frontend/wittymail-v2/src/app/sponsor-list/sponsor-list.component.ts @@ -0,0 +1,15 @@ +import { Component, OnInit } from '@angular/core'; + +@Component({ + selector: 'app-sponsor-list', + templateUrl: './sponsor-list.component.html', + styleUrls: ['./sponsor-list.component.css'] +}) +export class SponsorListComponent implements OnInit { + + constructor() { } + + ngOnInit() { + } + +} diff --git a/frontend/wittymail-v2/src/app/summary/summary.component.css b/frontend/wittymail-v2/src/app/summary/summary.component.css new file mode 100644 index 0000000..e69de29 diff --git a/frontend/wittymail-v2/src/app/summary/summary.component.html b/frontend/wittymail-v2/src/app/summary/summary.component.html new file mode 100644 index 0000000..fad0388 --- /dev/null +++ b/frontend/wittymail-v2/src/app/summary/summary.component.html @@ -0,0 +1,3 @@ +

+ summary works! +

diff --git a/frontend/wittymail-v2/src/app/summary/summary.component.ts b/frontend/wittymail-v2/src/app/summary/summary.component.ts new file mode 100644 index 0000000..fd3e3bd --- /dev/null +++ b/frontend/wittymail-v2/src/app/summary/summary.component.ts @@ -0,0 +1,15 @@ +import { Component, OnInit } from '@angular/core'; + +@Component({ + selector: 'app-summary', + templateUrl: './summary.component.html', + styleUrls: ['./summary.component.css'] +}) +export class SummaryComponent implements OnInit { + + constructor() { } + + ngOnInit() { + } + +} From 720d13cf7b2b3eed6b17d43d44bd323f48b363b0 Mon Sep 17 00:00:00 2001 From: Omkar Ekbote Date: Tue, 23 Apr 2019 07:40:37 +0530 Subject: [PATCH 18/64] Create app-level menu --- frontend/wittymail-v2/src/app/app.component.css | 11 ++++++++++- frontend/wittymail-v2/src/app/app.component.html | 10 ++++++++++ frontend/wittymail-v2/src/app/app.module.ts | 12 ++++++++++-- 3 files changed, 30 insertions(+), 3 deletions(-) diff --git a/frontend/wittymail-v2/src/app/app.component.css b/frontend/wittymail-v2/src/app/app.component.css index 4c733fe..46ff09d 100644 --- a/frontend/wittymail-v2/src/app/app.component.css +++ b/frontend/wittymail-v2/src/app/app.component.css @@ -1,3 +1,12 @@ .top-banner-logo { margin-right: 0.5rem; -} \ No newline at end of file +} + +.top-banner-spacer { + flex: 1 1 auto; +} + +.top-banner-menu-icon { + padding: 0 0.5rem; +} + \ No newline at end of file diff --git a/frontend/wittymail-v2/src/app/app.component.html b/frontend/wittymail-v2/src/app/app.component.html index 4a24a2a..0c1ea44 100644 --- a/frontend/wittymail-v2/src/app/app.component.html +++ b/frontend/wittymail-v2/src/app/app.component.html @@ -3,6 +3,16 @@ mail_outline WittyMail + + + + + + + + \ No newline at end of file diff --git a/frontend/wittymail-v2/src/app/app.module.ts b/frontend/wittymail-v2/src/app/app.module.ts index b3e17c8..7cb6f9f 100644 --- a/frontend/wittymail-v2/src/app/app.module.ts +++ b/frontend/wittymail-v2/src/app/app.module.ts @@ -9,6 +9,8 @@ import {MatStepperModule} from '@angular/material/stepper'; import { FlexLayoutModule } from '@angular/flex-layout'; import {MatTableModule} from '@angular/material/table'; import {MatRadioModule} from '@angular/material/radio'; +import {MatIconModule} from '@angular/material'; +import {MatMenuModule} from '@angular/material/menu'; import { AppRoutingModule } from './app-routing.module'; import { AppComponent } from './app.component'; @@ -22,6 +24,8 @@ import { EmailDesignComponent } from './email-design/email-design.component'; import { SummaryComponent } from './summary/summary.component'; import { AboutComponent } from './common/about/about.component'; import { ErrorDialogComponent } from './common/error-dialog/error-dialog.component'; +import { LoggerService } from './util/logger.service'; +import { ConsoleLoggerService } from './util/console-logger.service'; @NgModule({ declarations: [ @@ -48,9 +52,13 @@ import { ErrorDialogComponent } from './common/error-dialog/error-dialog.compone MatRadioModule, MatButtonModule, MatFormFieldModule, - MatInputModule + MatInputModule, + MatIconModule, + MatMenuModule + ], + providers: [ + { provide: LoggerService, useClass: ConsoleLoggerService } ], - providers: [], bootstrap: [AppComponent] }) export class AppModule { } From 4f944b21f3fb0f0162ab0c4b61c6a68bcb677e1d Mon Sep 17 00:00:00 2001 From: Omkar Ekbote Date: Tue, 23 Apr 2019 08:03:20 +0530 Subject: [PATCH 19/64] Add about dialog --- .../wittymail-v2/src/app/app.component.html | 2 +- .../wittymail-v2/src/app/app.component.ts | 12 +++++++++++- frontend/wittymail-v2/src/app/app.module.ts | 5 ++++- .../src/app/common/about/about.component.html | 19 ++++++++++++++++--- .../src/app/common/about/about.component.ts | 3 ++- 5 files changed, 34 insertions(+), 7 deletions(-) diff --git a/frontend/wittymail-v2/src/app/app.component.html b/frontend/wittymail-v2/src/app/app.component.html index 0c1ea44..32f5982 100644 --- a/frontend/wittymail-v2/src/app/app.component.html +++ b/frontend/wittymail-v2/src/app/app.component.html @@ -7,7 +7,7 @@ - + +
diff --git a/frontend/wittymail-v2/src/app/common/about/about.component.ts b/frontend/wittymail-v2/src/app/common/about/about.component.ts index d8a4231..ab1e5ac 100644 --- a/frontend/wittymail-v2/src/app/common/about/about.component.ts +++ b/frontend/wittymail-v2/src/app/common/about/about.component.ts @@ -1,4 +1,5 @@ import { Component, OnInit } from '@angular/core'; +import { MatDialogRef } from '@angular/material'; @Component({ selector: 'app-about', @@ -7,7 +8,7 @@ import { Component, OnInit } from '@angular/core'; }) export class AboutComponent implements OnInit { - constructor() { } + constructor(public dialogRef: MatDialogRef,) { } ngOnInit() { } From 93202f740e9507df37bd08e8b88835ce82f53c57 Mon Sep 17 00:00:00 2001 From: Omkar Ekbote Date: Tue, 23 Apr 2019 08:31:34 +0530 Subject: [PATCH 20/64] Added backend REST client and wired up to About dialog --- frontend/wittymail-v2/backend-proxy.conf.json | 11 + frontend/wittymail-v2/package.json | 4 +- .../wittymail-v2/src/app/app.component.ts | 2 +- frontend/wittymail-v2/src/app/app.module.ts | 2 + .../src/app/backend.service.spec.ts | 12 + .../wittymail-v2/src/app/backend.service.ts | 291 ++++++++++++++++++ .../src/app/common/about/about.component.html | 1 + .../src/app/common/about/about.component.ts | 27 +- frontend/wittymail-v2/yarn.lock | 4 +- 9 files changed, 345 insertions(+), 9 deletions(-) create mode 100644 frontend/wittymail-v2/backend-proxy.conf.json create mode 100644 frontend/wittymail-v2/src/app/backend.service.spec.ts create mode 100644 frontend/wittymail-v2/src/app/backend.service.ts diff --git a/frontend/wittymail-v2/backend-proxy.conf.json b/frontend/wittymail-v2/backend-proxy.conf.json new file mode 100644 index 0000000..9ceaa94 --- /dev/null +++ b/frontend/wittymail-v2/backend-proxy.conf.json @@ -0,0 +1,11 @@ +{ + "/api": { + "target": { + "host": "localhost", + "protocol": "http:", + "port": 5000 + }, + "secure": false, + "changeOrigin": true + } +} \ No newline at end of file diff --git a/frontend/wittymail-v2/package.json b/frontend/wittymail-v2/package.json index b18d2ff..10f0cf0 100644 --- a/frontend/wittymail-v2/package.json +++ b/frontend/wittymail-v2/package.json @@ -3,7 +3,7 @@ "version": "0.0.0", "scripts": { "ng": "ng", - "start": "ng serve", + "start": "ng serve --proxy-config backend-proxy.conf.json", "build": "ng build", "test": "ng test", "lint": "ng lint", @@ -25,7 +25,7 @@ "core-js": "^2.5.4", "hammerjs": "^2.0.8", "ng2-file-upload": "^1.3.0", - "rxjs": "~6.3.3", + "rxjs": "^6.4.0", "tslib": "^1.9.0", "zone.js": "~0.8.26" }, diff --git a/frontend/wittymail-v2/src/app/app.component.ts b/frontend/wittymail-v2/src/app/app.component.ts index e9024b0..b051bbb 100644 --- a/frontend/wittymail-v2/src/app/app.component.ts +++ b/frontend/wittymail-v2/src/app/app.component.ts @@ -15,6 +15,6 @@ export class AppComponent { constructor(public dialog: MatDialog) {} openAboutDialog() { - this.dialog.open(AboutComponent, {}); + this.dialog.open(AboutComponent); } } diff --git a/frontend/wittymail-v2/src/app/app.module.ts b/frontend/wittymail-v2/src/app/app.module.ts index f695414..dc0558d 100644 --- a/frontend/wittymail-v2/src/app/app.module.ts +++ b/frontend/wittymail-v2/src/app/app.module.ts @@ -3,6 +3,7 @@ import { NgModule } from '@angular/core'; import {BrowserAnimationsModule} from '@angular/platform-browser/animations'; import { FormsModule } from '@angular/forms'; import { FileUploadModule } from 'ng2-file-upload'; +import { HttpClientModule } from '@angular/common/http'; import {MatToolbarModule} from '@angular/material/toolbar'; import {MatStepperModule} from '@angular/material/stepper'; @@ -44,6 +45,7 @@ import { ConsoleLoggerService } from './util/console-logger.service'; BrowserModule, AppRoutingModule, BrowserAnimationsModule, + HttpClientModule, FlexLayoutModule, FileUploadModule, diff --git a/frontend/wittymail-v2/src/app/backend.service.spec.ts b/frontend/wittymail-v2/src/app/backend.service.spec.ts new file mode 100644 index 0000000..2fe8217 --- /dev/null +++ b/frontend/wittymail-v2/src/app/backend.service.spec.ts @@ -0,0 +1,12 @@ +import { TestBed } from '@angular/core/testing'; + +import { BackendService } from './backend.service'; + +describe('BackendService', () => { + beforeEach(() => TestBed.configureTestingModule({})); + + it('should be created', () => { + const service: BackendService = TestBed.get(BackendService); + expect(service).toBeTruthy(); + }); +}); diff --git a/frontend/wittymail-v2/src/app/backend.service.ts b/frontend/wittymail-v2/src/app/backend.service.ts new file mode 100644 index 0000000..3c462e5 --- /dev/null +++ b/frontend/wittymail-v2/src/app/backend.service.ts @@ -0,0 +1,291 @@ +import { Injectable } from '@angular/core'; +import { LoggerService } from './util/logger.service'; +import { HttpErrorResponse, HttpClient } from '@angular/common/http'; +import { Observable } from 'rxjs'; +import { catchError, retry } from 'rxjs/operators'; +import { throwError } from 'rxjs'; + +export interface VersionInfo { + version: string; +} + +export interface ColumnHeadersWithRowContent { + headers: string[]; + contents: any[]; +} + +export interface ColumnMappings { + to_column: string; + cc_column: string; + attachment_column: string; +} + +export interface EmailMetadata { + to_column: string; + cc_column: string; + subject_template: string; + body_template: string; +} + +export interface AttachmentMetadata { + attachment_column: string; +} + +export interface EmailServerDetails { + service: string; + username: string; + password: string; +} + +export interface TestEmailDetails { + to: string; +} + +export interface SendEmailContent { + from: string; + to: string; + cc: string; + subject: string; + attachment: any; + body: string; +} + +export interface TemplateInput { + template: string; +} + +export interface TemplateOutput { + reality: string; +} + +@Injectable({ + providedIn: 'root' +}) +export class BackendService { + + emailMetadataInstance: EmailMetadata; + attachmentMetadataInstance: AttachmentMetadata; + + urls = { + version: 'api/version', // GET + sheet: { + upload: 'api/sheet/upload', // POST + get_file: 'api/sheet/file', // GET + get_contents: 'api/sheet/contents', //GET + get_headers: 'api/sheet/headers', // GET + set_mapping: 'api/sheet/mapping' // POST + }, + attachment: { + upload: 'api/attachment/upload' // POST + }, + email: { + set_server: 'api/email/server', // POST + convert_template_to_string: 'api/email/template_to_reality', // POST + set_metadata_and_contents: 'api/email/metadata_contents', // POST + send_test: 'api/email/send_test', // POST + send: 'api/email/send' // POST + } + // fodder: 'api/fodder', // POST, GET + // regurgitate: 'api/fodder/regurgitate', // POST + // vomit: 'api/vomit', //POST + // attachment: 'api/fodder/achar', // POST + // attachment_metadata: 'api/fodder/achar/mapping', // POST + // email: 'api/burp', // POST + // email_server: 'api/burp/server', // POST + // email_test: 'api/burp/test', // POST + // email_send: 'api/burp/send', // POST + // template_resolver: 'api/burp/template' // POST + } + + constructor(private log: LoggerService, private http: HttpClient) { + this.log.info("Created: ", this); + this.emailMetadataInstance = {}; + this.attachmentMetadataInstance = {}; + } + + /** + * Common handler for all REST API call failures + * + * @param error HTTP error from REST API response + */ + private handleApiResponseError(error: HttpErrorResponse) { + if (error.error instanceof ErrorEvent) { + // A client-side or network error occurred. + console.log("Client-side failure for REST API call: " + error.error.message); + } else { + // The server returned an error HTTP status code + console.log("REST API failed, response: " + error); + } + + return throwError(error); + } + + private handleError(operation = 'operation') { + return (error: any) => { + let errorMessage = error.message; + + if (error instanceof HttpErrorResponse) { + // Sample: {operation} failed with HTTP 400 (BAD REQUEST): {custom error msg string from server} + this.log.error(`${operation} failed with HTTP ${error.status} (${error.statusText}): `, error.error); + errorMessage = error.error; + } else { + this.log.error(`${operation} failed: `, error.message); + } + + return throwError(errorMessage); + }; + } + + getVersion(): Observable { + let version: VersionInfo = { version: '' } + return this.http.get(this.urls.version) + .pipe( + catchError(this.handleError('getVersion')) + ); + } + + getFodderUploadUrl(): string { + return this.urls.sheet.upload; + } + + getFodderDownloadUrl(): string { + return this.urls.sheet.get_file; + } + + getAttachmentUploadUrl(): string { + return this.urls.attachment.upload; + } + + getColumnHeadersWithSampleRows(): Observable { + return this.http.get(this.urls.sheet.get_headers) + .pipe( + catchError(this.handleError('getColumnHeadersWithSampleRows')) + ); + } + + getVomit(): Observable { + return this.http.get(this.urls.sheet.get_contents) + .pipe( + catchError(this.handleError('getVomit')) + ); + + // let res: ColumnHeadersWithRowContent = { + // headers: [ + // 'Name of Child', 'Class', 'Sponsor', 'Mail ID', 'Reference', 'Reference mail ID' + // ], + // contents: [ + // { + // 'Name of Child': 'Aradhya Karche', + // 'Class': 'Nursery- kalewadi', + // 'Sponsor': 'Kalubai pratishthan', + // 'Mail ID': 'Sanjaysandhu8090@gmail.com', + // 'Reference': 'Ravi', + // 'Reference mail ID': 'amboreravi@gmail.com', + // 'status': 'Pending', + // 'email': { + // 'from': 'wittymail@acme.com', + // 'to': 'Sanjaysandhu8090@gmail.com', + // 'cc': 'amboreravi@gmail.com', + // 'attachment': { + // 'name': 'Aradhya Karche.pdf', + // 'url': 'api/attachment/Aradhya%20Karche.pdf' + // }, + // 'subject': 'First term progress report for Aradhya Karche', + // 'body': 'Dear Kalubai pratishthan,' + // } + // }, + // { + // 'Name of Child': 'Vedika Shirgire', + // 'Class': 'Nursery- kalewadi', + // 'Sponsor': 'Apurva kumar', + // 'Mail ID': 'apurv07vit@gmail.com', + // 'Reference': 'Anish', + // 'Reference mail ID': 'anishgarg07@gmail.com', + // 'status': 'Pending', + // 'email': { + // 'from': 'wittymail@acme.com', + // 'to': 'apurv07vit@gmail.com', + // 'cc': 'anishgarg07@gmail.com', + // 'attachment': { + // 'name': 'Vedika Shirgire.pdf', + // 'url': 'api/attachment/Vedika%20Shirgire.pdf' + // }, + // 'subject': 'First term progress report for Vedika Shirgire', + // 'body': 'Dear Apurva kumar,' + // } + // } + // ] + // }; + + // return res; + } + + saveEmailToCCColumns(to_column: string, cc_column: string) { + this.emailMetadataInstance.to_column = to_column; + this.emailMetadataInstance.cc_column = cc_column; + + this.log.info("emailMetadataInstance: ", this.emailMetadataInstance); + } + + saveEmailSubjectBodyTemplate(subject_template: string, body_template: string) { + this.emailMetadataInstance.subject_template = subject_template; + this.emailMetadataInstance.body_template = body_template; + + this.log.info("emailMetadataInstance: ", this.emailMetadataInstance); + } + + saveAttachmentMetadata(attachment_column: string) { + this.attachmentMetadataInstance.attachment_column = attachment_column; + + this.log.info("attachmentMetadataInstance: ", this.attachmentMetadataInstance); + } + + resolveTemplate(input: TemplateInput): Observable { + this.log.info("POSTing template: ", input); + return this.http.post(this.urls.email.convert_template_to_string, input) + .pipe( + catchError(this.handleError('resolveTemplate')) + ); + } + + postEmailMetadata(): Observable { + this.log.info("POSTing email metadata: ", this.emailMetadataInstance); + return this.http.post(this.urls.email.set_metadata_and_contents, this.emailMetadataInstance) + .pipe( + catchError(this.handleError('postEmailMetadata')) + ); + } + + postAttachmentMetadata(): Observable { + this.log.info("POSTing attachment metadata: ", this.attachmentMetadataInstance); + return this.http.post(this.urls.sheet.set_mapping, this.attachmentMetadataInstance) + .pipe( + catchError(this.handleError('postAttachmentMetadata')) + ); + } + + postEmailServerDetails(payload: EmailServerDetails): Observable { + this.log.info("POSTing email server details: ", payload); + return this.http.post(this.urls.email.set_server, payload) + .pipe( + catchError(this.handleError('postEmailServerDetails')) + ); + } + + postTestEmail(payload: TestEmailDetails): Observable { + this.log.info("POSTing test email details: ", payload); + return this.http.post(this.urls.email.send_test, payload) + .pipe( + catchError(this.handleError('postTestEmail')) + ); + } + + postSendEmail(payload: SendEmailContent): Observable { + this.log.info("POSTing email details: ", payload); + return this.http.post(this.urls.email.send, payload) + .pipe( + catchError(this.handleError('postSendEmail')) + ); + } + +} diff --git a/frontend/wittymail-v2/src/app/common/about/about.component.html b/frontend/wittymail-v2/src/app/common/about/about.component.html index 850a003..2ae7c1b 100644 --- a/frontend/wittymail-v2/src/app/common/about/about.component.html +++ b/frontend/wittymail-v2/src/app/common/about/about.component.html @@ -1,5 +1,6 @@

About WittyMail

+ {{ version }}

Open-source software licensed under the MIT License.
diff --git a/frontend/wittymail-v2/src/app/common/about/about.component.ts b/frontend/wittymail-v2/src/app/common/about/about.component.ts index ab1e5ac..2e524e6 100644 --- a/frontend/wittymail-v2/src/app/common/about/about.component.ts +++ b/frontend/wittymail-v2/src/app/common/about/about.component.ts @@ -1,5 +1,10 @@ -import { Component, OnInit } from '@angular/core'; -import { MatDialogRef } from '@angular/material'; +import { Component, OnInit, Inject } from '@angular/core'; +import { LoggerService } from 'src/app/util/logger.service'; +import { BackendService, VersionInfo } from 'src/app/backend.service'; + +export interface AboutDialogData { + version: string; +} @Component({ selector: 'app-about', @@ -8,9 +13,23 @@ import { MatDialogRef } from '@angular/material'; }) export class AboutComponent implements OnInit { - constructor(public dialogRef: MatDialogRef,) { } + /* Version string displayed on the About dialog, to be fetched from the backend*/ + version: string = ""; - ngOnInit() { + constructor(private log: LoggerService, private backend: BackendService) { } + + ngOnInit() { + this.log.info("About dialog created!"); + this.getVersionFromBackend(); } + getVersionFromBackend() { + this.backend.getVersion().subscribe( + data => { + let version:VersionInfo = data; + this.log.info("Version from backend: ", version); + this.version = version.version; + } + ); + } } diff --git a/frontend/wittymail-v2/yarn.lock b/frontend/wittymail-v2/yarn.lock index 0c62909..c2828ad 100644 --- a/frontend/wittymail-v2/yarn.lock +++ b/frontend/wittymail-v2/yarn.lock @@ -5642,14 +5642,14 @@ run-queue@^1.0.0, run-queue@^1.0.3: dependencies: aproba "^1.1.1" -rxjs@6.3.3, rxjs@~6.3.3: +rxjs@6.3.3: version "6.3.3" resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.3.3.tgz#3c6a7fa420e844a81390fb1158a9ec614f4bad55" integrity sha512-JTWmoY9tWCs7zvIk/CvRjhjGaOd+OVBM987mxFo+OW66cGpdKjZcpmc74ES1sB//7Kl/PAe8+wEakuhG4pcgOw== dependencies: tslib "^1.9.0" -rxjs@^6.1.0: +rxjs@^6.1.0, rxjs@^6.4.0: version "6.4.0" resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.4.0.tgz#f3bb0fe7bda7fb69deac0c16f17b50b0b8790504" integrity sha512-Z9Yfa11F6B9Sg/BK9MnqnQ+aQYicPLtilXBp2yUtDt2JRCE0h26d33EnfO3ZxoNxG0T92OUucP3Ct7cpfkdFfw== From 54e7206c3199625e35b671172a54f19d50041667 Mon Sep 17 00:00:00 2001 From: Ajay Nair Date: Tue, 23 Apr 2019 00:06:16 +0530 Subject: [PATCH 21/64] Added skeleton --- backend/EmailProviderTest.py | 28 ++ backend/mailer/Email.py | 32 +++ backend/mailer/EmailProvider.py | 19 ++ backend/mailer/SMTPEmailProvider.py | 95 ++++++ backend/mailer/emailapi.py | 136 --------- backend/mailer/emailapi_broker.py | 270 ------------------ backend/util/FileUtils.py | 137 +++++++++ .../wittymail_server/ColumnMapping.py | 18 ++ backend/webserver/wittymail_server/Sheet.py | 50 ++++ .../webserver/wittymail_server/rest_api.py | 19 +- 10 files changed, 395 insertions(+), 409 deletions(-) create mode 100644 backend/EmailProviderTest.py create mode 100644 backend/mailer/Email.py create mode 100644 backend/mailer/EmailProvider.py create mode 100644 backend/mailer/SMTPEmailProvider.py delete mode 100644 backend/mailer/emailapi.py delete mode 100644 backend/mailer/emailapi_broker.py create mode 100644 backend/util/FileUtils.py create mode 100644 backend/webserver/wittymail_server/ColumnMapping.py create mode 100644 backend/webserver/wittymail_server/Sheet.py diff --git a/backend/EmailProviderTest.py b/backend/EmailProviderTest.py new file mode 100644 index 0000000..be3bdae --- /dev/null +++ b/backend/EmailProviderTest.py @@ -0,0 +1,28 @@ +from mailer.Email import Email +from mailer.EmailProvider import EmailProvider +import sys + +''' +Basic Test1 +----------- +1. Get username and password from CLI +2. Login using SMTP +3. Send a basic email +4. Logout +''' +def basic_test1(username, password): + e = Email([username], [username], 'Subject', 'Body') + eP = EmailProvider() + selected_eP = eP.choose_email_provider("SMTP") + seP = selected_eP(username, 'smtp.gmail.com', 587, username, password) + seP.login() + seP.send_email(e) + seP.logout() + +if __name__ == '__main__': + if len(sys.argv) != 3: + print("EmailProviderTest.py ") + + username = sys.argv[1] + password = sys.argv[2] + basic_test1(username, password) \ No newline at end of file diff --git a/backend/mailer/Email.py b/backend/mailer/Email.py new file mode 100644 index 0000000..6988563 --- /dev/null +++ b/backend/mailer/Email.py @@ -0,0 +1,32 @@ +#!/usr/bin/env python +# coding=utf-8 + +import smtplib +from email.mime.multipart import MIMEMultipart +from email.mime.text import MIMEText +from email.mime.base import MIMEBase +from email import encoders +import os +import util.logger as logger + +log = logger.get_logger(__name__) + +class Email(): + subject_template = None + body_template = None + + def __init__(self, to, cc, subject, body, status = None): + assert to is not None and \ + cc is not None, \ + log.error('Incorrect value provided to=%s cc=%s' % (to, cc)) + self.to = to + self.cc = cc + self.subject = subject + self.body = body + self.status = status + self.attachment = None + + def __del__(self): + self.to = None + Email.subject_template = None + Email.body_template = None \ No newline at end of file diff --git a/backend/mailer/EmailProvider.py b/backend/mailer/EmailProvider.py new file mode 100644 index 0000000..91cbd73 --- /dev/null +++ b/backend/mailer/EmailProvider.py @@ -0,0 +1,19 @@ +import importlib +import pdb +#from mailer.SMTPEmailProvider import SMTPEmailProvider + +class EmailProvider: + def __init__(self): + pass + + def choose_email_provider(self, name): + from mailer.SMTPEmailProvider import SMTPEmailProvider + return SMTPEmailProvider + + def login(self): + raise NotImplementedError() + def send_email(self): + raise NotImplementedError() + def logout(self): + raise NotImplementedError() + diff --git a/backend/mailer/SMTPEmailProvider.py b/backend/mailer/SMTPEmailProvider.py new file mode 100644 index 0000000..9e547f1 --- /dev/null +++ b/backend/mailer/SMTPEmailProvider.py @@ -0,0 +1,95 @@ +#!/usr/bin/env python +# coding=utf-8 + +import smtplib +from email.mime.multipart import MIMEMultipart +from email.mime.text import MIMEText +from email.mime.base import MIMEBase +from email import encoders +import os +import util.logger as logger +from mailer.EmailProvider import EmailProvider + +log = logger.get_logger(__name__) + +class SMTPEmailProvider(EmailProvider): + def __init__(self, frm, server, port, username, password): + EmailProvider.__init__(self) + assert server is not None and port is not None and username is not None and password is not None,\ + log.error('server, port number, username or password is None') + + self.frm = frm + self.server = server + self.port = port + self.username = username + self.password = password + self.s = None + + def logout(self): + self.s.quit() + log.debug('emailapi teardown successful') + + # TODO Can you check if SMTPlib has different types of Exception (*Error) classes and write an except block for each? + def login(self): + # Connect to the SMTP server and login + try: + self.s = smtplib.SMTP(self.server, self.port) + self.s.ehlo() + self.s.starttls() + self.s.login(self.username, self.password) + + except: + log.exception('Incorrect server/user information provided') + return [-1, 'Incorrect server/user information provided'] + + log.debug('Login successful') + return [0, 'Login successful'] + + def send_email(self, e): + try: + # Extra

tags show up as multiple line breaks in the resulting email, so replace them + # with single line breaks + body = e.body.replace('

', '
') + + log.debug("Cleaned body: %s", body) + + msg = MIMEMultipart() + msg['From'] = self.frm + msg['To'] = ", ".join(e.to) + + ccs_to_send = [] + if e.cc is not None and e.cc[0] != 'None': + msg['Cc'] = ", ".join(e.cc) + for cc in e.cc: + ccs_to_send.append(cc.strip()) + else: + log.debug('No cc mailer provided') + + msg['Subject'] = e.subject + msg.attach(MIMEText(e.body, 'html')) + + if (e.attachment is not None): + for attachment in e.attachment: + if not os.path.isfile(attachment): + return [-1, 'Attachment not found'] + try: + a = open(attachment, "rb") + except: + log.exception("Failed to open attachment: %s", attachment) + raise + p = MIMEBase('application', 'octet-stream') + p.set_payload((a).read()) + encoders.encode_base64(p) + p.add_header('Content-Disposition', "attachment; filename= %s" % os.path.basename(attachment)) + msg.attach(p) + + msg_str = msg.as_string() + log.debug("ccs_to_send: %s", ccs_to_send) + if ccs_to_send: + self.s.sendmail(msg['From'], e.to + ccs_to_send, msg_str) + else: + self.s.sendmail(msg['From'], e.to, msg_str) + log.info('Email sent by %s to %s' % (msg['From'], msg['To'])) + return [0, 'Email sent successfully'] + except: + log.exception("Failed to send test email") \ No newline at end of file diff --git a/backend/mailer/emailapi.py b/backend/mailer/emailapi.py deleted file mode 100644 index f42b6af..0000000 --- a/backend/mailer/emailapi.py +++ /dev/null @@ -1,136 +0,0 @@ -#!/usr/bin/env python -# coding=utf-8 - -import smtplib -from email.mime.multipart import MIMEMultipart -from email.mime.text import MIMEText -from email.mime.base import MIMEBase -from email import encoders -import os -import util.logger as logger -import pdb - -log = logger.get_logger(__name__) - -# Boolean to make sure we do not try to send an mailer before login -INITIALIZED = False - -# TODO Can you check if SMTPlib has different types of Exception (*Error) classes and write an except block for each? -def set_login_details(server, port, username, password): - assert server is not None and port is not None and username is not None and password is not None,\ - log.error('server, port number, username or password is None') - - # s is a global object used to interact with the SMTP server - global s - - # Connect to the SMTP server and login - try: - s = smtplib.SMTP(server, port) - s.ehlo() - s.starttls() - s.login(username, password) - - except Exception as e: - log.exception('Incorrect server/user information provided') - return [-1, 'Incorrect server/user information provided'] - - global INITIALIZED - INITIALIZED = True - log.debug('Login successful') - return [0, 'Login successful'] - -#subject = SerialNo -def _test_values(frm, tos, subject, body, ccs, attachments): - index = subject.split()[1] - name_of_child = "Name Surname+" + index - class_val = "Class+" + index - sponsor_email_id = "ajaynair59+" + index + "@gmail.com" - sponsor = "Sponsor Name+" + index - reference = "Reference Name+" + index - reference_email_id = "ajaynair59+" + index + "cc@gmail.com" - test_attachment = name_of_child + ".pdf" - - tmpstr = index + " " + name_of_child + " " + class_val + " " + sponsor_email_id + " " + sponsor + " " + reference + " " + reference_email_id + " Name E-mail pending" - test_subject = "Subject: " + tmpstr - print(test_subject) - - test_body = "

Body: " + tmpstr + "

" - print(test_body) - - assert test_subject == subject, "subject did not match" - assert test_body == body, "body did not match" - assert tos[0] == sponsor_email_id, "sponsor do not match" - assert ccs[0] == reference_email_id, "CCs do not match" - assert test_attachment in attachments[0] , "attachment do not match" - -def send_email(frm, tos, subject, body, ccs = None, attachments = None): - try: - assert \ - frm is not None and \ - tos is not None and \ - subject is not None and \ - body is not None, log.error('Incorrect value provided from=%s to=%s subject=%s body=%s' - % (frm, tos, subject, body)) - - # _test_values(frm, tos, subject, body, ccs, attachments) - if not INITIALIZED: - log.error('send_email() called before set_login_details()') - return [-1, "Server or user details not yet set"] - - log.debug('Email information: from=%s to=%s subject=%s body=%s cc=%s attachment=%s' - % (frm, tos, subject[:50], body, ccs, attachments)) - - # Extra

tags show up as multiple line breaks in the resulting email, so replace them - # with single line breaks - body = body.replace('

', '
') - - log.debug("Cleaned body: %s", body) - - msg = MIMEMultipart() - msg['From'] = frm - msg['To'] = ", ".join(tos) - - ccs_to_send = [] - if ccs is not None and ccs[0] != 'None': - msg['Cc'] = ", ".join(ccs) - for cc in ccs: - ccs_to_send.append(cc.strip()) - else: - log.debug('No cc mailer provided') - - msg['Subject'] = subject - msg.attach(MIMEText(body, 'html')) - - if (attachments is not None): - for attachment in attachments: - if not os.path.isfile(attachment): - return [-1, 'Attachment not found'] - try: - a = open(attachment, "rb") - except: - log.exception("Failed to open attachment: %s", attachment) - raise - p = MIMEBase('application', 'octet-stream') - p.set_payload((a).read()) - encoders.encode_base64(p) - p.add_header('Content-Disposition', "attachment; filename= %s" % os.path.basename(attachment)) - msg.attach(p) - - msg_str = msg.as_string() - log.debug("ccs_to_send: %s", ccs_to_send) - if ccs_to_send: - s.sendmail(msg['From'], tos + ccs_to_send, msg_str) - else: - s.sendmail(msg['From'], tos, msg_str) - log.info('Email sent by %s to %s' % (msg['From'], msg['To'])) - return [0, 'Email sent successfully'] - except: - log.exception("Failed to send test email") - -def teardown(): - if not INITIALIZED: - log.error('teardown() called before set_login_details()') - return - - s.quit() - log.debug('emailapi teardown successful') diff --git a/backend/mailer/emailapi_broker.py b/backend/mailer/emailapi_broker.py deleted file mode 100644 index 0764667..0000000 --- a/backend/mailer/emailapi_broker.py +++ /dev/null @@ -1,270 +0,0 @@ -#!/usr/bin/env python -# coding=utf-8 - -import os, sys -import openpyxl -from wittymail_server import flask_app -import mailer.emailapi as emailapi -import re -import util.logger as logger -import tempfile - -# import ai.gender_guesser as gender_guesser - -log = logger.get_logger(__name__) - -global email_fodder_names -email_fodder_names = [] - -global email_fodder -email_fodder = [] - -email_fodder_names_FIRST_NAME = -2 -email_fodder_names_STATUS_INDEX = -1 - -extended_email_fodder_names = ['missing_attachment_count', 'pronoun', 'email_subject', 'email_body', 'email_attachment', 'email_sent'] - -extended_email_fodder_names_MISSINGATTACHMENTCOUNT_INDEX = -6 -extended_email_fodder_names_PRONOUN_INDEX = -5 -extended_email_fodder_names_EMAIL_SUBJECT_INDEX = -4 -extended_email_fodder_names_EMAIL_BODY_INDEX = -3 - -global extended_email_fodder_names_EMAIL_ATTACHMENT_INDEX -extended_email_fodder_names_EMAIL_ATTACHMENT_INDEX = -2 - -global extended_email_fodder - -# Index of the emailid in the email_fodder_names[]. The emailid will be used in the 'to' field -global EMAIL_FODDER_TO_INDEX -# Index of the emailid in the email_fodder_names[]. The emailid will be used in the 'cc' field -global EMAIL_FODDER_CC_INDEX - -global email_from -email_from = None - -global attachment_dir -global attachment_index -attachment_index = None - -EMAILPENDING = "E-mail pending" -ATTACHMENTNOTFOUND = "Attachment not found" - -def _init(): - global email_fodder - email_fodder = [] - - global email_fodder_names - email_fodder_names = [] - - global extended_email_fodder - extended_email_fodder = [] - - global EMAIL_FODDER_TO_INDEX - EMAIL_FODDER_TO_INDEX = None - - global EMAIL_FODDER_CC_INDEX - EMAIL_FODDER_CC_INDEX = None - - global attachment_index - attachment_index = None - -def save_fodder_to_file(): - wb=openpyxl.Workbook() - ws_write = wb.active - - headers = [] - - headers.extend(email_fodder_names) - - l = [] - l.append(headers) - excel_data = l + email_fodder - - for row in excel_data: - ws_write.append(row) - - wb.save(filename="wittymail_excel.xlsx") - return os.path.join(os.getcwd(), "wittymail_excel.xlsx") - -# TODO Add check to detect extention type -def save_fodder_from_file(loc, email_fodder_names_template = None): - global email_fodder - global email_fodder_names - email_fodder = [] - - _init() - # TODO Check if we should read wb_obj.active or wb_obj[0]. Do we have to close? - wb_obj = openpyxl.load_workbook(loc, data_only=True) - sheet_obj = wb_obj.active - - # Get headers - email_fodder_names = [] - for j in range(1, sheet_obj.max_column + 1): - email_fodder_names.append(str(sheet_obj.cell(row = 1, column = j).value)) - - for i in range(2, sheet_obj.max_row + 1): - cells = [] - - for j in range(1, len(email_fodder_names) + 1): - cells.append(str(sheet_obj.cell(row = i, column = j).value)) - - if all(c == 'None' for c in cells): - break - - tmp_str = _sanitize_names_str(cells[1]) - tmp_str2 = [i.split()[0] for i in tmp_str] - if len(tmp_str2) == 1: - tmp_str = tmp_str2[0] - else: - tmp_str3 = ', '.join(tmp_str2[:-1]) - tmp_str = tmp_str3 + " and " + tmp_str2[-1] - cells.append(tmp_str) - cells.append(EMAILPENDING) - email_fodder.append(cells) - - assert email_fodder_names_template == None or email_fodder_names == email_fodder_names_template, \ - "**** The headers in the excel sheet seems to be invalid ****" - assert len(email_fodder) > 0, \ - "**** There are no entries in the excel sheet! ****" - - # Add new fodder names to the excel. If you modify fodder names count/order, - # make sure you change the count/order of fodder. - email_fodder_names.append("First Name") - email_fodder_names.append("Status") - -def get_email_fodder_names(): - if len(email_fodder_names) == 0: - return [-1, "Excel sheet not yet uploaded"] - - return [0, email_fodder_names] - -def get_email_fodder(): - return email_fodder - -def get_extended_email_fodder(): - return extended_email_fodder - -# #{no} in _st will be replaced by l[no] -def template_to_str(st, l): - log.debug('template_to_str() str = %s' % (st)) - - str_to_replace = list(set(re.findall(r'#\d+', st))) - - def remove_hash(s): - return s[1:] - - index = map(int, [remove_hash(s) for s in str_to_replace]) - index = list(index) - - for i in range(len(index)): - st = st.replace(str_to_replace[i], l[index[i] - 1]) - - log.debug('template_to_str() final str = %s' % st) - return st - -def _sanitize_names_str(names_str): - tmp_str = names_str.replace(" and ", ",") - tmp_str = tmp_str.split(",") - return list(map(str.strip, tmp_str)) - -def change_email_fodder_status(new_attachment): - # If excel is not yet provided or if the attachment column is not yet provided no need to change the state - if attachment_index == None or len(email_fodder) == 0: - return - - for r,e in zip(email_fodder, extended_email_fodder): - _attachments = _sanitize_names_str(r[attachment_index]) - - if e[extended_email_fodder_names_MISSINGATTACHMENTCOUNT_INDEX] == 0: - continue - - for a in _attachments: - if a + ".pdf" == new_attachment: - e[extended_email_fodder_names_MISSINGATTACHMENTCOUNT_INDEX] -= 1 - if e[extended_email_fodder_names_MISSINGATTACHMENTCOUNT_INDEX] == 0: - r[email_fodder_names_STATUS_INDEX] = EMAILPENDING - break - -def save_extended_fodder(to_column, cc_column, subject_template, body_template): - global EMAIL_FODDER_TO_INDEX - global EMAIL_FODDER_CC_INDEX - global extended_email_fodder - - extended_email_fodder = [] - EMAIL_FODDER_TO_INDEX = email_fodder_names.index(to_column) - EMAIL_FODDER_CC_INDEX = email_fodder_names.index(cc_column) - - # 'cc' can be NULL, so skip checking for that - if '@' not in email_fodder[0][EMAIL_FODDER_TO_INDEX]: - return [-1, "Invalid to provided"] - - for r in email_fodder: - gender = "his" - - extended_fodder_entry = [] - - _attachments = _sanitize_names_str(r[attachment_index]) - # _attachments = r[attachment_index].replace(" and ", ",").replace(" ","").split(",") - extended_fodder_entry.append(len(_attachments)) - - pronoun = "her" if gender == "female" else "his" - extended_fodder_entry.append(pronoun) - - extended_fodder_entry.append(template_to_str(subject_template, r)) - extended_fodder_entry.append(template_to_str(body_template, r)) - - attachments = [a + ".pdf" for a in _attachments] - extended_fodder_entry.append(attachments) - - for a in attachments: - if not os.path.isfile(os.path.join(flask_app.config['ATTACHMENTS_DIR'], a)): - r[email_fodder_names_STATUS_INDEX] = ATTACHMENTNOTFOUND - else: - extended_fodder_entry[0] -= 1 - - extended_fodder_entry.append(False) - - extended_email_fodder.append(extended_fodder_entry) - return [0, "Data saved"] - -def save_attachment_dir(dir_loc): - global attachment_dir - attachment_dir = dir_loc - -def save_attachment_column(attachment_column): - global attachment_index - attachment_index = email_fodder_names.index(attachment_column) - -def test_email(tos): - ex = extended_email_fodder[0] - log.info('Test mail to be sent to+cc %s' % (''.join(tos))) - ccs = tos - - email_subject = ex[extended_email_fodder_names_EMAIL_SUBJECT_INDEX] - email_body = ex[extended_email_fodder_names_EMAIL_BODY_INDEX] - - attachment_list = ex[extended_email_fodder_names_EMAIL_ATTACHMENT_INDEX] - attachments = [os.path.join(attachment_dir, a) for a in attachment_list] - return emailapi.send_email(email_from, tos, email_subject, email_body, ccs, attachments) - -def _update_email_fodder_status(tos, subject, body, ccs, attachments): - for row in email_fodder: - if row[EMAIL_FODDER_TO_INDEX] in tos: - row[email_fodder_names_STATUS_INDEX] = "Email Sent" - -def send_email(email_from, tos, subject, body, ccs, attachments): - attachments = [os.path.join(attachment_dir, a) for a in attachments] - - e = emailapi.send_email(email_from, tos, subject, body, ccs, attachments) - if e[0] == 0: - _update_email_fodder_status(tos, subject, body, ccs, attachments) - return e - -def set_login_details(username, password, server="smtp.gmail.com", port=587): - assert username is not None and password is not None,\ - log.error('server, port number, username or password is None') - - global email_from - - email_from = username - return emailapi.set_login_details(server, port, username, password) \ No newline at end of file diff --git a/backend/util/FileUtils.py b/backend/util/FileUtils.py new file mode 100644 index 0000000..70edebf --- /dev/null +++ b/backend/util/FileUtils.py @@ -0,0 +1,137 @@ +import util.logger as logger +from enum import Enum +import PyPDF2 +import os +import shutil +from fuzzywuzzy import fuzz +import operator +import openpyxl +import re + +log = logger.get_logger(__name__) + +''' +Used to denote the direction of the rotation of pdf +''' +class Direction(Enum): + CLOCKWISE = 0 + ANTICLOCKWISE = 1 + +''' +All file related helper operations +''' +class FileUtils: + def __init__(self): + pass + + ''' + Rotate a pdf based on the direction provided + ''' + def pdf_rotate(self, filepath, direction): + if direction == Direction.CLOCKWISE: + rotation_degree = 270 + else: + rotation_degree = 90 + + output_file = filepath + '.tmp' + + with open(filepath, 'rb') as f: + pdf_reader = PyPDF2.PdfFileReader(f) + pdf_writer = PyPDF2.PdfFileWriter() + + for pagenum in range(pdf_reader.numPages): + page = pdf_reader.getPage(pagenum) + page.rotateCounterClockwise(rotation_degree) + pdf_writer.addPage(page) + + log.info("Writing PDF: %s", output_file) + with open(output_file, 'wb') as out: + pdf_writer.write(out) + os.remove(filepath) + shutil.move(output_file, filepath) + + ''' + Converts 'a b,c d and e' to 'a','b','c','d','e' + ''' + def sanitize_names_str(self, names_str): + tmp_str = names_str.replace(" and ", ",") + return [tmp_str2.strip() for tmp_str2 in tmp_str.split(',')] + + ''' + Reads excel from loc and returns [headers[] , data[]] + ''' + def read_excel_to_memory(self, loc): + wb_obj = openpyxl.load_workbook(loc, data_only=True) + sheet_obj = wb_obj.active + + # Get headers + excel_headers = [] + excel_rows = [] + for j in range(1, sheet_obj.max_column + 1): + excel_headers.append(str(sheet_obj.cell(row = 1, column = j).value)) + for i in range(2, sheet_obj.max_row + 1): + cells = [] + + for j in range(1, len(excel_headers) + 1): + cells.append(str(sheet_obj.cell(row = i, column = j).value)) + + if all(c == 'None' for c in cells): + break + + tmp_str = self.sanitize_names_str(cells[1]) + tmp_str2 = [i.split()[0] for i in tmp_str] + if len(tmp_str2) == 1: + tmp_str = tmp_str2[0] + else: + tmp_str3 = ', '.join(tmp_str2[:-1]) + tmp_str = tmp_str3 + " and " + tmp_str2[-1] + cells.append(tmp_str) + excel_rows.append(cells) + + assert len(excel_rows) > 0, \ + "**** There are no entries in the excel sheet! ****" + return [excel_headers, excel_rows] + + def find_n_files_by_fuzzymatch(self, directory, fuzzystring, filetype = 'pdf', n = 5, ignore_phrases = None): + candidates = {} + + for filename in os.listdir(directory): + if filename.endswith(filetype): + for phrase in ignore_phrases: + filename_tmp = filename.lower().replace(phrase.lower(), '') + ratio = fuzz.ratio(filename_tmp.lower(), fuzzystring.lower()) + candidates[filename] = ratio + sorted_candidates = sorted(candidates.items(), key=operator.itemgetter(1), reverse=True) + return [i[0] for i in sorted_candidates][:n] + + ''' + #no in st will be replaced by l[no] + ''' + def template_to_str(self, st, l): + log.debug('template_to_str() str = %s' % (st)) + + # Find all substitutes to be replaced by a string from the list + # For e.g. substitutes = ['#1', '#3', '#1'] + substitute = re.findall(r'#\d+', st) + + # Remove all duplicates + # substitutes = ['#1', '#3'] + substitute = list(set(substitute)) + + # Get index of each substitute + # index = [1,3] + index = [int(s[1:]) for s in substitute] + + # Iterate over each index and replace '#i' with l[i] in the input string + for i in range(len(index)): + st = st.replace(substitute[i], l[index[i] - 1]) + + log.debug('template_to_str() final str = %s' % st) + return st + +if __name__ == "__main__": + f = FileUtils() + #print(f.find_n_files_by_fuzzymatch(os.path.join("C:\\", "Users", "naira11", "Documents", "wittymail_data", 'allpdf'), 'aarahya jadav', ignore_phrases = ['Nursery', 'Kothrud'])) + #f.pdf_rotate(os.path.join("C:\\", "Users","naira11", 'Test.pdf'), Direction.CLOCKWISE) + #f.pdf_rotate(Direction.ANTICLOCKWISE) + f.read_excel_to_memory(os.path.join("C:\\", "Users", "naira11", "Documents", "Personal", "clean_sheet.xlsx")) diff --git a/backend/webserver/wittymail_server/ColumnMapping.py b/backend/webserver/wittymail_server/ColumnMapping.py new file mode 100644 index 0000000..3e91ff4 --- /dev/null +++ b/backend/webserver/wittymail_server/ColumnMapping.py @@ -0,0 +1,18 @@ +class ColumnMapping: + def __init__(self): + self.to = None + self.cc = None + self.status = None + self.frozen_attachment = None + + def set_column_mapping(self, map_info): + self.to = map_info['email_to'] + self.to = map_info['email_cc'] + self.to = map_info['email_status'] + self.frozen_attachment = map_info['email_email_frozen_attachment'] + + def __del__(self): + self.to = None + self.cc = None + self.status = None + self.frozen_attachment = None diff --git a/backend/webserver/wittymail_server/Sheet.py b/backend/webserver/wittymail_server/Sheet.py new file mode 100644 index 0000000..995eca8 --- /dev/null +++ b/backend/webserver/wittymail_server/Sheet.py @@ -0,0 +1,50 @@ +from util.FileUtils import FileUtils +from mailer.ColumnMapping import ColumnMapping + +class Sheet: + __instance = None + filepath = None + headers = [] + data = [] + c = ColumnMapping() + + @staticmethod + def getInstance(filepath=None): + """ Static access method. """ + if Sheet.__instance == None: + Sheet(filepath) + return Sheet.__instance + + def __init__(self, filepath): + """ Virtually private constructor. """ + if Sheet.__instance != None: + raise Exception("This class is a singleton!") + else: + Sheet.__instance = self + Sheet.filepath = filepath + + def __del__(self): + Sheet.rows = [] + Sheet.filepath = None + Sheet.__instance = None + + def dump_to_memory(self): + f = FileUtils() + self.headers, self.data = f.read_excel_to_memory(self.filepath) + + def get_headers_with_sample_rows(self, row_count = 5): + data = [] + data.append(self.headers) + for i in range(0, row_count): + data.append(self.data[i]) + return data + + def get_all_content(self): + return self.headers + self.data + + def template_to_str(self, st, l): + f = FileUtils() + return f.template_to_str(st, l) + + def set_column_mapping(self, map_info): + Sheet.c = ColumnMapping(map_info) \ No newline at end of file diff --git a/backend/webserver/wittymail_server/rest_api.py b/backend/webserver/wittymail_server/rest_api.py index ea2bcef..70e64dd 100644 --- a/backend/webserver/wittymail_server/rest_api.py +++ b/backend/webserver/wittymail_server/rest_api.py @@ -5,13 +5,13 @@ sys.path.append(os.path.abspath(os.path.join(os.curdir, '..', '..'))) -import mailer.emailapi_broker as emailapi_broker from wittymail_server import flask_app from flask import jsonify, request, json, url_for from flask_classy import FlaskView, route import util.version as version import util.logger as logger from flask import send_file +from sheet import sheet log = logger.get_logger(__name__) @@ -26,10 +26,11 @@ class SheetView(FlaskView): /api/sheet/... """ + s = sheet() route_prefix = flask_app.config['URL_DEFAULT_PREFIX_FOR_API'] @route('upload', methods=['POST']) - def some(self): + def upload(self): """ Upload a new Excel sheet as input @@ -170,7 +171,6 @@ def mapping(self): HTTP_OK, {'ContentType': 'application/json'}) - class AttachmentView(FlaskView): """ APIs for attachments to be used with the Sheet (by mapping) and sent with emails @@ -197,6 +197,19 @@ def upload_attachment(self): emailapi_broker.change_email_fodder_status(a.filename) return "Attachments saved successfully", HTTP_OK + @route('upload_for_row', methods=['POST']) + def upload_attachment_for_row(self): + """ + """ + a = request.files['attachment'] + attachment_dir = flask_app.config['ATTACHMENTS_DIR'] + + a.save(os.path.join(attachment_dir, a.filename)) + log.info('Attachment file saved as = %s' % (attachment_dir + a.filename)) + + data = json.loads(request.data) + emailapi_broker.change_email_fodder_status(a.filename, data['row']) + return "Attachments saved successfully", HTTP_OK class EmailView(FlaskView): """ From 2e7e23ed4ebf224539bcca4e49da30cf5aff6b6b Mon Sep 17 00:00:00 2001 From: Omkar Ekbote Date: Sat, 27 Apr 2019 15:25:47 +0530 Subject: [PATCH 22/64] Sponsor List page design --- frontend/wittymail-v2/src/app/app.module.ts | 4 +- .../sponsor-list/sponsor-list.component.css | 11 +++++ .../sponsor-list/sponsor-list.component.html | 43 +++++++++++++++++-- .../sponsor-list/sponsor-list.component.ts | 31 +++++++++++++ .../steps-slider/steps-slider.component.html | 2 +- 5 files changed, 86 insertions(+), 5 deletions(-) diff --git a/frontend/wittymail-v2/src/app/app.module.ts b/frontend/wittymail-v2/src/app/app.module.ts index dc0558d..b42eefb 100644 --- a/frontend/wittymail-v2/src/app/app.module.ts +++ b/frontend/wittymail-v2/src/app/app.module.ts @@ -13,6 +13,7 @@ import {MatRadioModule} from '@angular/material/radio'; import {MatIconModule} from '@angular/material'; import {MatMenuModule} from '@angular/material/menu'; import {MatDialogModule} from '@angular/material/dialog'; +import {MatTabsModule} from '@angular/material/tabs'; import { AppRoutingModule } from './app-routing.module'; import { AppComponent } from './app.component'; @@ -59,7 +60,8 @@ import { ConsoleLoggerService } from './util/console-logger.service'; MatInputModule, MatIconModule, MatMenuModule, - MatDialogModule + MatDialogModule, + MatTabsModule ], providers: [ { provide: LoggerService, useClass: ConsoleLoggerService } diff --git a/frontend/wittymail-v2/src/app/sponsor-list/sponsor-list.component.css b/frontend/wittymail-v2/src/app/sponsor-list/sponsor-list.component.css index e69de29..c1af0b0 100644 --- a/frontend/wittymail-v2/src/app/sponsor-list/sponsor-list.component.css +++ b/frontend/wittymail-v2/src/app/sponsor-list/sponsor-list.component.css @@ -0,0 +1,11 @@ +.sheet-contents-table { + width: 100%; +} + +table { + border-collapse: collapse; +} + +table td { + border: 1px solid grey; +} \ No newline at end of file diff --git a/frontend/wittymail-v2/src/app/sponsor-list/sponsor-list.component.html b/frontend/wittymail-v2/src/app/sponsor-list/sponsor-list.component.html index bce2eb9..685e7c3 100644 --- a/frontend/wittymail-v2/src/app/sponsor-list/sponsor-list.component.html +++ b/frontend/wittymail-v2/src/app/sponsor-list/sponsor-list.component.html @@ -1,3 +1,40 @@ -

- sponsor-list works! -

+ + +
+
+ Sponsor List +
+
+ +
+
+
+ + + + + Which column has the e-mail address of the recipient? + + + Which column has the e-mail address to be CC'd? + + + Which column has attachment names? + + + +
+ +
+ +
+ +
+ + + + + +
{{header}} {{element[header]}}
+
\ No newline at end of file diff --git a/frontend/wittymail-v2/src/app/sponsor-list/sponsor-list.component.ts b/frontend/wittymail-v2/src/app/sponsor-list/sponsor-list.component.ts index 9fe4d14..32ec9f4 100644 --- a/frontend/wittymail-v2/src/app/sponsor-list/sponsor-list.component.ts +++ b/frontend/wittymail-v2/src/app/sponsor-list/sponsor-list.component.ts @@ -7,6 +7,37 @@ import { Component, OnInit } from '@angular/core'; }) export class SponsorListComponent implements OnInit { + headers = ['Sr No.', 'Name of Child', 'Class', 'Sponsor', 'Mail ID', 'Reference', 'Reference Mail ID'] + sheetContents = [ + { + 'Sr No.': "1", + 'Name of Child': "Aradhya Karche", + 'Class': "Nursery-kalewadi", + 'Sponsor': "Kalubai pratishthan", + 'Mail ID': "Sanjaysandhu8090@gmail.com", + 'Reference': "Ravi", + 'Reference Mail ID': "amboreravi@gmail.com" + }, + { + 'Sr No.': "2", + 'Name of Child': "Aradhya Karche", + 'Class': "Nursery-kalewadi", + 'Sponsor': "Kalubai pratishthan", + 'Mail ID': "Sanjaysandhu8090@gmail.com", + 'Reference': "Ravi", + 'Reference Mail ID': "amboreravi@gmail.com" + }, + { + 'Sr No.': "3", + 'Name of Child': "Aradhya Karche", + 'Class': "Nursery-kalewadi", + 'Sponsor': "Kalubai pratishthan", + 'Mail ID': "Sanjaysandhu8090@gmail.com", + 'Reference': "Ravi", + 'Reference Mail ID': "amboreravi@gmail.com" + }, + ]; + constructor() { } ngOnInit() { diff --git a/frontend/wittymail-v2/src/app/steps-slider/steps-slider.component.html b/frontend/wittymail-v2/src/app/steps-slider/steps-slider.component.html index f095e4d..c57a131 100644 --- a/frontend/wittymail-v2/src/app/steps-slider/steps-slider.component.html +++ b/frontend/wittymail-v2/src/app/steps-slider/steps-slider.component.html @@ -1,6 +1,6 @@ - This is step 1 + From 7673affec6d8c6cb35ec3db1998e88c6c186016a Mon Sep 17 00:00:00 2001 From: Omkar Ekbote Date: Sat, 27 Apr 2019 15:46:11 +0530 Subject: [PATCH 23/64] Column selector UI --- .../src/app/sponsor-list/sponsor-list.component.css | 10 +++++++++- .../src/app/sponsor-list/sponsor-list.component.html | 5 ++++- .../src/app/sponsor-list/sponsor-list.component.ts | 9 +++++++++ 3 files changed, 22 insertions(+), 2 deletions(-) diff --git a/frontend/wittymail-v2/src/app/sponsor-list/sponsor-list.component.css b/frontend/wittymail-v2/src/app/sponsor-list/sponsor-list.component.css index c1af0b0..2bb9bbc 100644 --- a/frontend/wittymail-v2/src/app/sponsor-list/sponsor-list.component.css +++ b/frontend/wittymail-v2/src/app/sponsor-list/sponsor-list.component.css @@ -4,8 +4,16 @@ table { border-collapse: collapse; + border-spacing: 0; + overflow: hidden; + z-index: 1; } table td { border: 1px solid grey; -} \ No newline at end of file +} + +.column-selected-as { + text-align: center; + color: purple; +} diff --git a/frontend/wittymail-v2/src/app/sponsor-list/sponsor-list.component.html b/frontend/wittymail-v2/src/app/sponsor-list/sponsor-list.component.html index 685e7c3..811f311 100644 --- a/frontend/wittymail-v2/src/app/sponsor-list/sponsor-list.component.html +++ b/frontend/wittymail-v2/src/app/sponsor-list/sponsor-list.component.html @@ -29,7 +29,10 @@
-
+ diff --git a/frontend/wittymail-v2/src/app/sponsor-list/sponsor-list.component.ts b/frontend/wittymail-v2/src/app/sponsor-list/sponsor-list.component.ts index 32ec9f4..b755322 100644 --- a/frontend/wittymail-v2/src/app/sponsor-list/sponsor-list.component.ts +++ b/frontend/wittymail-v2/src/app/sponsor-list/sponsor-list.component.ts @@ -8,6 +8,15 @@ import { Component, OnInit } from '@angular/core'; export class SponsorListComponent implements OnInit { headers = ['Sr No.', 'Name of Child', 'Class', 'Sponsor', 'Mail ID', 'Reference', 'Reference Mail ID'] + columnSelectedAs = { + 'Sr No.': '', + 'Name of Child': 'Attachment Name', + 'Class': '', + 'Sponsor': '', + 'Mail ID': 'E-mail Address (To)', + 'Reference': '', + 'Reference Mail ID': 'E-mail Address (CC)' + } sheetContents = [ { 'Sr No.': "1", From 7687dc4cf0e1c35be1e0a6f9ba266e22973bab97 Mon Sep 17 00:00:00 2001 From: Omkar Ekbote Date: Sat, 27 Apr 2019 16:17:56 +0530 Subject: [PATCH 24/64] Email subject template with click-to-inset columns --- .../email-design/email-design.component.css | 7 +++ .../email-design/email-design.component.html | 40 +++++++++++++-- .../email-design/email-design.component.ts | 49 ++++++++++++++++++- .../steps-slider/steps-slider.component.html | 2 +- 4 files changed, 92 insertions(+), 6 deletions(-) diff --git a/frontend/wittymail-v2/src/app/email-design/email-design.component.css b/frontend/wittymail-v2/src/app/email-design/email-design.component.css index e69de29..abf5b4f 100644 --- a/frontend/wittymail-v2/src/app/email-design/email-design.component.css +++ b/frontend/wittymail-v2/src/app/email-design/email-design.component.css @@ -0,0 +1,7 @@ +.full-width { + width: 80%; +} + +.table-container { + overflow: auto; +} \ No newline at end of file diff --git a/frontend/wittymail-v2/src/app/email-design/email-design.component.html b/frontend/wittymail-v2/src/app/email-design/email-design.component.html index 762c1c4..28b0591 100644 --- a/frontend/wittymail-v2/src/app/email-design/email-design.component.html +++ b/frontend/wittymail-v2/src/app/email-design/email-design.component.html @@ -1,3 +1,37 @@ -

- email-design works! -

+ + +
+
{{header}} + +
{{columnSelectedAs[header]}}
+
{{element[header]}}
+
+ +
+ + + + + +
+ + {{element[header]}}
+
+ +
+ Subject: + + + {{subjectSample}} + +
+ Contents: + + + +
+ + + + + + + \ No newline at end of file diff --git a/frontend/wittymail-v2/src/app/email-design/email-design.component.ts b/frontend/wittymail-v2/src/app/email-design/email-design.component.ts index 0ddffa2..6bc76df 100644 --- a/frontend/wittymail-v2/src/app/email-design/email-design.component.ts +++ b/frontend/wittymail-v2/src/app/email-design/email-design.component.ts @@ -1,4 +1,6 @@ -import { Component, OnInit } from '@angular/core'; +import { Component, OnInit, ViewChild } from '@angular/core'; +import { LoggerService } from '../util/logger.service'; +import { MatInput } from '@angular/material'; @Component({ selector: 'app-email-design', @@ -7,9 +9,52 @@ import { Component, OnInit } from '@angular/core'; }) export class EmailDesignComponent implements OnInit { - constructor() { } + @ViewChild("subjectInput") + subjectInput: MatInput; + + headers = ['Sr No.', 'Name of Child', 'Class', 'Sponsor', 'Mail ID', 'Reference', 'Reference Mail ID'] + + sheetContents = [ + { + 'Sr No.': "1", + 'Name of Child': "Aradhya Karche", + 'Class': "Nursery-kalewadi", + 'Sponsor': "Kalubai pratishthan", + 'Mail ID': "Sanjaysandhu8090@gmail.com", + 'Reference': "Ravi", + 'Reference Mail ID': "amboreravi@gmail.com" + }, + { + 'Sr No.': "2", + 'Name of Child': "Aradhya Karche", + 'Class': "Nursery-kalewadi", + 'Sponsor': "Kalubai pratishthan", + 'Mail ID': "Sanjaysandhu8090@gmail.com", + 'Reference': "Ravi", + 'Reference Mail ID': "amboreravi@gmail.com" + }, + { + 'Sr No.': "3", + 'Name of Child': "Aradhya Karche", + 'Class': "Nursery-kalewadi", + 'Sponsor': "Kalubai pratishthan", + 'Mail ID': "Sanjaysandhu8090@gmail.com", + 'Reference': "Ravi", + 'Reference Mail ID': "amboreravi@gmail.com" + }, + ]; + + subjectTemplate: string = ""; + subjectSample: string = "This is the actual subject"; + + constructor(private log: LoggerService) { } ngOnInit() { } + onClickColumn(columnName) { + this.log.info("Selected column: %s", columnName); + this.subjectTemplate += " {" + columnName + "} "; + } + } diff --git a/frontend/wittymail-v2/src/app/steps-slider/steps-slider.component.html b/frontend/wittymail-v2/src/app/steps-slider/steps-slider.component.html index c57a131..984b305 100644 --- a/frontend/wittymail-v2/src/app/steps-slider/steps-slider.component.html +++ b/frontend/wittymail-v2/src/app/steps-slider/steps-slider.component.html @@ -8,7 +8,7 @@ - This is step 3 + From 1306b5d229d60004e78886c1e06bbcfc27d3839f Mon Sep 17 00:00:00 2001 From: Omkar Ekbote Date: Sat, 27 Apr 2019 16:32:25 +0530 Subject: [PATCH 25/64] Email contents rich text editor --- frontend/wittymail-v2/angular.json | 3 ++ frontend/wittymail-v2/package.json | 2 + frontend/wittymail-v2/src/app/app.module.ts | 2 + .../email-design/email-design.component.html | 7 ++- .../email-design/email-design.component.ts | 3 ++ frontend/wittymail-v2/yarn.lock | 45 ++++++++++++++++++- 6 files changed, 57 insertions(+), 5 deletions(-) diff --git a/frontend/wittymail-v2/angular.json b/frontend/wittymail-v2/angular.json index b5de8a1..d24d825 100644 --- a/frontend/wittymail-v2/angular.json +++ b/frontend/wittymail-v2/angular.json @@ -23,6 +23,9 @@ "src/assets" ], "styles": [ + "node_modules/quill/dist/quill.core.css", + "node_modules/quill/dist/quill.snow.css", + "node_modules/quill/dist/quill.bubble.css", "src/styles.css" ], "scripts": [], diff --git a/frontend/wittymail-v2/package.json b/frontend/wittymail-v2/package.json index 10f0cf0..542fe0c 100644 --- a/frontend/wittymail-v2/package.json +++ b/frontend/wittymail-v2/package.json @@ -25,6 +25,8 @@ "core-js": "^2.5.4", "hammerjs": "^2.0.8", "ng2-file-upload": "^1.3.0", + "ngx-quill": "^4.8.0", + "quill": "^1.3.6", "rxjs": "^6.4.0", "tslib": "^1.9.0", "zone.js": "~0.8.26" diff --git a/frontend/wittymail-v2/src/app/app.module.ts b/frontend/wittymail-v2/src/app/app.module.ts index b42eefb..8d1a0eb 100644 --- a/frontend/wittymail-v2/src/app/app.module.ts +++ b/frontend/wittymail-v2/src/app/app.module.ts @@ -3,6 +3,7 @@ import { NgModule } from '@angular/core'; import {BrowserAnimationsModule} from '@angular/platform-browser/animations'; import { FormsModule } from '@angular/forms'; import { FileUploadModule } from 'ng2-file-upload'; +import { QuillModule } from 'ngx-quill'; import { HttpClientModule } from '@angular/common/http'; import {MatToolbarModule} from '@angular/material/toolbar'; @@ -50,6 +51,7 @@ import { ConsoleLoggerService } from './util/console-logger.service'; FlexLayoutModule, FileUploadModule, + QuillModule, FormsModule, MatToolbarModule, MatStepperModule, diff --git a/frontend/wittymail-v2/src/app/email-design/email-design.component.html b/frontend/wittymail-v2/src/app/email-design/email-design.component.html index 28b0591..0d26588 100644 --- a/frontend/wittymail-v2/src/app/email-design/email-design.component.html +++ b/frontend/wittymail-v2/src/app/email-design/email-design.component.html @@ -23,10 +23,9 @@ {{subjectSample}}
- Contents: - - - +
+ +
diff --git a/frontend/wittymail-v2/src/app/email-design/email-design.component.ts b/frontend/wittymail-v2/src/app/email-design/email-design.component.ts index 6bc76df..120ee19 100644 --- a/frontend/wittymail-v2/src/app/email-design/email-design.component.ts +++ b/frontend/wittymail-v2/src/app/email-design/email-design.component.ts @@ -47,6 +47,9 @@ export class EmailDesignComponent implements OnInit { subjectTemplate: string = ""; subjectSample: string = "This is the actual subject"; + bodyTemplate: string = "" + bodySample: string = ""; + constructor(private log: LoggerService) { } ngOnInit() { diff --git a/frontend/wittymail-v2/yarn.lock b/frontend/wittymail-v2/yarn.lock index c2828ad..dd35a41 100644 --- a/frontend/wittymail-v2/yarn.lock +++ b/frontend/wittymail-v2/yarn.lock @@ -2302,6 +2302,11 @@ etag@~1.8.1: resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" integrity sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc= +eventemitter3@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-2.0.3.tgz#b5e1079b59fb5e1ba2771c0a993be060a58c99ba" + integrity sha1-teEHm1n7XhuidxwKmTvgYKWMmbo= + eventemitter3@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-3.1.0.tgz#090b4d6cdbd645ed10bf750d4b5407942d7ba163" @@ -2435,7 +2440,7 @@ extend-shallow@^3.0.0, extend-shallow@^3.0.2: assign-symbols "^1.0.0" is-extendable "^1.0.1" -extend@^3.0.0, extend@~3.0.2: +extend@^3.0.0, extend@^3.0.1, extend@^3.0.2, extend@~3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== @@ -2483,6 +2488,11 @@ fast-deep-equal@^2.0.1: resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz#7b05218ddf9667bf7f370bf7fdb2cb15fdd0aa49" integrity sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk= +fast-diff@1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.1.2.tgz#4b62c42b8e03de3f848460b639079920695d0154" + integrity sha512-KaJUt+M9t1qaIteSvjc6P3RbMdXsNhK61GRftR6SNxqmhthcd9MGIi4T+o0jD8LUSpSnSKXE20nLtJ3fOHxQig== + fast-json-stable-stringify@2.0.0, fast-json-stable-stringify@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2" @@ -4424,6 +4434,13 @@ ng2-file-upload@^1.3.0: resolved "https://registry.yarnpkg.com/ng2-file-upload/-/ng2-file-upload-1.3.0.tgz#d90f8f568f62383462175f8bdfa0096b131f277a" integrity sha512-Pudxik6LWYsT8hNiEW7RfjgGWAnvfQywxwJYMdt1snTUe+KnlRc/QqPv3QEQW6plXTanuLkYz/TbqilSfSHOsw== +ngx-quill@^4.8.0: + version "4.8.0" + resolved "https://registry.yarnpkg.com/ngx-quill/-/ngx-quill-4.8.0.tgz#be88a3e7f97bdbe1935dfe8e876f624dd54ad78e" + integrity sha512-BoJKaJz5wrccBOvFKsBx5J0fSg+hTH+0xCOb3U4DZJkeCjRLiFUjIE6EPm9aOD3HNo2BRSfItQzdgHygBywT3g== + dependencies: + tslib "^1.9.0" + nice-try@^1.0.4: version "1.0.5" resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" @@ -4907,6 +4924,11 @@ parallel-transform@^1.1.0: inherits "^2.0.3" readable-stream "^2.1.5" +parchment@^1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/parchment/-/parchment-1.1.4.tgz#aeded7ab938fe921d4c34bc339ce1168bc2ffde5" + integrity sha512-J5FBQt/pM2inLzg4hEWmzQx/8h8D0CiDxaG3vyp9rKrQRSDgBlhjdP5jQGgosEajXPSQouXGHOmVdgo7QmJuOg== + parse-asn1@^5.0.0: version "5.1.4" resolved "https://registry.yarnpkg.com/parse-asn1/-/parse-asn1-5.1.4.tgz#37f6628f823fbdeb2273b4d540434a22f3ef1fcc" @@ -5319,6 +5341,27 @@ querystringify@^2.0.0: resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-2.1.1.tgz#60e5a5fd64a7f8bfa4d2ab2ed6fdf4c85bad154e" integrity sha512-w7fLxIRCRT7U8Qu53jQnJyPkYZIaR4n5151KMfcJlO/A9397Wxb1amJvROTK6TOnp7PfoAmg/qXiNHI+08jRfA== +quill-delta@^3.6.2: + version "3.6.3" + resolved "https://registry.yarnpkg.com/quill-delta/-/quill-delta-3.6.3.tgz#b19fd2b89412301c60e1ff213d8d860eac0f1032" + integrity sha512-wdIGBlcX13tCHOXGMVnnTVFtGRLoP0imqxM696fIPwIf5ODIYUHIvHbZcyvGlZFiFhK5XzDC2lpjbxRhnM05Tg== + dependencies: + deep-equal "^1.0.1" + extend "^3.0.2" + fast-diff "1.1.2" + +quill@^1.3.6: + version "1.3.6" + resolved "https://registry.yarnpkg.com/quill/-/quill-1.3.6.tgz#99f4de1fee85925a0d7d4163b6d8328f23317a4d" + integrity sha512-K0mvhimWZN6s+9OQ249CH2IEPZ9JmkFuCQeHAOQax3EZ2nDJ3wfGh59mnlQaZV2i7u8eFarx6wAtvQKgShojug== + dependencies: + clone "^2.1.1" + deep-equal "^1.0.1" + eventemitter3 "^2.0.3" + extend "^3.0.1" + parchment "^1.1.4" + quill-delta "^3.6.2" + randombytes@^2.0.0, randombytes@^2.0.1, randombytes@^2.0.5: version "2.1.0" resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" From 7276c301e1f66d2418342f36f03f614aaf784242 Mon Sep 17 00:00:00 2001 From: Omkar Ekbote Date: Wed, 1 May 2019 17:21:48 +0530 Subject: [PATCH 26/64] Implement Error Dialog as MatSnackBar --- frontend/wittymail-v2/src/app/app.module.ts | 4 +++- .../app/common/error-dialog/error-dialog.component.html | 3 --- .../app/common/error-dialog/error-dialog.component.ts | 9 ++++++++- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/frontend/wittymail-v2/src/app/app.module.ts b/frontend/wittymail-v2/src/app/app.module.ts index 8d1a0eb..bd93ae3 100644 --- a/frontend/wittymail-v2/src/app/app.module.ts +++ b/frontend/wittymail-v2/src/app/app.module.ts @@ -15,6 +15,7 @@ import {MatIconModule} from '@angular/material'; import {MatMenuModule} from '@angular/material/menu'; import {MatDialogModule} from '@angular/material/dialog'; import {MatTabsModule} from '@angular/material/tabs'; +import {MatSnackBarModule} from '@angular/material/snack-bar'; import { AppRoutingModule } from './app-routing.module'; import { AppComponent } from './app.component'; @@ -63,7 +64,8 @@ import { ConsoleLoggerService } from './util/console-logger.service'; MatIconModule, MatMenuModule, MatDialogModule, - MatTabsModule + MatTabsModule, + MatSnackBarModule ], providers: [ { provide: LoggerService, useClass: ConsoleLoggerService } diff --git a/frontend/wittymail-v2/src/app/common/error-dialog/error-dialog.component.html b/frontend/wittymail-v2/src/app/common/error-dialog/error-dialog.component.html index 17d57ef..e69de29 100644 --- a/frontend/wittymail-v2/src/app/common/error-dialog/error-dialog.component.html +++ b/frontend/wittymail-v2/src/app/common/error-dialog/error-dialog.component.html @@ -1,3 +0,0 @@ -

- error-dialog works! -

diff --git a/frontend/wittymail-v2/src/app/common/error-dialog/error-dialog.component.ts b/frontend/wittymail-v2/src/app/common/error-dialog/error-dialog.component.ts index 9ffb819..cbddf9b 100644 --- a/frontend/wittymail-v2/src/app/common/error-dialog/error-dialog.component.ts +++ b/frontend/wittymail-v2/src/app/common/error-dialog/error-dialog.component.ts @@ -1,4 +1,6 @@ import { Component, OnInit } from '@angular/core'; +import { MatSnackBar } from '@angular/material'; +import { LoggerService } from 'src/app/util/logger.service'; @Component({ selector: 'app-error-dialog', @@ -7,9 +9,14 @@ import { Component, OnInit } from '@angular/core'; }) export class ErrorDialogComponent implements OnInit { - constructor() { } + constructor(private snackBar: MatSnackBar, private log: LoggerService) { } ngOnInit() { } + showError(message: string) { + this.log.error(message); + this.snackBar.open(message, 'OK', {}); + } + } From 5aa78b2599b70121a3009c5e92afc7fff7b0a49a Mon Sep 17 00:00:00 2001 From: Omkar Ekbote Date: Wed, 1 May 2019 17:21:57 +0530 Subject: [PATCH 27/64] Connect sheet upload to backend --- .../webserver/wittymail_server/rest_api.py | 4 +-- backend/webserver/wittymail_web_gui.py | 2 +- .../sponsor-list/sponsor-list.component.html | 6 ++-- .../sponsor-list/sponsor-list.component.ts | 28 +++++++++++++++++-- .../input-sheet/input-sheet.component.html | 2 +- 5 files changed, 34 insertions(+), 8 deletions(-) diff --git a/backend/webserver/wittymail_server/rest_api.py b/backend/webserver/wittymail_server/rest_api.py index ea2bcef..3fe693c 100644 --- a/backend/webserver/wittymail_server/rest_api.py +++ b/backend/webserver/wittymail_server/rest_api.py @@ -29,7 +29,7 @@ class SheetView(FlaskView): route_prefix = flask_app.config['URL_DEFAULT_PREFIX_FOR_API'] @route('upload', methods=['POST']) - def some(self): + def upload(self): """ Upload a new Excel sheet as input @@ -38,7 +38,7 @@ def some(self): log.debug("Uploading sheet: %s", request.files) fodder_dir = flask_app.config['FODDER_DIR'] - f = request.files['fodder'] + f = request.files['sponsor-sheet'] fodder_file = os.path.join(fodder_dir, f.filename) f.save(fodder_file) log.info('Sheet file saved as: %s', fodder_file) diff --git a/backend/webserver/wittymail_web_gui.py b/backend/webserver/wittymail_web_gui.py index 03d7d1e..bbe14e2 100644 --- a/backend/webserver/wittymail_web_gui.py +++ b/backend/webserver/wittymail_web_gui.py @@ -2,7 +2,7 @@ # coding=utf-8 import os, sys -sys.path.insert(0, os.path.abspath('..')) +sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))) # This should be the first import to bootstrap the runtime env import util.bootstrap diff --git a/frontend/wittymail-v2/src/app/sponsor-list/sponsor-list.component.html b/frontend/wittymail-v2/src/app/sponsor-list/sponsor-list.component.html index 811f311..0666af8 100644 --- a/frontend/wittymail-v2/src/app/sponsor-list/sponsor-list.component.html +++ b/frontend/wittymail-v2/src/app/sponsor-list/sponsor-list.component.html @@ -5,7 +5,7 @@ Sponsor List
- +
@@ -40,4 +40,6 @@ -
\ No newline at end of file +
+ + \ No newline at end of file diff --git a/frontend/wittymail-v2/src/app/sponsor-list/sponsor-list.component.ts b/frontend/wittymail-v2/src/app/sponsor-list/sponsor-list.component.ts index b755322..f8fab38 100644 --- a/frontend/wittymail-v2/src/app/sponsor-list/sponsor-list.component.ts +++ b/frontend/wittymail-v2/src/app/sponsor-list/sponsor-list.component.ts @@ -1,4 +1,9 @@ -import { Component, OnInit } from '@angular/core'; +import { Component, OnInit, ViewChild } from '@angular/core'; +import { FileUploader } from 'ng2-file-upload'; +import { BackendService } from '../backend.service'; +import { LoggerService } from '../util/logger.service'; +import { ErrorDialogComponent } from '../common/error-dialog/error-dialog.component'; +import { MatStepper } from '@angular/material'; @Component({ selector: 'app-sponsor-list', @@ -7,6 +12,10 @@ import { Component, OnInit } from '@angular/core'; }) export class SponsorListComponent implements OnInit { + @ViewChild('stepper') stepper: MatStepper; + @ViewChild('errorDialog') errorDialog: ErrorDialogComponent; + public uploader: FileUploader; + headers = ['Sr No.', 'Name of Child', 'Class', 'Sponsor', 'Mail ID', 'Reference', 'Reference Mail ID'] columnSelectedAs = { 'Sr No.': '', @@ -47,9 +56,24 @@ export class SponsorListComponent implements OnInit { }, ]; - constructor() { } + constructor(private backend: BackendService, private log: LoggerService) { } ngOnInit() { + this.uploader = new FileUploader({ url: this.backend.getFodderUploadUrl(), itemAlias: 'sponsor-sheet' }); + this.uploader.onAfterAddingFile = (file) => { + file.withCredentials = false; + this.uploader.uploadAll(); + }; + + this.uploader.onCompleteItem = (item: any, response: any, status: any, headers: any) => { + this.log.info('Sponsor sheet uploaded: ', item.file.name, status); + if (status === 200) { + this.stepper.next(); + //this.displayColumnMappingUi(); + } else { + this.errorDialog.showError("Failed to upload the sheet to the backend"); + } + }; } } diff --git a/frontend/wittymail/src/app/process/input-sheet/input-sheet.component.html b/frontend/wittymail/src/app/process/input-sheet/input-sheet.component.html index 981b93c..2b2f98a 100644 --- a/frontend/wittymail/src/app/process/input-sheet/input-sheet.component.html +++ b/frontend/wittymail/src/app/process/input-sheet/input-sheet.component.html @@ -8,7 +8,7 @@

Inputs > Sponsor List

- +
From 01538a6d53ab60e80e3b2536b817590200abbbb4 Mon Sep 17 00:00:00 2001 From: Omkar Ekbote Date: Wed, 1 May 2019 18:11:59 +0530 Subject: [PATCH 28/64] Connect the sponsor-list page to the backend --- .../sponsor-list/sponsor-list.component.css | 4 + .../sponsor-list/sponsor-list.component.html | 9 +- .../sponsor-list/sponsor-list.component.ts | 133 ++++++++++++------ .../steps-slider/steps-slider.component.html | 2 +- 4 files changed, 100 insertions(+), 48 deletions(-) diff --git a/frontend/wittymail-v2/src/app/sponsor-list/sponsor-list.component.css b/frontend/wittymail-v2/src/app/sponsor-list/sponsor-list.component.css index 2bb9bbc..aed7b83 100644 --- a/frontend/wittymail-v2/src/app/sponsor-list/sponsor-list.component.css +++ b/frontend/wittymail-v2/src/app/sponsor-list/sponsor-list.component.css @@ -2,6 +2,10 @@ width: 100%; } +.table-container { + overflow: auto; +} + table { border-collapse: collapse; border-spacing: 0; diff --git a/frontend/wittymail-v2/src/app/sponsor-list/sponsor-list.component.html b/frontend/wittymail-v2/src/app/sponsor-list/sponsor-list.component.html index 0666af8..22e1a65 100644 --- a/frontend/wittymail-v2/src/app/sponsor-list/sponsor-list.component.html +++ b/frontend/wittymail-v2/src/app/sponsor-list/sponsor-list.component.html @@ -11,7 +11,7 @@ - + Which column has the e-mail address of the recipient? @@ -25,20 +25,19 @@ -
+
- +
- +
{{columnSelectedAs[header]}}
{{element[header]}}
diff --git a/frontend/wittymail-v2/src/app/sponsor-list/sponsor-list.component.ts b/frontend/wittymail-v2/src/app/sponsor-list/sponsor-list.component.ts index f8fab38..e5a3e29 100644 --- a/frontend/wittymail-v2/src/app/sponsor-list/sponsor-list.component.ts +++ b/frontend/wittymail-v2/src/app/sponsor-list/sponsor-list.component.ts @@ -1,6 +1,6 @@ -import { Component, OnInit, ViewChild } from '@angular/core'; +import { Component, OnInit, ViewChild, Input } from '@angular/core'; import { FileUploader } from 'ng2-file-upload'; -import { BackendService } from '../backend.service'; +import { BackendService, ColumnHeadersWithRowContent } from '../backend.service'; import { LoggerService } from '../util/logger.service'; import { ErrorDialogComponent } from '../common/error-dialog/error-dialog.component'; import { MatStepper } from '@angular/material'; @@ -12,52 +12,26 @@ import { MatStepper } from '@angular/material'; }) export class SponsorListComponent implements OnInit { + @Input('mainStepper') mainStepper: MatStepper; @ViewChild('stepper') stepper: MatStepper; + @ViewChild('columnMappingStepper') columnMappingStepper: MatStepper; @ViewChild('errorDialog') errorDialog: ErrorDialogComponent; public uploader: FileUploader; - headers = ['Sr No.', 'Name of Child', 'Class', 'Sponsor', 'Mail ID', 'Reference', 'Reference Mail ID'] - columnSelectedAs = { - 'Sr No.': '', - 'Name of Child': 'Attachment Name', - 'Class': '', - 'Sponsor': '', - 'Mail ID': 'E-mail Address (To)', - 'Reference': '', - 'Reference Mail ID': 'E-mail Address (CC)' - } - sheetContents = [ - { - 'Sr No.': "1", - 'Name of Child': "Aradhya Karche", - 'Class': "Nursery-kalewadi", - 'Sponsor': "Kalubai pratishthan", - 'Mail ID': "Sanjaysandhu8090@gmail.com", - 'Reference': "Ravi", - 'Reference Mail ID': "amboreravi@gmail.com" - }, - { - 'Sr No.': "2", - 'Name of Child': "Aradhya Karche", - 'Class': "Nursery-kalewadi", - 'Sponsor': "Kalubai pratishthan", - 'Mail ID': "Sanjaysandhu8090@gmail.com", - 'Reference': "Ravi", - 'Reference Mail ID': "amboreravi@gmail.com" - }, - { - 'Sr No.': "3", - 'Name of Child': "Aradhya Karche", - 'Class': "Nursery-kalewadi", - 'Sponsor': "Kalubai pratishthan", - 'Mail ID': "Sanjaysandhu8090@gmail.com", - 'Reference': "Ravi", - 'Reference Mail ID': "amboreravi@gmail.com" - }, - ]; + /** List of strings, each being the heading text for a column */ + headers = []; + + /** Dict of columnHeaderName -> selectedMapping */ + columnSelectedAs = {}; + + /** Data displayed in the table */ + sheetContents = []; constructor(private backend: BackendService, private log: LoggerService) { } + /** + * Setup the file uploader component's event handlers + */ ngOnInit() { this.uploader = new FileUploader({ url: this.backend.getFodderUploadUrl(), itemAlias: 'sponsor-sheet' }); this.uploader.onAfterAddingFile = (file) => { @@ -69,11 +43,86 @@ export class SponsorListComponent implements OnInit { this.log.info('Sponsor sheet uploaded: ', item.file.name, status); if (status === 200) { this.stepper.next(); - //this.displayColumnMappingUi(); + this.displayColumnMappingUi(); } else { this.errorDialog.showError("Failed to upload the sheet to the backend"); } }; } + /** + * Populate the table that displays the column headers and a few sample rows + */ + displayColumnMappingUi() { + this.backend.getColumnHeadersWithSampleRows().subscribe( + data => { + this.log.info("Received column headers with samples: ", data); + let r: ColumnHeadersWithRowContent = data; + this.headers = r.headers; + this.sheetContents = r.contents; + + this.log.info("Got %d headers and %d rows", this.headers.length, this.sheetContents.length); + }, + error => { + this.errorDialog.showError("Failed to analyze the Excel sheet"); + } + ); + } + + /** + * Handle the button click event on a column header by noting it as the + * selected mapping for the currently active mapping step + * + * @param selectedColumnHeader Name of the column being clicked + */ + onSelectColumn(selectedColumnHeader: string) { + let currentColumnMapping = this.columnMappingStepper.selected.label; + this.log.info("Selected column %s for %s", selectedColumnHeader, currentColumnMapping) + + this.columnSelectedAs[selectedColumnHeader] = currentColumnMapping; + + + if (this.columnMappingStepper.selectedIndex == this.columnMappingStepper.steps.length - 1) { + this.log.info("Done selecting columns, moving on..."); + this.saveColumnMappingAndContinue(); + } else { + this.columnMappingStepper.next(); + } + } + + /** + * Save the selected column mapping to the backend and move to the next page + */ + saveColumnMappingAndContinue() { + let to_column: string = ""; + let cc_column: string = ""; + let attachment_column: string = ""; + + /* The map-stepper API returns a QueryList which, unlike an array, is not + * directly accesible by index, so convert it to a normal array first + */ + let mappingSteps = []; + this.columnMappingStepper.steps.forEach(step => {mappingSteps.push(step)}); + + /* The dict is the other way round (columnHeader -> selectedMapping), + * so we have to loop through it + */ + for (let key in this.columnSelectedAs) { + if (this.columnSelectedAs[key] == mappingSteps[0].label) { + to_column = key; + } + if (this.columnSelectedAs[key] == mappingSteps[1].label) { + cc_column = key; + } + if (this.columnSelectedAs[key] == mappingSteps[2].label) { + attachment_column = key; + } + } + this.log.info("Selected columns:\nto: %s\ncc: %s\nattachment: %s", + to_column, cc_column, attachment_column); + this.backend.saveEmailToCCColumns(to_column, cc_column); + this.backend.saveAttachmentMetadata(attachment_column); + + this.mainStepper.next(); + } } diff --git a/frontend/wittymail-v2/src/app/steps-slider/steps-slider.component.html b/frontend/wittymail-v2/src/app/steps-slider/steps-slider.component.html index 984b305..6885a8c 100644 --- a/frontend/wittymail-v2/src/app/steps-slider/steps-slider.component.html +++ b/frontend/wittymail-v2/src/app/steps-slider/steps-slider.component.html @@ -1,6 +1,6 @@ - + From 4b2121054e26df6881f549cd0c22820ef8c332dd Mon Sep 17 00:00:00 2001 From: Omkar Ekbote Date: Wed, 1 May 2019 22:56:53 +0530 Subject: [PATCH 29/64] Make things work after the merge --- backend/requirements.txt | 4 +++- backend/webserver/wittymail_server/Sheet.py | 2 +- backend/webserver/wittymail_server/rest_api.py | 4 ++-- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/backend/requirements.txt b/backend/requirements.txt index 4a440d2..c46f04a 100644 --- a/backend/requirements.txt +++ b/backend/requirements.txt @@ -4,4 +4,6 @@ openpyxl requests PyPDF2 pyinstaller -flask-classy \ No newline at end of file +flask-classy +fuzzywuzzy +python-Levenshtein diff --git a/backend/webserver/wittymail_server/Sheet.py b/backend/webserver/wittymail_server/Sheet.py index 995eca8..5f308da 100644 --- a/backend/webserver/wittymail_server/Sheet.py +++ b/backend/webserver/wittymail_server/Sheet.py @@ -1,5 +1,5 @@ from util.FileUtils import FileUtils -from mailer.ColumnMapping import ColumnMapping +from wittymail_server.ColumnMapping import ColumnMapping class Sheet: __instance = None diff --git a/backend/webserver/wittymail_server/rest_api.py b/backend/webserver/wittymail_server/rest_api.py index f02da7a..758b571 100644 --- a/backend/webserver/wittymail_server/rest_api.py +++ b/backend/webserver/wittymail_server/rest_api.py @@ -11,7 +11,7 @@ import util.version as version import util.logger as logger from flask import send_file -from sheet import sheet +from wittymail_server.Sheet import Sheet log = logger.get_logger(__name__) @@ -26,7 +26,7 @@ class SheetView(FlaskView): /api/sheet/... """ - s = sheet() + s = Sheet(None) route_prefix = flask_app.config['URL_DEFAULT_PREFIX_FOR_API'] @route('upload', methods=['POST']) From 523c856a7b0cd663934be66a38173015de2a70ff Mon Sep 17 00:00:00 2001 From: Omkar Ekbote Date: Wed, 1 May 2019 23:15:34 +0530 Subject: [PATCH 30/64] Add main stepper ref to all pages --- .../src/app/attachments/attachments.component.ts | 5 ++++- .../src/app/email-design/email-design.component.ts | 6 ++++-- .../src/app/steps-slider/steps-slider.component.html | 4 ++-- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/frontend/wittymail-v2/src/app/attachments/attachments.component.ts b/frontend/wittymail-v2/src/app/attachments/attachments.component.ts index bb1f15a..f9d784e 100644 --- a/frontend/wittymail-v2/src/app/attachments/attachments.component.ts +++ b/frontend/wittymail-v2/src/app/attachments/attachments.component.ts @@ -1,6 +1,7 @@ -import { Component, OnInit } from '@angular/core'; +import { Component, OnInit, Input } from '@angular/core'; import { SafeHtml, DomSanitizer } from '@angular/platform-browser'; import { LoggerService } from '../util/logger.service'; +import { MatStepper } from '@angular/material'; @Component({ selector: 'app-attachments', @@ -9,6 +10,8 @@ import { LoggerService } from '../util/logger.service'; }) export class AttachmentsComponent implements OnInit { + @Input('mainStepper') mainStepper: MatStepper; + headers = ['Sr No.', 'Name of Child', 'Class'] attachmentSubjectHeaderName = 'Name of Child' sheetContents = [ diff --git a/frontend/wittymail-v2/src/app/email-design/email-design.component.ts b/frontend/wittymail-v2/src/app/email-design/email-design.component.ts index 120ee19..d53ade6 100644 --- a/frontend/wittymail-v2/src/app/email-design/email-design.component.ts +++ b/frontend/wittymail-v2/src/app/email-design/email-design.component.ts @@ -1,6 +1,6 @@ -import { Component, OnInit, ViewChild } from '@angular/core'; +import { Component, OnInit, ViewChild, Input } from '@angular/core'; import { LoggerService } from '../util/logger.service'; -import { MatInput } from '@angular/material'; +import { MatInput, MatStepper } from '@angular/material'; @Component({ selector: 'app-email-design', @@ -9,6 +9,8 @@ import { MatInput } from '@angular/material'; }) export class EmailDesignComponent implements OnInit { + @Input('mainStepper') mainStepper: MatStepper; + @ViewChild("subjectInput") subjectInput: MatInput; diff --git a/frontend/wittymail-v2/src/app/steps-slider/steps-slider.component.html b/frontend/wittymail-v2/src/app/steps-slider/steps-slider.component.html index 6885a8c..a22132d 100644 --- a/frontend/wittymail-v2/src/app/steps-slider/steps-slider.component.html +++ b/frontend/wittymail-v2/src/app/steps-slider/steps-slider.component.html @@ -4,11 +4,11 @@ - + - + From 3cb228bde58107dfb43024459e85ec43313937f8 Mon Sep 17 00:00:00 2001 From: Omkar Ekbote Date: Wed, 1 May 2019 23:52:53 +0530 Subject: [PATCH 31/64] Connect attachment upload to backend --- .../webserver/wittymail_server/__init__.py | 3 ++ .../webserver/wittymail_server/rest_api.py | 29 +++++++++++++----- .../attachments/attachments.component.html | 9 ++++-- .../app/attachments/attachments.component.ts | 30 +++++++++++++++++-- 4 files changed, 59 insertions(+), 12 deletions(-) diff --git a/backend/webserver/wittymail_server/__init__.py b/backend/webserver/wittymail_server/__init__.py index 032c407..832613b 100644 --- a/backend/webserver/wittymail_server/__init__.py +++ b/backend/webserver/wittymail_server/__init__.py @@ -58,9 +58,12 @@ def get_attachments_dir(): CORS(flask_app) a = get_attachments_dir() + common_attachments_dir = os.path.join(a,'common') + os.makedirs(common_attachments_dir) f = get_fodder_dir() flask_app.config['ATTACHMENTS_DIR'] = a + flask_app.config['COMMON_ATTACHMENTS_DIR'] = common_attachments_dir flask_app.config['FODDER_DIR'] = f flask_app.config['URL_DEFAULT_PREFIX_FOR_API'] = '/api' diff --git a/backend/webserver/wittymail_server/rest_api.py b/backend/webserver/wittymail_server/rest_api.py index 758b571..8baa540 100644 --- a/backend/webserver/wittymail_server/rest_api.py +++ b/backend/webserver/wittymail_server/rest_api.py @@ -186,15 +186,30 @@ def upload_attachment(self): To workaround this stupidity, this API is idempotent and will just keep saving all files in the same dir """ - a = request.files['attachment'] - attachment_dir = flask_app.config['ATTACHMENTS_DIR'] + if 'attachment' in request.files: + a = request.files['attachment'] + attachment_save_path = os.path.join(flask_app.config['ATTACHMENTS_DIR'], a.filename) - a.save(os.path.join(attachment_dir, a.filename)) - log.info('Attachment file saved as = %s' % (attachment_dir + a.filename)) + a.save(attachment_save_path) + log.info('Attachment file saved at: %s', attachment_save_path) + + #emailapi_broker.save_attachment_dir(attachment_dir) + # TODO Call change_email_fodder_status() from save_attachment_dir() + #emailapi_broker.change_email_fodder_status(a.filename) + + elif 'common_attachment' in request.files: + a = request.files['common_attachment'] + attachment_save_path = os.path.join(flask_app.config['COMMON_ATTACHMENTS_DIR'], a.filename) + + a.save(attachment_save_path) + log.info('Attachment file saved at: %s', attachment_save_path) + + else: + log.error('No file found in payload: %s', request.files) + return (jsonify({'error': 'Request payload must have either files.attachment or files.common_attachment'}), + HTTP_BAD_INPUT, + {'ContentType': 'application/json'}) - emailapi_broker.save_attachment_dir(attachment_dir) - # TODO Call change_email_fodder_status() from save_attachment_dir() - emailapi_broker.change_email_fodder_status(a.filename) return "Attachments saved successfully", HTTP_OK @route('upload_for_row', methods=['POST']) diff --git a/frontend/wittymail-v2/src/app/attachments/attachments.component.html b/frontend/wittymail-v2/src/app/attachments/attachments.component.html index 9737152..6f6ace8 100644 --- a/frontend/wittymail-v2/src/app/attachments/attachments.component.html +++ b/frontend/wittymail-v2/src/app/attachments/attachments.component.html @@ -6,17 +6,18 @@ Common Attachments
-
Individual Attachments
-
+ @@ -97,4 +98,6 @@
-
\ No newline at end of file +
+ + diff --git a/frontend/wittymail-v2/src/app/attachments/attachments.component.ts b/frontend/wittymail-v2/src/app/attachments/attachments.component.ts index f9d784e..24642da 100644 --- a/frontend/wittymail-v2/src/app/attachments/attachments.component.ts +++ b/frontend/wittymail-v2/src/app/attachments/attachments.component.ts @@ -1,7 +1,10 @@ -import { Component, OnInit, Input } from '@angular/core'; +import { Component, OnInit, Input, ViewChild } from '@angular/core'; import { SafeHtml, DomSanitizer } from '@angular/platform-browser'; import { LoggerService } from '../util/logger.service'; import { MatStepper } from '@angular/material'; +import { FileUploader } from 'ng2-file-upload'; +import { BackendService } from '../backend.service'; +import { ErrorDialogComponent } from '../common/error-dialog/error-dialog.component'; @Component({ selector: 'app-attachments', @@ -11,6 +14,10 @@ import { MatStepper } from '@angular/material'; export class AttachmentsComponent implements OnInit { @Input('mainStepper') mainStepper: MatStepper; + @ViewChild('errorDialog') errorDialog: ErrorDialogComponent; + + public commonAttachmentUploader: FileUploader; + public individualAttachmentUploader: FileUploader; headers = ['Sr No.', 'Name of Child', 'Class'] attachmentSubjectHeaderName = 'Name of Child' @@ -105,9 +112,28 @@ export class AttachmentsComponent implements OnInit { selectedAttachmentCandidate: any = null; selectedPDFViewerHTML: SafeHtml = null; - constructor(private sanitizer: DomSanitizer, private log: LoggerService) { } + constructor(private sanitizer: DomSanitizer, private log: LoggerService, + private backend: BackendService) { } ngOnInit() { + this.commonAttachmentUploader = new FileUploader({ url: this.backend.getAttachmentUploadUrl(), itemAlias: 'common_attachment' }); + this.individualAttachmentUploader = new FileUploader({ url: this.backend.getAttachmentUploadUrl(), itemAlias: 'attachment' }); + let uploaders = [this.commonAttachmentUploader, this.individualAttachmentUploader]; + + uploaders.forEach(uploader => { + uploader.onAfterAddingFile = (file) => { + file.withCredentials = false; + uploader.uploadAll(); + }; + + uploader.onCompleteItem = (item: any, response: any, status: any, headers: any) => { + if (status == 200) { + this.log.info("Attachment uploaded: ", item.file.name, status); + } else { + this.errorDialog.showError("Failed to upload attachment '" + item.file.name + "': " + status + " " + response); + } + }; + }); } onClickRow(row) { From f0ba0fee26f9a9588af41f5f7ea42842ac9cbbe1 Mon Sep 17 00:00:00 2001 From: Omkar Ekbote Date: Wed, 1 May 2019 23:53:02 +0530 Subject: [PATCH 32/64] Add error handling for upload failures --- .../src/app/sponsor-list/sponsor-list.component.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/wittymail-v2/src/app/sponsor-list/sponsor-list.component.ts b/frontend/wittymail-v2/src/app/sponsor-list/sponsor-list.component.ts index e5a3e29..1f9ac23 100644 --- a/frontend/wittymail-v2/src/app/sponsor-list/sponsor-list.component.ts +++ b/frontend/wittymail-v2/src/app/sponsor-list/sponsor-list.component.ts @@ -40,12 +40,12 @@ export class SponsorListComponent implements OnInit { }; this.uploader.onCompleteItem = (item: any, response: any, status: any, headers: any) => { - this.log.info('Sponsor sheet uploaded: ', item.file.name, status); if (status === 200) { + this.log.info('Sponsor sheet uploaded: ', item.file.name, status); this.stepper.next(); this.displayColumnMappingUi(); } else { - this.errorDialog.showError("Failed to upload the sheet to the backend"); + this.errorDialog.showError("Failed to upload sponsor list '" + item.file.name + "': " + status + " " + response); } }; } From 875b79f1e1b7aecf4c32e9a36a0c77fd4afa37b9 Mon Sep 17 00:00:00 2001 From: Omkar Ekbote Date: Thu, 2 May 2019 02:04:57 +0530 Subject: [PATCH 33/64] Connect PDF rotation to backend --- backend/util/FileUtils.py | 28 ++++++--- .../wittymail_server/default_routes.py | 2 +- .../webserver/wittymail_server/rest_api.py | 18 +++++- .../attachments/attachments.component.html | 8 +-- .../app/attachments/attachments.component.ts | 57 ++++++++++++++----- .../wittymail-v2/src/app/backend.service.ts | 16 +++++- 6 files changed, 100 insertions(+), 29 deletions(-) diff --git a/backend/util/FileUtils.py b/backend/util/FileUtils.py index 70edebf..bb24c2b 100644 --- a/backend/util/FileUtils.py +++ b/backend/util/FileUtils.py @@ -14,8 +14,17 @@ Used to denote the direction of the rotation of pdf ''' class Direction(Enum): - CLOCKWISE = 0 - ANTICLOCKWISE = 1 + CLOCKWISE = 270 # Degrees to rotate + ANTICLOCKWISE = 90 + + @classmethod + def convert_from_string(cls, direction_str): + mapping = { + 'CLOCKWISE': Direction.CLOCKWISE, + 'ANTICLOCKWISE': Direction.ANTICLOCKWISE + } + + return mapping[direction_str] ''' All file related helper operations @@ -28,11 +37,14 @@ def __init__(self): Rotate a pdf based on the direction provided ''' def pdf_rotate(self, filepath, direction): - if direction == Direction.CLOCKWISE: - rotation_degree = 270 - else: - rotation_degree = 90 - + """ + Rotate all pages in the PDF and replace file on disk + + :param filepath: Full path to PDF file + :param direction: Direction enum value + """ + log.info("Rotating file '%s' by %s", filepath, direction) + direction = Direction.convert_from_string(direction) output_file = filepath + '.tmp' with open(filepath, 'rb') as f: @@ -41,7 +53,7 @@ def pdf_rotate(self, filepath, direction): for pagenum in range(pdf_reader.numPages): page = pdf_reader.getPage(pagenum) - page.rotateCounterClockwise(rotation_degree) + page.rotateCounterClockwise(direction.value) pdf_writer.addPage(page) log.info("Writing PDF: %s", output_file) diff --git a/backend/webserver/wittymail_server/default_routes.py b/backend/webserver/wittymail_server/default_routes.py index ee00f9c..8118c14 100644 --- a/backend/webserver/wittymail_server/default_routes.py +++ b/backend/webserver/wittymail_server/default_routes.py @@ -28,7 +28,7 @@ def route_static_files(path): ''' return send_from_directory(os.path.join(base_path, "static"), path) -@flask_app.route('/attachment/') +@flask_app.route('/api/attachment/file/') def route_attachment_files(path): return send_from_directory(flask_app.config['ATTACHMENTS_DIR'], path) diff --git a/backend/webserver/wittymail_server/rest_api.py b/backend/webserver/wittymail_server/rest_api.py index 8baa540..8e0503f 100644 --- a/backend/webserver/wittymail_server/rest_api.py +++ b/backend/webserver/wittymail_server/rest_api.py @@ -12,6 +12,7 @@ import util.logger as logger from flask import send_file from wittymail_server.Sheet import Sheet +from util.FileUtils import FileUtils log = logger.get_logger(__name__) @@ -19,6 +20,7 @@ HTTP_CREATED = 201 HTTP_NOT_FOUND = 404 HTTP_BAD_INPUT = 400 +HTTP_SERVER_ERROR = 500 class SheetView(FlaskView): """ @@ -224,7 +226,21 @@ def upload_attachment_for_row(self): data = json.loads(request.data) emailapi_broker.change_email_fodder_status(a.filename, data['row']) - return "Attachments saved successfully", HTTP_OK + return ("Attachments saved successfully", HTTP_OK, {'ContentType': 'text/plain'}) + + @route('rotate', methods=['POST']) + def rotate(self): + data = json.loads(request.data) + filepath = os.path.join(flask_app.config['ATTACHMENTS_DIR'], data['filename']) + + try: + util = FileUtils() + util.pdf_rotate(filepath, data['direction']) + except Exception as e: + log.exception("Failed to rotate: %s", data) + return (str(e), HTTP_SERVER_ERROR, {'ContentType': 'text/plain'}) + + return (jsonify({}), HTTP_OK, {'ContentType': 'application/json'}) class EmailView(FlaskView): """ diff --git a/frontend/wittymail-v2/src/app/attachments/attachments.component.html b/frontend/wittymail-v2/src/app/attachments/attachments.component.html index 6f6ace8..53fe1f1 100644 --- a/frontend/wittymail-v2/src/app/attachments/attachments.component.html +++ b/frontend/wittymail-v2/src/app/attachments/attachments.component.html @@ -51,9 +51,9 @@
- {{candidate.displayName}} + {{candidate.pdfName}}
@@ -63,10 +63,10 @@ fxLayoutWrap *ngIf="selectedAttachmentCandidate">
- - + diff --git a/frontend/wittymail-v2/src/app/email-design/email-design.component.ts b/frontend/wittymail-v2/src/app/email-design/email-design.component.ts index f4dac07..d7f069a 100644 --- a/frontend/wittymail-v2/src/app/email-design/email-design.component.ts +++ b/frontend/wittymail-v2/src/app/email-design/email-design.component.ts @@ -1,7 +1,7 @@ import { Component, OnInit, ViewChild, Input } from '@angular/core'; import { LoggerService } from '../util/logger.service'; import { MatInput, MatStepper } from '@angular/material'; -import { BackendService, ColumnHeadersWithRowContent, TemplateInput, TemplateOutput } from '../backend.service'; +import { BackendService, ColumnHeadersWithRowContent, TemplateInput, TemplateOutput, EmailServerDetails } from '../backend.service'; import { ErrorDialogComponent } from '../common/error-dialog/error-dialog.component'; enum LastFocusedInput { @@ -36,6 +36,12 @@ export class EmailDesignComponent implements OnInit { /* Which element was last focussed? */ lastFocused: LastFocusedInput = LastFocusedInput.SUBJECT; + emailSettings: EmailServerDetails = { + service: 'Gmail', + username: '', + password: '' + }; + constructor(private log: LoggerService, private backend: BackendService) { } ngOnInit() { @@ -124,4 +130,16 @@ export class EmailDesignComponent implements OnInit { ); } + onSubmitEmailServer() { + this.backend.postEmailServerDetails(this.emailSettings).subscribe( + data => { + this.log.info("Email server detailes posted, moving on..."); + this.mainStepper.next(); + }, + error => { + this.errorDialog.showError(error.error_message); + } + ); + } + } From 441798dd7baeb8333eb55d9fd5948f8095705166 Mon Sep 17 00:00:00 2001 From: Omkar Ekbote Date: Fri, 3 May 2019 10:50:20 +0530 Subject: [PATCH 41/64] Populate sheet contents from backend --- .../webserver/wittymail_server/rest_api.py | 8 +- .../attachments/attachments.component.html | 2 +- .../app/attachments/attachments.component.ts | 125 +++++++----------- .../wittymail-v2/src/app/backend.service.ts | 55 +------- 4 files changed, 58 insertions(+), 132 deletions(-) diff --git a/backend/webserver/wittymail_server/rest_api.py b/backend/webserver/wittymail_server/rest_api.py index 96457fb..1f8d421 100644 --- a/backend/webserver/wittymail_server/rest_api.py +++ b/backend/webserver/wittymail_server/rest_api.py @@ -72,7 +72,13 @@ def contents(self): :return: """ - log.info("URL: %s", url_for('SheetView:some')) + # TODO: Using implementation in /headers temporarily + sheet = Sheet.getInstance() + headers, data = sheet.get_headers_with_sample_rows(row_count = 3) + return (jsonify({'headers': headers, 'extended_headers': [], 'contents': data}), + HTTP_OK, + {'ContentType': 'application/json'}) + e = emailapi_broker.get_email_fodder_names() if e[0] is not 0: return (jsonify({"err_msg": e[1]}), diff --git a/frontend/wittymail-v2/src/app/attachments/attachments.component.html b/frontend/wittymail-v2/src/app/attachments/attachments.component.html index 53fe1f1..6dac4a2 100644 --- a/frontend/wittymail-v2/src/app/attachments/attachments.component.html +++ b/frontend/wittymail-v2/src/app/attachments/attachments.component.html @@ -1,5 +1,5 @@
- +
diff --git a/frontend/wittymail-v2/src/app/attachments/attachments.component.ts b/frontend/wittymail-v2/src/app/attachments/attachments.component.ts index dbc569d..31f080f 100644 --- a/frontend/wittymail-v2/src/app/attachments/attachments.component.ts +++ b/frontend/wittymail-v2/src/app/attachments/attachments.component.ts @@ -4,7 +4,7 @@ import { SafeHtml, DomSanitizer } from '@angular/platform-browser'; import { LoggerService } from '../util/logger.service'; import { MatStepper } from '@angular/material'; import { FileUploader } from 'ng2-file-upload'; -import { BackendService, AttachmentRotation } from '../backend.service'; +import { BackendService, AttachmentRotation, ColumnHeadersWithRowContent } from '../backend.service'; import { ErrorDialogComponent } from '../common/error-dialog/error-dialog.component'; @Component({ @@ -15,88 +15,23 @@ import { ErrorDialogComponent } from '../common/error-dialog/error-dialog.compon export class AttachmentsComponent implements OnInit { @Input('mainStepper') mainStepper: MatStepper; + @Input('stepper') stepper: MatStepper; @ViewChild('errorDialog') errorDialog: ErrorDialogComponent; public commonAttachmentUploader: FileUploader; public individualAttachmentUploader: FileUploader; - selectedPDF: any; - - headers = ['Sr No.', 'Name of Child', 'Class'] - attachmentSubjectHeaderName = 'Name of Child' - sheetContents = [ - { - 'Sr No.': "1", - 'Name of Child': "Aradhya Karche", - 'Class': "Nursery-kalewadi" - }, - { - 'Sr No.': "2", - 'Name of Child': "Vedika Shirgire", - 'Class': "Nursery-kalewadi" - }, - { - 'Sr No.': "2", - 'Name of Child': "Vedika Shirgire", - 'Class': "Nursery-kalewadi" - }, - { - 'Sr No.': "2", - 'Name of Child': "Vedika Shirgire", - 'Class': "Nursery-kalewadi" - }, - { - 'Sr No.': "2", - 'Name of Child': "Vedika Shirgire", - 'Class': "Nursery-kalewadi" - }, - { - 'Sr No.': "2", - 'Name of Child': "Vedika Shirgire", - 'Class': "Nursery-kalewadi" - }, - { - 'Sr No.': "2", - 'Name of Child': "Vedika Shirgire", - 'Class': "Nursery-kalewadi" - }, - { - 'Sr No.': "2", - 'Name of Child': "Vedika Shirgire", - 'Class': "Nursery-kalewadi" - }, - { - 'Sr No.': "2", - 'Name of Child': "Vedika Shirgire", - 'Class': "Nursery-kalewadi" - }, - { - 'Sr No.': "2", - 'Name of Child': "Vedika Shirgire", - 'Class': "Nursery-kalewadi" - }, - { - 'Sr No.': "2", - 'Name of Child': "Vedika Shirgire", - 'Class': "Nursery-kalewadi" - }, - { - 'Sr No.': "2", - 'Name of Child': "Vedika Shirgire", - 'Class': "Nursery-kalewadi" - }, - { - 'Sr No.': "2", - 'Name of Child': "Vedika Shirgire", - 'Class': "Nursery-kalewadi" - }, - { - 'Sr No.': "2", - 'Name of Child': "Vedika Shirgire", - 'Class': "Nursery-kalewadi" - } - ]; + /** List of strings, each being the heading text for a column */ + headers = []; + + /** Dict of columnHeaderName -> selectedMapping */ + columnSelectedAs = {}; + + /** Data displayed in the table */ + sheetContents = []; + selectedRow: any = null; + selectedPDF: any; attachmentCandidatesForSelectedRow = [ { @@ -136,9 +71,43 @@ export class AttachmentsComponent implements OnInit { }); } + /** + * Populate the table that displays the column headers and a few sample rows + * + * This is called by the main stepper when this step becomes visible, because + * the data fetching depends on previous steps. + */ + populateTable() { + this.backend.getSheetContents().subscribe( + data => { + let r: ColumnHeadersWithRowContent = data; + + /* Only show the first 4 columns as we have just half the page width for the table */ + this.headers = r.headers.slice(0, 3); + + /* Append the 'frozen_attachment' column */ + this.headers.concat(r.extended_headers); + this.sheetContents = r.contents; + + this.log.info("Using %d headers and %d rows", this.headers.length, this.sheetContents.length); + }, + error => { + this.errorDialog.showError("Failed to get contents of the Excel sheet: " + error); + } + ); + } + + onStepChange(stepper: MatStepper) { + this.log.info("Attachments page now showing step: ", stepper.selectedIndex); + + /* On the second step, populate the table with sheet contents */ + if (stepper.selectedIndex == 1) { + this.populateTable(); + } + } + onClickRow(row) { this.log.info(row) - this.log.info(row[this.attachmentSubjectHeaderName]) this.selectedRow = row; } diff --git a/frontend/wittymail-v2/src/app/backend.service.ts b/frontend/wittymail-v2/src/app/backend.service.ts index ce0aa6a..ea7a120 100644 --- a/frontend/wittymail-v2/src/app/backend.service.ts +++ b/frontend/wittymail-v2/src/app/backend.service.ts @@ -11,6 +11,7 @@ export interface VersionInfo { export interface ColumnHeadersWithRowContent { headers: string[]; + extended_headers: string[]; contents: any[]; } @@ -170,61 +171,11 @@ export class BackendService { ); } - getVomit(): Observable { + getSheetContents(): Observable { return this.http.get(this.urls.sheet.get_contents) .pipe( - catchError(this.handleError('getVomit')) + catchError(this.handleError('getSheetContents')) ); - - // let res: ColumnHeadersWithRowContent = { - // headers: [ - // 'Name of Child', 'Class', 'Sponsor', 'Mail ID', 'Reference', 'Reference mail ID' - // ], - // contents: [ - // { - // 'Name of Child': 'Aradhya Karche', - // 'Class': 'Nursery- kalewadi', - // 'Sponsor': 'Kalubai pratishthan', - // 'Mail ID': 'Sanjaysandhu8090@gmail.com', - // 'Reference': 'Ravi', - // 'Reference mail ID': 'amboreravi@gmail.com', - // 'status': 'Pending', - // 'email': { - // 'from': 'wittymail@acme.com', - // 'to': 'Sanjaysandhu8090@gmail.com', - // 'cc': 'amboreravi@gmail.com', - // 'attachment': { - // 'name': 'Aradhya Karche.pdf', - // 'url': 'api/attachment/Aradhya%20Karche.pdf' - // }, - // 'subject': 'First term progress report for Aradhya Karche', - // 'body': 'Dear Kalubai pratishthan,' - // } - // }, - // { - // 'Name of Child': 'Vedika Shirgire', - // 'Class': 'Nursery- kalewadi', - // 'Sponsor': 'Apurva kumar', - // 'Mail ID': 'apurv07vit@gmail.com', - // 'Reference': 'Anish', - // 'Reference mail ID': 'anishgarg07@gmail.com', - // 'status': 'Pending', - // 'email': { - // 'from': 'wittymail@acme.com', - // 'to': 'apurv07vit@gmail.com', - // 'cc': 'anishgarg07@gmail.com', - // 'attachment': { - // 'name': 'Vedika Shirgire.pdf', - // 'url': 'api/attachment/Vedika%20Shirgire.pdf' - // }, - // 'subject': 'First term progress report for Vedika Shirgire', - // 'body': 'Dear Apurva kumar,' - // } - // } - // ] - // }; - - // return res; } postColumnMapping(mapping: ColumnMappings) { From e0a68306d8d1012e408cbd71bb89623ecc4715bd Mon Sep 17 00:00:00 2001 From: Omkar Ekbote Date: Fri, 3 May 2019 17:03:00 +0530 Subject: [PATCH 42/64] Connect backend for candidate selection --- .../webserver/wittymail_server/rest_api.py | 15 ++++++ .../attachments/attachments.component.html | 8 ++-- .../app/attachments/attachments.component.ts | 46 ++++++++++++++----- .../wittymail-v2/src/app/backend.service.ts | 30 ++++++++++++ 4 files changed, 83 insertions(+), 16 deletions(-) diff --git a/backend/webserver/wittymail_server/rest_api.py b/backend/webserver/wittymail_server/rest_api.py index 1f8d421..43770ec 100644 --- a/backend/webserver/wittymail_server/rest_api.py +++ b/backend/webserver/wittymail_server/rest_api.py @@ -234,6 +234,21 @@ def rotate(self): return (str(e), HTTP_SERVER_ERROR, {'ContentType': 'text/plain'}) return (jsonify({}), HTTP_OK, {'ContentType': 'application/json'}) + + def candidate(self): + row = request.args.get("selected_row") + + log.info("Fetching candidates for: %s", row) + return (jsonify({'subject': 'John Doe', 'pdfNames': ['John Doe.pdf']}), + HTTP_OK, {'ContentType': 'application/json'}) + + @route('candidate/select', methods=['POST']) + def select_candidate(self): + data = json.loads(request.data) + + log.info("Selecting candidate: %s", data) + return (jsonify({}), HTTP_OK, {'ContentType': 'application/json'}) + class EmailView(FlaskView): """ diff --git a/frontend/wittymail-v2/src/app/attachments/attachments.component.html b/frontend/wittymail-v2/src/app/attachments/attachments.component.html index 6dac4a2..5370d94 100644 --- a/frontend/wittymail-v2/src/app/attachments/attachments.component.html +++ b/frontend/wittymail-v2/src/app/attachments/attachments.component.html @@ -47,13 +47,13 @@

- Pick the correct attachment for {{selectedRow[attachmentSubjectHeaderName]}}: + Pick the correct attachment for {{selectedRowSubject}}:
- {{candidate.pdfName}} + {{candidate}}
@@ -69,7 +69,7 @@ -
diff --git a/frontend/wittymail-v2/src/app/attachments/attachments.component.ts b/frontend/wittymail-v2/src/app/attachments/attachments.component.ts index 31f080f..25f7662 100644 --- a/frontend/wittymail-v2/src/app/attachments/attachments.component.ts +++ b/frontend/wittymail-v2/src/app/attachments/attachments.component.ts @@ -4,7 +4,7 @@ import { SafeHtml, DomSanitizer } from '@angular/platform-browser'; import { LoggerService } from '../util/logger.service'; import { MatStepper } from '@angular/material'; import { FileUploader } from 'ng2-file-upload'; -import { BackendService, AttachmentRotation, ColumnHeadersWithRowContent } from '../backend.service'; +import { BackendService, AttachmentRotation, ColumnHeadersWithRowContent, CandidateAttachmentSelection, CandidateAttachments } from '../backend.service'; import { ErrorDialogComponent } from '../common/error-dialog/error-dialog.component'; @Component({ @@ -31,19 +31,10 @@ export class AttachmentsComponent implements OnInit { sheetContents = []; selectedRow: any = null; + selectedRowSubject: string = ""; selectedPDF: any; - attachmentCandidatesForSelectedRow = [ - { - 'pdfName': "Aradhya Karche.pdf" - }, - { - 'pdfName': "Aaradhya Karche.pdf" - }, - { - 'pdfName': "Aradhya Kachre.pdf" - } - ] + attachmentCandidatesForSelectedRow: string[] = []; selectedAttachmentCandidate: any = null; selectedPDFViewerHTML: SafeHtml = null; @@ -109,6 +100,37 @@ export class AttachmentsComponent implements OnInit { onClickRow(row) { this.log.info(row) this.selectedRow = row; + + this.backend.getCandidateAttachments(row).subscribe( + data => { + this.log.info("Got attachment candidates: ", data); + let d: CandidateAttachments = data; + this.attachmentCandidatesForSelectedRow = d.pdfNames; + this.selectedRowSubject = d.subject; + }, + error => { + this.errorDialog.showError("Could not fetch any candidates for this row: " + error); + this.attachmentCandidatesForSelectedRow = []; + } + ); + } + + onSelectAttachmentCandidate() { + let payload: CandidateAttachmentSelection = { + pdfName: this.selectedAttachmentCandidate, + selected_row: this.selectedRow + }; + + this.log.info("Selecting candidate: ", payload); + + this.backend.selectAttachmentCandidate(payload).subscribe( + data => { + this.selectedRow = null; + }, + error => { + this.errorDialog.showError("Failed to select this candidate: " + error); + } + ); } _setPDFViewerHTML(url) { diff --git a/frontend/wittymail-v2/src/app/backend.service.ts b/frontend/wittymail-v2/src/app/backend.service.ts index ea7a120..6b0a372 100644 --- a/frontend/wittymail-v2/src/app/backend.service.ts +++ b/frontend/wittymail-v2/src/app/backend.service.ts @@ -64,6 +64,20 @@ export interface TemplateOutput { reality: string; } +export interface CandidateAttachmentsInput { + selected_row: any; +} + +export interface CandidateAttachments { + subject: string; + pdfNames: string[]; +} + +export interface CandidateAttachmentSelection { + selected_row: any; + pdfName: string; +} + @Injectable({ providedIn: 'root' }) @@ -85,6 +99,8 @@ export class BackendService { upload: 'api/attachment/upload', // POST rotate: 'api/attachment/rotate', // POST get_file: 'api/attachment/file/', // GET with filename appended to URL + candidate: 'api/attachment/candidate', // GET with selected_row + candidate_select: 'api/attachment/candidate/select', // POST with selected_row and attachment name }, email: { set_server: 'api/email/server', // POST @@ -212,6 +228,20 @@ export class BackendService { ); } + getCandidateAttachments(selected_row: CandidateAttachmentsInput): Observable { + return this.http.get(this.urls.attachment.candidate) + .pipe( + catchError(this.handleError('getCandidateAttachments')) + ); + } + + selectAttachmentCandidate(selected: CandidateAttachmentSelection) { + return this.http.post(this.urls.attachment.candidate_select, selected) + .pipe( + catchError(this.handleError('selectAttachmentCandidate')) + ); + } + resolveTemplate(input: TemplateInput): Observable { this.log.info("POSTing template: ", input); return this.http.post(this.urls.email.convert_template_to_string, input) From d1ea6b2d72407c2b212195888257094e4efbceba Mon Sep 17 00:00:00 2001 From: Ajay Nair Date: Sat, 4 May 2019 12:11:35 +0530 Subject: [PATCH 43/64] Bug fixes --- backend/mailer/Email.py | 18 +- backend/mailer/SMTPEmailProvider.py | 13 +- backend/util/FileUtils.py | 10 +- .../wittymail_server/ColumnMapping.py | 21 ++- backend/webserver/wittymail_server/Sheet.py | 27 ++- .../wittymail_server/default_routes.py | 4 +- .../webserver/wittymail_server/rest_api.py | 176 +++++++++--------- 7 files changed, 156 insertions(+), 113 deletions(-) diff --git a/backend/mailer/Email.py b/backend/mailer/Email.py index 40cebc2..03cd1dc 100644 --- a/backend/mailer/Email.py +++ b/backend/mailer/Email.py @@ -15,20 +15,22 @@ class Email(): subject_template = None body_template = None frm = None + common_attachment_dir = None - def __init__(self, to, cc, subject, body, status = None): - assert to is not None and \ - cc is not None, \ - log.error('Incorrect value provided to=%s cc=%s' % (to, cc)) - self.to = to - self.cc = cc + def __init__(self, tos, ccs, attachments, subject, body, status = None): + assert tos is not None, log.error('Incorrect value provided to=%s cc=%s' % (tos, ccs)) + self.tos = tos + self.ccs = ccs + self.attachments = attachments self.subject = subject self.body = body self.status = status - self.attachment = None def get_email_from(self): - return self.frm + return Email.frm + + def set_email_common_attachment_dir(self, attachment_dir): + Email.common_attachment_dir = attachment_dir def __del__(self): self.to = None diff --git a/backend/mailer/SMTPEmailProvider.py b/backend/mailer/SMTPEmailProvider.py index 9e547f1..78e1578 100644 --- a/backend/mailer/SMTPEmailProvider.py +++ b/backend/mailer/SMTPEmailProvider.py @@ -9,16 +9,17 @@ import os import util.logger as logger from mailer.EmailProvider import EmailProvider +from os import listdir +from os.path import isfile log = logger.get_logger(__name__) class SMTPEmailProvider(EmailProvider): - def __init__(self, frm, server, port, username, password): + def __init__(self, server, port, username, password): EmailProvider.__init__(self) assert server is not None and port is not None and username is not None and password is not None,\ log.error('server, port number, username or password is None') - self.frm = frm self.server = server self.port = port self.username = username @@ -68,8 +69,12 @@ def send_email(self, e): msg['Subject'] = e.subject msg.attach(MIMEText(e.body, 'html')) - if (e.attachment is not None): - for attachment in e.attachment: + common_attachments = [f for f in listdir(e.common_attachment_dir) if isfile(join(e.common_attachment_dir, f))] + + attachments = e.attachments + common_attachments + + if (attachments is not None): + for attachment in attachments: if not os.path.isfile(attachment): return [-1, 'Attachment not found'] try: diff --git a/backend/util/FileUtils.py b/backend/util/FileUtils.py index d6ce0ef..a1a209e 100644 --- a/backend/util/FileUtils.py +++ b/backend/util/FileUtils.py @@ -109,9 +109,11 @@ def find_n_files_by_fuzzymatch(self, directory, fuzzystring, filetype = 'pdf', n for filename in os.listdir(directory): if filename.endswith(filetype): - for phrase in ignore_phrases: - filename_tmp = filename.lower().replace(phrase.lower(), '') - ratio = fuzz.ratio(filename_tmp.lower(), fuzzystring.lower()) + filename_tmp = filename.lower() + if ignore_phrases: + for phrase in ignore_phrases: + filename_tmp = filename_tmp.replace(phrase.lower(), '') + ratio = fuzz.ratio(filename_tmp, fuzzystring.lower()) candidates[filename] = ratio sorted_candidates = sorted(candidates.items(), key=operator.itemgetter(1), reverse=True) return [i[0] for i in sorted_candidates][:n] @@ -136,7 +138,7 @@ def template_to_str(self, st, l): # Iterate over each index and replace '#i' with l[i] in the input string for i in range(len(index)): - st = st.replace(substitute[i], l[index[i] - 1]) + st = st.replace(substitute[i], l[index[i]]) log.debug('template_to_str() final str = %s' % st) return st diff --git a/backend/webserver/wittymail_server/ColumnMapping.py b/backend/webserver/wittymail_server/ColumnMapping.py index 2f4b761..145983d 100644 --- a/backend/webserver/wittymail_server/ColumnMapping.py +++ b/backend/webserver/wittymail_server/ColumnMapping.py @@ -1,3 +1,4 @@ +import pdb class ColumnMapping: def __init__(self): self.mapping = {} @@ -8,9 +9,18 @@ def set_column_delta(self, column_delta): def set_column_mappings(self, map_info): self.mapping = map_info - self.mapping['status'] = self.column_delta + 1 - self.mapping['frozen_attachments'] = self.column_delta + 2 - self.mapping['index'] = self.column_delta + 3 + self.mapping['status'] = self.column_delta + self.mapping['frozen_attachments'] = self.column_delta + 1 + self.mapping['index'] = self.column_delta + 2 + + def get_index_from_row(self, row): + return row['index'] + + def set_default_values(self, data): + for i in range(0, len(data)): + data[i].extend([None, None]) + data[i].append(i) + return data def set_column_mapping(self, map_info): self.mapping.append(map_info) @@ -18,5 +28,8 @@ def set_column_mapping(self, map_info): def get_column_mappings(self, column_names): column_maps = [] for c in column_names: - column_maps.append(self.mapping[c]) + if c in self.mapping.keys(): + column_maps.append(self.mapping[c]) + else: + column_maps.append(None) return tuple(column_maps) \ No newline at end of file diff --git a/backend/webserver/wittymail_server/Sheet.py b/backend/webserver/wittymail_server/Sheet.py index 52e0dae..bf7cdb9 100644 --- a/backend/webserver/wittymail_server/Sheet.py +++ b/backend/webserver/wittymail_server/Sheet.py @@ -1,6 +1,6 @@ from util.FileUtils import FileUtils from wittymail_server.ColumnMapping import ColumnMapping - +import pdb class Sheet: __instance = None filepath = None @@ -34,18 +34,25 @@ def get_column_mappings(self, column_names): return self.c.get_column_mappings(column_names) def get_column_value(self, row, column_name): - return row[self.c.get_column_mappings(column_name)] + index = self.c.get_column_mappings(column_name) + return row[index[0]] + def get_header_index_from_name(self, header_name): + return self.headers.index(header_name) def set_attachment(self, attachment_name): frozen_attachments = self.c.get_column_mappings(["frozen_attachments"]) self.data[frozen_attachments] = attachment_name + def set_extended_dafault_data(self): + self.data = self.c.set_default_values(self.data) + def dump_to_memory(self): f = FileUtils() self.headers, self.data = f.read_excel_to_memory(self.filepath) data_width = len(self.data[0]) self.c.set_column_delta(data_width) + self.set_extended_dafault_data() def save_to_file(self): f = FileUtils() @@ -63,9 +70,19 @@ def get_all_content(self): def get_extended_headers(self): return self.extended_headers - def template_to_str(self, st, l): + def template_to_str(self, st, list_ = None): f = FileUtils() - return f.template_to_str(st, l) + if list_ == None: + list_ = self.data[0] + return f.template_to_str(st, list_) def set_column_mappings(self, map_info): - self.c.set_column_mappings(map_info) \ No newline at end of file + for key in map_info: + map_info[key] = self.headers.index(map_info[key]) + self.c.set_column_mappings(map_info) + + def set_column_value(self, row, column, value): + index = self.c.get_index_from_row(row) + column = self.c.get_column_mappings([column]) + + self.data[index][column[0]] = value \ No newline at end of file diff --git a/backend/webserver/wittymail_server/default_routes.py b/backend/webserver/wittymail_server/default_routes.py index 194a930..8f55387 100644 --- a/backend/webserver/wittymail_server/default_routes.py +++ b/backend/webserver/wittymail_server/default_routes.py @@ -3,7 +3,7 @@ import os, sys sys.path.append(os.path.abspath(os.path.join(os.curdir, '..', '..'))) - +import pdb from wittymail_server import flask_app from flask import send_file, send_from_directory @@ -34,4 +34,4 @@ def route_attachment_files(path): @flask_app.route('/sheet/') def route_fodder_file(path): - return send_from_directory(flask_app.config['EXCEL_DIR'], path) \ No newline at end of file + return send_from_directory(flask_app.config['EXCEL_DIR'], path) diff --git a/backend/webserver/wittymail_server/rest_api.py b/backend/webserver/wittymail_server/rest_api.py index 669a093..cd1f457 100644 --- a/backend/webserver/wittymail_server/rest_api.py +++ b/backend/webserver/wittymail_server/rest_api.py @@ -2,9 +2,12 @@ # coding=utf-8 import os, sys +import re +import pdb sys.path.append(os.path.abspath(os.path.join(os.curdir, '..', '..'))) +from flask import send_from_directory from wittymail_server import flask_app from flask import jsonify, request, json, url_for from flask_classy import FlaskView, route @@ -73,30 +76,34 @@ def contents(self): :return: """ - log.info("URL: %s", url_for('SheetView:some')) sheet = Sheet.getInstance() headers, data = sheet.get_all_content() - frozen_attachment_index, email_to_index, email_cc_index, email_subject_index, email_body_index = sheet.get_column_mappings(["frozen_attachment", "email_to", "email_cc", "email_subject", "email_body"]) + index, frozen_attachments_index, email_to_index, email_cc_index, email_subject_index, email_body_index = sheet.get_column_mappings(["index", "frozen_attachments", "to_column", "cc_column", "email_subject", "email_body"]) - # Create fodder_list in email_broker output_list = [] for d in data: attachments = [] - for attachment in d[frozen_attachment_index]: - at_dict = {"name": attachment, "url": os.path.join("/attachment/", attachment)} + if frozen_attachments_index and d[frozen_attachments_index]: + at_dict = {"name": d[frozen_attachments_index], "url": os.path.join("/attachment/file/", d[frozen_attachments_index])} attachments.append(at_dict) - email = { \ - "from": Email.get_email_from(), - "to": d[email_to_index], - "cc": d[email_cc_index], - "attachment": attachments, - "subject": d[email_subject_index], - "body": d[email_body_index], - } + + email = {} + email["from"] = Email.frm + if email_to_index: + email["to"] = d[email_to_index] + if email_cc_index: + email["cc"] = d[email_cc_index] + if len(attachments) != 0: + email["attachment"] = attachments + if email_subject_index: + email["subject"] = d[email_subject_index] + if email_body_index: + email["body"] = d[email_body_index] tmp = dict(zip(headers, d)) tmp["email"] = email + tmp["index"] = d[index] output_list.append(tmp) return (jsonify({'headers': headers, 'contents': output_list}), @@ -122,6 +129,7 @@ def mapping(self): :return: """ + request.data data = json.loads(request.data) sheet = Sheet.getInstance() sheet.set_column_mappings(data) @@ -130,24 +138,51 @@ def mapping(self): HTTP_OK, {'ContentType': 'application/json'}) + @route('metadata_contents', methods=['POST']) + def metadata_contents(self): + """ + Specify email metadata (to, cc etc.) and content templates (subject, body) + + :return: + """ + data = json.loads(request.data) + + sheet = Sheet.getInstance() + sheet.set_column_mappings(data) + return (jsonify({}), + HTTP_OK, + {'ContentType': 'application/json'}) + class AttachmentView(FlaskView): """ APIs for attachments to be used with the Sheet (by mapping) and sent with emails """ route_prefix = flask_app.config['URL_DEFAULT_PREFIX_FOR_API'] - @route('get_candidates', methods=['GET']) + @route('candidate', methods=['GET']) def get_candidates(self): - data = json.loads(request.data) - row = data['row'] + row = request.args.get("selected_row") + + row = ['1', 'Aradhya Karche', 'Nursery- kalewadi', 'Kalubai pratishthan', 'Sanjaysandhu8090@gmail.com', 'Ravi', 'amboreravi@gmail.com', '9822809079'] sheet = Sheet.getInstance() - attachment_value = sheet.get_column_value(row, ['attachment']) - candidates = FileUtils.find_n_files_by_fuzzymatch(flask_app.config['ATTACHMENTS_DIR'], attachment_value) - candidate_list = [{'pdfname': c} for c in candidates] - return (jsonify({'candidates': candidate_list}), + attachment_value = sheet.get_column_value(row, ['attachment_column']) + f = FileUtils() + candidates = f.find_n_files_by_fuzzymatch(flask_app.config['ATTACHMENTS_DIR'], attachment_value) + + return (jsonify({'pdfNames': candidates, 'subject': attachment_value}), HTTP_OK, {'ContentType': 'application/json'}) - + + @route('candidate/select', methods=['POST']) + def select_candidate(self): + data = json.loads(request.data) + + row = data['selected_row'] + selected_candidate = data['pdfName'] + + sheet = Sheet.getInstance() + sheet.set_column_value(row, 'frozen_attachments', selected_candidate) + return (jsonify({}), HTTP_OK, {'ContentType': 'application/json'}) @route('upload', methods=['POST']) def upload_attachment(self): @@ -165,10 +200,6 @@ def upload_attachment(self): a.save(attachment_save_path) log.info('Attachment file saved at: %s', attachment_save_path) - #emailapi_broker.save_attachment_dir(attachment_dir) - # TODO Call change_email_fodder_status() from save_attachment_dir() - #emailapi_broker.change_email_fodder_status(a.filename) - elif 'common_attachment' in request.files: a = request.files['common_attachment'] attachment_save_path = os.path.join(flask_app.config['COMMON_ATTACHMENTS_DIR'], a.filename) @@ -204,7 +235,8 @@ def upload_attachment_for_row(self): @route('rotate', methods=['POST']) def rotate(self): data = json.loads(request.data) - filepath = os.path.join(flask_app.config['ATTACHMENTS_DIR'], data['filename']) + filename = 'PICT-3.pdf' #data['filename'] + filepath = os.path.join(flask_app.config['ATTACHMENTS_DIR'], filename) try: util = FileUtils() @@ -220,6 +252,7 @@ class EmailView(FlaskView): APIs for email server, contents and actions """ route_prefix = flask_app.config['URL_DEFAULT_PREFIX_FOR_API'] + email_provider_type = None @route('server', methods=['POST']) def server_details(self): @@ -232,53 +265,14 @@ def server_details(self): assert len(data['username']) > 0 and len(data['password']) > 0, "username or password not provided" - smtp_provider_class = email_provider.choose_email_provider("SMTP") - self.smtp_provider = smtp_provider_class(data['username'], "smtp.gmail.com", 587, data['username'], data['password']) + email_provider = EmailProvider() + email_provider_type_class = email_provider.choose_email_provider("SMTP") + self.email_provider_type = email_provider_type_class("smtp.gmail.com", 587, data['username'], data['password']) return (jsonify({'error_message': ""}), HTTP_OK, {'ContentType': 'application/json'}) - @route('template_to_reality', methods=['POST']) - def template_to_reality(self): - """ - Convert an email template (subject or body) by replacing column name placeholders with actual data - - :return: - """ - data = json.loads(request.data) - fodder = emailapi_broker.get_email_fodder() - result_str = emailapi_broker.template_to_str(data['template'], fodder[0]) - - return (jsonify({'reality': result_str}), - HTTP_OK, - {'ContentType': 'application/json'}) - - @route('metadata_contents', methods=['POST']) - def metadata_contents(self): - """ - Specify email metadata (to, cc etc.) and content templates (subject, body) - - :return: - """ - data = json.loads(request.data) - if data['to_column'] == None or data['cc_column'] == None or data['subject_template'] == None or data[ - 'body_template'] == None: - return (jsonify({'error_message': "to, cc, subject or body not provided"}), - HTTP_BAD_INPUT, - {'ContentType': 'application/json'}) - - e = emailapi_broker.save_extended_fodder(data['to_column'], data['cc_column'], data['subject_template'], - data['body_template']) - if e[0] is not 0: - return (jsonify({"err_msg": e[1]}), - HTTP_BAD_INPUT, - {'ContentType': 'application/json'}) - - return (jsonify({}), - HTTP_OK, - {'ContentType': 'application/json'}) - @route('send_test', methods=['POST']) def send_test(self): """ @@ -286,21 +280,7 @@ def send_test(self): :return: """ - try: - data = json.loads(request.data) - tos = [] - tos.append(data['to']) - e = emailapi_broker.test_email(tos) - if e[0] is not 0: - return (jsonify({"err_msg": e[1]}), - HTTP_BAD_INPUT, - {'ContentType': 'application/json'}) - - return (jsonify({}), - HTTP_OK, - {'ContentType': 'application/json'}) - except: - log.exception("Failed to send test email") + pass @route('send', methods=['POST']) def send(self): @@ -323,9 +303,11 @@ def send(self): for a in at: attachments.append(a["name"]) - e = emailapi_broker.send_email(data['from'], tos, data['subject'], data['body'], ccs, attachments) - if e[0] is not 0: - return (jsonify({"err_msg": e[1]}), + e = Email(tos, ccs, attachments, data['subject'], data['body'], flask_app.config['COMMON_ATTACHMENTS_DIR']) + self.email_provider_type() + err = email_provider_type.send_email(e) + if err[0] != 0: + return (jsonify({"err_msg": err[1]}), HTTP_BAD_INPUT, {'ContentType': 'application/json'}) @@ -335,6 +317,28 @@ def send(self): except: log.exception("Failed to send email") + @route('template_to_reality', methods=['POST']) + def template_to_reality(self): + """ + Convert an email template (subject or body) by replacing column name placeholders with actual data + + :return: + """ + template = json.loads(request.data)['template'] + header_names = re.findall("{.*?}", template) + + sheet = Sheet.getInstance() + for header_name in header_names: + header_name = header_name[1:-1] + header_index = sheet.get_header_index_from_name(header_name) + template = template.replace('{' + header_name + '}', '#' + str(header_index)) + + result_str = sheet.template_to_str(template) + + return (jsonify({'reality': result_str}), + HTTP_OK, + {'ContentType': 'application/json'}) + SheetView.register(flask_app) AttachmentView.register(flask_app) From 5f23abaec98df51d5d7c0ea703250761b0043091 Mon Sep 17 00:00:00 2001 From: Ajay Nair Date: Sat, 4 May 2019 12:44:53 +0530 Subject: [PATCH 44/64] Added code to support subject and body template --- backend/mailer/Email.py | 3 ++ backend/webserver/wittymail_server/Sheet.py | 13 +++++++++ .../webserver/wittymail_server/rest_api.py | 29 +++++++++---------- 3 files changed, 30 insertions(+), 15 deletions(-) diff --git a/backend/mailer/Email.py b/backend/mailer/Email.py index 03cd1dc..a4c42fb 100644 --- a/backend/mailer/Email.py +++ b/backend/mailer/Email.py @@ -29,6 +29,9 @@ def __init__(self, tos, ccs, attachments, subject, body, status = None): def get_email_from(self): return Email.frm + def set_email_frm(self, frm): + Email.frm = frm + def set_email_common_attachment_dir(self, attachment_dir): Email.common_attachment_dir = attachment_dir diff --git a/backend/webserver/wittymail_server/Sheet.py b/backend/webserver/wittymail_server/Sheet.py index bf7cdb9..ec5a26e 100644 --- a/backend/webserver/wittymail_server/Sheet.py +++ b/backend/webserver/wittymail_server/Sheet.py @@ -1,6 +1,8 @@ from util.FileUtils import FileUtils from wittymail_server.ColumnMapping import ColumnMapping import pdb +import re + class Sheet: __instance = None filepath = None @@ -70,6 +72,17 @@ def get_all_content(self): def get_extended_headers(self): return self.extended_headers + def _template_to_str(self, template, list_ = None): + header_names = re.findall("{.*?}", template) + + # TODO Modify template_to_str to support header name instead of header_index + for header_name in header_names: + header_name = header_name[1:-1] + header_index = self.get_header_index_from_name(header_name) + template = template.replace('{' + header_name + '}', '#' + str(header_index)) + + return self.template_to_str(template, list_) + def template_to_str(self, st, list_ = None): f = FileUtils() if list_ == None: diff --git a/backend/webserver/wittymail_server/rest_api.py b/backend/webserver/wittymail_server/rest_api.py index cd1f457..b9372e4 100644 --- a/backend/webserver/wittymail_server/rest_api.py +++ b/backend/webserver/wittymail_server/rest_api.py @@ -79,7 +79,7 @@ def contents(self): sheet = Sheet.getInstance() headers, data = sheet.get_all_content() - index, frozen_attachments_index, email_to_index, email_cc_index, email_subject_index, email_body_index = sheet.get_column_mappings(["index", "frozen_attachments", "to_column", "cc_column", "email_subject", "email_body"]) + index, frozen_attachments_index, email_to_index, email_cc_index = sheet.get_column_mappings(["index", "frozen_attachments", "to_column", "cc_column"]) output_list = [] for d in data: @@ -96,10 +96,12 @@ def contents(self): email["cc"] = d[email_cc_index] if len(attachments) != 0: email["attachment"] = attachments - if email_subject_index: - email["subject"] = d[email_subject_index] - if email_body_index: - email["body"] = d[email_body_index] + if Email.subject_template: + sheet = Sheet.getInstance() + email["subject"] = sheet._template_to_str(Email.subject_template, d) + if Email.body_template: + sheet = Sheet.getInstance() + email["body"] = sheet._template_to_str(Email.subject_template, d) tmp = dict(zip(headers, d)) tmp["email"] = email @@ -141,14 +143,15 @@ def mapping(self): @route('metadata_contents', methods=['POST']) def metadata_contents(self): """ - Specify email metadata (to, cc etc.) and content templates (subject, body) + Specify email metadata content templates (subject, body) :return: """ data = json.loads(request.data) - sheet = Sheet.getInstance() - sheet.set_column_mappings(data) + Email.subject_template = data['subject_template'] + Email.body_template = data['body_template'] + return (jsonify({}), HTTP_OK, {'ContentType': 'application/json'}) @@ -265,6 +268,8 @@ def server_details(self): assert len(data['username']) > 0 and len(data['password']) > 0, "username or password not provided" + Email.frm = data['username'] + email_provider = EmailProvider() email_provider_type_class = email_provider.choose_email_provider("SMTP") self.email_provider_type = email_provider_type_class("smtp.gmail.com", 587, data['username'], data['password']) @@ -325,15 +330,9 @@ def template_to_reality(self): :return: """ template = json.loads(request.data)['template'] - header_names = re.findall("{.*?}", template) sheet = Sheet.getInstance() - for header_name in header_names: - header_name = header_name[1:-1] - header_index = sheet.get_header_index_from_name(header_name) - template = template.replace('{' + header_name + '}', '#' + str(header_index)) - - result_str = sheet.template_to_str(template) + result_str = sheet._template_to_str(template) return (jsonify({'reality': result_str}), HTTP_OK, From b90208b211075bf14a38a6229b84dbd0da374299 Mon Sep 17 00:00:00 2001 From: Ajay Nair Date: Sat, 4 May 2019 16:30:01 +0530 Subject: [PATCH 45/64] Added support to send test emails --- .../webserver/wittymail_server/rest_api.py | 29 ++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/backend/webserver/wittymail_server/rest_api.py b/backend/webserver/wittymail_server/rest_api.py index b9372e4..18d7551 100644 --- a/backend/webserver/wittymail_server/rest_api.py +++ b/backend/webserver/wittymail_server/rest_api.py @@ -285,7 +285,34 @@ def send_test(self): :return: """ - pass + try: + data = json.loads(request.data) + + tos = [] + tos.append(Email.frm) + + ccs = [] + ccs.append(Email.frm) + + attachments = [] + at = data['attachment'] + for a in at: + attachments.append(a["name"]) + + e = Email(tos, ccs, attachments, data['subject'], data['body'], flask_app.config['COMMON_ATTACHMENTS_DIR']) + self.email_provider_type() + err = email_provider_type.send_email(e) + if err[0] != 0: + return (jsonify({"err_msg": err[1]}), + HTTP_BAD_INPUT, + {'ContentType': 'application/json'}) + + return (jsonify({}), + HTTP_OK, + {'ContentType': 'application/json'}) + except: + log.exception("Failed to send email") + @route('send', methods=['POST']) def send(self): From 8eeb2adf9d7103b82bb4c7024bad2ee46747a1ba Mon Sep 17 00:00:00 2001 From: Omkar Ekbote Date: Sat, 4 May 2019 22:50:48 +0530 Subject: [PATCH 46/64] Fix payload in REST API calls --- backend/webserver/wittymail_server/rest_api.py | 16 +++++++++++----- .../src/app/attachments/attachments.component.ts | 14 +++++++++----- frontend/wittymail-v2/src/app/backend.service.ts | 3 ++- 3 files changed, 22 insertions(+), 11 deletions(-) diff --git a/backend/webserver/wittymail_server/rest_api.py b/backend/webserver/wittymail_server/rest_api.py index 18d7551..2c1e032 100644 --- a/backend/webserver/wittymail_server/rest_api.py +++ b/backend/webserver/wittymail_server/rest_api.py @@ -162,13 +162,19 @@ class AttachmentView(FlaskView): """ route_prefix = flask_app.config['URL_DEFAULT_PREFIX_FOR_API'] - @route('candidate', methods=['GET']) - def get_candidates(self): + def candidate(self): row = request.args.get("selected_row") - - row = ['1', 'Aradhya Karche', 'Nursery- kalewadi', 'Kalubai pratishthan', 'Sanjaysandhu8090@gmail.com', 'Ravi', 'amboreravi@gmail.com', '9822809079'] + row = json.loads(row) + log.info("Find attachment candidate for row: %s", row) + # row = ['1', 'Aradhya Karche', 'Nursery- kalewadi', 'Kalubai pratishthan', 'Sanjaysandhu8090@gmail.com', 'Ravi', 'amboreravi@gmail.com', '9822809079'] sheet = Sheet.getInstance() + + return (jsonify({'pdfNames': ['Aradhya Karche.pdf'], 'subject': 'Aradhya Karche'}), + HTTP_OK, + {'ContentType': 'application/json'}) + attachment_value = sheet.get_column_value(row, ['attachment_column']) + log.info("Find attachment candidate for: %s", attachment_value) f = FileUtils() candidates = f.find_n_files_by_fuzzymatch(flask_app.config['ATTACHMENTS_DIR'], attachment_value) @@ -238,7 +244,7 @@ def upload_attachment_for_row(self): @route('rotate', methods=['POST']) def rotate(self): data = json.loads(request.data) - filename = 'PICT-3.pdf' #data['filename'] + filename = data['filename'] filepath = os.path.join(flask_app.config['ATTACHMENTS_DIR'], filename) try: diff --git a/frontend/wittymail-v2/src/app/attachments/attachments.component.ts b/frontend/wittymail-v2/src/app/attachments/attachments.component.ts index 25f7662..175ae40 100644 --- a/frontend/wittymail-v2/src/app/attachments/attachments.component.ts +++ b/frontend/wittymail-v2/src/app/attachments/attachments.component.ts @@ -4,7 +4,7 @@ import { SafeHtml, DomSanitizer } from '@angular/platform-browser'; import { LoggerService } from '../util/logger.service'; import { MatStepper } from '@angular/material'; import { FileUploader } from 'ng2-file-upload'; -import { BackendService, AttachmentRotation, ColumnHeadersWithRowContent, CandidateAttachmentSelection, CandidateAttachments } from '../backend.service'; +import { BackendService, AttachmentRotation, ColumnHeadersWithRowContent, CandidateAttachmentSelection, CandidateAttachments, CandidateAttachmentsInput } from '../backend.service'; import { ErrorDialogComponent } from '../common/error-dialog/error-dialog.component'; @Component({ @@ -101,7 +101,11 @@ export class AttachmentsComponent implements OnInit { this.log.info(row) this.selectedRow = row; - this.backend.getCandidateAttachments(row).subscribe( + let payload: CandidateAttachmentsInput = { + selected_row: JSON.stringify(row) + } + + this.backend.getCandidateAttachments(payload).subscribe( data => { this.log.info("Got attachment candidates: ", data); let d: CandidateAttachments = data; @@ -149,14 +153,14 @@ export class AttachmentsComponent implements OnInit { } onSelectCandidatePDF(candidate) { - this.log.info("Showing PDF for: ", candidate.pdfName); + this.log.info("Showing PDF for: ", candidate); this.selectedPDF = candidate; - this._setPDFViewerHTML(this.backend.urls.attachment.get_file + candidate.pdfName); + this._setPDFViewerHTML(this.backend.urls.attachment.get_file + candidate); } onClickRotate(direction: string) { let rotation: AttachmentRotation = { - filename: this.selectedPDF.pdfName, + filename: this.selectedPDF, direction: direction }; diff --git a/frontend/wittymail-v2/src/app/backend.service.ts b/frontend/wittymail-v2/src/app/backend.service.ts index 6b0a372..b296d23 100644 --- a/frontend/wittymail-v2/src/app/backend.service.ts +++ b/frontend/wittymail-v2/src/app/backend.service.ts @@ -229,7 +229,8 @@ export class BackendService { } getCandidateAttachments(selected_row: CandidateAttachmentsInput): Observable { - return this.http.get(this.urls.attachment.candidate) + return this.http.get(this.urls.attachment.candidate, + {params: {'selected_row': selected_row.selected_row}}) .pipe( catchError(this.handleError('getCandidateAttachments')) ); From f2d9ca714daadd017c885dc365513b53d9eb627c Mon Sep 17 00:00:00 2001 From: Ajay Nair Date: Sat, 4 May 2019 23:31:42 +0530 Subject: [PATCH 47/64] Modified ColumnMappings to map column_names to header index and header name --- .../wittymail_server/ColumnMapping.py | 19 +++++++++++++----- backend/webserver/wittymail_server/Sheet.py | 20 ++++++++++--------- .../webserver/wittymail_server/rest_api.py | 6 +----- 3 files changed, 26 insertions(+), 19 deletions(-) diff --git a/backend/webserver/wittymail_server/ColumnMapping.py b/backend/webserver/wittymail_server/ColumnMapping.py index 145983d..8480a2f 100644 --- a/backend/webserver/wittymail_server/ColumnMapping.py +++ b/backend/webserver/wittymail_server/ColumnMapping.py @@ -9,9 +9,9 @@ def set_column_delta(self, column_delta): def set_column_mappings(self, map_info): self.mapping = map_info - self.mapping['status'] = self.column_delta - self.mapping['frozen_attachments'] = self.column_delta + 1 - self.mapping['index'] = self.column_delta + 2 + self.mapping['status'] = ['status', self.column_delta] + self.mapping['frozen_attachments'] = ['frozen_attachments', self.column_delta + 1] + self.mapping['index'] = ['index', self.column_delta + 2] def get_index_from_row(self, row): return row['index'] @@ -25,11 +25,20 @@ def set_default_values(self, data): def set_column_mapping(self, map_info): self.mapping.append(map_info) - def get_column_mappings(self, column_names): + def get_column_mappings_index(self, column_names): column_maps = [] for c in column_names: if c in self.mapping.keys(): - column_maps.append(self.mapping[c]) + column_maps.append(self.mapping[c][1]) + else: + column_maps.append(None) + return tuple(column_maps) + + def get_column_mappings_name(self, column_names): + column_maps = [] + for c in column_names: + if c in self.mapping.keys(): + column_maps.append(self.mapping[c][0]) else: column_maps.append(None) return tuple(column_maps) \ No newline at end of file diff --git a/backend/webserver/wittymail_server/Sheet.py b/backend/webserver/wittymail_server/Sheet.py index ec5a26e..8868c91 100644 --- a/backend/webserver/wittymail_server/Sheet.py +++ b/backend/webserver/wittymail_server/Sheet.py @@ -32,19 +32,22 @@ def __del__(self): Sheet.filepath = None Sheet.__instance = None - def get_column_mappings(self, column_names): - return self.c.get_column_mappings(column_names) + def get_column_mappings_index(self, column_names): + return self.c.get_column_mappings_index(column_names) + def get_column_mappings_name(self, column_names): + return self.c.get_column_mappings_name(column_names) + def get_column_value(self, row, column_name): - index = self.c.get_column_mappings(column_name) + index = self.c.get_column_mappings_name(column_name) return row[index[0]] def get_header_index_from_name(self, header_name): return self.headers.index(header_name) def set_attachment(self, attachment_name): - frozen_attachments = self.c.get_column_mappings(["frozen_attachments"]) - self.data[frozen_attachments] = attachment_name + attachment_index = self.c.get_column_mappings_index(["frozen_attachments"]) + self.data[attachment_index] = attachment_name def set_extended_dafault_data(self): self.data = self.c.set_default_values(self.data) @@ -91,11 +94,10 @@ def template_to_str(self, st, list_ = None): def set_column_mappings(self, map_info): for key in map_info: - map_info[key] = self.headers.index(map_info[key]) + map_info[key] = [map_info[key], self.headers.index(map_info[key])] self.c.set_column_mappings(map_info) def set_column_value(self, row, column, value): index = self.c.get_index_from_row(row) - column = self.c.get_column_mappings([column]) - - self.data[index][column[0]] = value \ No newline at end of file + column_index = self.c.get_column_mappings_index([column]) + self.data[index][column_index[0]] = value \ No newline at end of file diff --git a/backend/webserver/wittymail_server/rest_api.py b/backend/webserver/wittymail_server/rest_api.py index 2c1e032..db21566 100644 --- a/backend/webserver/wittymail_server/rest_api.py +++ b/backend/webserver/wittymail_server/rest_api.py @@ -79,7 +79,7 @@ def contents(self): sheet = Sheet.getInstance() headers, data = sheet.get_all_content() - index, frozen_attachments_index, email_to_index, email_cc_index = sheet.get_column_mappings(["index", "frozen_attachments", "to_column", "cc_column"]) + index, frozen_attachments_index, email_to_index, email_cc_index = sheet.get_column_mappings_index(["index", "frozen_attachments", "to_column", "cc_column"]) output_list = [] for d in data: @@ -169,10 +169,6 @@ def candidate(self): # row = ['1', 'Aradhya Karche', 'Nursery- kalewadi', 'Kalubai pratishthan', 'Sanjaysandhu8090@gmail.com', 'Ravi', 'amboreravi@gmail.com', '9822809079'] sheet = Sheet.getInstance() - return (jsonify({'pdfNames': ['Aradhya Karche.pdf'], 'subject': 'Aradhya Karche'}), - HTTP_OK, - {'ContentType': 'application/json'}) - attachment_value = sheet.get_column_value(row, ['attachment_column']) log.info("Find attachment candidate for: %s", attachment_value) f = FileUtils() From dde020a1facdde30d495cf62f160e7f560a917e8 Mon Sep 17 00:00:00 2001 From: Ajay Nair Date: Sat, 4 May 2019 23:58:51 +0530 Subject: [PATCH 48/64] Added support for subject and body template --- backend/webserver/wittymail_server/rest_api.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/backend/webserver/wittymail_server/rest_api.py b/backend/webserver/wittymail_server/rest_api.py index db21566..d43b0b6 100644 --- a/backend/webserver/wittymail_server/rest_api.py +++ b/backend/webserver/wittymail_server/rest_api.py @@ -101,7 +101,7 @@ def contents(self): email["subject"] = sheet._template_to_str(Email.subject_template, d) if Email.body_template: sheet = Sheet.getInstance() - email["body"] = sheet._template_to_str(Email.subject_template, d) + email["body"] = sheet._template_to_str(Email.body_template, d) tmp = dict(zip(headers, d)) tmp["email"] = email @@ -275,7 +275,8 @@ def server_details(self): email_provider = EmailProvider() email_provider_type_class = email_provider.choose_email_provider("SMTP") self.email_provider_type = email_provider_type_class("smtp.gmail.com", 587, data['username'], data['password']) - + self.email_provider_type.login() + return (jsonify({'error_message': ""}), HTTP_OK, {'ContentType': 'application/json'}) From 6c2beafe36cad92cd16644124b9078b798eb6e1d Mon Sep 17 00:00:00 2001 From: Omkar Ekbote Date: Sun, 5 May 2019 08:11:25 +0530 Subject: [PATCH 49/64] Added button to post email subject/body templates to backend --- .../webserver/wittymail_server/rest_api.py | 32 +++++++++---------- .../wittymail-v2/src/app/backend.service.ts | 14 ++------ .../email-design/email-design.component.css | 3 ++ .../email-design/email-design.component.html | 3 ++ .../email-design/email-design.component.ts | 21 ++++++++++-- .../sponsor-list/sponsor-list.component.ts | 1 - 6 files changed, 43 insertions(+), 31 deletions(-) diff --git a/backend/webserver/wittymail_server/rest_api.py b/backend/webserver/wittymail_server/rest_api.py index d43b0b6..a3cebe6 100644 --- a/backend/webserver/wittymail_server/rest_api.py +++ b/backend/webserver/wittymail_server/rest_api.py @@ -140,22 +140,6 @@ def mapping(self): HTTP_OK, {'ContentType': 'application/json'}) - @route('metadata_contents', methods=['POST']) - def metadata_contents(self): - """ - Specify email metadata content templates (subject, body) - - :return: - """ - data = json.loads(request.data) - - Email.subject_template = data['subject_template'] - Email.body_template = data['body_template'] - - return (jsonify({}), - HTTP_OK, - {'ContentType': 'application/json'}) - class AttachmentView(FlaskView): """ APIs for attachments to be used with the Sheet (by mapping) and sent with emails @@ -259,6 +243,22 @@ class EmailView(FlaskView): route_prefix = flask_app.config['URL_DEFAULT_PREFIX_FOR_API'] email_provider_type = None + @route('metadata_contents', methods=['POST']) + def metadata_contents(self): + """ + Specify email metadata content templates (subject, body) + + :return: + """ + data = json.loads(request.data) + log.info("Got email metadata: %s", data) + Email.subject_template = data['subject_template'] + Email.body_template = data['body_template'] + + return (jsonify({}), + HTTP_OK, + {'ContentType': 'application/json'}) + @route('server', methods=['POST']) def server_details(self): """ diff --git a/frontend/wittymail-v2/src/app/backend.service.ts b/frontend/wittymail-v2/src/app/backend.service.ts index b296d23..c1998d7 100644 --- a/frontend/wittymail-v2/src/app/backend.service.ts +++ b/frontend/wittymail-v2/src/app/backend.service.ts @@ -22,8 +22,6 @@ export interface ColumnMappings { } export interface EmailMetadata { - to_column: string; - cc_column: string; subject_template: string; body_template: string; } @@ -201,13 +199,6 @@ export class BackendService { ); } - saveEmailToCCColumns(to_column: string, cc_column: string) { - this.emailMetadataInstance.to_column = to_column; - this.emailMetadataInstance.cc_column = cc_column; - - this.log.info("emailMetadataInstance: ", this.emailMetadataInstance); - } - saveEmailSubjectBodyTemplate(subject_template: string, body_template: string) { this.emailMetadataInstance.subject_template = subject_template; this.emailMetadataInstance.body_template = body_template; @@ -251,9 +242,8 @@ export class BackendService { ); } - postEmailMetadata(): Observable { - this.log.info("POSTing email metadata: ", this.emailMetadataInstance); - return this.http.post(this.urls.email.set_metadata_and_contents, this.emailMetadataInstance) + postEmailMetadata(templates: EmailMetadata): Observable { + return this.http.post(this.urls.email.set_metadata_and_contents, templates) .pipe( catchError(this.handleError('postEmailMetadata')) ); diff --git a/frontend/wittymail-v2/src/app/email-design/email-design.component.css b/frontend/wittymail-v2/src/app/email-design/email-design.component.css index 2a24aa2..740015a 100644 --- a/frontend/wittymail-v2/src/app/email-design/email-design.component.css +++ b/frontend/wittymail-v2/src/app/email-design/email-design.component.css @@ -11,6 +11,9 @@ border-color: grey; border-style: solid; padding: 0.5rem; + height: 100%; + overflow: auto; + } .email-settings-input-field { diff --git a/frontend/wittymail-v2/src/app/email-design/email-design.component.html b/frontend/wittymail-v2/src/app/email-design/email-design.component.html index b302c76..429d6d3 100644 --- a/frontend/wittymail-v2/src/app/email-design/email-design.component.html +++ b/frontend/wittymail-v2/src/app/email-design/email-design.component.html @@ -35,6 +35,9 @@
+
+ + diff --git a/frontend/wittymail-v2/src/app/email-design/email-design.component.ts b/frontend/wittymail-v2/src/app/email-design/email-design.component.ts index d7f069a..7f03b36 100644 --- a/frontend/wittymail-v2/src/app/email-design/email-design.component.ts +++ b/frontend/wittymail-v2/src/app/email-design/email-design.component.ts @@ -1,7 +1,7 @@ import { Component, OnInit, ViewChild, Input } from '@angular/core'; import { LoggerService } from '../util/logger.service'; import { MatInput, MatStepper } from '@angular/material'; -import { BackendService, ColumnHeadersWithRowContent, TemplateInput, TemplateOutput, EmailServerDetails } from '../backend.service'; +import { BackendService, ColumnHeadersWithRowContent, TemplateInput, TemplateOutput, EmailServerDetails, EmailMetadata } from '../backend.service'; import { ErrorDialogComponent } from '../common/error-dialog/error-dialog.component'; enum LastFocusedInput { @@ -130,10 +130,27 @@ export class EmailDesignComponent implements OnInit { ); } + onSubmitEmailTemplates() { + let payload: EmailMetadata = { + body_template: this.bodyTemplate, + subject_template: this.subjectTemplate + } + this.log.info("Posting email templates: ", payload); + this.backend.postEmailMetadata(payload).subscribe( + data => { + this.log.info("Email metadata posted, moving on..."); + this.stepper.next(); + }, + error => { + this.errorDialog.showError(error.error_message); + } + ); + } + onSubmitEmailServer() { this.backend.postEmailServerDetails(this.emailSettings).subscribe( data => { - this.log.info("Email server detailes posted, moving on..."); + this.log.info("Email server details posted, moving on..."); this.mainStepper.next(); }, error => { diff --git a/frontend/wittymail-v2/src/app/sponsor-list/sponsor-list.component.ts b/frontend/wittymail-v2/src/app/sponsor-list/sponsor-list.component.ts index cab0a88..4275024 100644 --- a/frontend/wittymail-v2/src/app/sponsor-list/sponsor-list.component.ts +++ b/frontend/wittymail-v2/src/app/sponsor-list/sponsor-list.component.ts @@ -123,7 +123,6 @@ export class SponsorListComponent implements OnInit { this.log.info("Selected columns: ", mapping); // TODO: Do we need this after refactoring? - this.backend.saveEmailToCCColumns(mapping.to_column, mapping.cc_column); this.backend.saveAttachmentMetadata(mapping.attachment_column); this.backend.postColumnMapping(mapping).subscribe( From f8703949b0d8d377673f67c8f0bdc059e8b72d88 Mon Sep 17 00:00:00 2001 From: Ajay Nair Date: Sun, 5 May 2019 17:52:11 +0530 Subject: [PATCH 50/64] Solved test email issues --- backend/mailer/SMTPEmailProvider.py | 28 ++++++++++------- .../webserver/wittymail_server/rest_api.py | 31 ++++++++++++------- 2 files changed, 37 insertions(+), 22 deletions(-) diff --git a/backend/mailer/SMTPEmailProvider.py b/backend/mailer/SMTPEmailProvider.py index 78e1578..6907227 100644 --- a/backend/mailer/SMTPEmailProvider.py +++ b/backend/mailer/SMTPEmailProvider.py @@ -11,6 +11,7 @@ from mailer.EmailProvider import EmailProvider from os import listdir from os.path import isfile +import pdb log = logger.get_logger(__name__) @@ -55,13 +56,13 @@ def send_email(self, e): log.debug("Cleaned body: %s", body) msg = MIMEMultipart() - msg['From'] = self.frm - msg['To'] = ", ".join(e.to) + msg['From'] = e.frm + msg['To'] = ", ".join(e.tos) ccs_to_send = [] - if e.cc is not None and e.cc[0] != 'None': - msg['Cc'] = ", ".join(e.cc) - for cc in e.cc: + if e.ccs is not None and e.ccs[0] != 'None': + msg['Cc'] = ", ".join(e.ccs) + for cc in e.ccs: ccs_to_send.append(cc.strip()) else: log.debug('No cc mailer provided') @@ -69,9 +70,13 @@ def send_email(self, e): msg['Subject'] = e.subject msg.attach(MIMEText(e.body, 'html')) - common_attachments = [f for f in listdir(e.common_attachment_dir) if isfile(join(e.common_attachment_dir, f))] - - attachments = e.attachments + common_attachments + common_attachments = listdir(e.common_attachment_dir) + common_attachments = [os.path.join(e.common_attachment_dir, ca) for ca in common_attachments] + + attachments_dir = os.path.dirname(e.common_attachment_dir) + attachments = [os.path.join(attachments_dir, a) for a in e.attachments] + + attachments = attachments + common_attachments if (attachments is not None): for attachment in attachments: @@ -91,10 +96,11 @@ def send_email(self, e): msg_str = msg.as_string() log.debug("ccs_to_send: %s", ccs_to_send) if ccs_to_send: - self.s.sendmail(msg['From'], e.to + ccs_to_send, msg_str) + self.s.sendmail(msg['From'], e.tos + ccs_to_send, msg_str) else: - self.s.sendmail(msg['From'], e.to, msg_str) + self.s.sendmail(msg['From'], e.tos, msg_str) log.info('Email sent by %s to %s' % (msg['From'], msg['To'])) return [0, 'Email sent successfully'] except: - log.exception("Failed to send test email") \ No newline at end of file + log.exception("Failed to send test email") + return [-1, 'Error'] \ No newline at end of file diff --git a/backend/webserver/wittymail_server/rest_api.py b/backend/webserver/wittymail_server/rest_api.py index a3cebe6..1f2bcef 100644 --- a/backend/webserver/wittymail_server/rest_api.py +++ b/backend/webserver/wittymail_server/rest_api.py @@ -156,7 +156,18 @@ def candidate(self): attachment_value = sheet.get_column_value(row, ['attachment_column']) log.info("Find attachment candidate for: %s", attachment_value) f = FileUtils() - candidates = f.find_n_files_by_fuzzymatch(flask_app.config['ATTACHMENTS_DIR'], attachment_value) + + phrases = [ + 'nursery', + 'kothrud', + 'balaji', + 'nagar', + 'junior', + 'kg', + 'jr', + 'kg', + ] + candidates = f.find_n_files_by_fuzzymatch(flask_app.config['ATTACHMENTS_DIR'], attachment_value, ignore_phrases = phrases) return (jsonify({'pdfNames': candidates, 'subject': attachment_value}), HTTP_OK, @@ -241,7 +252,7 @@ class EmailView(FlaskView): APIs for email server, contents and actions """ route_prefix = flask_app.config['URL_DEFAULT_PREFIX_FOR_API'] - email_provider_type = None + email_provider_type = None @route('metadata_contents', methods=['POST']) def metadata_contents(self): @@ -274,8 +285,8 @@ def server_details(self): email_provider = EmailProvider() email_provider_type_class = email_provider.choose_email_provider("SMTP") - self.email_provider_type = email_provider_type_class("smtp.gmail.com", 587, data['username'], data['password']) - self.email_provider_type.login() + EmailView.email_provider_type = email_provider_type_class("smtp.gmail.com", 587, data['username'], data['password']) + EmailView.email_provider_type.login() return (jsonify({'error_message': ""}), HTTP_OK, @@ -289,7 +300,7 @@ def send_test(self): :return: """ try: - data = json.loads(request.data) + data = json.loads(request.data)['email'] tos = [] tos.append(Email.frm) @@ -302,9 +313,9 @@ def send_test(self): for a in at: attachments.append(a["name"]) - e = Email(tos, ccs, attachments, data['subject'], data['body'], flask_app.config['COMMON_ATTACHMENTS_DIR']) - self.email_provider_type() - err = email_provider_type.send_email(e) + Email.common_attachment_dir = flask_app.config['COMMON_ATTACHMENTS_DIR'] + e = Email(tos, ccs, attachments, data['subject'], data['body']) + err = self.email_provider_type.send_email(e) if err[0] != 0: return (jsonify({"err_msg": err[1]}), HTTP_BAD_INPUT, @@ -316,7 +327,6 @@ def send_test(self): except: log.exception("Failed to send email") - @route('send', methods=['POST']) def send(self): """ @@ -339,8 +349,7 @@ def send(self): attachments.append(a["name"]) e = Email(tos, ccs, attachments, data['subject'], data['body'], flask_app.config['COMMON_ATTACHMENTS_DIR']) - self.email_provider_type() - err = email_provider_type.send_email(e) + err = self.email_provider_type.send_email(e) if err[0] != 0: return (jsonify({"err_msg": err[1]}), HTTP_BAD_INPUT, From 3acd6b561259eaf3d7206fac6affcb65402c7341 Mon Sep 17 00:00:00 2001 From: Omkar Ekbote Date: Fri, 10 May 2019 18:50:05 +0530 Subject: [PATCH 51/64] Create summary page --- frontend/wittymail-v2/src/app/app.module.ts | 5 +- .../app/attachments/attachments.component.ts | 2 +- .../steps-slider/steps-slider.component.html | 2 +- .../steps-slider/steps-slider.component.ts | 4 ++ .../src/app/summary/summary.component.css | 21 +++++++ .../src/app/summary/summary.component.html | 36 ++++++++++- .../src/app/summary/summary.component.ts | 61 ++++++++++++++++++- 7 files changed, 122 insertions(+), 9 deletions(-) diff --git a/frontend/wittymail-v2/src/app/app.module.ts b/frontend/wittymail-v2/src/app/app.module.ts index bd93ae3..f41b519 100644 --- a/frontend/wittymail-v2/src/app/app.module.ts +++ b/frontend/wittymail-v2/src/app/app.module.ts @@ -11,7 +11,7 @@ import {MatStepperModule} from '@angular/material/stepper'; import { FlexLayoutModule } from '@angular/flex-layout'; import {MatTableModule} from '@angular/material/table'; import {MatRadioModule} from '@angular/material/radio'; -import {MatIconModule} from '@angular/material'; +import {MatIconModule, MatCheckboxModule} from '@angular/material'; import {MatMenuModule} from '@angular/material/menu'; import {MatDialogModule} from '@angular/material/dialog'; import {MatTabsModule} from '@angular/material/tabs'; @@ -65,7 +65,8 @@ import { ConsoleLoggerService } from './util/console-logger.service'; MatMenuModule, MatDialogModule, MatTabsModule, - MatSnackBarModule + MatSnackBarModule, + MatCheckboxModule ], providers: [ { provide: LoggerService, useClass: ConsoleLoggerService } diff --git a/frontend/wittymail-v2/src/app/attachments/attachments.component.ts b/frontend/wittymail-v2/src/app/attachments/attachments.component.ts index 175ae40..9c7182d 100644 --- a/frontend/wittymail-v2/src/app/attachments/attachments.component.ts +++ b/frontend/wittymail-v2/src/app/attachments/attachments.component.ts @@ -63,7 +63,7 @@ export class AttachmentsComponent implements OnInit { } /** - * Populate the table that displays the column headers and a few sample rows + * Populate the table that displays the contents of the sheet * * This is called by the main stepper when this step becomes visible, because * the data fetching depends on previous steps. diff --git a/frontend/wittymail-v2/src/app/steps-slider/steps-slider.component.html b/frontend/wittymail-v2/src/app/steps-slider/steps-slider.component.html index 99572e7..0a8896b 100644 --- a/frontend/wittymail-v2/src/app/steps-slider/steps-slider.component.html +++ b/frontend/wittymail-v2/src/app/steps-slider/steps-slider.component.html @@ -12,6 +12,6 @@ - This is step 4 + \ No newline at end of file diff --git a/frontend/wittymail-v2/src/app/steps-slider/steps-slider.component.ts b/frontend/wittymail-v2/src/app/steps-slider/steps-slider.component.ts index 5913936..751777b 100644 --- a/frontend/wittymail-v2/src/app/steps-slider/steps-slider.component.ts +++ b/frontend/wittymail-v2/src/app/steps-slider/steps-slider.component.ts @@ -2,6 +2,7 @@ import { Component, OnInit, ViewChild } from '@angular/core'; import { EmailDesignComponent } from '../email-design/email-design.component'; import { MatStepper } from '@angular/material'; import { LoggerService } from '../util/logger.service'; +import { SummaryComponent } from '../summary/summary.component'; @Component({ selector: 'app-steps-slider', @@ -11,6 +12,7 @@ import { LoggerService } from '../util/logger.service'; export class StepsSliderComponent implements OnInit { @ViewChild("stepEmailDesign") stepEmailDesign: EmailDesignComponent; + @ViewChild("stepSummary") stepSummary: SummaryComponent; constructor(private log: LoggerService) { } @@ -26,6 +28,8 @@ export class StepsSliderComponent implements OnInit { if (stepper.selectedIndex == 2) { this.stepEmailDesign.populateTable(); + } else if (stepper.selectedIndex == 3) { + this.stepSummary.populateTable(); } } diff --git a/frontend/wittymail-v2/src/app/summary/summary.component.css b/frontend/wittymail-v2/src/app/summary/summary.component.css index e69de29..2bd9bba 100644 --- a/frontend/wittymail-v2/src/app/summary/summary.component.css +++ b/frontend/wittymail-v2/src/app/summary/summary.component.css @@ -0,0 +1,21 @@ +.table-container { + overflow: auto; + height: 70vh; +} + +.sheet-contents-table { + width: 100%; +} + +.wrap{ + white-space: -moz-pre-wrap !important; /* Mozilla, since 1999 */ + white-space: -webkit-pre-wrap; /*Chrome & Safari */ + white-space: -pre-wrap; /* Opera 4-6 */ + white-space: -o-pre-wrap; /* Opera 7 */ + white-space: pre-wrap; /* css-3 */ + word-wrap: break-word; /* Internet Explorer 5.5+ */ + word-break: break-all; + white-space: normal; + + padding: 0.2rem; +} \ No newline at end of file diff --git a/frontend/wittymail-v2/src/app/summary/summary.component.html b/frontend/wittymail-v2/src/app/summary/summary.component.html index fad0388..c24e1b7 100644 --- a/frontend/wittymail-v2/src/app/summary/summary.component.html +++ b/frontend/wittymail-v2/src/app/summary/summary.component.html @@ -1,3 +1,33 @@ -

- summary works! -

+ +
+ + + + + +
+ +
+ + + + + +
+ + + + + + + {{header}} + + {{element[header]}} +
+
+ + \ No newline at end of file diff --git a/frontend/wittymail-v2/src/app/summary/summary.component.ts b/frontend/wittymail-v2/src/app/summary/summary.component.ts index fd3e3bd..8e48f9f 100644 --- a/frontend/wittymail-v2/src/app/summary/summary.component.ts +++ b/frontend/wittymail-v2/src/app/summary/summary.component.ts @@ -1,4 +1,9 @@ -import { Component, OnInit } from '@angular/core'; +import { Component, OnInit, Input, ViewChild } from '@angular/core'; +import { LoggerService } from '../util/logger.service'; +import { BackendService, ColumnHeadersWithRowContent } from '../backend.service'; +import { MatStepper } from '@angular/material'; +import { ErrorDialogComponent } from '../common/error-dialog/error-dialog.component'; +import { SelectionModel } from '@angular/cdk/collections'; @Component({ selector: 'app-summary', @@ -7,9 +12,61 @@ import { Component, OnInit } from '@angular/core'; }) export class SummaryComponent implements OnInit { - constructor() { } + @Input('mainStepper') mainStepper: MatStepper; + @ViewChild('errorDialog') errorDialog: ErrorDialogComponent; + + /** List of strings, each being the heading text for a column */ + headers = []; + displayedHeaders = ['select']; + + /** Data displayed in the table */ + sheetContents = []; + + selection = new SelectionModel(true, []); + + constructor(private log: LoggerService, private backend: BackendService) { } ngOnInit() { } + /** + * Populate the table that displays the contents of the sheet + * + * This is called by the main stepper when this step becomes visible, because + * the data fetching depends on previous steps. + */ + populateTable() { + this.backend.getSheetContents().subscribe( + data => { + let r: ColumnHeadersWithRowContent = data; + + this.headers = this.headers.concat(r.headers); + this.headers = this.headers.concat(r.extended_headers); + this.displayedHeaders = this.displayedHeaders.concat(this.headers); + this.sheetContents = r.contents; + + this.log.info("Using %s headers and %d rows", this.headers, this.sheetContents.length); + }, + error => { + this.errorDialog.showError("Failed to get contents of the Excel sheet: " + error); + } + ); + } + + isAllSelected() { + const numSelected = this.selection.selected.length; + const numRows = this.sheetContents.length; + return numSelected == numRows; + } + + /** Selects all rows if they are not all selected; otherwise clear selection. */ + masterToggle() { + this.isAllSelected() ? + this.selection.clear() : + this.sheetContents.forEach(row => this.selection.select(row)); + } + + onSendSelectedEmails() { + this.log.info("Selected rows: ", this.selection.selected); + } } From 0be5ad8a8faa2336746226d03a7c907a41bd8526 Mon Sep 17 00:00:00 2001 From: Omkar Ekbote Date: Fri, 10 May 2019 19:11:30 +0530 Subject: [PATCH 52/64] Add email viewer dialog --- frontend/wittymail-v2/src/app/app.module.ts | 6 ++-- .../single-email-dialog.component.css | 0 .../single-email-dialog.component.html | 7 +++++ .../single-email-dialog.component.ts | 28 +++++++++++++++++++ .../src/app/summary/summary.component.html | 17 ++++++++++- .../src/app/summary/summary.component.ts | 19 +++++++++++-- 6 files changed, 72 insertions(+), 5 deletions(-) create mode 100644 frontend/wittymail-v2/src/app/summary/single-email-dialog/single-email-dialog.component.css create mode 100644 frontend/wittymail-v2/src/app/summary/single-email-dialog/single-email-dialog.component.html create mode 100644 frontend/wittymail-v2/src/app/summary/single-email-dialog/single-email-dialog.component.ts diff --git a/frontend/wittymail-v2/src/app/app.module.ts b/frontend/wittymail-v2/src/app/app.module.ts index f41b519..21c228b 100644 --- a/frontend/wittymail-v2/src/app/app.module.ts +++ b/frontend/wittymail-v2/src/app/app.module.ts @@ -31,6 +31,7 @@ import { AboutComponent } from './common/about/about.component'; import { ErrorDialogComponent } from './common/error-dialog/error-dialog.component'; import { LoggerService } from './util/logger.service'; import { ConsoleLoggerService } from './util/console-logger.service'; +import { SingleEmailDialogComponent } from './summary/single-email-dialog/single-email-dialog.component'; @NgModule({ declarations: [ @@ -41,9 +42,10 @@ import { ConsoleLoggerService } from './util/console-logger.service'; EmailDesignComponent, SummaryComponent, AboutComponent, - ErrorDialogComponent + ErrorDialogComponent, + SingleEmailDialogComponent ], - entryComponents: [AboutComponent], + entryComponents: [AboutComponent, SingleEmailDialogComponent], imports: [ BrowserModule, AppRoutingModule, diff --git a/frontend/wittymail-v2/src/app/summary/single-email-dialog/single-email-dialog.component.css b/frontend/wittymail-v2/src/app/summary/single-email-dialog/single-email-dialog.component.css new file mode 100644 index 0000000..e69de29 diff --git a/frontend/wittymail-v2/src/app/summary/single-email-dialog/single-email-dialog.component.html b/frontend/wittymail-v2/src/app/summary/single-email-dialog/single-email-dialog.component.html new file mode 100644 index 0000000..3f6873f --- /dev/null +++ b/frontend/wittymail-v2/src/app/summary/single-email-dialog/single-email-dialog.component.html @@ -0,0 +1,7 @@ +

E-Mail

+
+ {{contents}} +
+
+ +
diff --git a/frontend/wittymail-v2/src/app/summary/single-email-dialog/single-email-dialog.component.ts b/frontend/wittymail-v2/src/app/summary/single-email-dialog/single-email-dialog.component.ts new file mode 100644 index 0000000..bf8f9e5 --- /dev/null +++ b/frontend/wittymail-v2/src/app/summary/single-email-dialog/single-email-dialog.component.ts @@ -0,0 +1,28 @@ +import { Component, OnInit, Inject } from '@angular/core'; +import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material'; +import { LoggerService } from 'src/app/util/logger.service'; + +@Component({ + selector: 'app-single-email-dialog', + templateUrl: './single-email-dialog.component.html', + styleUrls: ['./single-email-dialog.component.css'] +}) +export class SingleEmailDialogComponent implements OnInit { + + contents: string = ""; + + constructor( + public dialogRef: MatDialogRef, + @Inject(MAT_DIALOG_DATA) public data: any, + private log: LoggerService) {} + + ngOnInit() { + this.contents = JSON.stringify(this.data); + } + + onSendEmail() { + this.log.info("Sending Email for: ", this.data); + this.dialogRef.close(); + } + +} diff --git a/frontend/wittymail-v2/src/app/summary/summary.component.html b/frontend/wittymail-v2/src/app/summary/summary.component.html index c24e1b7..41eb7a6 100644 --- a/frontend/wittymail-v2/src/app/summary/summary.component.html +++ b/frontend/wittymail-v2/src/app/summary/summary.component.html @@ -1,6 +1,7 @@
+ + + + +
- +
+ + + + + E-mail + + + @@ -26,7 +41,7 @@
diff --git a/frontend/wittymail-v2/src/app/summary/summary.component.ts b/frontend/wittymail-v2/src/app/summary/summary.component.ts index 8e48f9f..2e1c104 100644 --- a/frontend/wittymail-v2/src/app/summary/summary.component.ts +++ b/frontend/wittymail-v2/src/app/summary/summary.component.ts @@ -1,9 +1,10 @@ import { Component, OnInit, Input, ViewChild } from '@angular/core'; import { LoggerService } from '../util/logger.service'; import { BackendService, ColumnHeadersWithRowContent } from '../backend.service'; -import { MatStepper } from '@angular/material'; +import { MatStepper, MatDialog } from '@angular/material'; import { ErrorDialogComponent } from '../common/error-dialog/error-dialog.component'; import { SelectionModel } from '@angular/cdk/collections'; +import { SingleEmailDialogComponent } from './single-email-dialog/single-email-dialog.component'; @Component({ selector: 'app-summary', @@ -24,7 +25,8 @@ export class SummaryComponent implements OnInit { selection = new SelectionModel(true, []); - constructor(private log: LoggerService, private backend: BackendService) { } + constructor(private log: LoggerService, private backend: BackendService, + public dialog: MatDialog) { } ngOnInit() { } @@ -43,6 +45,7 @@ export class SummaryComponent implements OnInit { this.headers = this.headers.concat(r.headers); this.headers = this.headers.concat(r.extended_headers); this.displayedHeaders = this.displayedHeaders.concat(this.headers); + this.displayedHeaders = this.displayedHeaders.concat(["view-email"]); this.sheetContents = r.contents; this.log.info("Using %s headers and %d rows", this.headers, this.sheetContents.length); @@ -69,4 +72,16 @@ export class SummaryComponent implements OnInit { onSendSelectedEmails() { this.log.info("Selected rows: ", this.selection.selected); } + + onViewSingleEmail(row: any) { + this.log.info("View single e-mail for: ", row); + + const dialogRef = this.dialog.open(SingleEmailDialogComponent, { + data: row.email + }); + + dialogRef.afterClosed().subscribe(result => { + this.log.info('The dialog was closed'); + }); + } } From 14a0d3a1c022335ce4dd9b8015fcb2663d6a2fda Mon Sep 17 00:00:00 2001 From: Ajay Nair Date: Fri, 10 May 2019 19:39:25 +0530 Subject: [PATCH 53/64] Added support for multiple attachments for a row --- backend/mailer/SMTPEmailProvider.py | 1 + backend/util/FileUtils.py | 69 ++++++++++----- .../webserver/wittymail_server/rest_api.py | 88 +++++++++++-------- 3 files changed, 100 insertions(+), 58 deletions(-) diff --git a/backend/mailer/SMTPEmailProvider.py b/backend/mailer/SMTPEmailProvider.py index 6907227..ad8af80 100644 --- a/backend/mailer/SMTPEmailProvider.py +++ b/backend/mailer/SMTPEmailProvider.py @@ -102,5 +102,6 @@ def send_email(self, e): log.info('Email sent by %s to %s' % (msg['From'], msg['To'])) return [0, 'Email sent successfully'] except: + self.login() log.exception("Failed to send test email") return [-1, 'Error'] \ No newline at end of file diff --git a/backend/util/FileUtils.py b/backend/util/FileUtils.py index a1a209e..813dea3 100644 --- a/backend/util/FileUtils.py +++ b/backend/util/FileUtils.py @@ -1,4 +1,4 @@ -import util.logger as logger +import util.logger as logger from enum import Enum import PyPDF2 import os @@ -7,6 +7,8 @@ import operator import openpyxl import re +import pdb +import math log = logger.get_logger(__name__) @@ -63,7 +65,7 @@ def pdf_rotate(self, filepath, direction): shutil.move(output_file, filepath) ''' - Converts 'a b,c d and e' to 'a','b','c','d','e' + Converts 'a b,c , d and e' to 'a','b','c','d','e' ''' def sanitize_names_str(self, names_str): tmp_str = names_str.replace(" and ", ",") @@ -90,21 +92,21 @@ def read_excel_to_memory(self, loc): if all(c == 'None' for c in cells): break - tmp_str = self.sanitize_names_str(cells[1]) - tmp_str2 = [i.split()[0] for i in tmp_str] - if len(tmp_str2) == 1: - tmp_str = tmp_str2[0] - else: - tmp_str3 = ', '.join(tmp_str2[:-1]) - tmp_str = tmp_str3 + " and " + tmp_str2[-1] - cells.append(tmp_str) + #tmp_str = self.sanitize_names_str(cells[1]) + #tmp_str2 = [i.split()[0] for i in tmp_str] + #if len(tmp_str2) == 1: + # tmp_str = tmp_str2[0] + #else: + # tmp_str3 = ', '.join(tmp_str2[:-1]) + # tmp_str = tmp_str3 + " and " + tmp_str2[-1] + #cells.append(tmp_str) excel_rows.append(cells) assert len(excel_rows) > 0, \ "**** There are no entries in the excel sheet! ****" return [excel_headers, excel_rows] - def find_n_files_by_fuzzymatch(self, directory, fuzzystring, filetype = 'pdf', n = 5, ignore_phrases = None): + def _find_n_files_by_fuzzymatch(self, directory, fuzzystring, filetype = 'pdf', n = 5, ignore_phrases = None): candidates = {} for filename in os.listdir(directory): @@ -118,6 +120,20 @@ def find_n_files_by_fuzzymatch(self, directory, fuzzystring, filetype = 'pdf', n sorted_candidates = sorted(candidates.items(), key=operator.itemgetter(1), reverse=True) return [i[0] for i in sorted_candidates][:n] + def find_n_files_by_fuzzymatch(self, directory, fuzzystring, filetype = 'pdf', n = 5, ignore_phrases = None): + fuzzystring_set = self.sanitize_names_str(fuzzystring) + fuzzymatch_res = [] + for f in fuzzystring_set: + fuzzymatch_res.append(self._find_n_files_by_fuzzymatch(directory, f, filetype, n, ignore_phrases)) + + fetch_count_from_each_res = math.ceil(n / len(fuzzystring_set)) + + res = [] + for f in fuzzymatch_res: + res.extend(f[:fetch_count_from_each_res]) + + return res[:n] + ''' #no in st will be replaced by l[no] ''' @@ -143,19 +159,32 @@ def template_to_str(self, st, l): log.debug('template_to_str() final str = %s' % st) return st -def save_to_excel(excel_data, out_file): - wb=openpyxl.Workbook() - ws_write = wb.active + def save_to_excel(self, excel_data, out_file): + wb=openpyxl.Workbook() + ws_write = wb.active - for row in excel_data: - ws_write.append(row) + for row in excel_data: + ws_write.append(row) - wb.save(filename=out_file) - return os.path.join(os.getcwd(), out_file) + wb.save(filename=out_file) + return os.path.join(os.getcwd(), out_file) -if __name__ == "__main__": +def add_next_class_to_excel(input_excel, output_excel): f = FileUtils() + excel_headers, excel_rows = f.read_excel_to_memory(os.path.join("C:\\", "Users", "naira11", "Desktop", "SnehMail", "Clean_sheet.xlsx")) + for i in range(0, len(excel_rows)): + if 'Nur' in excel_rows[i][2] or 'nur' in excel_rows[i][2]: + excel_rows[i].append('Jr.Kg.') + if 'Jr' in excel_rows[i][2] or 'jr' in excel_rows[i][2] or 'unior' in excel_rows[i][2]: + excel_rows[i].append('Sr.Kg.') + data = [excel_headers] + data.extend(excel_rows) + return f.save_to_excel(data, output_excel) + +if __name__ == "__main__": + #f = FileUtils() #print(f.find_n_files_by_fuzzymatch(os.path.join("C:\\", "Users", "naira11", "Documents", "wittymail_data", 'allpdf'), 'aarahya jadav', ignore_phrases = ['Nursery', 'Kothrud'])) #f.pdf_rotate(os.path.join("C:\\", "Users","naira11", 'Test.pdf'), Direction.CLOCKWISE) #f.pdf_rotate(Direction.ANTICLOCKWISE) - f.read_excel_to_memory(os.path.join("C:\\", "Users", "naira11", "Documents", "Personal", "clean_sheet.xlsx")) + print(add_next_class_to_excel(os.path.join("C:\\", "Users", "naira11", "Desktop", "SnehMail", "Clean_sheet.xlsx"), 'test1.xlsx')) + next diff --git a/backend/webserver/wittymail_server/rest_api.py b/backend/webserver/wittymail_server/rest_api.py index 1f2bcef..44aa750 100644 --- a/backend/webserver/wittymail_server/rest_api.py +++ b/backend/webserver/wittymail_server/rest_api.py @@ -150,7 +150,6 @@ def candidate(self): row = request.args.get("selected_row") row = json.loads(row) log.info("Find attachment candidate for row: %s", row) - # row = ['1', 'Aradhya Karche', 'Nursery- kalewadi', 'Kalubai pratishthan', 'Sanjaysandhu8090@gmail.com', 'Ravi', 'amboreravi@gmail.com', '9822809079'] sheet = Sheet.getInstance() attachment_value = sheet.get_column_value(row, ['attachment_column']) @@ -181,7 +180,20 @@ def select_candidate(self): selected_candidate = data['pdfName'] sheet = Sheet.getInstance() - sheet.set_column_value(row, 'frozen_attachments', selected_candidate) + current_frozen_attachments = sheet.get_column_value_from_data(row, 'frozen_attachments') + if current_frozen_attachments != 'None': + new_frozen_attachments = current_frozen_attachments + ',' + selected_candidate + else: + new_frozen_attachments = selected_candidate + + sheet.set_column_value(row, 'frozen_attachments', new_frozen_attachments) + + required_attachment_count = sheet.get_count_of_column_value_from_data(row, 'attachment_column') + current_attachment_count = sheet.get_count_of_column_value_from_data(row, 'frozen_attachments') + + if current_attachment_count == required_attachment_count: + sheet.set_column_value(row, 'status', 'Email Pending') + return (jsonify({}), HTTP_OK, {'ContentType': 'application/json'}) @route('upload', methods=['POST']) @@ -292,21 +304,24 @@ def server_details(self): HTTP_OK, {'ContentType': 'application/json'}) - @route('send_test', methods=['POST']) - def send_test(self): - """ - Send a test email (metadata and actual content in payload) + def _send_email(self, row, test_email = True): + sheet = Sheet.getInstance() - :return: - """ try: - data = json.loads(request.data)['email'] + assert(row['status'] == 'Email Pending') + data = row['email'] tos = [] - tos.append(Email.frm) + if (test_email): + tos.append(Email.frm) + else: + tos.append(data['to']) ccs = [] - ccs.append(Email.frm) + if (test_email): + ccs.append(Email.frm) + else: + ccs.append(data['cc']) attachments = [] at = data['attachment'] @@ -315,51 +330,48 @@ def send_test(self): Email.common_attachment_dir = flask_app.config['COMMON_ATTACHMENTS_DIR'] e = Email(tos, ccs, attachments, data['subject'], data['body']) - err = self.email_provider_type.send_email(e) + for i in range(0,3): + try: + err = self.email_provider_type.send_email(e) + except: + continue + break + if err[0] != 0: return (jsonify({"err_msg": err[1]}), HTTP_BAD_INPUT, {'ContentType': 'application/json'}) + sheet.set_column_value(row, 'status', 'sent') return (jsonify({}), HTTP_OK, {'ContentType': 'application/json'}) except: log.exception("Failed to send email") - - @route('send', methods=['POST']) - def send(self): + + + @route('send_test', methods=['POST']) + def send_test(self): """ - Send a single email (metadata and actual content in payload) + Send a test email (metadata and actual content in payload) :return: """ - try: - data = json.loads(request.data) + row = json.loads(request.data) - tos = [] - tos.append(data['to']) - - ccs = [] - ccs.append(data['cc']) + return self._send_email(row) - attachments = [] - at = data['attachment'] - for a in at: - attachments.append(a["name"]) + @route('send', methods=['POST']) + def send(self): + """ + Send a single email (metadata and actual content in payload) - e = Email(tos, ccs, attachments, data['subject'], data['body'], flask_app.config['COMMON_ATTACHMENTS_DIR']) - err = self.email_provider_type.send_email(e) - if err[0] != 0: - return (jsonify({"err_msg": err[1]}), - HTTP_BAD_INPUT, - {'ContentType': 'application/json'}) + :return: + """ + row = json.loads(request.data) - return (jsonify({}), - HTTP_OK, - {'ContentType': 'application/json'}) - except: - log.exception("Failed to send email") + return self._send_email(row, test_email = False) + @route('template_to_reality', methods=['POST']) def template_to_reality(self): From 86912552e4867fd55f6bb99988c07291361fc10f Mon Sep 17 00:00:00 2001 From: Ajay Nair Date: Fri, 10 May 2019 19:45:51 +0530 Subject: [PATCH 54/64] Added support for multiple attachments upload --- .../wittymail_server/ColumnMapping.py | 4 +- backend/webserver/wittymail_server/Sheet.py | 38 +++++++++++++++---- 2 files changed, 33 insertions(+), 9 deletions(-) diff --git a/backend/webserver/wittymail_server/ColumnMapping.py b/backend/webserver/wittymail_server/ColumnMapping.py index 8480a2f..a519a6d 100644 --- a/backend/webserver/wittymail_server/ColumnMapping.py +++ b/backend/webserver/wittymail_server/ColumnMapping.py @@ -14,11 +14,11 @@ def set_column_mappings(self, map_info): self.mapping['index'] = ['index', self.column_delta + 2] def get_index_from_row(self, row): - return row['index'] + return int(row['index']) def set_default_values(self, data): for i in range(0, len(data)): - data[i].extend([None, None]) + data[i].extend(['Attachment Pending', 'None']) data[i].append(i) return data diff --git a/backend/webserver/wittymail_server/Sheet.py b/backend/webserver/wittymail_server/Sheet.py index 8868c91..460ada6 100644 --- a/backend/webserver/wittymail_server/Sheet.py +++ b/backend/webserver/wittymail_server/Sheet.py @@ -2,13 +2,14 @@ from wittymail_server.ColumnMapping import ColumnMapping import pdb import re +from util.FileUtils import FileUtils class Sheet: __instance = None filepath = None headers = [] data = [] - extended_headers = ["status", "frozen_attachments"] + extended_headers = ["status", "frozen_attachments", "index"] c = ColumnMapping() @staticmethod @@ -25,7 +26,6 @@ def __init__(self, filepath): else: Sheet.__instance = self Sheet.filepath = filepath - Sheet.extended_headers = ["ID", "Attachment Name", "Status"] def __del__(self): Sheet.rows = [] @@ -42,6 +42,17 @@ def get_column_value(self, row, column_name): index = self.c.get_column_mappings_name(column_name) return row[index[0]] + def get_count_of_column_value_from_data(self, row, column_name): + index = self.c.get_index_from_row(row) + column_index = self.c.get_column_mappings_index([column_name])[0] + f = FileUtils() + return len(f.sanitize_names_str(self.data[index][column_index])) + + def get_column_value_from_data(self, row, column_name): + index = self.c.get_index_from_row(row) + column_index = self.c.get_column_mappings_index([column_name])[0] + return self.data[index][column_index] + def get_header_index_from_name(self, header_name): return self.headers.index(header_name) @@ -56,12 +67,25 @@ def dump_to_memory(self): f = FileUtils() self.headers, self.data = f.read_excel_to_memory(self.filepath) data_width = len(self.data[0]) + + if ('status' in self.headers): + data_width -= 3 + else: + self.set_extended_dafault_data() + self.c.set_column_delta(data_width) - self.set_extended_dafault_data() - def save_to_file(self): + def add_extended_headers(self, headers_): + if ('status' not in self.headers): + headers_.extend(self.extended_headers) + return headers_ + + def save_to_file(self, outfile = 'outfile.xlsx'): f = FileUtils() - return f.save_to_excel(self.headers + self.data) + extended_headers = self.add_extended_headers(self.headers) + data = [extended_headers] + data.extend(self.data) + return f.save_to_excel(data, outfile) def get_headers_with_sample_rows(self, row_count = 5): data = [] @@ -99,5 +123,5 @@ def set_column_mappings(self, map_info): def set_column_value(self, row, column, value): index = self.c.get_index_from_row(row) - column_index = self.c.get_column_mappings_index([column]) - self.data[index][column_index[0]] = value \ No newline at end of file + column_index = self.c.get_column_mappings_index([column])[0] + self.data[index][column_index] = value \ No newline at end of file From f4ce0aed3c1fe1c44f39b9f376a1e77c9a047458 Mon Sep 17 00:00:00 2001 From: Omkar Ekbote Date: Fri, 10 May 2019 22:18:44 +0530 Subject: [PATCH 55/64] Add column-wise sorting to summary table --- frontend/wittymail-v2/src/app/app.module.ts | 5 +++-- .../src/app/summary/summary.component.css | 1 + .../src/app/summary/summary.component.html | 12 +++++------ .../src/app/summary/summary.component.ts | 21 ++++++++++++------- 4 files changed, 23 insertions(+), 16 deletions(-) diff --git a/frontend/wittymail-v2/src/app/app.module.ts b/frontend/wittymail-v2/src/app/app.module.ts index 21c228b..f2b4ce5 100644 --- a/frontend/wittymail-v2/src/app/app.module.ts +++ b/frontend/wittymail-v2/src/app/app.module.ts @@ -11,7 +11,7 @@ import {MatStepperModule} from '@angular/material/stepper'; import { FlexLayoutModule } from '@angular/flex-layout'; import {MatTableModule} from '@angular/material/table'; import {MatRadioModule} from '@angular/material/radio'; -import {MatIconModule, MatCheckboxModule} from '@angular/material'; +import {MatIconModule, MatCheckboxModule, MatSortModule} from '@angular/material'; import {MatMenuModule} from '@angular/material/menu'; import {MatDialogModule} from '@angular/material/dialog'; import {MatTabsModule} from '@angular/material/tabs'; @@ -68,7 +68,8 @@ import { SingleEmailDialogComponent } from './summary/single-email-dialog/single MatDialogModule, MatTabsModule, MatSnackBarModule, - MatCheckboxModule + MatCheckboxModule, + MatSortModule ], providers: [ { provide: LoggerService, useClass: ConsoleLoggerService } diff --git a/frontend/wittymail-v2/src/app/summary/summary.component.css b/frontend/wittymail-v2/src/app/summary/summary.component.css index 2bd9bba..f89deac 100644 --- a/frontend/wittymail-v2/src/app/summary/summary.component.css +++ b/frontend/wittymail-v2/src/app/summary/summary.component.css @@ -1,5 +1,6 @@ .table-container { overflow: auto; + overflow-x: auto; height: 70vh; } diff --git a/frontend/wittymail-v2/src/app/summary/summary.component.html b/frontend/wittymail-v2/src/app/summary/summary.component.html index 41eb7a6..2962a00 100644 --- a/frontend/wittymail-v2/src/app/summary/summary.component.html +++ b/frontend/wittymail-v2/src/app/summary/summary.component.html @@ -1,15 +1,15 @@
- +
- - -
+ + @@ -19,10 +19,10 @@ - + E-mail + @@ -32,7 +32,7 @@
-
+ {{header}} diff --git a/frontend/wittymail-v2/src/app/summary/summary.component.ts b/frontend/wittymail-v2/src/app/summary/summary.component.ts index 2e1c104..1e76f56 100644 --- a/frontend/wittymail-v2/src/app/summary/summary.component.ts +++ b/frontend/wittymail-v2/src/app/summary/summary.component.ts @@ -1,7 +1,7 @@ import { Component, OnInit, Input, ViewChild } from '@angular/core'; import { LoggerService } from '../util/logger.service'; import { BackendService, ColumnHeadersWithRowContent } from '../backend.service'; -import { MatStepper, MatDialog } from '@angular/material'; +import { MatStepper, MatDialog, MatTableDataSource, MatSort } from '@angular/material'; import { ErrorDialogComponent } from '../common/error-dialog/error-dialog.component'; import { SelectionModel } from '@angular/cdk/collections'; import { SingleEmailDialogComponent } from './single-email-dialog/single-email-dialog.component'; @@ -14,14 +14,16 @@ import { SingleEmailDialogComponent } from './single-email-dialog/single-email-d export class SummaryComponent implements OnInit { @Input('mainStepper') mainStepper: MatStepper; + @ViewChild(MatSort) sortedTable: MatSort; @ViewChild('errorDialog') errorDialog: ErrorDialogComponent; /** List of strings, each being the heading text for a column */ headers = []; - displayedHeaders = ['select']; + defaultDisplayedHeaders = ['select', 'view-email'] + displayedHeaders = []; /** Data displayed in the table */ - sheetContents = []; + sheetContents = null; selection = new SelectionModel(true, []); @@ -42,13 +44,16 @@ export class SummaryComponent implements OnInit { data => { let r: ColumnHeadersWithRowContent = data; - this.headers = this.headers.concat(r.headers); - this.headers = this.headers.concat(r.extended_headers); + this.headers = r.headers; + if (r.extended_headers && r.extended_headers.length) { + this.headers = this.headers.concat(r.extended_headers); + } + this.displayedHeaders = this.defaultDisplayedHeaders; this.displayedHeaders = this.displayedHeaders.concat(this.headers); - this.displayedHeaders = this.displayedHeaders.concat(["view-email"]); - this.sheetContents = r.contents; + this.sheetContents = new MatTableDataSource(r.contents); + this.sheetContents.sort = this.sortedTable; - this.log.info("Using %s headers and %d rows", this.headers, this.sheetContents.length); + this.log.info("Using %d headers and %d rows", this.headers.length, this.sheetContents.length); }, error => { this.errorDialog.showError("Failed to get contents of the Excel sheet: " + error); From 24dbad85061e4403ac52ce7d3fb9c774b7d8b530 Mon Sep 17 00:00:00 2001 From: Omkar Ekbote Date: Fri, 10 May 2019 22:29:10 +0530 Subject: [PATCH 56/64] Add vertical scrollbar to attachment candidates list --- .../src/app/attachments/attachments.component.css | 6 ++++++ .../src/app/attachments/attachments.component.html | 2 +- .../src/app/attachments/attachments.component.ts | 1 + 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/frontend/wittymail-v2/src/app/attachments/attachments.component.css b/frontend/wittymail-v2/src/app/attachments/attachments.component.css index 1715cf1..5f172c2 100644 --- a/frontend/wittymail-v2/src/app/attachments/attachments.component.css +++ b/frontend/wittymail-v2/src/app/attachments/attachments.component.css @@ -12,6 +12,12 @@ table { margin: 15px 0; } +.attachment-cadidates-list-container { + height: 30%; + overflow: auto; + margin-bottom: 0.3rem; +} + .attachment-candidate-list-item { margin: 5px; } diff --git a/frontend/wittymail-v2/src/app/attachments/attachments.component.html b/frontend/wittymail-v2/src/app/attachments/attachments.component.html index 5370d94..2de0f92 100644 --- a/frontend/wittymail-v2/src/app/attachments/attachments.component.html +++ b/frontend/wittymail-v2/src/app/attachments/attachments.component.html @@ -39,7 +39,7 @@
-
+

diff --git a/frontend/wittymail-v2/src/app/attachments/attachments.component.ts b/frontend/wittymail-v2/src/app/attachments/attachments.component.ts index 9c7182d..5901ad2 100644 --- a/frontend/wittymail-v2/src/app/attachments/attachments.component.ts +++ b/frontend/wittymail-v2/src/app/attachments/attachments.component.ts @@ -130,6 +130,7 @@ export class AttachmentsComponent implements OnInit { this.backend.selectAttachmentCandidate(payload).subscribe( data => { this.selectedRow = null; + this.selectedAttachmentCandidate = null; }, error => { this.errorDialog.showError("Failed to select this candidate: " + error); From 7d381b1f33a383e47c200f5d1c94b3a481c85c15 Mon Sep 17 00:00:00 2001 From: Omkar Ekbote Date: Fri, 10 May 2019 22:33:44 +0530 Subject: [PATCH 57/64] Remove 'summary' step from attachments view and add a 'next' button instead --- .../app/attachments/attachments.component.css | 4 ++++ .../app/attachments/attachments.component.html | 16 ++-------------- .../src/app/attachments/attachments.component.ts | 5 +++++ 3 files changed, 11 insertions(+), 14 deletions(-) diff --git a/frontend/wittymail-v2/src/app/attachments/attachments.component.css b/frontend/wittymail-v2/src/app/attachments/attachments.component.css index 5f172c2..4306e4a 100644 --- a/frontend/wittymail-v2/src/app/attachments/attachments.component.css +++ b/frontend/wittymail-v2/src/app/attachments/attachments.component.css @@ -50,4 +50,8 @@ button { .summary-table-container { height: 100vh; overflow: auto; +} + +.next-button { + text-align: right; } \ No newline at end of file diff --git a/frontend/wittymail-v2/src/app/attachments/attachments.component.html b/frontend/wittymail-v2/src/app/attachments/attachments.component.html index 2de0f92..62e5bf7 100644 --- a/frontend/wittymail-v2/src/app/attachments/attachments.component.html +++ b/frontend/wittymail-v2/src/app/attachments/attachments.component.html @@ -81,22 +81,10 @@

+
+ - -
- -
- -
- - - - - -
{{header}} {{element[header]}}
-
-
diff --git a/frontend/wittymail-v2/src/app/attachments/attachments.component.ts b/frontend/wittymail-v2/src/app/attachments/attachments.component.ts index 5901ad2..6c9f425 100644 --- a/frontend/wittymail-v2/src/app/attachments/attachments.component.ts +++ b/frontend/wittymail-v2/src/app/attachments/attachments.component.ts @@ -178,4 +178,9 @@ export class AttachmentsComponent implements OnInit { ); } + onClickNext() { + this.log.info("Done selecting attachment PDFs, moving on..."); + this.mainStepper.next(); + } + } From 479946f617119b7b2887226a978fd5905a71b381 Mon Sep 17 00:00:00 2001 From: Ajay Nair Date: Fri, 10 May 2019 22:44:20 +0530 Subject: [PATCH 58/64] Added support to send headers and extended_headers separately --- backend/util/FileUtils.py | 16 ++++++-------- backend/webserver/wittymail_server/Sheet.py | 17 +++++++++----- .../webserver/wittymail_server/rest_api.py | 22 ++++++++++++++----- 3 files changed, 35 insertions(+), 20 deletions(-) diff --git a/backend/util/FileUtils.py b/backend/util/FileUtils.py index 813dea3..f16a2b4 100644 --- a/backend/util/FileUtils.py +++ b/backend/util/FileUtils.py @@ -106,7 +106,7 @@ def read_excel_to_memory(self, loc): "**** There are no entries in the excel sheet! ****" return [excel_headers, excel_rows] - def _find_n_files_by_fuzzymatch(self, directory, fuzzystring, filetype = 'pdf', n = 5, ignore_phrases = None): + def _find_n_files_by_fuzzymatch(self, directory, fuzzystring, filetype = 'pdf', n = 3, ignore_phrases = None): candidates = {} for filename in os.listdir(directory): @@ -120,19 +120,17 @@ def _find_n_files_by_fuzzymatch(self, directory, fuzzystring, filetype = 'pdf', sorted_candidates = sorted(candidates.items(), key=operator.itemgetter(1), reverse=True) return [i[0] for i in sorted_candidates][:n] - def find_n_files_by_fuzzymatch(self, directory, fuzzystring, filetype = 'pdf', n = 5, ignore_phrases = None): + def find_n_files_by_fuzzymatch(self, directory, fuzzystring, filetype = 'pdf', n = 3, ignore_phrases = None): fuzzystring_set = self.sanitize_names_str(fuzzystring) fuzzymatch_res = [] for f in fuzzystring_set: fuzzymatch_res.append(self._find_n_files_by_fuzzymatch(directory, f, filetype, n, ignore_phrases)) - fetch_count_from_each_res = math.ceil(n / len(fuzzystring_set)) - res = [] for f in fuzzymatch_res: - res.extend(f[:fetch_count_from_each_res]) + res.extend(f) - return res[:n] + return res ''' #no in st will be replaced by l[no] @@ -182,9 +180,9 @@ def add_next_class_to_excel(input_excel, output_excel): return f.save_to_excel(data, output_excel) if __name__ == "__main__": - #f = FileUtils() - #print(f.find_n_files_by_fuzzymatch(os.path.join("C:\\", "Users", "naira11", "Documents", "wittymail_data", 'allpdf'), 'aarahya jadav', ignore_phrases = ['Nursery', 'Kothrud'])) + f = FileUtils() + print(f.find_n_files_by_fuzzymatch(os.path.join("C:\\", "Users", "naira11", "Documents", "wittymail_data", 'allpdf'), 'aarahya jadav,ayush kurund,aarohiBhagat,aahil sayyed', ignore_phrases = ['Nursery', 'Kothrud'])) #f.pdf_rotate(os.path.join("C:\\", "Users","naira11", 'Test.pdf'), Direction.CLOCKWISE) #f.pdf_rotate(Direction.ANTICLOCKWISE) - print(add_next_class_to_excel(os.path.join("C:\\", "Users", "naira11", "Desktop", "SnehMail", "Clean_sheet.xlsx"), 'test1.xlsx')) + #print(add_next_class_to_excel(os.path.join("C:\\", "Users", "naira11", "Desktop", "SnehMail", "Clean_sheet.xlsx"), 'test1.xlsx')) next diff --git a/backend/webserver/wittymail_server/Sheet.py b/backend/webserver/wittymail_server/Sheet.py index 460ada6..481e746 100644 --- a/backend/webserver/wittymail_server/Sheet.py +++ b/backend/webserver/wittymail_server/Sheet.py @@ -54,7 +54,11 @@ def get_column_value_from_data(self, row, column_name): return self.data[index][column_index] def get_header_index_from_name(self, header_name): - return self.headers.index(header_name) + if header_name in self.headers: + return self.headers.index(header_name) + if header_name in self.extended_headers: + return self.extended_headers.index(header_name) + return None def set_attachment(self, attachment_name): attachment_index = self.c.get_column_mappings_index(["frozen_attachments"]) @@ -70,19 +74,20 @@ def dump_to_memory(self): if ('status' in self.headers): data_width -= 3 + self.headers = self.headers[:-3] else: self.set_extended_dafault_data() self.c.set_column_delta(data_width) - def add_extended_headers(self, headers_): - if ('status' not in self.headers): - headers_.extend(self.extended_headers) + def add_extended_headers(self): + headers_ = self.headers + headers_.extend(self.extended_headers) return headers_ def save_to_file(self, outfile = 'outfile.xlsx'): f = FileUtils() - extended_headers = self.add_extended_headers(self.headers) + extended_headers = self.add_extended_headers() data = [extended_headers] data.extend(self.data) return f.save_to_excel(data, outfile) @@ -94,7 +99,7 @@ def get_headers_with_sample_rows(self, row_count = 5): return self.headers, data def get_all_content(self): - return self.headers, self.data + return self.headers, self.extended_headers, self.data def get_extended_headers(self): return self.extended_headers diff --git a/backend/webserver/wittymail_server/rest_api.py b/backend/webserver/wittymail_server/rest_api.py index 44aa750..47cbb18 100644 --- a/backend/webserver/wittymail_server/rest_api.py +++ b/backend/webserver/wittymail_server/rest_api.py @@ -70,14 +70,23 @@ def file(self): return send_file(excel_file) + def _convert_header_data_list_to_dict(self, headers, extended_headers, data): + dict_ = dict(zip(headers, data)) + extended_headers.reverse() + data.reverse() + dict2_ = dict(zip(extended_headers, data)) + dict_.update(dict2_) + return dict_ + def contents(self): """ Get the contents of the sheet updated with 'status' and other columns :return: """ + f = FileUtils() sheet = Sheet.getInstance() - headers, data = sheet.get_all_content() + headers, extended_headers, data = sheet.get_all_content() index, frozen_attachments_index, email_to_index, email_cc_index = sheet.get_column_mappings_index(["index", "frozen_attachments", "to_column", "cc_column"]) @@ -85,8 +94,10 @@ def contents(self): for d in data: attachments = [] if frozen_attachments_index and d[frozen_attachments_index]: - at_dict = {"name": d[frozen_attachments_index], "url": os.path.join("/attachment/file/", d[frozen_attachments_index])} - attachments.append(at_dict) + attachment_list = f.sanitize_names_str(d[frozen_attachments_index]) + for a in attachment_list: + at_dict = {"name": a, "url": os.path.join("/attachment/file/", a)} + attachments.append(at_dict) email = {} email["from"] = Email.frm @@ -103,12 +114,13 @@ def contents(self): sheet = Sheet.getInstance() email["body"] = sheet._template_to_str(Email.body_template, d) - tmp = dict(zip(headers, d)) + tmp = self._convert_header_data_list_to_dict(headers, extended_headers, d) + tmp["email"] = email tmp["index"] = d[index] output_list.append(tmp) - return (jsonify({'headers': headers, 'contents': output_list}), + return (jsonify({'headers': headers, 'extended_headers': extended_headers, 'contents': output_list}), HTTP_OK, {'ContentType': 'application/json'}) From 39a1e239027387f3986a01871456fac688ad201c Mon Sep 17 00:00:00 2001 From: Omkar Ekbote Date: Fri, 10 May 2019 22:46:20 +0530 Subject: [PATCH 59/64] Connect backend to 'send email' button --- .../single-email-dialog.component.html | 2 ++ .../single-email-dialog.component.ts | 20 +++++++++++++++---- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/frontend/wittymail-v2/src/app/summary/single-email-dialog/single-email-dialog.component.html b/frontend/wittymail-v2/src/app/summary/single-email-dialog/single-email-dialog.component.html index 3f6873f..e919a38 100644 --- a/frontend/wittymail-v2/src/app/summary/single-email-dialog/single-email-dialog.component.html +++ b/frontend/wittymail-v2/src/app/summary/single-email-dialog/single-email-dialog.component.html @@ -5,3 +5,5 @@

E-Mail

+ + \ No newline at end of file diff --git a/frontend/wittymail-v2/src/app/summary/single-email-dialog/single-email-dialog.component.ts b/frontend/wittymail-v2/src/app/summary/single-email-dialog/single-email-dialog.component.ts index bf8f9e5..0b3af49 100644 --- a/frontend/wittymail-v2/src/app/summary/single-email-dialog/single-email-dialog.component.ts +++ b/frontend/wittymail-v2/src/app/summary/single-email-dialog/single-email-dialog.component.ts @@ -1,6 +1,8 @@ -import { Component, OnInit, Inject } from '@angular/core'; +import { Component, OnInit, Inject, ViewChild } from '@angular/core'; import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material'; import { LoggerService } from 'src/app/util/logger.service'; +import { BackendService, SendEmailContent } from 'src/app/backend.service'; +import { ErrorDialogComponent } from 'src/app/common/error-dialog/error-dialog.component'; @Component({ selector: 'app-single-email-dialog', @@ -9,12 +11,14 @@ import { LoggerService } from 'src/app/util/logger.service'; }) export class SingleEmailDialogComponent implements OnInit { + @ViewChild('errorDialog') errorDialog: ErrorDialogComponent; contents: string = ""; constructor( public dialogRef: MatDialogRef, - @Inject(MAT_DIALOG_DATA) public data: any, - private log: LoggerService) {} + @Inject(MAT_DIALOG_DATA) public data: SendEmailContent, + private log: LoggerService, + private backend: BackendService) {} ngOnInit() { this.contents = JSON.stringify(this.data); @@ -22,7 +26,15 @@ export class SingleEmailDialogComponent implements OnInit { onSendEmail() { this.log.info("Sending Email for: ", this.data); - this.dialogRef.close(); + this.backend.postSendEmail(this.data).subscribe( + data => { + this.log.info("Email sent successfully"); + this.dialogRef.close(); + }, + error => { + this.errorDialog.showError("Failed to send email: " + error); + } + ); } } From d8b631dfb3d03a40eb7b5b59f84a15f6695efbbc Mon Sep 17 00:00:00 2001 From: Omkar Ekbote Date: Fri, 10 May 2019 23:02:11 +0530 Subject: [PATCH 60/64] Connect backend to 'send selected emails' --- .../src/app/summary/summary.component.ts | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/frontend/wittymail-v2/src/app/summary/summary.component.ts b/frontend/wittymail-v2/src/app/summary/summary.component.ts index 1e76f56..855e2bc 100644 --- a/frontend/wittymail-v2/src/app/summary/summary.component.ts +++ b/frontend/wittymail-v2/src/app/summary/summary.component.ts @@ -46,7 +46,7 @@ export class SummaryComponent implements OnInit { this.headers = r.headers; if (r.extended_headers && r.extended_headers.length) { - this.headers = this.headers.concat(r.extended_headers); + // this.headers = this.headers.concat(r.extended_headers); } this.displayedHeaders = this.defaultDisplayedHeaders; this.displayedHeaders = this.displayedHeaders.concat(this.headers); @@ -76,6 +76,18 @@ export class SummaryComponent implements OnInit { onSendSelectedEmails() { this.log.info("Selected rows: ", this.selection.selected); + + this.selection.selected.forEach(row => { + this.log.info("Sending Email for: ", row); + this.backend.postSendEmail(row.email).subscribe( + data => { + this.log.info("Email sent successfully"); + }, + error => { + this.errorDialog.showError("Failed to send email: " + error); + } + ); + }); } onViewSingleEmail(row: any) { From e4233fab665be9a274a748f94d2b0b8a84bbb39f Mon Sep 17 00:00:00 2001 From: Ajay Nair Date: Fri, 10 May 2019 23:03:23 +0530 Subject: [PATCH 61/64] Solved a minor issue --- backend/webserver/wittymail_server/rest_api.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/backend/webserver/wittymail_server/rest_api.py b/backend/webserver/wittymail_server/rest_api.py index 47cbb18..4e527f3 100644 --- a/backend/webserver/wittymail_server/rest_api.py +++ b/backend/webserver/wittymail_server/rest_api.py @@ -4,7 +4,7 @@ import os, sys import re import pdb - +import copy sys.path.append(os.path.abspath(os.path.join(os.curdir, '..', '..'))) from flask import send_from_directory @@ -70,7 +70,11 @@ def file(self): return send_file(excel_file) - def _convert_header_data_list_to_dict(self, headers, extended_headers, data): + def _convert_header_data_list_to_dict(self, headers_, extended_headers_, data_): + headers = copy.deepcopy(headers_) + extended_headers = copy.deepcopy(extended_headers_) + data = copy.deepcopy(data_) + dict_ = dict(zip(headers, data)) extended_headers.reverse() data.reverse() From d677a11ab80f28cf28553056589dacc11aab2818 Mon Sep 17 00:00:00 2001 From: Omkar Ekbote Date: Fri, 10 May 2019 23:17:33 +0530 Subject: [PATCH 62/64] Added button to download sheet --- frontend/wittymail-v2/src/app/backend.service.ts | 2 +- .../src/app/summary/summary.component.css | 4 ++++ .../src/app/summary/summary.component.html | 3 ++- .../src/app/summary/summary.component.ts | 16 ++++++++++++++-- 4 files changed, 21 insertions(+), 4 deletions(-) diff --git a/frontend/wittymail-v2/src/app/backend.service.ts b/frontend/wittymail-v2/src/app/backend.service.ts index c1998d7..db4892f 100644 --- a/frontend/wittymail-v2/src/app/backend.service.ts +++ b/frontend/wittymail-v2/src/app/backend.service.ts @@ -170,7 +170,7 @@ export class BackendService { return this.urls.sheet.upload; } - getFodderDownloadUrl(): string { + getSheetDownloadUrl(): string { return this.urls.sheet.get_file; } diff --git a/frontend/wittymail-v2/src/app/summary/summary.component.css b/frontend/wittymail-v2/src/app/summary/summary.component.css index f89deac..feb7160 100644 --- a/frontend/wittymail-v2/src/app/summary/summary.component.css +++ b/frontend/wittymail-v2/src/app/summary/summary.component.css @@ -8,6 +8,10 @@ width: 100%; } +.top-action-button { + margin: 0.3rem; +} + .wrap{ white-space: -moz-pre-wrap !important; /* Mozilla, since 1999 */ white-space: -webkit-pre-wrap; /*Chrome & Safari */ diff --git a/frontend/wittymail-v2/src/app/summary/summary.component.html b/frontend/wittymail-v2/src/app/summary/summary.component.html index 2962a00..fa050fc 100644 --- a/frontend/wittymail-v2/src/app/summary/summary.component.html +++ b/frontend/wittymail-v2/src/app/summary/summary.component.html @@ -1,4 +1,5 @@ - + +
diff --git a/frontend/wittymail-v2/src/app/summary/summary.component.ts b/frontend/wittymail-v2/src/app/summary/summary.component.ts index 855e2bc..746e13c 100644 --- a/frontend/wittymail-v2/src/app/summary/summary.component.ts +++ b/frontend/wittymail-v2/src/app/summary/summary.component.ts @@ -27,10 +27,21 @@ export class SummaryComponent implements OnInit { selection = new SelectionModel(true, []); + downloadSheetUrl: string = ''; + constructor(private log: LoggerService, private backend: BackendService, public dialog: MatDialog) { } ngOnInit() { + this.downloadSheetUrl = this.backend.getSheetDownloadUrl(); + /* Cache buster, because the sheet will have the same name */ + this.downloadSheetUrl += "?" + Math.random(); + } + + onClickDownloadSheet() { + this.downloadSheetUrl = this.backend.getSheetDownloadUrl(); + /* Cache buster, because the sheet will have the same name */ + this.downloadSheetUrl += "?" + Math.random(); } /** @@ -44,9 +55,10 @@ export class SummaryComponent implements OnInit { data => { let r: ColumnHeadersWithRowContent = data; - this.headers = r.headers; if (r.extended_headers && r.extended_headers.length) { - // this.headers = this.headers.concat(r.extended_headers); + this.headers = r.extended_headers.concat(r.headers); + } else { + this.headers = r.headers; } this.displayedHeaders = this.defaultDisplayedHeaders; this.displayedHeaders = this.displayedHeaders.concat(this.headers); From 893086fcf1b5934bed62b8c17243586a508bdf6f Mon Sep 17 00:00:00 2001 From: Ajay Nair Date: Sat, 11 May 2019 00:24:15 +0530 Subject: [PATCH 63/64] Added index to be passed inbetween front and backend --- backend/util/FileUtils.py | 2 +- backend/webserver/wittymail_server/Sheet.py | 3 ++- backend/webserver/wittymail_server/rest_api.py | 11 +++++------ 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/backend/util/FileUtils.py b/backend/util/FileUtils.py index f16a2b4..d17cb48 100644 --- a/backend/util/FileUtils.py +++ b/backend/util/FileUtils.py @@ -130,7 +130,7 @@ def find_n_files_by_fuzzymatch(self, directory, fuzzystring, filetype = 'pdf', n for f in fuzzymatch_res: res.extend(f) - return res + return list(set(res)) ''' #no in st will be replaced by l[no] diff --git a/backend/webserver/wittymail_server/Sheet.py b/backend/webserver/wittymail_server/Sheet.py index 481e746..b0d7a92 100644 --- a/backend/webserver/wittymail_server/Sheet.py +++ b/backend/webserver/wittymail_server/Sheet.py @@ -3,6 +3,7 @@ import pdb import re from util.FileUtils import FileUtils +import copy class Sheet: __instance = None @@ -81,7 +82,7 @@ def dump_to_memory(self): self.c.set_column_delta(data_width) def add_extended_headers(self): - headers_ = self.headers + headers_ = copy.deepcopy(self.headers) headers_.extend(self.extended_headers) return headers_ diff --git a/backend/webserver/wittymail_server/rest_api.py b/backend/webserver/wittymail_server/rest_api.py index 4e527f3..34b5d6d 100644 --- a/backend/webserver/wittymail_server/rest_api.py +++ b/backend/webserver/wittymail_server/rest_api.py @@ -99,11 +99,13 @@ def contents(self): attachments = [] if frozen_attachments_index and d[frozen_attachments_index]: attachment_list = f.sanitize_names_str(d[frozen_attachments_index]) + attachment_list = list(set(attachment_list)) for a in attachment_list: at_dict = {"name": a, "url": os.path.join("/attachment/file/", a)} attachments.append(at_dict) email = {} + email["index"] = d[index] email["from"] = Email.frm if email_to_index: email["to"] = d[email_to_index] @@ -121,7 +123,7 @@ def contents(self): tmp = self._convert_header_data_list_to_dict(headers, extended_headers, d) tmp["email"] = email - tmp["index"] = d[index] + output_list.append(tmp) return (jsonify({'headers': headers, 'extended_headers': extended_headers, 'contents': output_list}), @@ -320,13 +322,10 @@ def server_details(self): HTTP_OK, {'ContentType': 'application/json'}) - def _send_email(self, row, test_email = True): + def _send_email(self, data, test_email = True): sheet = Sheet.getInstance() try: - assert(row['status'] == 'Email Pending') - data = row['email'] - tos = [] if (test_email): tos.append(Email.frm) @@ -358,7 +357,7 @@ def _send_email(self, row, test_email = True): HTTP_BAD_INPUT, {'ContentType': 'application/json'}) - sheet.set_column_value(row, 'status', 'sent') + sheet.set_column_value(data, 'status', 'Email Sent') return (jsonify({}), HTTP_OK, {'ContentType': 'application/json'}) From 51bb745c1a224c15a9ef827bc95a5402dde18fdc Mon Sep 17 00:00:00 2001 From: Ajay Nair Date: Mon, 13 May 2019 23:40:37 +0530 Subject: [PATCH 64/64] Improved logging --- backend/mailer/SMTPEmailProvider.py | 2 +- backend/util/FileUtils.py | 8 ++++---- backend/webserver/wittymail_server/rest_api.py | 7 +------ 3 files changed, 6 insertions(+), 11 deletions(-) diff --git a/backend/mailer/SMTPEmailProvider.py b/backend/mailer/SMTPEmailProvider.py index ad8af80..1c91f90 100644 --- a/backend/mailer/SMTPEmailProvider.py +++ b/backend/mailer/SMTPEmailProvider.py @@ -103,5 +103,5 @@ def send_email(self, e): return [0, 'Email sent successfully'] except: self.login() - log.exception("Failed to send test email") + log.exception("Failed to send email") return [-1, 'Error'] \ No newline at end of file diff --git a/backend/util/FileUtils.py b/backend/util/FileUtils.py index d17cb48..2e43f9b 100644 --- a/backend/util/FileUtils.py +++ b/backend/util/FileUtils.py @@ -169,7 +169,7 @@ def save_to_excel(self, excel_data, out_file): def add_next_class_to_excel(input_excel, output_excel): f = FileUtils() - excel_headers, excel_rows = f.read_excel_to_memory(os.path.join("C:\\", "Users", "naira11", "Desktop", "SnehMail", "Clean_sheet.xlsx")) + excel_headers, excel_rows = f.read_excel_to_memory(input_excel) for i in range(0, len(excel_rows)): if 'Nur' in excel_rows[i][2] or 'nur' in excel_rows[i][2]: excel_rows[i].append('Jr.Kg.') @@ -181,8 +181,8 @@ def add_next_class_to_excel(input_excel, output_excel): if __name__ == "__main__": f = FileUtils() - print(f.find_n_files_by_fuzzymatch(os.path.join("C:\\", "Users", "naira11", "Documents", "wittymail_data", 'allpdf'), 'aarahya jadav,ayush kurund,aarohiBhagat,aahil sayyed', ignore_phrases = ['Nursery', 'Kothrud'])) + #print(f.find_n_files_by_fuzzymatch(os.path.join("C:\\", "Users", "naira11", "Documents", "wittymail_data", 'allpdf'), 'aarahya jadav,ayush kurund,aarohiBhagat,aahil sayyed', ignore_phrases = ['Nursery', 'Kothrud'])) #f.pdf_rotate(os.path.join("C:\\", "Users","naira11", 'Test.pdf'), Direction.CLOCKWISE) #f.pdf_rotate(Direction.ANTICLOCKWISE) - #print(add_next_class_to_excel(os.path.join("C:\\", "Users", "naira11", "Desktop", "SnehMail", "Clean_sheet.xlsx"), 'test1.xlsx')) - next + print(add_next_class_to_excel(os.path.join("C:\\", "Users", "naira11", "Desktop", "SnehMail", "MissingReportCards.xlsx"), 'test1.xlsx')) + next \ No newline at end of file diff --git a/backend/webserver/wittymail_server/rest_api.py b/backend/webserver/wittymail_server/rest_api.py index 34b5d6d..e69e025 100644 --- a/backend/webserver/wittymail_server/rest_api.py +++ b/backend/webserver/wittymail_server/rest_api.py @@ -345,12 +345,7 @@ def _send_email(self, data, test_email = True): Email.common_attachment_dir = flask_app.config['COMMON_ATTACHMENTS_DIR'] e = Email(tos, ccs, attachments, data['subject'], data['body']) - for i in range(0,3): - try: - err = self.email_provider_type.send_email(e) - except: - continue - break + err = self.email_provider_type.send_email(e) if err[0] != 0: return (jsonify({"err_msg": err[1]}),