diff --git a/.eslintrc.json b/.eslintrc.json new file mode 100644 index 0000000..6f56318 --- /dev/null +++ b/.eslintrc.json @@ -0,0 +1,34 @@ +{ + "env": { + "browser": true, + "es6": true + }, + "extends": "eslint:recommended", + "parserOptions": { + "ecmaVersion": 2015, + "sourceType": "module" + }, + "rules": { + "indent": [ + "error", + 4 + ], + "linebreak-style": [ + "error", + "unix" + ], + "quotes": [ + "error", + "double" + ], + "semi": [ + "error", + "always" + ], + "no-unused-vars": [ + "error", + {"args": "all", "argsIgnorePattern": "^_"} + ], + "array-bracket-spacing": ["error", "never"] + } +} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..415914e --- /dev/null +++ b/.gitignore @@ -0,0 +1,62 @@ +# Logs +logs +bak +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage + +# nyc test coverage +.nyc_output + +# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# Bower dependency directory (https://bower.io/) +bower_components + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (https://nodejs.org/api/addons.html) +build/Release + +# Dependency directories +node_modules/ +jspm_packages/ + +# TypeScript v1 declaration files +typings/ + +# Optional npm cache directory +.npm + +# Optional eslint cache +.eslintcache + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + +# dotenv environment variables file +.env + +# next.js build output +.next diff --git a/README.md b/README.md index 8dc8eb5..db34d63 100644 --- a/README.md +++ b/README.md @@ -1 +1,19 @@ -# vaccination-metadata \ No newline at end of file +Setup metadata to use Vaccination App in a DHIS2 instance. + +## Generate metadata + +``` +$ node src/cli.js generate --url='http://admin:district@localhost:8080' -i source-data.json -o metadata.json +``` + +This will generate metadata prepared for a specific DHIS2 instance, so objects will be re-used if existing (uses field `name` as key). + +## Post metadata + +Once the metadata is generated, you can send it the same DHIS2 instance: + +``` +$ node src/cli.js post --url='http://admin:district@localhost:8080' -i metadata.json +``` + +Records will be created or updated as necessary. This command may be run many times, no duplicates should be created. \ No newline at end of file diff --git a/package.json b/package.json new file mode 100644 index 0000000..0771e8f --- /dev/null +++ b/package.json @@ -0,0 +1,23 @@ +{ + "name": "vaccination-metadata", + "version": "1.0.0", + "main": "index.js", + "repository": "https://github.com/EyeSeeTea/vaccination-metadata", + "author": "arnau@eyeseetea.com", + "license": "MIT", + "scripts": { + "lint": "eslint src" + }, + "dependencies": { + "argparse": "^1.0.10", + "lodash": "^4.17.11", + "md5": "^2.2.1", + "node-fetch": "^2.3.0", + "p-map": "^2.0.0" + }, + "devDependencies": { + "babel-eslint": "^10.0.1", + "eslint": "^5.10.0", + "eslint-plugin-react": "^7.11.1" + } +} diff --git a/source-data.json b/source-data.json new file mode 100644 index 0000000..f6a5ccb --- /dev/null +++ b/source-data.json @@ -0,0 +1,490 @@ +{ + "antigens": { + "measles": { + "name": "Measles", + "code": "RVC_MEASLES", + "ageGroups": ["6 - 8 m", "9 - 11 m", "12 - 23 m", "24 - 59 m", "5 - 14 y", "15 - 29 y"] + }, + "meningitis-polysaccharide": { + "name": "Meningitis Polysaccharide", + "shortName": "MenPol", + "code": "RVC_MENPOLY", + "ageGroups": ["6 - 8 m", "9 - 11 m", "12 - 59 m", "5 - 14 y", "15 - 29 y"] + }, + "meningitis-conjugate": { + "name": "Meningitis Conjugate", + "shortName": "MenCon", + "code": "RVC_MENCONJ", + "ageGroups": ["6 - 8 m", "9 - 11 m", "12 - 59 m", "5 - 14 y", "15 - 29 y"] + }, + "cholera": { + "name": "Cholera", + "code": "RVC_CHOLERA", + "ageGroups": ["6 - 8 m", "9 - 11 m", "12 - 59 m", "5 - 14 y", "15 - 29 y"] + }, + "pcv": { + "name": "PCV", + "code": "RVC_PCV", + "ageGroups": ["6 - 8 m", "9 - 11 m", "12 - 59 m", "5 - 14 y", "15 - 29 y"] + }, + "pertussis-penta": { + "name": "Pertussis Penta", + "code": "RVC_PERTPENTA", + "ageGroups": ["6 - 8 m", "9 - 11 m", "12 - 59 m", "5 - 14 y", "15 - 29 y"] + }, + "yellow-fever": { + "name": "Yellow Fever", + "code": "RVC_YELLOW_FEVER", + "ageGroups": ["6 - 8 m", "9 - 11 m", "12 - 59 m", "5 - 14 y", "15 - 29 y"] + }, + "japanese-encephalitis": { + "name": "Japanese Encephalitis", + "code": "RVC_JPENC", + "ageGroups": ["6 - 8 m", "9 - 11 m", "12 - 59 m", "5 - 14 y", "15 - 29 y"] + }, + "dengue": { + "name": "Dengue", + "code": "RVC_DENGUE", + "ageGroups": ["6 - 8 m", "9 - 11 m", "12 - 59 m", "5 - 14 y", "15 - 29 y"] + }, + "typhoid-fever": { + "name": "Typhoid Fever", + "code": "RVC_TYPHOID_FEVER", + "ageGroups": ["6 - 11 m", "12 - 59 m", "5 - 14 y", "15 - 45 y"] + } + }, + + "dataElements": { + "total-population": { + "name": "Total population", + "code": "RVC_AD_001", + "aggregationType": "LAST", + "valueType": "NUMBER" + }, + "age-distribution": { + "name": "Age distribution (%)", + "valueType": "PERCENTAGE", + "code": "RVC_AD_002", + "aggregationType": "LAST", + "$categoryCombo": "demographic-age" + }, + "population-by-age": { + "$byAntigen": false, + "name": "Population by age", + "code": "RVC_AD_003", + "valueType": "NUMBER", + "aggregationType": "LAST", + "$categoryCombo": "demographic-age" + }, + + "vaccine-doses-administered": { + "$byAntigen": true, + "name": "Vaccine doses administered", + "shortName": "Doses adm", + "code": "RVC_AD_005", + "valueType": "NUMBER", + "$categoryCombo": "age-group-${antigen.key}" + }, + "vaccine-doses-used": { + "$byAntigen": true, + "name": "Vaccine doses used", + "shortName": "Doses used", + "code": "RVC_AD_006", + "valueType": "NUMBER", + "$categoryCombo": "age-group-${antigen.key}" + }, + "ads-used": { + "$byAntigen": true, + "name": "ADS (Auto Disable Syringe) used", + "shortName": "ADS used", + "code": "RVC_AD_007", + "valueType": "NUMBER" + }, + "ads-dilution": { + "$byAntigen": true, + "name": "ADS (Auto Disable Syringe) for dilution", + "shortName": "ADS dilution", + "code": "RVC_AD_008", + "valueType": "NUMBER" + }, + "safety-boxes": { + "$byAntigen": true, + "name": "Safety boxes", + "code": "RVC_AD_009", + "valueType": "NUMBER" + }, + "syringes": { + "$byAntigen": true, + "name": "Syringes", + "code": "RVC_AD_010", + "valueType": "NUMBER" + }, + "syringes-dilution": { + "$byAntigen": true, + "name": "Syringes for dilution", + "code": "RVC_AD_011", + "valueType": "NUMBER" + }, + "needles": { + "$byAntigen": true, + "name": "Needles", + "key": "needles", + "code": "RVC_AD_012", + "valueType": "NUMBER" + }, + "aeb": { + "$byAntigen": true, + "name": "Accidental Exposure to Blood (AEB)", + "shortName": "AEB", + "code": "RVC_AD_013", + "valueType": "NUMBER" + }, + "adverse-event": { + "$byAntigen": true, + "name": "Adverse Event Following Immunization", + "shortName": "AEFI", + "code": "RVC_AD_014", + "valueType": "NUMBER", + "$categoryCombo": "severity" + } + }, + + "indicators": { + "ads-wastage-rate": { + "$byAntigen": true, + "name": "ADS (Auto Disable Syringe) wastage rate", + "shortName": "ADS wastage rate", + "code": "RVC_IN_001", + "$indicatorType": "percentage", + "numeratorDescription": "ADS used - Total Doses adm", + "numerator": "#{${dataElements['ads-used-' + antigen.key].id}} - #{${dataElements['vaccine-doses-administered-' + antigen.key].id}}", + "denominatorDescription": "ADS used", + "denominator": "#{${dataElements['ads-used-' + antigen.key].id}}" + }, + "safety-boxes-ratio": { + "$byAntigen": true, + "name": "Safety boxes ratio", + "code": "RVC_IN_002", + "$indicatorType": "ratio", + "numeratorDescription": "Syringes", + "numerator": "#{${dataElements['syringes-' + antigen.key].id}}", + "denominatorDescription": "Safety Boxes", + "denominator": "#{${dataElements['safety-boxes-' + antigen.key].id}}" + }, + "dilution-syringes-ratio": { + "$byAntigen": true, + "name": "Dilution syringes ratio", + "code": "RVC_IN_003", + "$indicatorType": "percentage", + "numeratorDescription": "Syringes for dilution", + "numerator": "#{${dataElements['syringes-dilution-' + antigen.key].id}}", + "denominatorDescription": "Total doses used", + "denominator": "#{${dataElements['vaccine-doses-used-' + antigen.key].id}}" + }, + "vaccine-utilization-rate": { + "$byAntigen": true, + "name": "Vaccine utilization rate", + "shortName": "Utilization rate", + "code": "RVC_IN_004", + "$indicatorType": "percentage", + "numeratorDescription": "Doses administered", + "numerator": "#{${dataElements['vaccine-doses-administered-' + antigen.key].id}}", + "denominatorDescription": "Doses used", + "denominator": "#{${dataElements['vaccine-doses-used-' + antigen.key].id}}" + }, + "vaccine-campaign-coverage": { + "$byAntigen": true, + "name": "Vaccine campaign coverage", + "shortName": "Campaign coverage", + "code": "RVC_IN_005", + "$indicatorType": "percentage", + "numeratorDescription": "Doses administered", + "numerator": "#{${dataElements['vaccine-doses-administered-' + antigen.key].id}}", + "denominatorDescription": "Population by age ${antigen.name}", + "denominator": "#{${dataElements['population-by-age'].id}}" + } + }, + + "categories": { + "teams": { + "name": "Teams", + "code": "RVC_TEAMS", + "dataDimensionType": "ATTRIBUTE", + "dataDimension": true, + "$categoryOptions": ["Team 1", "Team 2", "Team 3"] + }, + "gender": { + "name": "Gender", + "dataDimensionType": "DISAGGREGATION", + "dataDimension": true, + "$categoryOptions": ["Female", "Male"] + }, + "severity": { + "name": "Severity", + "dataDimensionType": "DISAGGREGATION", + "dataDimension": true, + "$categoryOptions": ["Minor", "Severe"] + }, + "displacement-status": { + "name": "Displacement Status", + "dataDimensionType": "DISAGGREGATION", + "dataDimension": true, + "$categoryOptions": ["Host", "IDP", "Refugees"] + }, + "demographic-age": { + "name": "Demographic age distribution", + "dataDimensionType": "DISAGGREGATION", + "dataDimension": false, + "$categoryOptions": [ + "0 - 6 w", "7 w - 2 m", "3 - 5 m", "6 - 8 m", "9 - 11 m", + "12 - 23 m", "12 - 59 m", "24 - 59 m", "5 - 14 y", "15 - 29 y", ">= 30y" + ] + } + }, + + "categoryCombos": { + "age-group-gender": { + "$byAntigen": true, + "key": "age-group-gender-${antigen.key}", + "name": "Age group / gender - ${antigen.name}", + "$categories": ["age-group-${antigen.key}", "gender"] + } + }, + + "indicatorTypes": { + "ratio": { + "name": "ratio", + "factor": 1 + }, + "percentage": { + "name": "percentage", + "factor": 100 + } + }, + + "userRoles": { + "encoder": { + "name": "Campaign Encoder", + "authorities": [ + "F_DATAVALUE_ADD", + "F_DATAVALUE_DELETE", + "M_dhis-web-cache-cleaner", + "M_dhis-web-dataentry", + "M_dhis-web-pivot", + "M_dhis-web-messaging", + "M_dhis-web-dashboard", + "M_dhis-web-visualizer", + "M_Vaccination_App" + ] + }, + "configurator": { + "name": "Campaign Configurator", + "authorities": [ + "F_DATASET_ADD", + "F_DATASET_DELETE", + "M_dhis-web-cache-cleaner", + "M_dhis-web-pivot", + "M_dhis-web-messaging", + "M_dhis-web-dashboard", + "M_dhis-web-visualizer", + "M_Vaccination_App" + ] + }, + "dashboard": { + "name": "Campaign Dasbboard", + "authorities": [ + "M_dhis-web-cache-cleaner", + "M_dhis-web-pivot", + "M_dhis-web-messaging", + "M_dhis-web-dashboard", + "M_dhis-web-visualizer", + "M_Vaccination_App" + ] + }, + "admin": { + "name": "Campaign admin", + "authorities": [ + "F_CATEGORY_COMBO_DELETE", + "F_CATEGORY_COMBO_PUBLIC_ADD", + "F_CATEGORY_DELETE", + "F_CATEGORY_OPTION_DELETE", + "F_CATEGORY_OPTION_GROUP_DELETE", + "F_CATEGORY_OPTION_GROUP_PUBLIC_ADD", + "F_CATEGORY_OPTION_GROUP_SET_DELETE", + "F_CATEGORY_OPTION_GROUP_SET_PUBLIC_ADD", + "F_CATEGORY_OPTION_PUBLIC_ADD", + "F_CATEGORY_PUBLIC_ADD", + "F_DATAELEMENT_DELETE", + "F_DATAELEMENTGROUP_DELETE", + "F_DATAELEMENTGROUP_PUBLIC_ADD", + "F_DATAELEMENTGROUPSET_DELETE", + "F_DATAELEMENTGROUPSET_PUBLIC_ADD", + "F_DATAELEMENT_PUBLIC_ADD", + "F_DATASET_DELETE", + "F_DATASET_PUBLIC_ADD", + "F_INDICATOR_DELETE", + "F_INDICATORGROUP_DELETE", + "F_INDICATORGROUP_PUBLIC_ADD", + "F_INDICATORGROUPSET_DELETE", + "F_INDICATORGROUPSET_PUBLIC_ADD", + "F_INDICATOR_PUBLIC_ADD", + "F_INDICATORTYPE_ADD", + "F_INDICATORTYPE_DELETE", + "M_dhis-web-cache-cleaner", + "M_dhis-web-messaging", + "M_Vaccination_App" + ] + } + }, + + "dataSets": { + "demography": { + "name": "Demographic Information", + "shortName": "Demographic Information", + "code": "DS_ERm", + "periodType": "Monthly", + "dataElementDecoration": true, + "renderAsTabs": true, + "openFuturePeriods": 1, + "timelyDays": 15, + "$dataElements": ["total-population", "age-distribution"], + "$organisationUnits": {"names": ["OCBA"], "levels": [4, 5]}, + "$sections": { + "Population": { + "sortOrder": 0, + "name": "Population Age Distribution (%)", + "showRowTotals": true, + "$dataElements": ["total-population", "age-distribution"] + } + } + } + }, + + "organisationUnitLevels": { + "msf-international": { + "name": "MSF International", + "level": 1 + }, + "operational-center": { + "name": "Operational Center", + "level": 2 + }, + "missing-office": { + "name": "Mission Office", + "level": 3 + }, + "project": { + "name": "Project", + "level": 4 + }, + "health-site": { + "name": "Health Site", + "level": 5 + }, + "health-service": { + "name": "Health Service", + "level": 6 + } + }, + + "test": { + "organisationUnits": { + "name": "MSF", + "children": { + "center": { + "name": "OCBA", + "children": { + "office1": { + "name": "MALI", + "children": { + "project1": { + "name": "KIDAL, PHC", + "code": "ESML105", + "children": { + "site1": { + "name": "Vaccination Preventive (CPS)", + "children": { + "service1": { + "name": "Vaccination - Abadjo" + }, + "service2": { + "name": "Vaccination - Tanainat" + } + } + } + } + } + } + }, + "office2": { + "name": "CAR", + "children": { + "project2": { + "name": "KABO", + "code": "ESCF105", + "children": { + "site2": { + "name": "BELALO", + "children": { + "service3": { + "name": "Vaccination" + } + } + }, + "site3": { + "name": "KAKOBO", + "children": { + "service4": { + "name": "Vaccination2" + } + } + } + } + } + } + } + } + } + } + }, + "dataSets": { + "test-campaign1": { + "name": "Vaccination Reactive Campaign - ESML105 - Daily", + "periodType": "Daily", + "dataElementDecoration": true, + "renderAsTabs": true, + "openFuturePeriods": 1, + "timelyDays": 15, + "$categoryCombo": "teams", + "$organisationUnits": { + "keys": [ + "service1", + "service2", + "service3", + "service4" + ] + }, + "$sections": { + "population": { + "sortOrder": 0, + "name": "Population", + "$dataElements": ["population-by-age"], + "$greyedDataElements": ["population-by-age"] + }, + "test-campaign1-cholera": { + "sortOrder": 1, + "name": "Cholera", + "$dataElementsByGroups": ["cholera"], + "$dataElements": [] + }, + "test-campaign1-measles": { + "sortOrder": 2, + "name": "Measles", + "$dataElementsByGroups": ["measles"], + "$dataElements": [] + } + } + } + } + } +} diff --git a/src/cli.js b/src/cli.js new file mode 100644 index 0000000..a8e0e22 --- /dev/null +++ b/src/cli.js @@ -0,0 +1,91 @@ +const _ = require("lodash"); +const fs = require("fs"); +const argparse = require("argparse"); +const {debug, inspect} = require("./utils"); +const {getPayload, postPayload} = require("./metadata"); + +async function generate({url, sourceDataFilePath, outputMetadataFilePath}) { + debug(`Source data: ${sourceDataFilePath}`); + const sourceData = JSON.parse(fs.readFileSync(sourceDataFilePath, "utf8")); + const metadata = await getPayload(url, sourceData); + const json = JSON.stringify(metadata, null, 2); + fs.writeFileSync(outputMetadataFilePath, json, "utf8"); + debug(`Metadata output: ${outputMetadataFilePath}`); +} + +async function post({url, sourceMetadataFilePath}) { + const payloadAll = JSON.parse(fs.readFileSync(sourceMetadataFilePath, "utf8")); + const payload = _(payloadAll) + .omit(["organisationUnitLevels", "organisationUnits", "dataSets", "sections"]) + .value(); + + const responseJson = await postPayload(url, payload, {updateCOCs: true}); + + if (responseJson.status === "OK") { + debug(`Import success:" ${inspect(responseJson.stats)}`); + _(responseJson.typeReports).each(typeReport => { + const modelName = _.last(typeReport.klass.split(".")); + debug(" - " + `${modelName}: ${inspect(typeReport.stats)}`); + }); + } else { + debug("Import error:"); + debug(inspect(responseJson)); + } +} + +function getArgsParser() { + const parser = argparse.ArgumentParser(); + + const subparsers = parser.addSubparsers({ + title: "COMMAND", + dest: "command", + }); + + const parserGenerate = subparsers.addParser("generate", {addHelp: true}); + const parserPost = subparsers.addParser("post", {addHelp: true}); + const urlArg = [["-u", "--url"], { + required: true, + help: "DHIS2 instance URL: http://username:password@server:port", + }]; + + parserGenerate.addArgument(...urlArg); + parserGenerate.addArgument(["-i", "--data-input"], { + dest: "sourceDataFilePath", + help: "Source JSON data path", + required: true, + }); + parserGenerate.addArgument(["-o", "--metadata-output"], { + dest: "outputMetadataFilePath", + help: "Output JSON metadata path", + required: true, + }); + + parserPost.addArgument(...urlArg); + parserPost.addArgument(["-i", "--metadata-input"], { + dest: "sourceMetadataFilePath", + help: "Source JSON metadata path", + required: true, + }); + + return parser.parseArgs(); +} + +function main() { + const args = getArgsParser(); + + switch (args.command) { + case "generate": + return generate(args); + case "post": + return post(args); + default: + throw new Error(`Command not implemented: ${args.command}`); + } +} + +const logErrorAndExit = err => { + console.error(err); // eslint-disable-line no-console + process.exit(1); +}; + +main().catch(logErrorAndExit); diff --git a/src/db.js b/src/db.js new file mode 100644 index 0000000..b79c240 --- /dev/null +++ b/src/db.js @@ -0,0 +1,105 @@ +const _ = require("lodash"); +const pMap = require("p-map"); +const md5 = require("md5"); +const fetch = require("node-fetch"); +const {repeat, inspect} = require("./utils"); + +// DHIS2 UID :: /^[a-zA-Z]{1}[a-zA-Z0-9]{10}$/ +const asciiLetters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; +const asciiNumbers = "0123456789"; +const asciiLettersAndNumbers = asciiLetters + asciiNumbers; +const uidStructure = [asciiLetters, ...repeat(asciiLettersAndNumbers, 10)]; +const maxHashValue = _(uidStructure).map(cs => cs.length).reduce((acc, n) => acc * n, 1); + +/* Return UID from key */ +function getUid(key, prefix) { + const md5hash = md5(prefix + key); + const nHashChars = Math.ceil(Math.log(maxHashValue) / Math.log(16)); + const hashInteger = parseInt(md5hash.slice(0, nHashChars), 16); + const result = uidStructure.reduce((acc, chars) => { + const {n, uid} = acc; + const nChars = chars.length; + const quotient = Math.floor(n / nChars); + const remainder = n % nChars; + const uidChar = chars[remainder]; + return {n: quotient, uid: uid + uidChar}; + }, {n: hashInteger, uid: ""}); + + return result.uid; +} + +class Db { + constructor(url, data) { + this.url = url; + this.data = data; + } + + static async init(url, {models} = {}) { + let data; + + if (models) { + const getExistingAsPairs = async (value) => { + const {name: model, fields} = value.name + ? value + : {name: value, fields: ["id", "name"]}; + + const json = await fetch(`${url}/api/${model}?fields=${fields.join(',')}&paging=false`) + .then(res => res.json()); + return [model, json[model]]; + }; + data = _.fromPairs(await pMap(models, getExistingAsPairs, {concurrency: 2})); + } else { + data = {}; + } + + return new Db(url, data); + } + + getObjectsForModel(model) { + return this.data[model]; + } + + get(model, allAttributes, {field = "name"} = {}) { + const {key, ...attributes} = allAttributes; + const value = attributes[field]; + const valuesByField = _.keyBy(this.data[model], field); + + if (!valuesByField) { + throw `Model not found in data: ${model}`; + } else if (!value) { + throw `Property ${field} is required in attributes: ${inspect(attributes)}`; + } else { + const uid = _(valuesByField).get([value, "id"]) || + getUid(key || value, model + "-"); + return {...attributes, id: uid, key}; + } + } + + getByKey(model, allAttributes) { + const { key, ...attributes } = allAttributes; + if (!key) { + throw `Name key is required in attributes: ${inspect(attributes)}`; + } else { + const uid = getUid(key, model + "-"); + return {...attributes, id: uid, key}; + } + } + + async postMetadata(payload) { + const headers = {"Content-Type": "application/json"}; + const response = await fetch(`${this.url}/api/metadata`, { + method: "POST", + body: JSON.stringify(payload), + headers, + }); + return response.json(); + } + + async updateCOCs() { + return fetch(`${this.url}/api/maintenance/categoryOptionComboUpdate`, { + method: "POST", + }); + } +} + +exports.Db = Db; diff --git a/src/metadata.js b/src/metadata.js new file mode 100644 index 0000000..25acb7f --- /dev/null +++ b/src/metadata.js @@ -0,0 +1,513 @@ +const _ = require("lodash"); +const {interpolate, get, debug, inspect, cartesianProduct} = require("./utils"); +const {Db} = require("./db"); + +const models = [ + {name: "organisationUnits", fields: ["id", "name", "level"]}, + "organisationUnitLevels", + + "categories", + { name: "categoryCombos", fields: ["id", "name", "categoryOptionCombos"] }, + "categoryOptions", + "categoryOptionCombos", + + "dataElementGroupSets", + "dataElementGroups", + "dataElements", + + "indicatorTypes", + "indicatorGroupSets", + "indicatorGroups", + "indicators", + + "userRoles", + + "dataSets", + "sections", +]; + +/* Transform an array of {key1: [...], key2: [...]} into a single accumulated object */ +function flattenPayloads(payloads) { + return _(payloads) + .map(_.toPairs) + .flatten() + .groupBy(([key, _values]) => key) + .mapValues(pairs => + _(pairs) + .flatMap(([_key, values]) => values) + .uniqBy("id") + .value()) + .value(); +} + +function addCategoryOptionCombos(db, payload) { + const {categories, categoryOptions, categoryCombos} = payload; + const categoriesById = _.keyBy(categories, "id"); + const categoryOptionsById = _.keyBy(categoryOptions, "id"); + + const categoryOptionCombos = _(categoryCombos).flatMap(categoryCombo => { + const categoryOptionsList = _(categoryCombo.categories) + .map(category => get(categoriesById, [category.id, "categoryOptions"]).map(co => co.id)) + .value(); + + return cartesianProduct(...categoryOptionsList).map(categoryOptionIds => { + const categoryOptions = _(categoryOptionsById).at(categoryOptionIds).value(); + const key = [categoryCombo.id, ...categoryOptionIds].join("."); + + return db.getByKey("categoryOptionCombos", { + key: key, + name: _(categoryOptions).map("name").join(", "), + categoryCombo: {id: categoryCombo.id}, + categoryOptions: categoryOptionIds.map(id => ({id})), + }); + }); + }).value(); + + return {...payload, categoryOptionCombos}; +} + +function toKeyList(object, path) { + if (!object) { + throw new Error("No object"); + } else if (!_.has(object, path)) { + throw new Error(`Path ${path} not found in object:\n${inspect(object)}`); + } else { + const innerObject = { + ..._.get(object, path), + ..._.get(object, "test." + path), + }; + return _(innerObject) + .map((value, key) => _(value).has("key") ? value : ({...value, key})) + .value(); + } +} + +function getIds(objs) { + return objs.map(obj => ({id: obj.id})); +} + +async function getPayloadFromDb(db, sourceData) { + const categoryOptionsAntigens = toKeyList(sourceData, "antigens").map(antigen => { + return db.get("categoryOptions", { + name: antigen.name, + code: antigen.code, + shortName: antigen.name, + }); + }); + + const categoryAntigens = db.get("categories", { + key: "antigens", + name: "Antigens", + code: "RVC_ANTIGENS", + dataDimensionType: "DISAGGREGATION", + dimensionType: "CATEGORY", + dataDimension: false, + categoryOptions: getIds(categoryOptionsAntigens), + }); + + const categoriesAntigensMetadata = getCategoriesMetadataForAntigens(db, sourceData); + + const categoriesMetadata = addCategoryOptionCombos(db, + getCategoriesMetadata(sourceData, db, categoriesAntigensMetadata)); + + const dataElementsMetadata = getDataElementsMetadata(db, sourceData, categoriesMetadata); + + const indicatorsMetadata = getIndicatorsMetadata(db, sourceData, dataElementsMetadata); + + const orgUnitsMetadata = getTestOrgUnitsMetadata(db, sourceData); + + const userRoles = toKeyList(sourceData, "userRoles").map(userRole => { + return db.get("userRoles", userRole); + }); + + const dataSetsMetadata = getDataSetsMetadata(db, sourceData, + categoriesMetadata, dataElementsMetadata, orgUnitsMetadata); + + const payloadBase = { + categories: [categoryAntigens], + categoryOptions: categoryOptionsAntigens, + userRoles, + }; + + return flattenPayloads([ + payloadBase, + dataElementsMetadata, + indicatorsMetadata, + categoriesMetadata, + orgUnitsMetadata, + dataSetsMetadata, + ]); +} + +function getDataSetsMetadata(db, sourceData, categoriesMetadata, dataElementsMetadata, orgUnitsMetadata) { + const organisationUnits = orgUnitsMetadata.organisationUnits; + const dataElementsById = _.keyBy(dataElementsMetadata.dataElements, "id"); + const dataElementsByKey = _.keyBy(dataElementsMetadata.dataElements, "key"); + const dataElementGroupsByKey = _.keyBy(dataElementsMetadata.dataElementGroups, "key"); + const cocsByCategoryComboId = _.groupBy(categoriesMetadata.categoryOptionCombos, coc => coc.categoryCombo.id); + + return flattenPayloads(toKeyList(sourceData, "dataSets").map($dataSet => { + const sections = toKeyList($dataSet, "$sections").map($section => { + const dataElements = _.concat( + _(dataElementsByKey).at($section.$dataElements || []).value(), + _(dataElementGroupsByKey) + .at($section.$dataElementsByGroups || []) + .flatMap("dataElements") + .map(de => dataElementsById[de.id]) + .value(), + ); + + const greyedFields = _(dataElementsByKey) + .at($section.$greyedDataElements || []) + .flatMap(dataElement => { + const cocs = _.flatten(get(cocsByCategoryComboId, dataElement.categoryCombo.id)); + return cocs.map(coc => ({ + dataElement: {id: dataElement.id}, + categoryOptionCombo: {id: coc.id}, + })); + }); + + return db.getByKey("sections", { + ...$section, + greyedFields, + dataElements: getIds(dataElements), + }); + }); + + const {keys, levels} = $dataSet.$organisationUnits; + const organisationUnitsForDataSet = organisationUnits.filter(orgUnit => { + return _(keys).includes(orgUnit.key) || _(levels).includes(orgUnit.level); + }); + + const dataSet = db.get("dataSets", { + ...$dataSet, + categoryCombo: getCategoryComboId(db, categoriesMetadata, $dataSet), + organisationUnits: getIds(organisationUnitsForDataSet), + }); + + const dataSetElements = _(sections) + .flatMap("dataElements") + .map(de => dataElementsById[de.id]) + .map(dataElement => ({ + dataElement: {id: dataElement.id}, + dataSet: {id: dataSet.id}, + categoryCombo: {id: dataElement.categoryCombo.id} + })) + .value(); + + return { + dataSets: [{...dataSet, dataSetElements}], + sections: sections.map(section => ({ + ...section, + dataSet: {id: dataSet.id}, + })), + }; + })); +} + +function getOrgUnitsFromTree(db, parentOrgUnit, orgUnitsByKey) { + return _(orgUnitsByKey).map((values, key) => ({...values, key})).flatMap(attributes => { + const orgUnit = db.get("organisationUnits", { + level: parentOrgUnit ? parentOrgUnit.level + 1 : 1, + shortName: attributes.name, + openingDate: "1970-01-01T00:00:00.000", + parent: parentOrgUnit ? {id: parentOrgUnit.id} : undefined, + ..._.omit(attributes, ["children"]), + }); + + const childrenOrgUnits = attributes.children + ? getOrgUnitsFromTree(db, orgUnit, attributes.children) + : []; + + return [orgUnit, ...childrenOrgUnits]; + }).value(); +} + +function getTestOrgUnitsMetadata(db, sourceData) { + const organisationUnits = getOrgUnitsFromTree(db, null, {root: sourceData.test.organisationUnits}); + + const organisationUnitLevels = toKeyList(sourceData, "organisationUnitLevels").map(orgUnitLevel => { + return db.get("organisationUnitLevels", orgUnitLevel, {field: "level"}); + }); + + return {organisationUnits, organisationUnitLevels}; +} + +function getCategoriesMetadataForAntigens(db, sourceData) { + return flattenPayloads(toKeyList(sourceData, "antigens").map(antigen => { + const categoryOptionsForAge = antigen.ageGroups.map(ageGroupName => { + return db.get("categoryOptions", { + name: ageGroupName, + shortName: ageGroupName, + }); + }); + + const categoryAgeGroup = db.get("categories", { + key: `age-group-${antigen.key}`, + name: `Age group ${antigen.name}`, + dataDimensionType: "DISAGGREGATION", + dimensionType: "CATEGORY", + dataDimension: true, + categoryOptions: getIds(categoryOptionsForAge), + }); + + const categoryComboAge = db.get("categoryCombos", { + key: `age-group-${antigen.key}`, + code: antigen.code, + name: `Age group ${antigen.name}`, + dataDimensionType: "DISAGGREGATION", + categories: getIds([categoryAgeGroup]), + }); + + return { + categories: [categoryAgeGroup], + categoryOptions: categoryOptionsForAge, + categoryCombos: [categoryComboAge], + }; + })); +} + +function interpolateObj(attributes, namespace) { + return _(attributes) + .mapValues(value => { + if (_(value).isString()) { + return interpolate(value, namespace); + } else if (_(value).isArray()) { + return value.map(v => interpolate(v, namespace)); + } else if(_(value).isObject()) { + return interpolateObj(value, namespace); + } else if (_(value).isBoolean()) { + return value; + } else { + throw `Unsupported interpolation object: ${inspect(value)}`; + } + }).value(); +} + +function getIndicator(db, indicatorTypesByKey, namespace, plainAttributes) { + const attributes = interpolateObj(plainAttributes, namespace); + + return db.get("indicators", { + shortName: attributes.name, + indicatorType: { + id: get(indicatorTypesByKey, [attributes.$indicatorType, "id"]), + }, + ...attributes, + }); +} + +function getCategoryComboId(db, categoriesMetadata, obj) { + const categoryCombosByName = _.keyBy(db.getObjectsForModel("categoryCombos"), "name"); + const categoryCombosByKey = _.keyBy(categoriesMetadata.categoryCombos, "key"); + const ccId = obj.$categoryCombo + ? get(categoryCombosByKey, [obj.$categoryCombo, "id"]) + : get(categoryCombosByName, ["default", "id"]); + return {id: ccId}; +} + +function getDataElementsMetadata(db, sourceData, categoriesMetadata) { + const dataElementsMetadata = flattenPayloads(toKeyList(sourceData, "dataElements").map(dataElement => { + if (dataElement.$byAntigen) { + const dataElements = toKeyList(sourceData, "antigens").map(antigen => { + const dataElementInterpolated = interpolateObj(dataElement, {antigen}); + + return db.get("dataElements", { + ...dataElement, + key: `${dataElement.key}-${antigen.key}`, + name: `${dataElement.name} - ${antigen.name}`, + shortName: `${antigen.shortName || antigen.name} ${dataElement.shortName || dataElement.name}`, + code: `${dataElement.code}_${antigen.code}`, + domainType: "AGGREGATE", + aggregationType: "SUM", + categoryCombo: getCategoryComboId(db, categoriesMetadata, dataElementInterpolated), + $antigen: antigen, + }, {antigen}); + }); + + const dataElementGroup = db.get("dataElementGroups", { + name: dataElement.name, + key: dataElement.key, + dataElements: getIds(dataElements), + }); + + return {dataElementGroups: [dataElementGroup], dataElements}; + } else { + const dataElementDb = db.get("dataElements", { + shortName: dataElement.shortName || dataElement.name, + domainType: "AGGREGATE", + aggregationType: "SUM", + categoryCombo: getCategoryComboId(db, categoriesMetadata, dataElement), + ...dataElement, + }); + + return {dataElements: [dataElementDb]}; + } + })); + + const dataElementGroupsForAntigens = _(dataElementsMetadata.dataElements) + .filter("$antigen") + .groupBy(dataElement => dataElement.$antigen.key) + .map((dataElementsForAntigen, antigenKey) => { + const antigen = sourceData.antigens[antigenKey]; + return db.get("dataElementGroups", { + name: antigen.name, + key: antigenKey, + code: antigen.code, + dataElements: getIds(dataElementsForAntigen), + }); + }) + .value(); + + const dataElementGroupSet = db.get("dataElementGroupSets", { + key: "reactive-vaccination", + name: "Reactive Vaccination", + dataDimension: false, + dataElementGroups: getIds(dataElementsMetadata.dataElementGroups), + }); + + return flattenPayloads([ + dataElementsMetadata, + { + dataElementGroups: dataElementGroupsForAntigens, + dataElementGroupSets: [dataElementGroupSet], + }, + ]); +} + +function getIndicatorsMetadata(db, sourceData, dataElementsMetadata) { + const indicatorTypesByKey = _(toKeyList(sourceData, "indicatorTypes")) + .map(indicatorType => db.get("indicatorTypes", indicatorType)) + .keyBy("key") + .value(); + + const namespace = { + dataElements: _.keyBy(dataElementsMetadata.dataElements, "key"), + dataElementGroups: _.keyBy(dataElementsMetadata.dataElementGroups, "key"), + }; + + const indicatorsMetadata = flattenPayloads(toKeyList(sourceData, "indicators").map(indicator => { + if (indicator.$byAntigen) { + const indicators = toKeyList(sourceData, "antigens").map(antigen => { + return getIndicator(db, indicatorTypesByKey, {...namespace, antigen}, { + ...indicator, + key: `${indicator.key}-${antigen.key}`, + name: `${indicator.name} - ${antigen.name}`, + shortName: `${antigen.shortName || antigen.name} ${indicator.shortName || indicator.name}`, + code: `${indicator.code}_${antigen.code}`, + domainType: "AGGREGATE", + aggregationType: "SUM", + }); + }); + + const indicatorGroup = db.get("indicatorGroups", { + name: indicator.name, + indicators: getIds(indicators), + }); + + return {indicatorGroups: [indicatorGroup], indicators: indicators}; + } else { + const indicatorDb = getIndicator(db, indicatorTypesByKey, namespace, { + shortName: indicator.shortName || indicator.name, + domainType: "AGGREGATE", + aggregationType: "SUM", + ...indicator, + }); + + return {indicators: [indicatorDb]}; + } + })); + + const indicatorGroupSet = db.get("indicatorGroupSets", { + key: "reactive-vaccination", + name: "Reactive Vaccination", + indicatorGroups: getIds(indicatorsMetadata.indicatorGroups), + }); + + const groupsMetadata = { + indicatorGroupSets: [indicatorGroupSet], + indicatorTypes: _.values(indicatorTypesByKey), + }; + + return flattenPayloads([indicatorsMetadata, groupsMetadata]); +} + +function getCategoriesMetadata(sourceData, db, categoriesAntigensMetadata) { + const customMetadata = flattenPayloads(toKeyList(sourceData, "categories").map(attributes => { + const categoryOptions = get(attributes, "$categoryOptions").map(name => { + return db.get("categoryOptions", { + name: name, + shortName: name, + }); + }); + + const category = db.get("categories", { + dataDimensionType: "DISAGGREGATION", + dimensionType: "CATEGORY", + dataDimension: false, + categoryOptions: getIds(categoryOptions), + ...attributes, + }); + + const categoryCombo = db.get("categoryCombos", { + key: attributes.key, + name: attributes.name, + code: attributes.code, + dataDimensionType: attributes.dataDimensionType || "DISAGGREGATION", + categories: getIds([category]), + }); + + return { + categories: [category], + categoryOptions, + categoryCombos: [categoryCombo], + }; + })); + + const payload = flattenPayloads([categoriesAntigensMetadata, customMetadata]); + + const categoryCombos = _(toKeyList(sourceData, "categoryCombos")).flatMap(categoryCombo => { + const categoryCombos = categoryCombo.$byAntigen + ? toKeyList(sourceData, "antigens").map(antigen => interpolateObj(categoryCombo, { antigen })) + : [categoryCombo]; + + return categoryCombos.map(categoryCombo => { + const categoriesForCatCombo = + _(payload.categories).keyBy("key").at(categoryCombo.$categories).value(); + + return db.get("categoryCombos", { + dataDimensionType: "DISAGGREGATION", + categories: getIds(categoriesForCatCombo), + ...categoryCombo, + }); + }); + }).value(); + + return flattenPayloads([payload, {categoryCombos}]); +} + +/* Public interface */ + +/* Return JSON payload metadata from source data for a specific DHIS2 instance */ +async function getPayload(url, sourceData) { + const db = await Db.init(url, {models}); + return getPayloadFromDb(db, sourceData); +} + +/* POST JSON payload metadata to a DHIS2 instance */ +async function postPayload(url, payload, {updateCOCs = false} = {}) { + const db = await Db.init(url); + const responseJson = await db.postMetadata(payload); + + if (responseJson.status === "OK" && updateCOCs) { + debug("Update category option combinations"); + /* + const res = await db.updateCOCs(); + if (res.status < 200 || res.status > 299) { + throw `Error upding category option combo: ${inspect(res)}`; + } + */ + } + return responseJson; +} + +module.exports = {getPayload, postPayload}; diff --git a/src/utils.js b/src/utils.js new file mode 100644 index 0000000..3eb2216 --- /dev/null +++ b/src/utils.js @@ -0,0 +1,73 @@ +const util = require("util"); +const _ = require("lodash"); +const fp = require("lodash/fp"); + +function output(s) { + process.stdout.write(s + "\n"); +} + +function debug(s) { + process.stderr.write(s + "\n"); +} + +function debugInspect(obj) { + debug(inspect(obj)); +} + +function repeat(value, n) { + return _.flatten(_.times(n, _.constant([value]))); +} + +function base64Encode(s) { + return Buffer.from(s).toString("base64"); +} + +function inspect(obj) { + return util.inspect(obj, false, null, true); +} + +function get(obj, path, {defaultValue} = {}) { + const value = _.get(obj, path); + + if (_.isUndefined(value)) { + if (_.isUndefined(defaultValue)) { + const pathString = _(path).castArray().join(" -> "); + throw new Error(`No path '${pathString}' in object:\n${inspect(obj)}`); + } else { + return defaultValue; + } + } else { + return value; + } +} + +function interpolate(template, namespace) { + const names = Object.keys(namespace); + const values = Object.values(namespace); + try { + return new Function(...names, `return \`${template}\`;`)(...values); + } catch (err) { + console.error(`Interpolate error.\nTemplate: ${template}`); // eslint-disable-line no-console + throw err; + } +} + +function cartesianProduct(...rest) { + return fp.reduce((a, b) => + fp.flatMap(x => + fp.map(y => x.concat([y]))(b) + )(a) + )([[]])(rest); +} + +module.exports = { + output, + debug, + debugInspect, + repeat, + base64Encode, + inspect, + interpolate, + get, + cartesianProduct, +}; diff --git a/yarn.lock b/yarn.lock new file mode 100644 index 0000000..d7abf68 --- /dev/null +++ b/yarn.lock @@ -0,0 +1,1033 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@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.2.2": + version "7.2.2" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.2.2.tgz#18c816c70962640eab42fe8cae5f3947a5c65ccc" + integrity sha512-I4o675J/iS8k+P38dvJ3IBGqObLXyQLTxtrR4u9cSUJOURvafeEWb/pFMOTwtNrmq73mJzyF6ueTbO1BtN0Zeg== + dependencies: + "@babel/types" "^7.2.2" + jsesc "^2.5.1" + lodash "^4.17.10" + 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.0.0": + version "7.0.0" + resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.0.0.tgz#3aae285c0311c2ab095d997b8c9a94cad547d813" + integrity sha512-MXkOJqva62dfC0w85mEf/LucPPS/1+04nmmRMPEBUB++hiiThQ2zPtX/mEWQ3mtzCEjIJvPY8nuwxXtQeQwUag== + dependencies: + "@babel/types" "^7.0.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.2.2", "@babel/parser@^7.2.3": + version "7.2.3" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.2.3.tgz#32f5df65744b70888d17872ec106b02434ba1489" + integrity sha512-0LyEcVlfCoFmci8mXx8A5oIkpkOgyo8dRHtxBnK9RRBwxO2+JZPNsqtVEZQ7mJFPxnXF9lfmU24mHOPI0qnlkA== + +"@babel/template@^7.1.0": + version "7.2.2" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.2.2.tgz#005b3fdf0ed96e88041330379e0da9a708eb2907" + integrity sha512-zRL0IMM02AUDwghf5LMSSDEz7sBCO2YnNmpg3uWTZj/v1rcG2BmQUvaGU8GhU8BvfMh1k2KIAYZ7Ji9KXPUg7g== + dependencies: + "@babel/code-frame" "^7.0.0" + "@babel/parser" "^7.2.2" + "@babel/types" "^7.2.2" + +"@babel/traverse@^7.0.0": + version "7.2.3" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.2.3.tgz#7ff50cefa9c7c0bd2d81231fdac122f3957748d8" + integrity sha512-Z31oUD/fJvEWVR0lNZtfgvVt512ForCTNKYcJBGbPb1QZfve4WGH8Wsy7+Mev33/45fhP/hwQtvgusNdcCMgSw== + dependencies: + "@babel/code-frame" "^7.0.0" + "@babel/generator" "^7.2.2" + "@babel/helper-function-name" "^7.1.0" + "@babel/helper-split-export-declaration" "^7.0.0" + "@babel/parser" "^7.2.3" + "@babel/types" "^7.2.2" + debug "^4.1.0" + globals "^11.1.0" + lodash "^4.17.10" + +"@babel/types@^7.0.0", "@babel/types@^7.2.2": + version "7.2.2" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.2.2.tgz#44e10fc24e33af524488b716cdaee5360ea8ed1e" + integrity sha512-fKCuD6UFUMkR541eDWL+2ih/xFZBXPOg/7EQFeTluMDebfqR4jrpaCjLhkWlQS4hT6nRa2PMEgXKbRB5/H2fpg== + dependencies: + esutils "^2.0.2" + lodash "^4.17.10" + to-fast-properties "^2.0.0" + +acorn-jsx@^5.0.0: + version "5.0.1" + resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.0.1.tgz#32a064fd925429216a09b141102bfdd185fae40e" + integrity sha512-HJ7CfNHrfJLlNTzIEUTj43LNWGkqpRLxm3YjAlcD0ACydk9XynzYsCBHxut+iqt+1aBXkx9UP/w/ZqMr13XIzg== + +acorn@^6.0.2: + version "6.0.4" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.0.4.tgz#77377e7353b72ec5104550aa2d2097a2fd40b754" + integrity sha512-VY4i5EKSKkofY2I+6QLTbTTN/UvEQPCo6eiwzzSaSWfpaDhOmStMCMod6wmuPciNq+XS0faCglFu2lHZpdHUtg== + +ajv@^6.5.3, ajv@^6.6.1: + version "6.6.2" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.6.2.tgz#caceccf474bf3fc3ce3b147443711a24063cc30d" + integrity sha512-FBHEW6Jf5TB9MGBgUUA9XHkTbjXYfAUjY43ACMfmdMRHniyoMHjHjzD50OK8LGDWQwp4rWEsIq5kEqq7rvIM1g== + 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" + +ansi-escapes@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-3.1.0.tgz#f73207bb81207d75fd6c83f125af26eea378ca30" + integrity sha512-UgAb8H9D41AQnu/PbWlCofQVcnV4Gs2bBJi9eZPxfU/hgglFh3SMDMENRIqdr7H6XFnXdoknctFByVsCOotTVw== + +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.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.0.0.tgz#70de791edf021404c3fd615aa89118ae0432e5a9" + integrity sha512-iB5Dda8t/UqpPI/IjsejXu5jOGDrzn41wJyljwPH65VCIbk6+1BzFIMJGFwTNrYXT1CrD+B4l19U7awiQ8rk7w== + +ansi-styles@^3.2.0, ansi-styles@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" + integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== + dependencies: + color-convert "^1.9.0" + +argparse@^1.0.10, 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" + +array-includes@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.0.3.tgz#184b48f62d92d7452bb31b323165c7f8bd02266d" + integrity sha1-GEtI9i2S10UrsxsyMWXH+L0CJm0= + dependencies: + define-properties "^1.1.2" + es-abstract "^1.7.0" + +astral-regex@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-1.0.0.tgz#6c8c3fb827dd43ee3918f27b82782ab7658a6fd9" + integrity sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg== + +babel-eslint@^10.0.1: + version "10.0.1" + resolved "https://registry.yarnpkg.com/babel-eslint/-/babel-eslint-10.0.1.tgz#919681dc099614cd7d31d45c8908695092a1faed" + integrity sha512-z7OT1iNV+TjOwHNLLyJk+HN+YVWX+CLE6fPD2SymJZOZQBs+QIexFjhm4keGTm8MW9xr4EC9Q0PbaLB24V5GoQ== + dependencies: + "@babel/code-frame" "^7.0.0" + "@babel/parser" "^7.0.0" + "@babel/traverse" "^7.0.0" + "@babel/types" "^7.0.0" + eslint-scope "3.7.1" + eslint-visitor-keys "^1.0.0" + +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= + +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" + +caller-path@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/caller-path/-/caller-path-0.1.0.tgz#94085ef63581ecd3daa92444a8fe94e82577751f" + integrity sha1-lAhe9jWB7NPaqSREqP6U6CV3dR8= + dependencies: + callsites "^0.2.0" + +callsites@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/callsites/-/callsites-0.2.0.tgz#afab96262910a7f33c19a5775825c69f34e350ca" + integrity sha1-r6uWJikQp/M8GaV3WCXGnzTjUMo= + +chalk@^2.0.0, chalk@^2.1.0: + version "2.4.1" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.1.tgz#18c49ab16a037b6eb0152cc83e3471338215b66e" + integrity sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ== + 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== + +charenc@~0.0.1: + version "0.0.2" + resolved "https://registry.yarnpkg.com/charenc/-/charenc-0.0.2.tgz#c0a1d2f3a7092e03774bfa83f14c0fc5790a8667" + integrity sha1-wKHS86cJLgN3S/qD8UwPxXkKhmc= + +circular-json@^0.3.1: + version "0.3.3" + resolved "https://registry.yarnpkg.com/circular-json/-/circular-json-0.3.3.tgz#815c99ea84f6809529d2f45791bdf82711352d66" + integrity sha512-UZK3NBx2Mca+b5LsG7bY183pHWt5Y1xts4P3Pz7ENTwGVnJOUWbRb3ocjvX7hx9tq/yTAdclXm9sZ38gNuem4A== + +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= + +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= + +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= + +cross-spawn@^6.0.5: + version "6.0.5" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" + integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ== + dependencies: + nice-try "^1.0.4" + path-key "^2.0.1" + semver "^5.5.0" + shebang-command "^1.2.0" + which "^1.2.9" + +crypt@~0.0.1: + version "0.0.2" + resolved "https://registry.yarnpkg.com/crypt/-/crypt-0.0.2.tgz#88d7ff7ec0dfb86f713dc87bbb42d044d3e6c41b" + integrity sha1-iNf/fsDfuG9xPch7u0LQRNPmxBs= + +debug@^4.0.1, debug@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.0.tgz#373687bffa678b38b1cd91f861b63850035ddc87" + integrity sha512-heNPJUJIqC+xB6ayLAMHaIrmN9HKa7aQO8MGqKpvCA+uJYVcvR6l5kgdrhRuwPFHU7P5/A1w0BjByPHwpfTDKg== + dependencies: + ms "^2.1.1" + +deep-is@~0.1.3: + version "0.1.3" + resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" + integrity sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ= + +define-properties@^1.1.2: + version "1.1.3" + resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1" + integrity sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ== + dependencies: + object-keys "^1.0.12" + +doctrine@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.1.0.tgz#5cd01fc101621b42c4cd7f5d1a66243716d3f39d" + integrity sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw== + dependencies: + esutils "^2.0.2" + +es-abstract@^1.7.0: + version "1.12.0" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.12.0.tgz#9dbbdd27c6856f0001421ca18782d786bf8a6165" + integrity sha512-C8Fx/0jFmV5IPoMOFPA9P9G5NtqW+4cOPit3MIuvR2t7Ag2K15EJTpxnHAYTzL+aYQJIESYeXZmDBfOBE1HcpA== + dependencies: + es-to-primitive "^1.1.1" + function-bind "^1.1.1" + has "^1.0.1" + is-callable "^1.1.3" + is-regex "^1.0.4" + +es-to-primitive@^1.1.1: + version "1.2.0" + resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.0.tgz#edf72478033456e8dda8ef09e00ad9650707f377" + integrity sha512-qZryBOJjV//LaxLTV6UC//WewneB3LcXOL9NP++ozKVXsIIIpm/2c13UDiD9Jp2eThsecw9m3jPqDwTyobcdbg== + dependencies: + is-callable "^1.1.4" + is-date-object "^1.0.1" + is-symbol "^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-plugin-react@^7.11.1: + version "7.11.1" + resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.11.1.tgz#c01a7af6f17519457d6116aa94fc6d2ccad5443c" + integrity sha512-cVVyMadRyW7qsIUh3FHp3u6QHNhOgVrLQYdQEB1bPWBsgbNCHdFAeNMquBMCcZJu59eNthX053L70l7gRt4SCw== + dependencies: + array-includes "^3.0.3" + doctrine "^2.1.0" + has "^1.0.3" + jsx-ast-utils "^2.0.1" + prop-types "^15.6.2" + +eslint-scope@3.7.1: + version "3.7.1" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-3.7.1.tgz#3d63c3edfda02e06e01a452ad88caacc7cdcb6e8" + integrity sha1-PWPD7f2gLgbgGkUq2IyqzHzctug= + dependencies: + esrecurse "^4.1.0" + estraverse "^4.1.1" + +eslint-scope@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-4.0.0.tgz#50bf3071e9338bcdc43331794a0cb533f0136172" + integrity sha512-1G6UTDi7Jc1ELFwnR58HV4fK9OQK4S6N985f166xqXxpjU6plxFISJa2Ba9KCQuFa8RCnj/lSFJbHo7UFDBnUA== + dependencies: + esrecurse "^4.1.0" + estraverse "^4.1.1" + +eslint-utils@^1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-1.3.1.tgz#9a851ba89ee7c460346f97cf8939c7298827e512" + integrity sha512-Z7YjnIldX+2XMcjr7ZkgEsOj/bREONV60qYeB/bjMAqqqZ4zxKyWX+BOUkdmRmA9riiIPVvo5x86m5elviOk0Q== + +eslint-visitor-keys@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz#3f3180fb2e291017716acb4c9d6d5b5c34a6a81d" + integrity sha512-qzm/XxIbxm/FHyH341ZrbnMUpe+5Bocte9xkmFMzPMjRaZMcXww+MpBptFvtU+79L362nqiLhekCxCxDPaUMBQ== + +eslint@^5.10.0: + version "5.10.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-5.10.0.tgz#24adcbe92bf5eb1fc2d2f2b1eebe0c5e0713903a" + integrity sha512-HpqzC+BHULKlnPwWae9MaVZ5AXJKpkxCVXQHrFaRw3hbDj26V/9ArYM4Rr/SQ8pi6qUPLXSSXC4RBJlyq2Z2OQ== + dependencies: + "@babel/code-frame" "^7.0.0" + ajv "^6.5.3" + chalk "^2.1.0" + cross-spawn "^6.0.5" + debug "^4.0.1" + doctrine "^2.1.0" + eslint-scope "^4.0.0" + eslint-utils "^1.3.1" + eslint-visitor-keys "^1.0.0" + espree "^5.0.0" + esquery "^1.0.1" + esutils "^2.0.2" + file-entry-cache "^2.0.0" + functional-red-black-tree "^1.0.1" + glob "^7.1.2" + globals "^11.7.0" + ignore "^4.0.6" + imurmurhash "^0.1.4" + inquirer "^6.1.0" + js-yaml "^3.12.0" + json-stable-stringify-without-jsonify "^1.0.1" + levn "^0.3.0" + lodash "^4.17.5" + minimatch "^3.0.4" + mkdirp "^0.5.1" + natural-compare "^1.4.0" + optionator "^0.8.2" + path-is-inside "^1.0.2" + pluralize "^7.0.0" + progress "^2.0.0" + regexpp "^2.0.1" + require-uncached "^1.0.3" + semver "^5.5.1" + strip-ansi "^4.0.0" + strip-json-comments "^2.0.1" + table "^5.0.2" + text-table "^0.2.0" + +espree@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/espree/-/espree-5.0.0.tgz#fc7f984b62b36a0f543b13fb9cd7b9f4a7f5b65c" + integrity sha512-1MpUfwsdS9MMoN7ZXqAr9e9UKdVHDcvrJpyx7mm1WuQlx/ygErEQBzgi5Nh5qBHIoYweprhtMkTCb9GhcAIcsA== + dependencies: + acorn "^6.0.2" + acorn-jsx "^5.0.0" + eslint-visitor-keys "^1.0.0" + +esprima@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" + integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== + +esquery@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.0.1.tgz#406c51658b1f5991a5f9b62b1dc25b00e3e5c708" + integrity sha512-SmiyZ5zIWH9VM+SRUReLS5Q8a7GxtRdxEBVZpm98rJM7Sb+A9DVCndXfkeFUd3byderg+EbDkfnevfCwynWaNA== + dependencies: + estraverse "^4.0.0" + +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.0.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= + +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" + +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: + 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= + +fast-levenshtein@~2.0.4: + version "2.0.6" + resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" + integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc= + +figures@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/figures/-/figures-2.0.0.tgz#3ab1a2d2a62c8bfb431a0c94cb797a2fce27c962" + integrity sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI= + dependencies: + escape-string-regexp "^1.0.5" + +file-entry-cache@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-2.0.0.tgz#c392990c3e684783d838b8c84a45d8a048458361" + integrity sha1-w5KZDD5oR4PYOLjISkXYoEhFg2E= + dependencies: + flat-cache "^1.2.1" + object-assign "^4.0.1" + +flat-cache@^1.2.1: + version "1.3.4" + resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-1.3.4.tgz#2c2ef77525cc2929007dfffa1dd314aa9c9dee6f" + integrity sha512-VwyB3Lkgacfik2vhqR4uv2rvebqmDvFu4jlN/C1RzWoJEo8I7z4Q404oiqYCkq41mni8EzQnm95emU9seckwtg== + dependencies: + circular-json "^0.3.1" + graceful-fs "^4.1.2" + rimraf "~2.6.2" + write "^0.2.1" + +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= + +function-bind@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" + integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== + +functional-red-black-tree@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" + integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc= + +glob@^7.0.5, glob@^7.1.2: + 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, globals@^11.7.0: + version "11.9.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-11.9.0.tgz#bde236808e987f290768a93d065060d78e6ab249" + integrity sha512-5cJVtyXWH8PiJPVLZzzoIizXx944O4OmRro5MWKx5fT4MgcN7OfaMutPeaTdJCCURwbWdhhcCWcKIffPnmTzBg== + +graceful-fs@^4.1.2: + 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== + +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-symbols@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.0.tgz#ba1a8f1af2a0fc39650f5c850367704122063b44" + integrity sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q= + +has@^1.0.1, has@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" + integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== + dependencies: + function-bind "^1.1.1" + +iconv-lite@^0.4.24: + version "0.4.24" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" + integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== + dependencies: + safer-buffer ">= 2.1.2 < 3" + +ignore@^4.0.6: + version "4.0.6" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" + integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg== + +imurmurhash@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" + integrity sha1-khi5srkoojixPcT7a21XbyMUU+o= + +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: + version "2.0.3" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" + integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= + +inquirer@^6.1.0: + 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" + +is-buffer@~1.1.1: + version "1.1.6" + resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" + integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== + +is-callable@^1.1.3, is-callable@^1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.1.4.tgz#1e1adf219e1eeb684d691f9d6a05ff0d30a24d75" + integrity sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA== + +is-date-object@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.1.tgz#9aa20eb6aeebbff77fbd33e74ca01b33581d3a16" + integrity sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY= + +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-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-regex@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.0.4.tgz#5517489b547091b0930e095654ced25ee97e9491" + integrity sha1-VRdIm1RwkbCTDglWVM7SXul+lJE= + dependencies: + has "^1.0.1" + +is-symbol@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.2.tgz#a055f6ae57192caee329e7a860118b497a950f38" + integrity sha512-HS8bZ9ox60yCJLH9snBpIwv9pYUAkcuLhSA1oero1UB5y9aiQpRA8y2ex945AOtCZL1lJDeIk3G5LthswI46Lw== + dependencies: + has-symbols "^1.0.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= + +"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-yaml@^3.12.0: + version "3.12.0" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.12.0.tgz#eaed656ec8344f10f527c6bfa1b6e2244de167d1" + integrity sha512-PIt2cnwmPfL4hKNwqeiuz4bKfnzHTBv6HyVgjahA6mPLwPDzjDWrplJBMjHUFxku/N3FlmrbyPclad+I+4mJ3A== + dependencies: + argparse "^1.0.7" + esprima "^4.0.0" + +jsesc@^2.5.1: + version "2.5.2" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" + integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== + +json-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-stable-stringify-without-jsonify@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" + integrity sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE= + +jsx-ast-utils@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-2.0.1.tgz#e801b1b39985e20fffc87b40e3748080e2dcac7f" + integrity sha1-6AGxs5mF4g//yHtA43SAgOLcrH8= + dependencies: + array-includes "^3.0.3" + +levn@^0.3.0, levn@~0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" + integrity sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4= + dependencies: + prelude-ls "~1.1.2" + type-check "~0.3.2" + +lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.5: + version "4.17.11" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.11.tgz#b39ea6229ef607ecd89e2c8df12536891cac9b8d" + integrity sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg== + +loose-envify@^1.3.1: + 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" + +md5@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/md5/-/md5-2.2.1.tgz#53ab38d5fe3c8891ba465329ea23fac0540126f9" + integrity sha1-U6s41f48iJG6RlMp6iP6wFQBJvk= + dependencies: + charenc "~0.0.1" + crypt "~0.0.1" + is-buffer "~1.1.1" + +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== + +minimatch@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" + integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== + dependencies: + brace-expansion "^1.1.7" + +minimist@0.0.8: + version "0.0.8" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" + integrity sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0= + +mkdirp@^0.5.1: + 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" + +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== + +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= + +natural-compare@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" + integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc= + +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@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.3.0.tgz#1a1d940bbfb916a1d3e0219f037e89e71f8c5fa5" + integrity sha512-MOd8pV3fxENbryESLgVIeaGKrdl+uaYhCSSVkjeOb/31/njTpcis5aWfdqgNlHIrKOLRbMnfPINPOML2CIFeXA== + +object-assign@^4.0.1, object-assign@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" + integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= + +object-keys@^1.0.12: + version "1.0.12" + resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.0.12.tgz#09c53855377575310cca62f55bb334abff7b3ed2" + integrity sha512-FTMyFUm2wBcGHnH2eXmz7tC6IwlqQZ6mVZ+6dm6vZ4IQIHjs6FdNsQBuKGPuUUUY6NfJw2PshC08Tn6LzLDOag== + +once@^1.3.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" + +optionator@^0.8.2: + version "0.8.2" + resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.2.tgz#364c5e409d3f4d6301d6c0b4c05bba50180aeb64" + integrity sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q= + dependencies: + deep-is "~0.1.3" + fast-levenshtein "~2.0.4" + levn "~0.3.0" + prelude-ls "~1.1.2" + type-check "~0.3.2" + wordwrap "~1.0.0" + +os-tmpdir@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" + integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ= + +p-map@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/p-map/-/p-map-2.0.0.tgz#be18c5a5adeb8e156460651421aceca56c213a50" + integrity sha512-GO107XdrSUmtHxVoi60qc9tUl/KkNKm+X2CF4P9amalpGxv5YqVPJNfSb0wcA+syCopkZvYYIzW8OVTQW59x/w== + +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= + +path-is-inside@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53" + integrity sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM= + +path-key@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" + integrity sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A= + +pluralize@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-7.0.0.tgz#298b89df8b93b0221dbf421ad2b1b1ea23fc6777" + integrity sha512-ARhBOdzS3e41FbkW/XWrTEtukqqLoK5+Z/4UeDaLuSW+39JPeFgs4gCGqsrJHVZX0fUrx//4OF0K1CUGwlIFow== + +prelude-ls@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" + integrity sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ= + +progress@^2.0.0: + version "2.0.3" + resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" + integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== + +prop-types@^15.6.2: + version "15.6.2" + resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.6.2.tgz#05d5ca77b4453e985d60fc7ff8c859094a497102" + integrity sha512-3pboPvLiWD7dkI3qf3KbUe6hKFKa52w+AE0VCqECtf+QHAKgOL37tTaNCnuX1nAAQ4ZhyP+kYVKf8rLmJ/feDQ== + dependencies: + loose-envify "^1.3.1" + object-assign "^4.1.1" + +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== + +regexpp@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-2.0.1.tgz#8d19d31cf632482b589049f8281f93dbcba4d07f" + integrity sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw== + +require-uncached@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/require-uncached/-/require-uncached-1.0.3.tgz#4e0d56d6c9662fd31e43011c4b95aa49955421d3" + integrity sha1-Tg1W1slmL9MeQwEcS5WqSZVUIdM= + dependencies: + caller-path "^0.1.0" + resolve-from "^1.0.0" + +resolve-from@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-1.0.1.tgz#26cbfe935d1aeeeabb29bc3fe5aeb01e93d44226" + integrity sha1-Jsv+k10a7uq7Kbw/5a6wHpPUQiY= + +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" + +rimraf@~2.6.2: + version "2.6.2" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.2.tgz#2ed8150d24a16ea8651e6d6ef0f47c4158ce7a36" + integrity sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w== + dependencies: + glob "^7.0.5" + +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" + +rxjs@^6.1.0: + 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" + +"safer-buffer@>= 2.1.2 < 3": + version "2.1.2" + resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" + integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== + +semver@^5.5.0, semver@^5.5.1: + version "5.6.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.6.0.tgz#7e74256fbaa49c75aa7c7a205cc22799cac80004" + integrity sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg== + +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= + +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= + +slice-ansi@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-2.0.0.tgz#5373bdb8559b45676e8541c66916cdd6251612e7" + integrity sha512-4j2WTWjp3GsZ+AOagyzVbzp4vWGtZ0hEZ/gDY/uTvm6MTxUfTUIsnMIFb1bn8o0RuXiqUw15H1bue8f22Vw2oQ== + dependencies: + ansi-styles "^3.2.0" + astral-regex "^1.0.0" + is-fullwidth-code-point "^2.0.0" + +source-map@^0.5.0: + version "0.5.7" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" + integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= + +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= + +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" + +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.0.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.0.0.tgz#f78f68b5d0866c20b2c9b8c61b5298508dc8756f" + integrity sha512-Uu7gQyZI7J7gn5qLn1Np3G9vcYGTVqB+lFTytnDJv83dd8T22aGH451P3jueT2/QemInJDfxHB5Tde5OzgG1Ow== + dependencies: + ansi-regex "^4.0.0" + +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= + +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" + +table@^5.0.2: + version "5.1.1" + resolved "https://registry.yarnpkg.com/table/-/table-5.1.1.tgz#92030192f1b7b51b6eeab23ed416862e47b70837" + integrity sha512-NUjapYb/qd4PeFW03HnAuOJ7OMcBkJlqeClWxeNlQ0lXGSb52oZXGzkO0/I0ARegQ2eUT1g2VDJH0eUxDRcHmw== + dependencies: + ajv "^6.6.1" + lodash "^4.17.11" + slice-ansi "2.0.0" + string-width "^2.1.1" + +text-table@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" + integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ= + +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= + +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-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= + +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= + +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== + +type-check@~0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" + integrity sha1-WITKtRLPHTVeP7eE8wgEsrUg23I= + dependencies: + prelude-ls "~1.1.2" + +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" + +which@^1.2.9: + version "1.3.1" + resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" + integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== + dependencies: + isexe "^2.0.0" + +wordwrap@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" + integrity sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus= + +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= + +write@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/write/-/write-0.2.1.tgz#5fc03828e264cea3fe91455476f7a3c566cb0757" + integrity sha1-X8A4KOJkzqP+kUVUdvejxWbLB1c= + dependencies: + mkdirp "^0.5.1"