├── .circleci └── config.yml ├── .dockerignore ├── .gitignore ├── .npmignore ├── Dockerfile ├── README.md ├── package-lock.json ├── package.json ├── src ├── SimpleQueryStrategy.js ├── Strategy.js ├── datasource │ └── MockData.js ├── index.js ├── read-strategy │ ├── AggregateReadStrategy.js │ ├── LongPathReadStrategy.js │ ├── MetadataReadStrategy.js │ └── RandomAccessReadStrategy.js ├── run-configuration.js ├── run-workload.js ├── schemas │ └── users.json ├── sessionPool.js ├── stats │ ├── ProbabilityTable.js │ └── index.js ├── strategies.js ├── termination-condition.js ├── workload.js ├── workloads │ ├── all-reads.json │ ├── all-writes.json │ ├── mixed.json │ ├── nary-only.json │ └── rac.json └── write-strategy │ ├── FatNodeAppendStrategy.js │ ├── IndexHeavyStrategy.js │ ├── LockTortureStrategy.js │ ├── LuceneWriteStrategy.js │ ├── MergeWriteStrategy.js │ ├── NAryTreeStrategy.js │ ├── RandomLinkageStrategy.js │ ├── RawWriteStrategy.js │ ├── StarWriteStrategy.js │ └── WritePropertyDataStrategy.js ├── stress-testing.yaml ├── test ├── SimpleQueryStrategy_test.js ├── Strategy_test.js ├── datasource │ └── MockData_test.js ├── index_test.js ├── mocks.js ├── read-strategy │ └── read-strategy_test.js ├── run-configuration_test.js ├── sessionPool_test.js ├── stats │ ├── ProbabilityTable_test.js │ └── index_test.js ├── strategies_test.js ├── termination-condition_test.js ├── test.js ├── workload_test.js └── write-strategy │ └── write-strategy_test.js └── yarn.lock /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | jobs: 3 | build: 4 | working_directory: ~/graph-workload 5 | docker: 6 | - image: circleci/node:10-browsers-legacy 7 | steps: 8 | - checkout 9 | - setup_remote_docker 10 | - restore_cache: 11 | name: Restore Yarn Package Cache 12 | keys: 13 | - yarn-packages-{{ checksum "yarn.lock" }} 14 | - run: 15 | name: Install Dependencies 16 | command: yarn install --frozen-lockfile 17 | - save_cache: 18 | name: Save Yarn Package Cache 19 | key: yarn-packages-{{ checksum "yarn.lock" }} 20 | paths: 21 | - ~/.cache/yarn 22 | - run: 23 | name: test 24 | command: yarn run test 25 | - run: 26 | name: Build Docker Container 27 | command: docker build -t mdavidallen/graph-workload:latest -f Dockerfile . 28 | - run: 29 | name: Deploy to Docker Hub 30 | command: | 31 | docker login -u $DOCKER_USERNAME -p $DOCKER_PASSWORD 32 | if [ "${CIRCLE_BRANCH}" = "master" ]; then 33 | echo "Pushing docker image" 34 | docker push mdavidallen/graph-workload:latest 35 | else 36 | echo "Not deploying; not master branch." 37 | fi 38 | - store_artifacts: 39 | path: test-results.xml 40 | prefix: tests 41 | - store_artifacts: 42 | path: coverage 43 | prefix: coverage 44 | - store_test_results: 45 | path: test-results.xml -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .DS_Store 3 | .nyc_output 4 | coverage 5 | experiments 6 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | experiments 2 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:9-alpine 2 | MAINTAINER David Allen 3 | RUN mkdir /app 4 | COPY . /app 5 | RUN cd app && npm install 6 | ENV NEO4J_URI "bolt://localhost" 7 | ENV NEO4J_USER "neo4j" 8 | ENV NEO4J_PASSWORD "neo4j" 9 | ENV CONCURRENCY "10" 10 | 11 | WORKDIR /app 12 | ENTRYPOINT ["/usr/local/bin/node", "/app/src/run-workload.js"] 13 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Graph Workloads 2 | 3 | [![CircleCI](https://circleci.com/gh/moxious/graph-workload.svg?style=svg)](https://circleci.com/gh/moxious/graph-workload) 4 | 5 | Tools for generating workloads on Neo4j. 6 | 7 | I use this for benchmarking and load testing Neo4j instances. It provides a framework where you 8 | can either design your own mixed read/write workload from strategies provided, or design your own 9 | reads/writes to execute against a database, while keeping track of execution stats. 10 | 11 | You can run workloads timed (i.e. for 5,000 ms) or numbered (i.e. 5,000 runs). 12 | 13 | # Usage 14 | 15 | ``` 16 | Usage: run-workload.js -p password 17 | [-a address] 18 | [-u username] 19 | [-n hits] how many total queries to run 20 | [--ms milliseconds] how many milliseconds to test for 21 | [--workload /path/to/workload.json] probability table spec 22 | [--query CYPHER_QUERY] single cypher query to run 23 | [--schema /path/to/schema.json] schema for generated records (only used with 24 | --query) 25 | [--batchsize [1000]] number of records from schema to generate per batch 26 | [--concurrency c] how many concurrent queries to run (default: 10) 27 | [--checkpoint cn] how often to print results in milliseconds (default: 5000) 28 | [--fail-fast] if specified, the work will stop after encountering one 29 | failure. 30 | 31 | You may only specify one of the options --n or --ms. 32 | You may only specify one of the options --workload or --query 33 | 34 | 35 | Options: 36 | --help Show help [boolean] 37 | --version Show version number [boolean] 38 | -a address to connect to [default: "localhost"] 39 | -u username [default: "neo4j"] 40 | -p password [required] 41 | -d database 42 | --schema batch schema file 43 | --batchsize number of records per batch, usable only with schema 44 | -n number of hits on the database 45 | --ms number of milliseconds to execute 46 | --workload absolute path to JSON probability table/workload 47 | --query Cypher query to run 48 | --concurrency [default: 10] 49 | --checkpoint [default: 5000] 50 | 51 | Examples: 52 | run-workload.js -a localhost -u neo4j -p Run 10 hits on the local database 53 | secret -n 10 54 | ``` 55 | 56 | # Run in Docker 57 | 58 | Simply pass any arguments the command recognizes to the docker container. 59 | 60 | ``` 61 | docker run --tty --interactive mdavidallen/graph-workload:latest -a my-neo4j-host.com -u neo4j -p password 2>&1 62 | ``` 63 | 64 | # Running Stand-Alone from Source 65 | 66 | ``` 67 | yarn install 68 | node src/run-workload.js -a localhost -u neo4j -p password 69 | ``` 70 | 71 | See the `workloads` directory for the format of the probability table. 72 | 73 | You can use the script `npm run graph-workload` as a synonym for running the index.js file, but keep in mind npm requires an extra `--` argument prior to passing 74 | program arguments, as in, `npm run graph-workload -- --n 20` 75 | 76 | # Examples 77 | 78 | ## Create a lot of nodes as fast as possible: 79 | 80 | ``` 81 | npm run graph-workload -- -a localhost -u neo4j -p admin --query 'Unwind range(1,1000000) as id create (n);' -n 50 --concurrency 4 82 | ``` 83 | 84 | ## Write custom data generated in batches 85 | 86 | Fake/mock data can be generated with functions from [fakerjs](https://www.npmjs.com/package/faker). 87 | 88 | Using this technique you can generate your own data and create 89 | custom load patterns. Similar to other Neo4j utilities, the batch will be present in the query form: "UNWIND batch AS event". 90 | 91 | ``` 92 | npm run graph-workload -- -a localhost -u neo4j -p admin \ 93 | --query 'CREATE (t:Test) SET t += event' \ 94 | --batchsize 1000 \ 95 | --schema /absolute/path/to/schemas/myschema.json 96 | ``` 97 | 98 | See `src/schemas/user.json` as an example of a schema you can use in this way. Keys are field names to generate, values are the faker functions used to populate that field. 99 | 100 | ## Explicit Transactions 101 | 102 | If you use the `--query` option, you may also use `--mode READ` or `WRITE`. This enables the program 103 | to use explicit read or write transactions, so that when queries are sent to a cluster, they are routed 104 | appropriately according to the Neo4j routing rules. 105 | 106 | # Neo4j 4.0 / Multidatabase 107 | 108 | As of Neo4j 4.0, sessions support multi-database. Use the `-d` or `--database` argument to direct 109 | where the workload should go. By default, the workload goes to the default database (usually `neo4j`). 110 | 111 | Example: 112 | 113 | ``` 114 | npm run graph-workload -- -a neo4j://my-cluster -u neo4j -p admin -d mydb 115 | ``` 116 | 117 | # Tests 118 | 119 | ``` 120 | yarn run test 121 | ``` 122 | 123 | # Building Graph Workloads as a Docker Container 124 | 125 | ``` 126 | docker build -t mdavidallen/graph-workload:latest -f Dockerfile . 127 | ``` 128 | 129 | # Defining your own Custom Workload 130 | 131 | - Stress tester has a number of 'read strategies' and 'write strategies' 132 | - There is a probability table; the stress tester rolls random numbers and picks a strategy 133 | based on the probability table. 134 | - By tweaking which strategies are available and what their probability is, you can generate 135 | whichever kind of load you like 136 | - You can write a new strategy to simulate any specific kind of load you like. 137 | 138 | See workload.js for details. -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "graph-workload", 3 | "version": "0.5.1", 4 | "description": "Tool for generating workloads running on Neo4j", 5 | "main": "src/run-workload.js", 6 | "scripts": { 7 | "graph-workload": "node src/run-workload.js", 8 | "test": "nyc --reporter=lcov mocha --recursive" 9 | }, 10 | "repository": { 11 | "type": "git", 12 | "url": "https://github.com/moxious/graph-workload.git" 13 | }, 14 | "author": "", 15 | "license": "ISC", 16 | "bugs": { 17 | "url": "https://github.com/moxious/graph-workload.git/issues" 18 | }, 19 | "homepage": "https://github.com/moxious/graph-workload", 20 | "dependencies": { 21 | "bluebird": "^3.7.2", 22 | "dimsum": "^0.2.2", 23 | "es6-promise-pool": "^2.5.0", 24 | "faker": "^4.1.0", 25 | "generic-pool": "^3.6.1", 26 | "lodash": "^4.17.20", 27 | "moment": "^2.27.0", 28 | "neo4j-driver": "^4.1.1", 29 | "randomstring": "^1.1.5", 30 | "uuid": "^3.3.2", 31 | "yargs": "^12.0.5" 32 | }, 33 | "devDependencies": { 34 | "chai": "^4.2.0", 35 | "chai-as-promised": "^7.1.1", 36 | "mocha": "^7.2.0", 37 | "nyc": "^15.1.0", 38 | "sinon": "^7.2.4" 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/SimpleQueryStrategy.js: -------------------------------------------------------------------------------- 1 | const Strategy = require('./Strategy'); 2 | const _ = require('lodash'); 3 | 4 | /** 5 | * Represents a container class for a strategy that is just running some 6 | * simple query with no setup. 7 | */ 8 | module.exports = class SimpleQueryStrategy extends Strategy { 9 | constructor(props) { 10 | super(props); 11 | this.name = props.name || 'SimpleQuery'; 12 | this.query = props.query; 13 | this.params = props.params || {}; 14 | this.generator = props.generator; 15 | this.batchSize = props.batchSize; 16 | 17 | if (!(props.mode === 'READ') && !(props.mode === 'WRITE')) { 18 | throw new Error('Mode must be READ or WRITE'); 19 | } 20 | 21 | this.mode = props.mode; 22 | } 23 | 24 | run() { 25 | const f = (s) => { 26 | const txRunner = tx => { 27 | if (this.generator) { 28 | const batch = this.generator.generate(this.batchSize); 29 | console.log('batchrun with ', batch.length, 'elements'); 30 | return tx.run( 31 | `UNWIND $batch AS event ${this.query}`, 32 | _.merge({ batch }, this.params) 33 | ); 34 | } 35 | return tx.run(this.query, this.params); 36 | }; 37 | 38 | if (this.props.mode === 'READ') { 39 | return s.readTransaction(txRunner); 40 | } 41 | 42 | return s.writeTransaction(txRunner); 43 | }; 44 | 45 | return this.time(f); 46 | } 47 | } -------------------------------------------------------------------------------- /src/Strategy.js: -------------------------------------------------------------------------------- 1 | const uuid = require('uuid'); 2 | const randomstring = require('randomstring'); 3 | const _ = require('lodash'); 4 | 5 | class Strategy { 6 | constructor(props) { 7 | this.name = 'Undefined'; 8 | this.props = props; 9 | this.timings = []; 10 | } 11 | 12 | sessionOptions() { 13 | const opts = {}; 14 | 15 | if (this.props.runConfig && this.props.runConfig.database) { 16 | opts.database = this.props.runConfig.database; 17 | } else if (!this.props.runConfig) { 18 | throw new Error('Strategy initialized without runConfig'); 19 | } 20 | 21 | return opts; 22 | } 23 | 24 | setup(driver) { 25 | this.driver = driver; 26 | return Promise.resolve(true); 27 | } 28 | 29 | getName() { return this.name; } 30 | run() { 31 | return Promise.reject('Override me in subclass'); 32 | } 33 | 34 | randInt(max) { 35 | return Math.floor(Math.random() * Math.floor(max)); 36 | } 37 | 38 | getTimings() { 39 | return this.timings; 40 | } 41 | 42 | countRuns() { return this.getTimings().length; } 43 | 44 | csv() { 45 | const runs = this.timings.length; 46 | const elapsedArr = this.timings.map(t => t.elapsed); 47 | const avgV = elapsedArr.reduce((a, b) => a + b, 0) / runs || 0; 48 | const minV = elapsedArr.reduce((min, p) => p < min ? p : min, elapsedArr[0] || 0); 49 | const maxV = elapsedArr.reduce((max, p) => p > max ? p : max, elapsedArr[0] || 0); 50 | 51 | return [ 52 | this.name, runs, avgV, minV, maxV 53 | ].join(',') + '\n'; 54 | } 55 | 56 | totalTimeSpent() { 57 | const elapsedArr = this.timings.map(t => t.elapsed); 58 | const total = elapsedArr.reduce((a, b) => a + b, 0); 59 | return total; 60 | } 61 | 62 | summarize() { 63 | const runs = this.timings.length; 64 | const elapsedArr = this.timings.map(t => t.elapsed); 65 | const total = this.totalTimeSpent(); 66 | const avgV = total / runs || 0; 67 | const minV = elapsedArr.reduce((min, p) => p < min ? p : min, elapsedArr[0] || 0); 68 | const maxV = elapsedArr.reduce((max, p) => p > max ? p : max, elapsedArr[0] || 0); 69 | 70 | const key = `BENCHMARK_${this.name}`.replace(/strategy/gi, ''); 71 | 72 | console.log(`${key}_ELAPSED=${total}`); 73 | console.log(`${key}_AVG=${avgV}`); 74 | console.log(`${key}_MIN=${minV}`); 75 | console.log(`${key}_MAX=${maxV}`); 76 | console.log(`${key}_RUNS=${runs}`); 77 | console.log(`${this.name}: ${runs} runs avg ${avgV.toFixed(2)} ms min ${minV} ms max ${maxV} ms\n`); 78 | } 79 | 80 | ignore(e, match) { 81 | const str = `${e}`; 82 | 83 | if (str.indexOf(match) > -1) { 84 | return true; 85 | } 86 | 87 | throw e; 88 | } 89 | 90 | time(somePromiseFunc, data={}) { 91 | const start = new Date().getTime(); 92 | 93 | if (!this.props.sessionPool) { 94 | throw new Error('Missing sessionPool'); 95 | } 96 | 97 | const closure = () => { 98 | let s; 99 | 100 | // console.log('Acuquiring from ', this.props.sessionPool); 101 | return this.props.sessionPool.acquire() 102 | .then(session => { 103 | s = session; 104 | return somePromiseFunc(session); 105 | }) 106 | .then(result => { 107 | const end = new Date().getTime(); 108 | const elapsed = end - start; 109 | this.timings.push(_.merge({ elapsed }, data)); 110 | }) 111 | .finally(() => this.props.sessionPool.release(s)); 112 | }; 113 | 114 | return closure(); 115 | } 116 | 117 | randString(len) { 118 | return randomstring.generate(len); 119 | } 120 | } 121 | 122 | module.exports = Strategy; -------------------------------------------------------------------------------- /src/datasource/MockData.js: -------------------------------------------------------------------------------- 1 | const _ = require('lodash'); 2 | const faker = require('faker'); 3 | 4 | class MockData { 5 | /** 6 | * Create a mock data source. 7 | * @param {Object} schema a map of field names to data types 8 | */ 9 | constructor(schema) { 10 | this.schema = _.cloneDeep(schema); 11 | this.validateSchema(); 12 | this.columns = Object.keys(schema); 13 | } 14 | 15 | generate(batchSize=1) { 16 | const r = []; 17 | for (let i=0; i this.schema[col]())); 19 | r.push(record); 20 | } 21 | return r; 22 | } 23 | 24 | /** 25 | * Validate that for each schema field, there is a corresponding faker function. 26 | * For example, there is a faker.address.city() function. So if the user specifies 27 | * 'address.city' we will find that function. 28 | * @throws Error when an unidentified function is specified. 29 | */ 30 | validateSchema() { 31 | if (_.isNil(this.schema) || _.isEmpty(this.schema)) { 32 | throw new Error('Empty or invalid schema specified'); 33 | } 34 | 35 | Object.keys(this.schema).forEach(fieldName => { 36 | const val = this.schema[fieldName]; 37 | if (!val) { throw new Error(`Field name ${fieldName} in schema has no specification`); } 38 | const parts = val.split('.'); 39 | 40 | let f = faker; 41 | parts.forEach(part => { 42 | f = f[part]; 43 | if (!f) { 44 | throw new Error(`Invalid schema: Unknown function part '${part}' in field type ${fieldName}`); 45 | } 46 | }); 47 | 48 | // If we've worked through all parts we have our terminal function. 49 | this.schema[fieldName] = f; 50 | }); 51 | } 52 | } 53 | 54 | module.exports = MockData; -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Quick stress testing script to apply lots of concurrent writes to the cluster. 3 | * 4 | * Usage: 5 | * export NEO4J_URI=bolt+routing://localhost 6 | * export NEO4J_USERNAME=neo4j 7 | * export NEO4J_PASSWORD=super-secret 8 | * 9 | * npm install 10 | * 11 | * node stress.js 12 | * 13 | * To customize the workload, consult the probabilityTable. 14 | */ 15 | const strategies = require('./strategies'); 16 | const runConfiguration = require('./run-configuration'); 17 | const _ = require('lodash'); 18 | const Workload = require('./workload'); 19 | 20 | const sigintHandler = workload => { 21 | workload.interrupted = true; 22 | console.log('Caught interrupt. Allowing current batch to finish.'); 23 | }; 24 | 25 | const main = (args) => { 26 | const runConfig = runConfiguration.generateFromArgs(args); 27 | const workload = new Workload(runConfig); 28 | 29 | console.log(_.pick(workload.runConfig, [ 30 | 'address', 'username', 'concurrency', 'n', 'ms', 'checkpointFreq', 31 | ])); 32 | 33 | let exitCode = 0; 34 | 35 | const startTime = new Date().getTime(); 36 | 37 | return workload.initialize() 38 | .then(() => { 39 | process.on('SIGINT', () => sigintHandler(workload)); 40 | return workload.printStatus(); 41 | }) 42 | .then(() => workload.start()) 43 | .catch(err => console.log(err)) 44 | .finally(() => workload.shutdown()) 45 | .then(() => { 46 | const endTime = new Date().getTime(); 47 | // Because strategies run in parallel, you can not time this 48 | // by adding their times. Rather we time the overall execution 49 | // process. 50 | let totalElapsed = (endTime - startTime); 51 | console.log(`BENCHMARK_ELAPSED=${totalElapsed}\n`); 52 | }) 53 | .then(() => strategies.report(workload.strategyTable)) 54 | .then(() => console.log(workload.stats.getState())) 55 | .then(() => process.exit(exitCode)); 56 | }; 57 | 58 | module.exports = { 59 | main, 60 | Workload, 61 | sessionPool: require('./sessionPool'), 62 | terminationCondition: require('./termination-condition'), 63 | ProbabilityTable: require('./stats/ProbabilityTable'), 64 | WorkloadStats: require('./stats/index'), 65 | strategies: require('./strategies'), 66 | }; 67 | -------------------------------------------------------------------------------- /src/read-strategy/AggregateReadStrategy.js: -------------------------------------------------------------------------------- 1 | const Strategy = require('../Strategy'); 2 | const Promise = require('bluebird'); 3 | const uuid = require('uuid'); 4 | 5 | class AggregateReadStrategy extends Strategy { 6 | constructor(props) { 7 | super(props); 8 | this.name = 'AggregateRead'; 9 | } 10 | 11 | run() { 12 | const f = (s) => s.readTransaction(tx => tx.run(` 13 | MATCH (v:NAryTree) 14 | WHERE id(v) % $r = 0 15 | RETURN min(v.val), max(v.val), stdev(v.val), count(v.val)`, 16 | { r: this.randInt(13) })); 17 | 18 | return this.time(f); 19 | } 20 | } 21 | 22 | module.exports = AggregateReadStrategy; -------------------------------------------------------------------------------- /src/read-strategy/LongPathReadStrategy.js: -------------------------------------------------------------------------------- 1 | const Strategy = require('../Strategy'); 2 | const Promise = require('bluebird'); 3 | const uuid = require('uuid'); 4 | 5 | class LongPathReadStrategy extends Strategy { 6 | constructor(props) { 7 | super(props); 8 | this.name = 'LongPathRead'; 9 | } 10 | 11 | run() { 12 | const start = 1 + this.randInt(1000); 13 | 14 | const f = (s) => s.readTransaction(tx => tx.run(` 15 | MATCH p=(s:NAryTree { val: $start })-[r:child*]->(e:NAryTree { val: $end }) 16 | RETURN count(r)`, 17 | { start, end: start + this.randInt(500) })); 18 | 19 | return this.time(f); 20 | } 21 | } 22 | 23 | module.exports = LongPathReadStrategy; -------------------------------------------------------------------------------- /src/read-strategy/MetadataReadStrategy.js: -------------------------------------------------------------------------------- 1 | const Strategy = require('../Strategy'); 2 | const Promise = require('bluebird'); 3 | const uuid = require('uuid'); 4 | 5 | class MetadataReadStrategy extends Strategy { 6 | constructor(props) { 7 | super(props); 8 | this.name = 'MetadataRead'; 9 | } 10 | 11 | run() { 12 | const i = this.randInt(50); 13 | 14 | const f = (s) => { 15 | let query; 16 | const choice = i % 3; 17 | 18 | if (i === 0) { 19 | query = "CALL db.labels()"; 20 | } else if(i === 1) { 21 | query = "CALL db.propertyKeys()"; 22 | } else { 23 | query = "CALL okapi.schema()"; 24 | } 25 | 26 | return s.readTransaction(tx => tx.run(query, {})); 27 | }; 28 | 29 | return this.time(f); 30 | } 31 | } 32 | 33 | module.exports = MetadataReadStrategy; -------------------------------------------------------------------------------- /src/read-strategy/RandomAccessReadStrategy.js: -------------------------------------------------------------------------------- 1 | const Strategy = require('../Strategy'); 2 | const neo4j = require('neo4j-driver'); 3 | 4 | class RandomAccessReadStrategy extends Strategy { 5 | constructor(props) { 6 | super(props); 7 | this.name = 'RandomAccessRead'; 8 | this.prime = neo4j.int(props.prime || 1093); 9 | this.limit = neo4j.int(props.limit || 50); 10 | } 11 | 12 | run() { 13 | const nth = neo4j.int(Math.floor(Math.random() * this.prime) + 1); 14 | const skip = neo4j.int(Math.floor(Math.random() * 1000) + 1); 15 | 16 | const f = (s) => s.readTransaction(tx => tx.run(` 17 | MATCH (node) 18 | WHERE id(node) % $prime = $nth 19 | RETURN keys(node) 20 | SKIP $skip LIMIT $limit`, 21 | { prime: this.prime, nth, skip, limit: this.limit })); 22 | 23 | return this.time(f); 24 | } 25 | } 26 | 27 | module.exports = RandomAccessReadStrategy; -------------------------------------------------------------------------------- /src/run-configuration.js: -------------------------------------------------------------------------------- 1 | const terminateAfter = require('./termination-condition'); 2 | const ProbabilityTable = require('./stats/ProbabilityTable'); 3 | const _ = require('lodash'); 4 | const MockData = require('./datasource/MockData'); 5 | const { usage } = require('yargs'); 6 | 7 | const usageStr = ` 8 | Usage: run-workload.js -p password 9 | [-a address] 10 | [-u username] 11 | [-n hits] how many total queries to run 12 | [--ms milliseconds] how many milliseconds to test for 13 | [--workload /path/to/workload.json] probability table spec 14 | [--query CYPHER_QUERY] single cypher query to run 15 | [--mode READ or WRITE] query mode to use, applies to usage of --query only 16 | [--schema /path/to/schema.json] schema for generated records (only used with --query) 17 | [--batchsize [1000]] number of records from schema to generate per batch 18 | [--concurrency c] how many concurrent queries to run (default: 10) 19 | [--checkpoint cn] how often to print results in milliseconds (default: 5000) 20 | [--fail-fast] if specified, the work will stop after encountering one failure. 21 | 22 | You may only specify one of the options --n or --ms. 23 | You may only specify one of the options --workload or --query 24 | `; 25 | 26 | const defaultProbabilityTable = [ 27 | [0.1, 'fatnodeWrite'], 28 | [0.2, 'naryWrite'], 29 | [0.3, 'mergeWrite'], 30 | [0.4, 'randomLinkage'], 31 | [0.45, 'starWrite'], 32 | [0.55, 'indexHeavy'], 33 | [0.60, 'aggregateRead'], 34 | [0.695, 'randomAccess'], 35 | [0.70, 'longPathRead'], 36 | [1, 'rawWrite'], 37 | ]; 38 | 39 | /** 40 | * @param {*} args a yargs object 41 | * @returns { iterateUntil, runType } of when to stop. 42 | */ 43 | const chooseTerminationType = (args) => { 44 | let iterateUntil; 45 | let runType; 46 | 47 | if (args.n) { 48 | iterateUntil = terminateAfter.nRuns(args.n); 49 | runType = 'counted'; 50 | } else if (args.ms) { 51 | iterateUntil = terminateAfter.timeoutMilliseconds(args.ms); 52 | runType = 'timed'; 53 | } else { 54 | console.log('no n in ', args); 55 | iterateUntil = terminateAfter.nRuns(10000); 56 | runType = 'counted'; 57 | } 58 | 59 | return { iterateUntil, runType }; 60 | }; 61 | 62 | /** 63 | * @param {*} args a yargs object 64 | * @returns { username, password, address } of where to connect 65 | */ 66 | const chooseConnectionDetails = (args) => { 67 | const addressify = str => 68 | str.indexOf('://') === -1 ? `bolt://${str}` : str; 69 | 70 | return { 71 | username: args.u || process.env.NEO4J_USER || 'neo4j', 72 | password: args.p || process.env.NEO4J_PASSWORD, 73 | address: addressify(args.a || process.env.NEO4J_URI), 74 | }; 75 | }; 76 | 77 | const chooseConcurrency = (args) => { 78 | const p = Number(args.concurrency) || Number(process.env.CONCURRENCY); 79 | return { 80 | concurrency: (!Number.isNaN(p) && p > 0) ? p : 10, 81 | }; 82 | }; 83 | 84 | const chooseProbabilityTable = (args) => { 85 | let ptData = args.workload ? require(args.workload) : defaultProbabilityTable; 86 | 87 | if (args.query) { 88 | // Always run the custom query. 89 | ptData = [ 90 | [ 1.0, 'custom' ], 91 | ]; 92 | } 93 | 94 | const result = { 95 | probabilityTable: new ProbabilityTable(ptData) 96 | }; 97 | 98 | if (args.query) { 99 | result.query = args.query; 100 | } 101 | 102 | return result; 103 | }; 104 | 105 | const generateFromArgs = (args) => { 106 | const badlyConfigured = [ 107 | args => (args.n && args.ms) ? 'You cannot use both n and ms for timing' : null, 108 | args => (args.query && args.workload) ? 'You cannot specify both a workload and a single query' : null, 109 | args => (!process.env.NEO4J_URI && !args.a) ? 'No address specified to connect!' : null, 110 | args => (!process.env.NEO4J_PASSWORD && !args.p) ? 'No password specified' : null, 111 | args => (args.schema && !args.query) ? 'You cannot specify a schema if you do not have a query to consume it' : null, 112 | args => (args.mode && !args.query) ? 'Specifying mode only works with --query' : null, 113 | ]; 114 | 115 | for (let idx in badlyConfigured) { 116 | const problem = badlyConfigured[idx](args); 117 | if (problem) { 118 | console.log(problem); 119 | throw new Error(); 120 | } 121 | } 122 | 123 | const terminationType = chooseTerminationType(args); 124 | const connectionDetails = chooseConnectionDetails(args); 125 | const concurrency = chooseConcurrency(args); 126 | const probabilityTable = chooseProbabilityTable(args); 127 | 128 | const schema = args.schema ? require(args.schema) : null; 129 | const batchSize = args.batchSize ? args.batchSize : 1000; 130 | const failFast = ('fail-fast' in args) ? args['fail-fast'] : false; 131 | 132 | // Merge sub-objects. 133 | const obj = _.merge({ 134 | generator: schema ? new MockData(schema) : null, 135 | batchSize, 136 | runcheckpoint: args.runcheckpoint, 137 | checkpointFreq: args.checkpoint || process.env.CHECKPOINT_FREQUENCY || 5000, 138 | mode: args.mode, 139 | failFast, 140 | phase: 'NOT_STARTED', 141 | database: args.d || null, 142 | }, terminationType, probabilityTable, connectionDetails, concurrency); 143 | 144 | if (obj.runType === 'counted') { 145 | obj.n = args.n || 10000; 146 | } else { 147 | obj.ms = args.ms || 1000 * 60 * 5; // 5 minutes 148 | } 149 | 150 | return obj; 151 | }; 152 | 153 | module.exports = { 154 | generateFromArgs, 155 | yargs: () => { 156 | return require('yargs') 157 | .usage(usageStr) 158 | .example('$0 -a localhost -u neo4j -p secret -n 10', 'Run 10 hits on the local database') 159 | .default('a', 'localhost') 160 | .default('u', 'neo4j') 161 | .describe('a', 'address to connect to') 162 | .describe('u', 'username') 163 | .describe('p', 'password') 164 | .describe('d', 'database') 165 | .describe('runcheckpoint', 'whether to run db checkpointing or not') 166 | .describe('schema', 'batch schema file') 167 | .describe('batchsize', 'number of records per batch, usable only with schema') 168 | .describe('n', 'number of hits on the database') 169 | .describe('ms', 'number of milliseconds to execute') 170 | .describe('workload', 'absolute path to JSON probability table/workload') 171 | .describe('query', 'Cypher query to run') 172 | .default('concurrency', 10) 173 | .default('checkpoint', 5000) 174 | .default('runcheckpoint', false) 175 | .demandOption(['p']) 176 | .argv; 177 | }, 178 | }; -------------------------------------------------------------------------------- /src/run-workload.js: -------------------------------------------------------------------------------- 1 | const runConfig = require('./run-configuration'); 2 | const everything = require('./index'); 3 | 4 | everything.main(runConfig.yargs()); -------------------------------------------------------------------------------- /src/schemas/users.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "random.uuid", 3 | "firstName": "name.firstName", 4 | "lastName": "name.lastName", 5 | "email": "internet.email", 6 | "job": "name.jobTitle", 7 | "phone": "phone.phoneNumber", 8 | "favoriteColor": "commerce.color" 9 | } -------------------------------------------------------------------------------- /src/sessionPool.js: -------------------------------------------------------------------------------- 1 | const genericPool = require('generic-pool'); 2 | let sessionPool = null; 3 | 4 | /** 5 | * A session pool is just what it sounds like. In bolt, there is overhead associated 6 | * with sessions (particularly network round trips) that can increase latency. 7 | * For this reason we aggressively reuse sessions as much as we can without trying to run 8 | * more than one transaction on a given session. 9 | * 10 | * This pool object lets users lease/release a session. In general the strategies are the 11 | * ones who are pulling these sessions. 12 | */ 13 | module.exports = { 14 | getPool: (driver, options) => { 15 | if (sessionPool) { 16 | return sessionPool; 17 | } 18 | 19 | // How to create/destroy sessions. 20 | // See the generic-pool module for more details. 21 | const factory = { 22 | create: () => { 23 | const config = {}; 24 | if (options.database) { 25 | config.database = options.database; 26 | } 27 | const s = driver.session(config); 28 | return s; 29 | }, 30 | destroy: session => { 31 | return session.close(); 32 | }, 33 | validate: session => 34 | session.run('RETURN 1;', {}) 35 | .then(results => true) 36 | .catch(err => false), 37 | }; 38 | 39 | const sessionPoolOpts = { min: 1, max: options.concurrency || 10 }; 40 | console.log('Creating session pool with ', sessionPoolOpts); 41 | sessionPool = genericPool.createPool(factory, sessionPoolOpts); 42 | sessionPool.on('factoryCreateError', err => console.log('SESSION POOL ERROR', err)); 43 | sessionPool.on('factoryDestroyError', err => console.error('SESSION POOL DESTROY ERROR', err)); 44 | sessionPool.start(); 45 | 46 | return sessionPool; 47 | }, 48 | }; -------------------------------------------------------------------------------- /src/stats/ProbabilityTable.js: -------------------------------------------------------------------------------- 1 | const _ = require('lodash'); 2 | 3 | /** 4 | * Represents a table of probabilities, and different chosen outcomes. 5 | * A table is an array of arrays, where the first cell is a float from 0-1, 6 | * and the second cell is a string token. 7 | * 8 | * The final cell should always be 1.0, and all other cells should 9 | * be strictly ordered and <= 1.0. 10 | * 11 | * Example: 12 | * 13 | * [ 14 | * [ 0.5, "heads" ], 15 | * [ 1.0, "tails" ] 16 | * ] 17 | */ 18 | module.exports = class ProbabilityTable { 19 | constructor(nestedArray) { 20 | this.data = nestedArray; 21 | this.validate(); 22 | } 23 | 24 | validate() { 25 | if (!(this.data instanceof Array) || this.data.length === 0) { 26 | throw new Error('A probability table must be an array of arrays'); 27 | } 28 | 29 | for (let i=0; i row[1])); 42 | } 43 | 44 | choose() { 45 | const roll = Math.random(); 46 | 47 | for (let i = 0; i < this.data.length; i++) { 48 | const entry = this.data[i]; 49 | if (roll <= entry[0]) { 50 | return entry[1]; 51 | } 52 | } 53 | 54 | return this.data[this.data.length-1][1]; 55 | } 56 | } -------------------------------------------------------------------------------- /src/stats/index.js: -------------------------------------------------------------------------------- 1 | module.exports = class WorkloadStats { 2 | constructor(runConfig) { 3 | this.complete = 0; 4 | this.running = 0; 5 | this.errors = 0; 6 | this.runConfig = runConfig; 7 | } 8 | 9 | getState() { 10 | return { 11 | complete: this.complete, 12 | running: this.running, 13 | errors: this.errors, 14 | }; 15 | } 16 | 17 | errorSeen(err) { 18 | this.errors++; 19 | console.error(err); 20 | } 21 | 22 | internalError(err) { 23 | this.errors++; 24 | console.error(err); 25 | } 26 | 27 | startStrategy(strategyKey) { 28 | this.running++; 29 | this[strategyKey] = (this[strategyKey] || 0) + 1; 30 | } 31 | 32 | endStrategy(data) { 33 | this.running = this.running - 1; 34 | this.complete++; 35 | return data; 36 | } 37 | }; -------------------------------------------------------------------------------- /src/strategies.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Library of strategies for easy inclusion. 3 | */ 4 | const SimpleQueryStrategy = require('./SimpleQueryStrategy'); 5 | const NAryTreeStrategy = require('./write-strategy/NAryTreeStrategy'); 6 | const FatNodeAppendStrategy = require('./write-strategy/FatNodeAppendStrategy'); 7 | const MergeWriteStrategy = require('./write-strategy/MergeWriteStrategy'); 8 | const RawWriteStrategy = require('./write-strategy/RawWriteStrategy'); 9 | const StarWriteStrategy = require('./write-strategy/StarWriteStrategy'); 10 | const IndexHeavyStrategy = require('./write-strategy/IndexHeavyStrategy'); 11 | const LuceneWriteStrategy = require('./write-strategy/LuceneWriteStrategy'); 12 | const LockTortureStrategy = require('./write-strategy/LockTortureStrategy'); 13 | const RandomLinkageStrategy = require('./write-strategy/RandomLinkageStrategy'); 14 | const AggregateReadStrategy = require('./read-strategy/AggregateReadStrategy'); 15 | const MetadataReadStrategy = require('./read-strategy/MetadataReadStrategy'); 16 | const LongPathReadStrategy = require('./read-strategy/LongPathReadStrategy'); 17 | const RandomAccessReadStrategy = require('./read-strategy/RandomAccessReadStrategy'); 18 | 19 | /** 20 | * Produces a strategy table by looking through the probability table and assigning 21 | * only those strategies that are needed. 22 | * @param {SessionPool} sessionPool 23 | * @param {runConfig} a runconfig object 24 | * @returns {Object} key is strategy name, value is a Strategy instance object. 25 | */ 26 | const builder = (sessionPool, runConfig) => { 27 | const defaultStratTable = { 28 | // WRITE STRATEGIES 29 | naryWrite: new NAryTreeStrategy({ n: 2, sessionPool, runConfig }), 30 | fatnodeWrite: new FatNodeAppendStrategy({ sessionPool, runConfig }), 31 | mergeWrite: new MergeWriteStrategy({ n: 1000000, sessionPool, runConfig }), 32 | rawWrite: new RawWriteStrategy({ n: 10, sessionPool, runConfig }), 33 | randomLinkage: new RandomLinkageStrategy({ n: 1000000, sessionPool, runConfig }), 34 | starWrite: new StarWriteStrategy({ sessionPool, runConfig }), 35 | indexHeavy: new IndexHeavyStrategy({ sessionPool, runConfig }), 36 | lockTorture: new LockTortureStrategy({ sessionPool, runConfig }), 37 | luceneWrite: new LuceneWriteStrategy({ sessionPool, runConfig }), 38 | 39 | // READ STRATEGIES 40 | aggregateRead: new AggregateReadStrategy({ sessionPool, runConfig }), 41 | metadataRead: new MetadataReadStrategy({ sessionPool, runConfig }), 42 | longPathRead: new LongPathReadStrategy({ sessionPool, runConfig }), 43 | randomAccess: new RandomAccessReadStrategy({ sessionPool, runConfig }), 44 | }; 45 | 46 | if (runConfig) { 47 | // By choosing which strats are in the table (by probability table) 48 | // We're limiting which setup methods get run too. 49 | const labels = runConfig.probabilityTable.getLabels(); 50 | const chosenTable = {}; 51 | 52 | labels.forEach(label => { 53 | const strat = defaultStratTable[label]; 54 | 55 | if (label === 'custom') { 56 | chosenTable[label] = new SimpleQueryStrategy({ 57 | sessionPool, 58 | generator: runConfig.generator, 59 | batchSize: runConfig.batchSize, 60 | query: runConfig.query, 61 | mode: runConfig.mode || 'WRITE', 62 | }); 63 | return; 64 | } else if(!strat) { 65 | throw new Error(`Probability table references strat ${label} which is unknown`); 66 | } 67 | 68 | chosenTable[label] = strat; 69 | }); 70 | 71 | return chosenTable; 72 | } 73 | 74 | return defaultStratTable; 75 | }; 76 | 77 | /** 78 | * Reports key stats about strategies 79 | * @param {StrategyTable} strategyTable 80 | */ 81 | const report = strategyTable => { 82 | console.log('Strategy report'); 83 | 84 | Object.keys(strategyTable).forEach(strategy => { 85 | const strat = strategyTable[strategy]; 86 | 87 | if (strat.countRuns() > 0) { 88 | strat.summarize(); 89 | } 90 | }); 91 | }; 92 | 93 | const showLastQuery = strategyTable => { 94 | Object.keys(strategyTable).forEach(strat => { 95 | if (strategyTable[strat].lastQuery) { 96 | console.log(strat, 'last query'); 97 | console.log(strategyTable[strat].lastQuery); 98 | console.log(strategyTable[strat].lastParams); 99 | } 100 | }); 101 | }; 102 | 103 | module.exports = { 104 | builder, report, showLastQuery, 105 | }; -------------------------------------------------------------------------------- /src/termination-condition.js: -------------------------------------------------------------------------------- 1 | const moment = require('moment'); 2 | /** 3 | * This module represents a termination condition. 4 | * 5 | * You can choose to terminate either after a certain number of runs, or after a certain timeout. 6 | * 7 | * Later if needed custom conditions can be added, such as terminate after too many 8 | * errors, etc. 9 | */ 10 | module.exports = { 11 | /** 12 | * Terminate after n runs. 13 | * @param {Number} n the number of maximum runs to allow before termination. 14 | * @returns {Object} with a next and progress function. 15 | */ 16 | nRuns: n => { 17 | let range = { from: 0, to: n, counter: 0 }; 18 | 19 | return { 20 | next: () => { 21 | const value = range.counter++; 22 | return { 23 | done: range.counter > range.to, 24 | value, 25 | }; 26 | }, 27 | progress: () => range.counter / range.to, 28 | }; 29 | }, 30 | 31 | /** 32 | * Terminate after a certain number of milliseconds. 33 | * 34 | * The timer does not begin until the next function is called for the first 35 | * time. 36 | * 37 | * @param {Number} ms the number of milliseconds. 38 | * @returns {Object} with a next and progress function. 39 | */ 40 | timeoutMilliseconds: ms => { 41 | let range = { 42 | startTime: -1, 43 | endTime: -1, 44 | counter: 0, 45 | timeout: false, 46 | ms, 47 | }; 48 | 49 | return { 50 | next: () => { 51 | if (range.startTime === -1) { 52 | range.startTime = moment.utc(); 53 | range.endTime = moment.utc().add(ms, 'milliseconds'); 54 | 55 | console.log('Starting timer at ', 56 | range.startTime.format(), 57 | ' to expire at', 58 | range.endTime.format() + 59 | ' after ', ms, 'ms'); 60 | setTimeout(() => { 61 | range.timeout = true; 62 | }, ms); 63 | } 64 | 65 | if (range.timeout) { 66 | console.log('Timeout'); 67 | return { done: true, value: null }; 68 | } 69 | return { done: false, value: range.counter++ }; 70 | }, 71 | progress: () => { 72 | if (range.startTime === -1) { return 0; } 73 | 74 | const diff = moment.utc().diff(range.startTime); 75 | return diff / ms; 76 | }, 77 | }; 78 | }, 79 | }; -------------------------------------------------------------------------------- /src/workload.js: -------------------------------------------------------------------------------- 1 | const pool = require('./sessionPool'); 2 | const strategies = require('./strategies'); 3 | const WorkloadStats = require('./stats'); 4 | const neo4j = require('neo4j-driver'); 5 | const uuid = require('uuid'); 6 | const PromisePool = require('es6-promise-pool'); 7 | 8 | /** 9 | * This function produces a promise in a pool. It basically wraps 10 | * workload.runStrategy but in a friendly way that can be iterated 11 | * as controlled by the run strategy's termination condition. 12 | * @param {*} workload the main workload 13 | * @returns {Promise} that is a running strategy. 14 | */ 15 | const promiseProducer = workload => () => { 16 | if (workload.interrupted) { return null; } 17 | const rc = workload.getRunConfiguration(); 18 | const stats = workload.getStats(); 19 | 20 | const v = rc.iterateUntil.next(); 21 | if (v.done) { 22 | // Signal to the pool that we're done. 23 | return null; 24 | } 25 | 26 | return workload.runStrategy() 27 | .catch(err => { 28 | console.error('RunStrat error', err); 29 | stats.errorSeen(err); 30 | if (rc.failFast) { 31 | // Don't recover. 32 | throw err; 33 | } 34 | 35 | return null; 36 | }) 37 | .then(data => stats.endStrategy(data)); 38 | }; 39 | 40 | /** 41 | * Controller class that runs a workload. 42 | */ 43 | class Workload { 44 | /** 45 | * @param {*} runConfig a run configuration 46 | */ 47 | constructor(runConfig) { 48 | this.runConfig = runConfig; 49 | this.interrupted = false; 50 | this.started = false; 51 | this.id = uuid.v4(); 52 | } 53 | 54 | /** 55 | * Prior to running a workload it must be initialized, to include tasks 56 | * such as: 57 | * - Creating a driver to connect to the target database 58 | * - Setting up resource pools 59 | * - Doing any pre-creation of data as required by strategy setup() 60 | * methods. 61 | * @returns Promise that resolves to an array of strategy setup actions. 62 | */ 63 | initialize() { 64 | console.log('Connecting to ', this.runConfig.address); 65 | this.driver = neo4j.driver(this.runConfig.address, 66 | neo4j.auth.basic(this.runConfig.username, this.runConfig.password)); 67 | 68 | this.sessionPool = pool.getPool(this.driver, this.runConfig); 69 | this.strategyTable = strategies.builder(this.sessionPool, this.runConfig); 70 | this.stats = new WorkloadStats(this.runConfig); 71 | 72 | this.promisePool = new PromisePool(promiseProducer(this), this.runConfig.concurrency); 73 | this.promisePool.addEventListener('rejected', 74 | event => this.stats.internalError(event)); 75 | 76 | const runStrategySetupPromises = Object.keys(this.strategyTable) 77 | .map(stratName => this.strategyTable[stratName].setup(this.driver)); 78 | 79 | return Promise.all(runStrategySetupPromises) 80 | .then(results => { 81 | if (this.runConfig.runcheckpoint) { 82 | const opts = {}; 83 | if (this.runConfig.database) { opts.database = this.runConfig.database; } 84 | const session = this.driver.session(opts); 85 | console.log('Calling db.checkpoint method to flush prior to run'); 86 | return session.run('CALL db.checkpoint()') 87 | .then(session.close); 88 | } 89 | 90 | return results; 91 | }); 92 | } 93 | 94 | getRunConfiguration() { return this.runConfig; } 95 | getStats() { return this.stats; } 96 | 97 | /** 98 | * Starts the main workload process. 99 | * @returns {Promise} that resolves to a completed workload. 100 | */ 101 | start() { 102 | console.log('Starting main promise pool'); 103 | this.started = true; 104 | this.interrupted = false; 105 | return this.promisePool.start(); 106 | } 107 | 108 | /** 109 | * Shuts down all resources and stops the process. 110 | * This also closes the driver; the object should not be reused 111 | * after calling this function. 112 | */ 113 | shutdown() { 114 | if (!this.started) { 115 | throw new Error('Workload not yet started'); 116 | } 117 | 118 | console.log('Shutting down'); 119 | this.started = false; 120 | this.interrupted = true; 121 | 122 | if (!this.promisePool) { 123 | throw new Error('Cannot shut down; not yet initialized.'); 124 | } 125 | 126 | return this.sessionPool.drain() 127 | .then(() => this.sessionPool.clear()) 128 | .catch(err => console.error('Some error draining/clearing pool', err)) 129 | .then(() => this.driver.close()); 130 | } 131 | 132 | printStatus() { 133 | const pctDone = parseFloat(Math.round(this.runConfig.iterateUntil.progress() * 100)).toFixed(2); 134 | const s = this.stats.getState(); 135 | console.log(`Progress: ${pctDone}% ${s.complete} completed; ${s.running} running ${s.errors} error`); 136 | 137 | if (!this.interrupted) { 138 | // Schedule myself again. 139 | setTimeout(() => this.printStatus(), this.runConfig.checkpointFreq); 140 | } 141 | } 142 | 143 | /** 144 | * Run a single randomly chosen strategy from the probability table 145 | * in the run configuration. 146 | * @returns {Promise} of the strategy running. 147 | */ 148 | runStrategy() { 149 | if (this.interrupted) { 150 | return Promise.resolve(null); 151 | } 152 | 153 | const key = this.runConfig.probabilityTable.choose(); 154 | const strat = this.strategyTable[key]; 155 | 156 | this.stats.startStrategy(key); 157 | return strat.run(this.driver); 158 | }; 159 | }; 160 | 161 | module.exports = Workload; -------------------------------------------------------------------------------- /src/workloads/all-reads.json: -------------------------------------------------------------------------------- 1 | [ 2 | [ 0.33, "aggregateRead" ], 3 | [ 0.66, "longPathRead" ], 4 | [ 1, "randomAccess" ] 5 | ] -------------------------------------------------------------------------------- /src/workloads/all-writes.json: -------------------------------------------------------------------------------- 1 | [ 2 | [ 0.2, "fatnodeWrite" ], 3 | [ 0.4, "naryWrite" ], 4 | [ 0.6, "mergeWrite" ], 5 | [ 0.7, "randomLinkage" ], 6 | [ 0.8, "starWrite" ], 7 | [ 0.9, "indexHeavy" ], 8 | [ 1, "rawWrite" ] 9 | ] -------------------------------------------------------------------------------- /src/workloads/mixed.json: -------------------------------------------------------------------------------- 1 | [ 2 | [ 0.1, "fatnodeWrite" ], 3 | [ 0.2, "naryWrite" ], 4 | [ 0.3, "mergeWrite" ], 5 | [ 0.4, "randomLinkage" ], 6 | [ 0.50, "aggregateRead" ], 7 | [ 0.70, "longPathRead" ], 8 | [ 1, "rawWrite" ] 9 | ] -------------------------------------------------------------------------------- /src/workloads/nary-only.json: -------------------------------------------------------------------------------- 1 | [ 2 | [ 1.0, "naryWrite" ] 3 | ] -------------------------------------------------------------------------------- /src/workloads/rac.json: -------------------------------------------------------------------------------- 1 | [ 2 | [ 1, "randomAccess" ] 3 | ] -------------------------------------------------------------------------------- /src/write-strategy/FatNodeAppendStrategy.js: -------------------------------------------------------------------------------- 1 | const Strategy = require('../Strategy'); 2 | const Promise = require('bluebird'); 3 | const uuid = require('uuid'); 4 | 5 | class FatNodeAppendStrategy extends Strategy { 6 | constructor(props) { 7 | super(props); 8 | this.name = 'FatNodeAppend'; 9 | this.label = props.label; 10 | } 11 | 12 | run() { 13 | const p = this.randInt(10000000); 14 | const r = p - 10000; 15 | 16 | const data = []; 17 | for (let i = 0; i < 1000; i++) { 18 | data.push(uuid.v4()); 19 | } 20 | 21 | this.lastQuery = `FOREACH (id IN range(0,10) | CREATE (f:FatNode { 22 | timestamp: timestamp(), 23 | data: $data, 24 | uuid: $uuid 25 | }))`; 26 | this.lastParams = { uuid: uuid.v4(), data }; 27 | 28 | const f = (s) => s.writeTransaction(tx => tx.run(this.lastQuery, this.lastParams)); 29 | return this.time(f); 30 | } 31 | } 32 | 33 | module.exports = FatNodeAppendStrategy; -------------------------------------------------------------------------------- /src/write-strategy/IndexHeavyStrategy.js: -------------------------------------------------------------------------------- 1 | const Strategy = require('../Strategy'); 2 | const Promise = require('bluebird'); 3 | const uuid = require('uuid'); 4 | const faker = require('faker'); 5 | 6 | const MAX_STAR_SIZE = 100; 7 | 8 | class IndexHeavyStrategy extends Strategy { 9 | constructor(props) { 10 | super(props); 11 | this.name = 'IndexHeavy'; 12 | this.n = props.n || MAX_STAR_SIZE; 13 | } 14 | 15 | setup(driver) { 16 | super.setup(driver); 17 | const session = driver.session(this.sessionOptions()); 18 | 19 | const queries = [ 20 | 'CREATE INDEX ON :Customer(id)', 21 | 'CREATE INDEX ON :Customer(name)', 22 | 'CREATE INDEX ON :Customer(email)', 23 | 'CREATE INDEX ON :Customer(username)', 24 | 'CREATE INDEX ON :Customer(created)', 25 | 'CREATE INDEX ON :Customer(score)', 26 | 'CREATE INDEX ON :Address(location)', 27 | 'CREATE INDEX ON :Address(created)', 28 | 'CREATE INDEX ON :Address(zip)', 29 | 'CREATE INDEX ON :Address(city)', 30 | 'CREATE INDEX ON :Address(cityPrefix)', 31 | 'CREATE INDEX ON :Address(streetName)', 32 | 'CREATE INDEX ON :Address(streetAddress)', 33 | 'CREATE INDEX ON :Address(streetPrefix)', 34 | 'CREATE INDEX ON :Address(secondaryAddress)', 35 | 'CREATE INDEX ON :Address(country)', 36 | 'CREATE INDEX ON :Address(county)', 37 | 'CREATE INDEX ON :Address(countryCode)', 38 | 'CREATE INDEX ON :Address(state)', 39 | 'CREATE INDEX ON :Address(stateAbbr)', 40 | 'CREATE INDEX ON :Address(score)', 41 | ]; 42 | 43 | return Promise.all(queries.map(q => { 44 | const session = driver.session(this.sessionOptions()); 45 | return session.run(q) 46 | .then(() => session.close()) 47 | .catch(e => this.ignore(e, 'An equivalent index already exists')); 48 | })); 49 | } 50 | 51 | run() { 52 | const id = uuid.v4(); 53 | const q = ` 54 | MERGE (c:Customer { username: $username }) 55 | ON CREATE SET 56 | c.id = $id, 57 | c.name = $name, 58 | c.email = $email, 59 | c.created = datetime(), 60 | c.score = rand() 61 | 62 | WITH c 63 | 64 | CREATE (a:Address { 65 | location: point({ latitude: $latitude, longitude: $longitude }), 66 | created: datetime(), 67 | zip: $zipCode, city: $city, 68 | cityPrefix: $cityPrefix, 69 | streetName: $streetName, 70 | streetAddress: $streetAddress, 71 | streetPrefix: $streetPrefix, 72 | secondaryAddress: $secondaryAddress, 73 | country: $country, 74 | county: $county, 75 | countryCode: $countryCode, 76 | state: $state, stateAbbr: $stateAbbr, 77 | score: rand() 78 | }) 79 | CREATE (c)-[:address]->(a) 80 | `; 81 | 82 | const params = { 83 | id, 84 | name: faker.name.findName(), 85 | username: faker.internet.userName(), 86 | email: faker.internet.email(), 87 | }; 88 | 89 | // See: https://www.npmjs.com/package/faker 90 | const fakeFuncs = [ 91 | 'zipCode', 'city', 'cityPrefix', 92 | 'streetName', 'streetAddress', 93 | 'streetPrefix', 'secondaryAddress', 94 | 'country', 'county', 'countryCode', 95 | 'state', 'stateAbbr', 96 | ]; 97 | 98 | params.latitude = Number(faker.address.latitude()); 99 | params.longitude = Number(faker.address.longitude()); 100 | 101 | fakeFuncs.forEach(f => { 102 | params[f] = faker.address[f](); 103 | }); 104 | 105 | const f = (s) => s.writeTransaction(tx => tx.run(q, params)); 106 | return this.time(f); 107 | } 108 | } 109 | 110 | module.exports = IndexHeavyStrategy; -------------------------------------------------------------------------------- /src/write-strategy/LockTortureStrategy.js: -------------------------------------------------------------------------------- 1 | const Strategy = require('../Strategy'); 2 | const Promise = require('bluebird'); 3 | const uuid = require('uuid'); 4 | const faker = require('faker'); 5 | 6 | const MAX_STAR_SIZE = 100; 7 | 8 | /** 9 | * This strategy is intended to be run with some concurrency, and it 10 | * intentionally creates situations where the same node is going to get 11 | * locked and modified by different concurrent queries. 12 | */ 13 | class LockTortureStrategy extends Strategy { 14 | constructor(props) { 15 | super(props); 16 | this.name = 'LockTorture'; 17 | this.n = props.n || 5; 18 | } 19 | 20 | setup(driver) { 21 | super.setup(driver); 22 | const session = driver.session(this.sessionOptions()); 23 | 24 | // Set up some basic nodes and index. 25 | const queries = [ 26 | 'CREATE INDEX ON :LockTorture(id)', 27 | `UNWIND range(1, ${this.n}) as id MERGE (l:LockTorture {id: id })`, 28 | ]; 29 | 30 | return Promise.map(queries, q => session.run(q)) 31 | .then(() => session.close()); 32 | } 33 | 34 | run() { 35 | const id1 = this.randInt(this.n); 36 | const id2 = this.randInt(this.n); 37 | 38 | const p1Name = `prop${this.randInt(1000)}`; 39 | const p2Name = `prop${this.randInt(1000)}`; 40 | 41 | const q = ` 42 | MATCH 43 | (l1:LockTorture { id: $id1 }), 44 | (l2:LockTorture { id: $id2 }) 45 | OPTIONAL MATCH (l1)-[r:related_to]->(l2) 46 | WHERE id(r) % 11 = 0 47 | WITH l1, l2, r 48 | CREATE (l1)-[:related_to]->(l2) 49 | SET l1.${p1Name} = $p1Name, 50 | l2.${p2Name} = $p2Name 51 | DELETE r 52 | RETURN 1; 53 | `; 54 | 55 | const params = { 56 | id1, id2, p1Name, p2Name, 57 | }; 58 | 59 | const f = (s) => s.writeTransaction(tx => tx.run(q, params)); 60 | return this.time(f); 61 | } 62 | } 63 | 64 | module.exports = LockTortureStrategy; -------------------------------------------------------------------------------- /src/write-strategy/LuceneWriteStrategy.js: -------------------------------------------------------------------------------- 1 | const Strategy = require('../Strategy'); 2 | const Promise = require('bluebird'); 3 | const uuid = require('uuid'); 4 | const dimsum = require('dimsum'); 5 | 6 | class LuceneWriteStrategy extends Strategy { 7 | constructor(props) { 8 | super(props); 9 | this.name = 'LuceneWrite'; 10 | this.label = props.label; 11 | 12 | this.jabberwocky = dimsum.configure({ flavor: 'jabberwocky' }); 13 | } 14 | 15 | setup(driver) { 16 | super.setup(driver); 17 | const session = driver.session(this.sessionOptions()); 18 | 19 | // Set up some basic nodes and index. 20 | const queries = [ 21 | 'CALL db.index.fulltext.createNodeIndex("luceneIndex",["LuceneNode"],["text"])', 22 | ]; 23 | 24 | return Promise.map(queries, q => session.run(q)) 25 | .catch(err => null) 26 | .then(() => session.close()); 27 | } 28 | 29 | run() { 30 | const p = this.randInt(10000000); 31 | const r = p - 10000; 32 | 33 | const data = []; 34 | for (let i = 0; i < 1000; i++) { 35 | data.push(uuid.v4()); 36 | } 37 | 38 | this.lastQuery = ` 39 | CREATE (:LuceneNode { id: $id1, text: $text1 }) 40 | CREATE (:LuceneNode { id: $id2, text: $text2 }) 41 | CREATE (:LuceneNode { id: $id3, text: $text3 }) 42 | CREATE (:LuceneNode { id: $id4, text: $text4 }) 43 | CREATE (:LuceneNode { id: $id5, text: $text5 }) 44 | `; 45 | 46 | this.lastParams = { 47 | id1: uuid.v4(), 48 | id2: uuid.v4(), 49 | id3: uuid.v4(), 50 | id4: uuid.v4(), 51 | id5: uuid.v4(), 52 | text1: this.jabberwocky(), 53 | text2: this.jabberwocky(), 54 | text3: this.jabberwocky(), 55 | text4: this.jabberwocky(), 56 | text5: this.jabberwocky(), 57 | }; 58 | 59 | const f = (s) => s.writeTransaction(tx => tx.run(this.lastQuery, this.lastParams)); 60 | return this.time(f); 61 | } 62 | } 63 | 64 | module.exports = LuceneWriteStrategy; -------------------------------------------------------------------------------- /src/write-strategy/MergeWriteStrategy.js: -------------------------------------------------------------------------------- 1 | const Strategy = require('../Strategy'); 2 | const Promise = require('bluebird'); 3 | const uuid = require('uuid'); 4 | 5 | class MergeWriteStrategy extends Strategy { 6 | constructor(props) { 7 | super(props); 8 | this.name = 'MergeWrite'; 9 | this.n = props.n || 100000000; 10 | } 11 | 12 | setup(driver) { 13 | super.setup(driver); 14 | 15 | const queries = [ 16 | 'CREATE INDEX ON :MergeNode(id)', 17 | 'FOREACH (id IN range(0,10000) | MERGE (:MergeNode {id:id}));', 18 | ]; 19 | 20 | return Promise.all(queries.map(q => { 21 | const session = driver.session(this.sessionOptions()); 22 | return session.run(q).then(() => session.close()) 23 | .catch(e => this.ignore(e, 'An equivalent index already exists')); 24 | })); 25 | } 26 | 27 | run() { 28 | this.lastQuery = ` 29 | MERGE (n:MergeNode { id: $id1 }) ON CREATE SET n.uuid = $u1 SET n:SimpleWrite 30 | MERGE (p:MergeNode { id: $id2 }) ON CREATE SET p.uuid = $u2 SET p:SimpleWrite 31 | MERGE (z:MergeNode { id: $id3 }) ON CREATE SET z.uuid = $u3 SET z:SimpleWrite 32 | MERGE (n)-[:link {r: $r, uuid: $u4 }]->(p) 33 | MERGE (n)-[:otherlink { r: $r2, uuid: $u5 }]->(z) 34 | RETURN 1;`; 35 | 36 | this.lastParams = { 37 | r: this.randInt(100000), 38 | id1: this.randInt(this.n), 39 | id2: this.randInt(this.n), 40 | id3: this.randInt(this.n), 41 | u1: uuid.v4(), u2: uuid.v4(), u3: uuid.v4(), u4: uuid.v4(), u5: uuid.v4(), 42 | r2: this.randInt(100000), 43 | }; 44 | 45 | const f = (s) => s.writeTransaction(tx => tx.run(this.lastQuery, this.lastParams)); 46 | return this.time(f); 47 | } 48 | } 49 | 50 | module.exports = MergeWriteStrategy; -------------------------------------------------------------------------------- /src/write-strategy/NAryTreeStrategy.js: -------------------------------------------------------------------------------- 1 | const Strategy = require('../Strategy'); 2 | const Promise = require('bluebird'); 3 | const neo4j = require('neo4j-driver'); 4 | 5 | class NAryTreeStrategy extends Strategy { 6 | constructor(props) { 7 | super(props); 8 | this.n = props.n || 2; 9 | this.name = 'NAryTree'; 10 | this.tracker = -10; 11 | } 12 | 13 | setup(driver) { 14 | super.setup(driver); 15 | 16 | const queries = [ 17 | "CREATE INDEX ON :NAryTree(val)", 18 | "CREATE INDEX ON :Leaf(val)", 19 | "CREATE (a:NAryTree:Leaf { label: 'ROOT', val: 2 })", 20 | ]; 21 | 22 | return Promise.all(queries.map(q => { 23 | const session = driver.session(this.sessionOptions()); 24 | return session.run(q) 25 | .catch(e => this.ignore(e, 'An equivalent index already exists')) 26 | .then(() => session.close()); 27 | })); 28 | } 29 | 30 | run() { 31 | // this.tracker++; 32 | this.lastParams = { tracker: this.tracker }; 33 | 34 | this.lastQuery = ` 35 | MATCH (p:Leaf) 36 | WHERE p.val >= $tracker 37 | WITH p ORDER BY p.val DESC, rand() 38 | LIMIT ${neo4j.int(this.n)} 39 | WHERE NOT (p)-[:child]->(:NAryTree) 40 | WITH p 41 | REMOVE p:Leaf 42 | ${ 43 | Array.apply(null, { length: this.n }).map((z, idx) => { 44 | return ` 45 | CREATE (p)-[:child]->(i${idx}:NAryTree:Leaf { val: p.val + ${idx + 1} }) 46 | ` 47 | }).join('\n') 48 | } 49 | RETURN count(p) as value; 50 | `; 51 | 52 | const f = (s) => s.writeTransaction(tx => tx.run(this.lastQuery, this.lastParams)); 53 | return this.time(f); 54 | } 55 | } 56 | 57 | module.exports = NAryTreeStrategy; -------------------------------------------------------------------------------- /src/write-strategy/RandomLinkageStrategy.js: -------------------------------------------------------------------------------- 1 | const Strategy = require('../Strategy'); 2 | const neo4j = require('neo4j-driver'); 3 | const uuid = require('uuid'); 4 | 5 | class RandomLinkageStrategy extends Strategy { 6 | constructor(props) { 7 | super(props); 8 | this.name = 'RandomLinkage'; 9 | this.n = props.n || 1000000; 10 | } 11 | 12 | run() { 13 | this.lastQuery = ` 14 | MATCH (a) 15 | WITH a 16 | SKIP $idx1 LIMIT 3 17 | MATCH (b) WITH a,b 18 | SKIP $idx2 LIMIT 3 19 | CREATE (a)-[r:randomlinkage { 20 | id: $id, created: datetime() 21 | }]->(b) 22 | RETURN count(r) 23 | `; 24 | 25 | this.lastParams = { 26 | idx1: neo4j.int(this.randInt(this.n)), 27 | idx2: neo4j.int(this.randInt(this.n)), 28 | id: uuid.v4(), 29 | }; 30 | const f = (s) => s.writeTransaction(tx => tx.run(this.lastQuery, this.lastParams)); 31 | return this.time(f); 32 | } 33 | } 34 | 35 | module.exports = RandomLinkageStrategy; -------------------------------------------------------------------------------- /src/write-strategy/RawWriteStrategy.js: -------------------------------------------------------------------------------- 1 | const Strategy = require('../Strategy'); 2 | const Promise = require('bluebird'); 3 | const uuid = require('uuid'); 4 | 5 | class RawWriteStrategy extends Strategy { 6 | constructor(props) { 7 | super(props); 8 | this.name = 'RawWrite'; 9 | this.n = props.n || 10; 10 | } 11 | 12 | // setup(driver) { 13 | // return Promise.resolve(true); 14 | // const queries = [ 15 | // 'CREATE INDEX ON :MergeNode(id)', 16 | // 'FOREACH (id IN range(0,10000) | MERGE (:MergeNode {id:id}));', 17 | // ]; 18 | 19 | // const session = driver.session(this.sessionOptions()); 20 | // return Promise.map(queries, query => session.run(query)) 21 | // .then(() => session.close()); 22 | // } 23 | 24 | run() { 25 | this.lastQuery = ` 26 | FOREACH (id IN range(0,${this.n}) | 27 | CREATE (:RawWriteNode { 28 | id:id * rand(), 29 | uuid: $uuid, 30 | f1: rand(), f2: rand(), f3: rand(), f4: rand(), f5: rand(), 31 | created: datetime() 32 | })-[:rawrite]->(:RawWriteNode { 33 | id:id * rand(), 34 | uuid: $uuid, 35 | f1: rand(), f2: rand(), f3: rand(), f4: rand(), f5: rand(), 36 | created: datetime() 37 | }) 38 | );`; 39 | 40 | this.lastParams = { uuid: uuid.v4() }; 41 | const f = (s) => s.writeTransaction(tx => tx.run(this.lastQuery, this.lastParams)); 42 | return this.time(f); 43 | } 44 | } 45 | 46 | module.exports = RawWriteStrategy; -------------------------------------------------------------------------------- /src/write-strategy/StarWriteStrategy.js: -------------------------------------------------------------------------------- 1 | const Strategy = require('../Strategy'); 2 | const Promise = require('bluebird'); 3 | const uuid = require('uuid'); 4 | const faker = require('faker'); 5 | 6 | const MAX_STAR_SIZE = 100; 7 | 8 | class StarWriteStrategy extends Strategy { 9 | constructor(props) { 10 | super(props); 11 | this.name = 'StarWrite'; 12 | this.n = props.n || MAX_STAR_SIZE; 13 | } 14 | 15 | run() { 16 | const id = uuid.v4(); 17 | const q = ` 18 | CREATE (h:Hub { id: $id }) 19 | WITH h 20 | FOREACH (id IN range(0, $starSize) | MERGE (:Spoke { hub: $id, n: id })-[:hub]->(h)) 21 | RETURN null 22 | `; 23 | 24 | const params = { 25 | id, starSize: this.n, 26 | }; 27 | 28 | const f = (s) => s.writeTransaction(tx => tx.run(q, params)); 29 | return this.time(f); 30 | } 31 | } 32 | 33 | module.exports = StarWriteStrategy; -------------------------------------------------------------------------------- /src/write-strategy/WritePropertyDataStrategy.js: -------------------------------------------------------------------------------- 1 | const Strategy = require('../Strategy'); 2 | const Promise = require('bluebird'); 3 | 4 | class WritePropertyDataStrategy extends Strategy { 5 | constructor(props) { 6 | super(props); 7 | this.name = 'WritePropertyData'; 8 | this.label = props.label; 9 | } 10 | 11 | setup(driver) { 12 | super.setup(driver); 13 | const queries = [ 14 | 'CREATE INDEX ON :Node(id)', 15 | 'FOREACH (id IN range(0,10000) | MERGE (:Node {id:id}));', 16 | ]; 17 | 18 | const session = driver.session(this.sessionOptions()); 19 | return Promise.map(queries, query => session.run(query)) 20 | .then(() => session.close()); 21 | } 22 | 23 | run() { 24 | const p = this.randInt(10000); 25 | const r = p - 1000; 26 | 27 | const data = []; 28 | for (let i = 0; i < 100; i++) { 29 | data.push(uuid.v4()); 30 | } 31 | 32 | const f = (s) => s.writeTransaction(tx => tx.run(` 33 | MATCH (a:Node) WHERE a.id >= $r and a.id <= $p 34 | WITH a LIMIT 100 35 | SET a.list${randInt(100)} = $data SET a:WriteArray 36 | RETURN count(a); 37 | `, { data, r, p })); 38 | 39 | return this.time(f); 40 | } 41 | } 42 | 43 | module.exports = WritePropertyDataStrategy; -------------------------------------------------------------------------------- /stress-testing.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Pod 3 | metadata: 4 | name: stress-testing 5 | spec: 6 | containers: 7 | - name: stress-testing 8 | image: mdavidallen/neo4j-stress-testing:latest 9 | env: 10 | - name: NEO4J_URI 11 | value: "bolt+routing://my-internal-endpoint.default.svc.cluster.local" 12 | - name: NEO4J_USERNAME 13 | value: neo4j 14 | - name: NEO4J_PASSWORD 15 | value: supersecret 16 | - name: CONCURRENCY 17 | value: "10" -------------------------------------------------------------------------------- /test/SimpleQueryStrategy_test.js: -------------------------------------------------------------------------------- 1 | const expect = require('chai').expect; 2 | const SimpleQueryStrategy = require('../src/SimpleQueryStrategy'); 3 | const Promise = require('bluebird'); 4 | const mocks = require('./mocks'); 5 | const chai = require('chai'); 6 | const chaiAsPromised = require("chai-as-promised"); 7 | chai.use(chaiAsPromised); 8 | 9 | describe('Simple Query Strategy', () => { 10 | let s; 11 | const props = { 12 | mode: 'READ', 13 | query: 'RETURN 1', 14 | name: 'PING', 15 | sessionPool: new mocks.MockSessionPool(), 16 | }; 17 | const name = 'FooStrategy'; 18 | 19 | beforeEach(() => { 20 | s = new SimpleQueryStrategy(props); 21 | }); 22 | 23 | it('requires a mode of READ or WRITE', () => { 24 | const badProps = { 25 | query: 'RETURN 1', 26 | mode: 'eh' 27 | }; 28 | 29 | expect(() => new SimpleQueryStrategy(badProps)).to.throw(Error); 30 | badProps.mode = null; 31 | expect(() => new SimpleQueryStrategy(badProps)).to.throw(Error); 32 | const goodProps = { 33 | query: 'RETURN 1', 34 | mode: 'WRITE' 35 | }; 36 | 37 | expect(() => new SimpleQueryStrategy(goodProps)).to.not.throw(Error); 38 | }); 39 | 40 | it('calls readTransaction on mode READ', () => { 41 | props.mode = 'READ'; 42 | props.sessionPool = new mocks.MockSessionPool(); 43 | const sq = new SimpleQueryStrategy(props); 44 | 45 | return sq.run() 46 | .then(() => { 47 | console.log(props.sessionPool.session); 48 | expect(props.sessionPool.session.reads).to.equal(1); 49 | expect(props.sessionPool.session.writes).to.equal(0); 50 | }); 51 | }); 52 | 53 | it('calls writeTransaction on mode WRITE', () => { 54 | props.mode = 'WRITE'; 55 | props.sessionPool = new mocks.MockSessionPool(); 56 | const sq = new SimpleQueryStrategy(props); 57 | 58 | return sq.run() 59 | .then(() => { 60 | console.log(props.sessionPool.session); 61 | expect(props.sessionPool.session.reads).to.equal(0); 62 | expect(props.sessionPool.session.writes).to.equal(1); 63 | }); 64 | }); 65 | }); -------------------------------------------------------------------------------- /test/Strategy_test.js: -------------------------------------------------------------------------------- 1 | const expect = require('chai').expect; 2 | const assert = require('chai').assert; 3 | const Strategy = require('../src/Strategy'); 4 | const Promise = require('bluebird'); 5 | const mocks = require('./mocks'); 6 | const chai = require('chai'); 7 | const chaiAsPromised = require("chai-as-promised"); 8 | chai.use(chaiAsPromised); 9 | 10 | describe('Strategy', () => { 11 | let s; 12 | const props = { x: 1, y: 2, sessionPool: new mocks.MockSessionPool() }; 13 | const name = 'FooStrategy'; 14 | 15 | beforeEach(() => { 16 | s = new Strategy(props); 17 | s.name = name; 18 | }) 19 | 20 | it('can be constructed, and stores props', () => { 21 | expect(s.props).to.deep.equal(props); 22 | }); 23 | 24 | it('knows its name', () => expect(s.getName()).to.equal(name)); 25 | 26 | it('should be able to roll a random number', () => { 27 | for(let i=0; i<100; i++) { 28 | const z = s.randInt(100); 29 | expect(z).to.be.greaterThan(-1); 30 | expect(z).to.be.lessThan(100); 31 | } 32 | }); 33 | 34 | it('should support timings', () => { 35 | expect(s.getTimings()).to.be.instanceOf(Array); 36 | }); 37 | 38 | it('should count runs', () => { 39 | expect(s.countRuns()).to.equal(0); 40 | }); 41 | 42 | it('can be turned into CSV', () => { 43 | const csv = s.csv(); 44 | expect(csv).to.be.a.string; 45 | expect(csv.split(',')[0]).to.equal(name); 46 | }); 47 | 48 | it('has a summarize method', () => { 49 | s.summarize(); 50 | }); 51 | 52 | it('tracks total time spent', () => { 53 | expect(s.totalTimeSpent()).to.equal(0); 54 | }); 55 | 56 | it('rejects run efforts because that has to be overridden', () => { 57 | expect(s.run()).to.be.rejected; 58 | }); 59 | 60 | it('can time a function', done => { 61 | const promiseFn = () => 62 | new Promise((resolve, reject) => { 63 | setTimeout(() => resolve(true), 1000); 64 | }); 65 | const timingPromise = s.time(promiseFn, {}); 66 | 67 | expect(timingPromise).to.be.instanceOf(Promise); 68 | timingPromise.then(() => { 69 | expect(s.countRuns()).to.equal(1); 70 | expect(s.getTimings().length).to.equal(1); 71 | expect(s.totalTimeSpent()).to.be.greaterThan(0); 72 | done(); 73 | }).catch(err => done(err)); 74 | }); 75 | }); -------------------------------------------------------------------------------- /test/datasource/MockData_test.js: -------------------------------------------------------------------------------- 1 | const expect = require('chai').expect; 2 | const mocks = require('../mocks'); 3 | const chai = require('chai'); 4 | const chaiAsPromised = require("chai-as-promised"); 5 | chai.use(chaiAsPromised); 6 | 7 | const MockData = require('../../src/datasource/MockData'); 8 | 9 | describe('Mock Data', function() { 10 | const goodSchema = { 11 | streetAddress: 'address.streetAddress', 12 | city: 'address.city', 13 | state: 'address.state', 14 | country: 'address.country', 15 | }; 16 | 17 | it('can create something with a good schema', () => { 18 | const md = new MockData(goodSchema); 19 | expect(md).to.be.ok; 20 | }); 21 | 22 | it('refuses empty schema', () => { 23 | expect(() => new MockData()).to.throw(Error); 24 | }); 25 | 26 | it('refuses wrong schema', () => { 27 | expect(() => new MockData({ 28 | foo: 'i.do.not.exist', 29 | })).to.throw(Error); 30 | }); 31 | 32 | it('can generate a batch', () => { 33 | const md = new MockData(goodSchema); 34 | 35 | console.log('generating'); 36 | const r = md.generate(10); 37 | console.log(r); 38 | // expect(r).to.be.an(Array); 39 | expect(r.length).to.equal(10); 40 | for (let i=0; i { 42 | expect(r[i][field]).to.be.ok; 43 | }); 44 | } 45 | }); 46 | }); -------------------------------------------------------------------------------- /test/index_test.js: -------------------------------------------------------------------------------- 1 | const gl = require('../src/index'); 2 | const expect = require('chai').expect; 3 | 4 | describe('Module Public API', function () { 5 | it('exports main', () => expect(gl.main).to.be.instanceOf(Function)); 6 | 7 | ['Workload', 'sessionPool', 'terminationCondition', 'ProbabilityTable', 8 | 'WorkloadStats', 'strategies'].forEach(key => { 9 | it(`exports ${key}`, () => expect(gl[key]).to.be.ok); 10 | }); 11 | }); -------------------------------------------------------------------------------- /test/mocks.js: -------------------------------------------------------------------------------- 1 | const Promise = require('bluebird'); 2 | 3 | class MockTx { 4 | run() { 5 | return Promise.resolve(true); 6 | } 7 | } 8 | 9 | class MockSession { 10 | constructor() { 11 | this.reads = 0; 12 | this.writes = 0; 13 | this.runs = 0; 14 | } 15 | 16 | run(stmt, params) { 17 | this.runs++; 18 | return Promise.resolve({}); 19 | } 20 | 21 | writeTransaction(fn) { 22 | this.writes++; 23 | return fn(new MockTx()); 24 | } 25 | 26 | readTransaction(fn) { 27 | this.reads++; 28 | return fn(new MockTx()); 29 | } 30 | 31 | close() { 32 | return Promise.resolve(true); 33 | } 34 | } 35 | 36 | class MockDriver { 37 | constructor() { 38 | this.sessions = 0; 39 | this.open = true; 40 | } 41 | 42 | session() { 43 | this.sessions++; 44 | return new MockSession(); 45 | } 46 | 47 | close() { 48 | this.open = false; 49 | } 50 | } 51 | 52 | class MockSessionPool { 53 | constructor() { 54 | this.inUse = 0; 55 | this.session = new MockSession(); 56 | } 57 | 58 | acquire() { 59 | this.inUse++; 60 | return Promise.resolve(this.session); 61 | } 62 | 63 | release(s) { 64 | if (s !== this.session) { 65 | throw new Error('Releasing a session which is not what was acquired!'); 66 | } 67 | 68 | this.inUse--; 69 | return Promise.resolve(true); 70 | } 71 | } 72 | 73 | module.exports = { 74 | MockSessionPool, MockDriver, MockSession, 75 | }; -------------------------------------------------------------------------------- /test/read-strategy/read-strategy_test.js: -------------------------------------------------------------------------------- 1 | const expect = require('chai').expect; 2 | const mocks = require('../mocks'); 3 | const chai = require('chai'); 4 | const chaiAsPromised = require("chai-as-promised"); 5 | chai.use(chaiAsPromised); 6 | 7 | const AggregateReadStrategy = require('../../src/read-strategy/AggregateReadStrategy'); 8 | const MetadataReadStrategy = require('../../src/read-strategy/MetadataReadStrategy'); 9 | const LongPathReadStrategy = require('../../src/read-strategy/LongPathReadStrategy'); 10 | const RandomAccessReadStrategy = require('../../src/read-strategy/RandomAccessReadStrategy'); 11 | 12 | describe('Read Strategies', function() { 13 | const strats = { 14 | AggregateRead: AggregateReadStrategy, 15 | MetadataRead: MetadataReadStrategy, 16 | LongPathRead: LongPathReadStrategy, 17 | RandomAccessRead: RandomAccessReadStrategy, 18 | }; 19 | 20 | Object.keys(strats).forEach(stratName => { 21 | const Strat = strats[stratName]; 22 | describe(`${stratName} Strategy`, () => { 23 | let s; 24 | let sp; 25 | let driver; 26 | 27 | beforeEach(() => { 28 | sp = new mocks.MockSessionPool(); 29 | s = new Strat({ sessionPool: sp, runConfig: {} }); 30 | driver = new mocks.MockDriver(); 31 | }); 32 | 33 | it('can be created', () => { 34 | expect(s).to.be.ok; 35 | }); 36 | 37 | it('is appropriately named', () => expect(s.name).to.equal(stratName)); 38 | 39 | it('has a setup method', () => expect(s.setup(driver)).to.be.fulfilled); 40 | 41 | it('runs exactly 1 read query, and that run is timed.', () => 42 | s.run() 43 | .then(results => { 44 | expect(sp.inUse).to.equal(0); 45 | expect(sp.session.reads).to.equal(1); 46 | expect(sp.session.writes).to.equal(0); 47 | expect(s.getTimings().length).to.be.greaterThan(0); 48 | })); 49 | }); 50 | }); 51 | }); -------------------------------------------------------------------------------- /test/run-configuration_test.js: -------------------------------------------------------------------------------- 1 | const expect = require('chai').expect; 2 | const assert = require('chai').assert; 3 | const runConfig = require('../src/run-configuration'); 4 | const ProbabilityTable = require('../src/stats/ProbabilityTable'); 5 | const _ = require('lodash'); 6 | 7 | describe('Run Configuration', function() { 8 | const args = { 9 | n: 10, p: 'admin', a: 'bolt://localhost', concurrency: 27, 10 | }; 11 | 12 | beforeEach(() => { 13 | process.env = {}; 14 | }); 15 | 16 | it('throws Error when missing n or ms', () => { 17 | expect(() => runConfig.generateFromArgs({})).to.throw(Error); 18 | }); 19 | 20 | it('throws Error when URI is missing', () => 21 | expect(() => runConfig.generateFromArgs({ n: 1 })).to.throw(Error)); 22 | 23 | it('throws Error when password is missing', () => 24 | expect(() => runConfig.generateFromArgs({ n: 1, a: 'bolt://localhost' })).to.throw(Error)); 25 | 26 | it('returns a good config with minimal input', () => { 27 | const c = runConfig.generateFromArgs(args); 28 | expect(c.username).to.equal('neo4j'); 29 | expect(c.password).to.equal(args.p); 30 | expect(c.address).to.equal(args.a); 31 | expect(c.runType).to.equal('counted'); 32 | expect(c.failFast).to.equal(false); 33 | expect(c.concurrency).to.equal(args.concurrency); 34 | expect(c.iterateUntil).to.be.ok; 35 | expect(c.probabilityTable).to.be.ok; 36 | expect(c.probabilityTable).to.be.instanceOf(ProbabilityTable); 37 | expect(c.checkpointFreq).to.be.ok; 38 | }); 39 | 40 | it('supports timed run types', () => { 41 | const newArgs = _.merge({ ms: 1000 }, _.pick(args, ['p', 'a'])); 42 | const c = runConfig.generateFromArgs(newArgs); 43 | expect(c.runType).to.equal('timed'); 44 | expect(c.ms).to.equal(newArgs.ms); 45 | }); 46 | 47 | it('returns a query and fixed probability table when asked', () => { 48 | const newArgs = _.merge({ 49 | query: 'RETURN 1;' 50 | }, args); 51 | 52 | const c = runConfig.generateFromArgs(newArgs); 53 | expect(c.query).to.equal(newArgs.query); 54 | expect(c.probabilityTable.choose()).to.equal('custom'); 55 | }); 56 | }); -------------------------------------------------------------------------------- /test/sessionPool_test.js: -------------------------------------------------------------------------------- 1 | const expect = require('chai').expect; 2 | const assert = require('chai').assert; 3 | const sessionPool = require('../src/sessionPool'); 4 | const mocks = require('./mocks'); 5 | 6 | describe('Session Pool', function() { 7 | const driver = new mocks.MockDriver(); 8 | let pool; 9 | 10 | beforeEach(() => { 11 | pool = sessionPool.getPool(driver, 10); 12 | expect(pool).to.be.ok; 13 | }); 14 | 15 | it('can acquire', () => { 16 | return pool.acquire() 17 | .then(s => { 18 | expect(s).to.be.ok; 19 | expect(s).to.be.instanceOf(mocks.MockSession); 20 | }); 21 | }); 22 | 23 | it('can release', () => { 24 | return pool.acquire() 25 | .then(s => pool.release(s)); 26 | }); 27 | }); -------------------------------------------------------------------------------- /test/stats/ProbabilityTable_test.js: -------------------------------------------------------------------------------- 1 | const expect = require('chai').expect; 2 | const ProbabilityTable = require('../../src/stats/ProbabilityTable'); 3 | 4 | describe('Stats', function() { 5 | let pt; 6 | const SURE_BET = 'Always heads'; 7 | const HEADS = 'heads'; 8 | const TAILS = 'tails'; 9 | 10 | const simple = [ 11 | [ 1.0, SURE_BET ], 12 | ]; 13 | 14 | const coinFlip = [ 15 | [ 0.5, HEADS ], 16 | [ 1.0, TAILS ], 17 | ]; 18 | 19 | it('should be constructable', () => 20 | expect(new ProbabilityTable(simple)).to.be.ok); 21 | 22 | describe('Validation', () => { 23 | it('Requires arrays', () => { 24 | expect(() => new ProbabilityTable(null)).to.throw(Error); 25 | expect(() => new ProbabilityTable({heads: 0.5})).to.throw(Error); 26 | }); 27 | 28 | it('requires nested arrays', () => { 29 | expect(() => new ProbabilityTable([])).to.throw(Error); 30 | expect(() => new ProbabilityTable([ {foo: 'bar' }])).to.throw(Error); 31 | }); 32 | }); 33 | 34 | it('chooses a sure thing when there is only one option', () => { 35 | const pt = new ProbabilityTable(simple); 36 | expect(pt.choose()).to.equal(SURE_BET); 37 | }); 38 | 39 | it('chooses the LAST ITEM when there is no 1.0 probability', () => { 40 | const pt = new ProbabilityTable([ 41 | [ 0.00000001, 'not gonna happen' ], 42 | [ 0.00000002, 'last item' ], 43 | ]); 44 | 45 | expect(pt.choose()).to.equal('last item'); 46 | }); 47 | 48 | it('always chooses one or the other in the coin flip scenario', () => { 49 | const pt = new ProbabilityTable(coinFlip); 50 | 51 | for (let i=0; i<1000; i++) { 52 | const choice = pt.choose(); 53 | 54 | expect(choice).to.be.oneOf([HEADS, TAILS]); 55 | } 56 | }); 57 | 58 | it('can return unique labels', () => { 59 | const pt = new ProbabilityTable([ 60 | [ 0.1, 'cat' ], 61 | [ 0.2, 'cat' ], 62 | [ 0.5, 'dog' ], 63 | [ 1, 'fox' ], 64 | ]); 65 | 66 | const labels = pt.getLabels(); 67 | expect(labels).to.contain('cat'); 68 | expect(labels).to.contain('dog'); 69 | expect(labels).to.contain('fox'); 70 | expect(labels.length).to.equal(3); 71 | }); 72 | }); -------------------------------------------------------------------------------- /test/stats/index_test.js: -------------------------------------------------------------------------------- 1 | const expect = require('chai').expect; 2 | const assert = require('chai').assert; 3 | const WorkloadStats = require('../../src/stats/'); 4 | 5 | describe('Stats', function() { 6 | let s; 7 | 8 | beforeEach(() => { 9 | s = new WorkloadStats(); 10 | }); 11 | 12 | it('should be constructable', () => expect(s).to.be.ok); 13 | 14 | it('should return a state', () => { 15 | expect(s.getState()).to.deep.equal({ 16 | complete: 0, running: 0, errors: 0, 17 | }); 18 | }); 19 | 20 | it('should be able to start a strategy', () => { 21 | s.startStrategy('foo'); 22 | expect(s.running).to.equal(1); 23 | expect(s.foo).to.equal(1); 24 | }); 25 | 26 | it('should be able to end a strategy', () => { 27 | s.startStrategy('foo'); 28 | const data = { bar: 1 }; 29 | const results = s.endStrategy(data); 30 | expect(s.complete).to.equal(1); 31 | expect(results).to.deep.equal(data); 32 | }); 33 | 34 | it('should allow flagging errors', () => { 35 | const err = new Error('Bad stuff'); 36 | s.errorSeen(err); 37 | expect(s.errors).to.equal(1); 38 | }); 39 | }); -------------------------------------------------------------------------------- /test/strategies_test.js: -------------------------------------------------------------------------------- 1 | const expect = require('chai').expect; 2 | const assert = require('chai').assert; 3 | const strategies = require('../src/strategies'); 4 | const ProbabilityTable = require('../src/stats/ProbabilityTable'); 5 | const Strategy = require('../src/Strategy'); 6 | const mocks = require('./mocks'); 7 | 8 | describe('Strategies', function() { 9 | const pool = new mocks.MockSessionPool(); 10 | let table; 11 | let mockRunConfig = { 12 | probabilityTable: new ProbabilityTable([ 13 | [ 1.0, 'custom'], 14 | ]), 15 | query: "RETURN 1", 16 | }; 17 | 18 | beforeEach(() => { 19 | table = strategies.builder(pool); 20 | }); 21 | 22 | it('should build a strategy table', () => { 23 | expect(table).to.be.ok; 24 | 25 | Object.values(table).forEach(strat => expect(strat).to.be.instanceOf(Strategy)); 26 | }); 27 | 28 | it('should build a strategy table with only things in the probability table', () => { 29 | const tbl = strategies.builder(pool, mockRunConfig); 30 | expect(Object.keys(tbl).length).to.equal(1); 31 | expect(tbl['custom']).to.be.instanceOf(Strategy); 32 | }); 33 | 34 | it('can report', () => { 35 | strategies.report(table); 36 | }); 37 | 38 | it('can show last query', () => { 39 | strategies.showLastQuery(table); 40 | }); 41 | }); -------------------------------------------------------------------------------- /test/termination-condition_test.js: -------------------------------------------------------------------------------- 1 | const expect = require('chai').expect; 2 | const assert = require('chai').assert; 3 | const tc = require('../src/termination-condition'); 4 | 5 | describe('Termination Conditions', function () { 6 | it('can make an nRuns termination condition', () => { 7 | const n = tc.nRuns(3); 8 | 9 | expect(n).to.be.ok; 10 | 11 | // Run 1 12 | let v = n.next(); 13 | expect(v.done).to.equal(false); 14 | 15 | // Run 2 16 | v = n.next(); 17 | expect(v.done).to.equal(false); 18 | console.log(n.progress()); 19 | expect(n.progress()).to.equal(2/3); 20 | 21 | // Run 3 22 | v = n.next(); 23 | expect(v.done).to.equal(false); 24 | 25 | v = n.next(); 26 | expect(v.done).to.equal(true); 27 | }); 28 | 29 | it('can make a timeoutMilliseconds termination condition', () => { 30 | const n = tc.timeoutMilliseconds(1000); 31 | 32 | return new Promise((resolve, reject) => { 33 | const p = n.next(); 34 | expect(p.done).to.equal(false); 35 | 36 | setTimeout(() => { 37 | const p = n.next(); 38 | expect(p.done).to.equal(false); 39 | }, 200); 40 | 41 | setTimeout(() => { 42 | const p = n.next(); 43 | expect(p.done).to.equal(true); 44 | resolve(true); 45 | }, 1005); 46 | }); 47 | }); 48 | }); -------------------------------------------------------------------------------- /test/test.js: -------------------------------------------------------------------------------- 1 | const expect = require('chai').expect; 2 | const assert = require('chai').assert; 3 | 4 | describe('Array', function() { 5 | describe('#indexOf()', function() { 6 | it('should return -1 when the value is not present', function() { 7 | assert.equal([1, 2, 3].indexOf(4), -1); 8 | }); 9 | }); 10 | }); -------------------------------------------------------------------------------- /test/workload_test.js: -------------------------------------------------------------------------------- 1 | const expect = require('chai').expect; 2 | const assert = require('chai').assert; 3 | const Workload = require('../src/workload'); 4 | const runConfig = require('../src/run-configuration'); 5 | const WorkloadStats = require('../src/stats/index'); 6 | const neo4j = require('neo4j-driver'); 7 | const sinon = require('sinon'); 8 | const mocks = require('./mocks'); 9 | 10 | sinon.replace(neo4j, 'driver', () => new mocks.MockDriver()); 11 | 12 | describe('Workload', function() { 13 | const args = { 14 | a: 'bolt://localhost', p: 'admin', n: 10, concurrency: 1, 15 | }; 16 | const rc = runConfig.generateFromArgs(args); 17 | 18 | let w; 19 | 20 | beforeEach(() => { 21 | w = new Workload(rc); 22 | }); 23 | 24 | it('should have basics', () => { 25 | expect(w.id).to.be.ok; 26 | expect(w.runConfig).to.deep.equal(rc); 27 | expect(w.interrupted).to.equal(false); 28 | expect(w.started).to.equal(false); 29 | }); 30 | 31 | it('should get runConfig', () => expect(w.getRunConfiguration()).to.deep.equal(rc)); 32 | 33 | it('can be initialized', () => { 34 | return w.initialize() 35 | .then(ready => { 36 | expect(w.getStats()).to.be.instanceOf(WorkloadStats); 37 | expect(w.promisePool).to.be.ok; 38 | expect(w.strategyTable).to.be.ok; 39 | expect(w.sessionPool).to.be.ok; 40 | }); 41 | }); 42 | 43 | it('can be started and run', () => { 44 | return w.initialize() 45 | .then(() => w.start()) 46 | .then(results => { 47 | const stats = w.getStats(); 48 | expect(stats.complete).to.equal(args.n); 49 | expect(stats.running).to.equal(0); 50 | }); 51 | }); 52 | }); -------------------------------------------------------------------------------- /test/write-strategy/write-strategy_test.js: -------------------------------------------------------------------------------- 1 | const expect = require('chai').expect; 2 | const mocks = require('../mocks'); 3 | const chai = require('chai'); 4 | const chaiAsPromised = require("chai-as-promised"); 5 | chai.use(chaiAsPromised); 6 | 7 | const NAryTreeStrategy = require('../../src/write-strategy/NAryTreeStrategy'); 8 | const FatNodeAppendStrategy = require('../../src/write-strategy/FatNodeAppendStrategy'); 9 | const MergeWriteStrategy = require('../../src/write-strategy/MergeWriteStrategy'); 10 | const RawWriteStrategy = require('../../src/write-strategy/RawWriteStrategy'); 11 | const StarWriteStrategy = require('../../src/write-strategy/StarWriteStrategy'); 12 | const IndexHeavyStrategy = require('../../src/write-strategy/IndexHeavyStrategy'); 13 | const LuceneWriteStrategy = require('../../src/write-strategy/LuceneWriteStrategy'); 14 | const LockTortureStrategy = require('../../src/write-strategy/LockTortureStrategy'); 15 | const RandomLinkageStrategy = require('../../src/write-strategy/RandomLinkageStrategy'); 16 | 17 | describe('Write Strategies', function() { 18 | const strats = { 19 | NAryTree: NAryTreeStrategy, 20 | FatNodeAppend: FatNodeAppendStrategy, 21 | RawWrite: RawWriteStrategy, 22 | StarWrite: StarWriteStrategy, 23 | IndexHeavy: IndexHeavyStrategy, 24 | LuceneWrite: LuceneWriteStrategy, 25 | LockTorture: LockTortureStrategy, 26 | RandomLinkage: RandomLinkageStrategy, 27 | MergeWrite: MergeWriteStrategy, 28 | }; 29 | 30 | Object.keys(strats).forEach(stratName => { 31 | const Strat = strats[stratName]; 32 | describe(`${stratName} Strategy`, () => { 33 | let s; 34 | let sp; 35 | let driver; 36 | 37 | beforeEach(() => { 38 | sp = new mocks.MockSessionPool(); 39 | s = new Strat({ sessionPool: sp, runConfig: {} }); 40 | driver = new mocks.MockDriver(); 41 | }); 42 | 43 | it('can be created', () => { 44 | expect(s).to.be.ok; 45 | }); 46 | 47 | it('is appropriately named', () => expect(s.name).to.equal(stratName)); 48 | 49 | it('has a setup method', () => expect(s.setup(driver)).to.be.fulfilled); 50 | 51 | it('runs exactly 1 write query, and for it to be timed.', () => 52 | s.run() 53 | .then(results => { 54 | expect(sp.inUse).to.equal(0); 55 | expect(sp.session.reads).to.equal(0); 56 | expect(sp.session.writes).to.equal(1); 57 | expect(s.getTimings().length).to.be.greaterThan(0); 58 | })); 59 | }); 60 | }); 61 | }); -------------------------------------------------------------------------------- /yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | "@babel/code-frame@^7.10.1": 6 | version "7.10.1" 7 | resolved "https://neo.jfrog.io/neo/api/npm/npm/@babel/code-frame/-/code-frame-7.10.1.tgz#d5481c5095daa1c57e16e54c6f9198443afb49ff" 8 | integrity sha1-1UgcUJXaocV+FuVMb5GYRDr7Sf8= 9 | dependencies: 10 | "@babel/highlight" "^7.10.1" 11 | 12 | "@babel/core@^7.7.5": 13 | version "7.10.2" 14 | resolved "https://neo.jfrog.io/neo/api/npm/npm/@babel/core/-/core-7.10.2.tgz#bd6786046668a925ac2bd2fd95b579b92a23b36a" 15 | integrity sha1-vWeGBGZoqSWsK9L9lbV5uSojs2o= 16 | dependencies: 17 | "@babel/code-frame" "^7.10.1" 18 | "@babel/generator" "^7.10.2" 19 | "@babel/helper-module-transforms" "^7.10.1" 20 | "@babel/helpers" "^7.10.1" 21 | "@babel/parser" "^7.10.2" 22 | "@babel/template" "^7.10.1" 23 | "@babel/traverse" "^7.10.1" 24 | "@babel/types" "^7.10.2" 25 | convert-source-map "^1.7.0" 26 | debug "^4.1.0" 27 | gensync "^1.0.0-beta.1" 28 | json5 "^2.1.2" 29 | lodash "^4.17.13" 30 | resolve "^1.3.2" 31 | semver "^5.4.1" 32 | source-map "^0.5.0" 33 | 34 | "@babel/generator@^7.10.1", "@babel/generator@^7.10.2": 35 | version "7.10.2" 36 | resolved "https://neo.jfrog.io/neo/api/npm/npm/@babel/generator/-/generator-7.10.2.tgz#0fa5b5b2389db8bfdfcc3492b551ee20f5dd69a9" 37 | integrity sha1-D6W1sjiduL/fzDSStVHuIPXdaak= 38 | dependencies: 39 | "@babel/types" "^7.10.2" 40 | jsesc "^2.5.1" 41 | lodash "^4.17.13" 42 | source-map "^0.5.0" 43 | 44 | "@babel/helper-function-name@^7.10.1": 45 | version "7.10.1" 46 | resolved "https://neo.jfrog.io/neo/api/npm/npm/@babel/helper-function-name/-/helper-function-name-7.10.1.tgz#92bd63829bfc9215aca9d9defa85f56b539454f4" 47 | integrity sha1-kr1jgpv8khWsqdne+oX1a1OUVPQ= 48 | dependencies: 49 | "@babel/helper-get-function-arity" "^7.10.1" 50 | "@babel/template" "^7.10.1" 51 | "@babel/types" "^7.10.1" 52 | 53 | "@babel/helper-get-function-arity@^7.10.1": 54 | version "7.10.1" 55 | resolved "https://neo.jfrog.io/neo/api/npm/npm/@babel/helper-get-function-arity/-/helper-get-function-arity-7.10.1.tgz#7303390a81ba7cb59613895a192b93850e373f7d" 56 | integrity sha1-cwM5CoG6fLWWE4laGSuThQ43P30= 57 | dependencies: 58 | "@babel/types" "^7.10.1" 59 | 60 | "@babel/helper-member-expression-to-functions@^7.10.1": 61 | version "7.10.1" 62 | resolved "https://neo.jfrog.io/neo/api/npm/npm/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.10.1.tgz#432967fd7e12a4afef66c4687d4ca22bc0456f15" 63 | integrity sha1-Qyln/X4SpK/vZsRofUyiK8BFbxU= 64 | dependencies: 65 | "@babel/types" "^7.10.1" 66 | 67 | "@babel/helper-module-imports@^7.10.1": 68 | version "7.10.1" 69 | resolved "https://neo.jfrog.io/neo/api/npm/npm/@babel/helper-module-imports/-/helper-module-imports-7.10.1.tgz#dd331bd45bccc566ce77004e9d05fe17add13876" 70 | integrity sha1-3TMb1FvMxWbOdwBOnQX+F63ROHY= 71 | dependencies: 72 | "@babel/types" "^7.10.1" 73 | 74 | "@babel/helper-module-transforms@^7.10.1": 75 | version "7.10.1" 76 | resolved "https://neo.jfrog.io/neo/api/npm/npm/@babel/helper-module-transforms/-/helper-module-transforms-7.10.1.tgz#24e2f08ee6832c60b157bb0936c86bef7210c622" 77 | integrity sha1-JOLwjuaDLGCxV7sJNshr73IQxiI= 78 | dependencies: 79 | "@babel/helper-module-imports" "^7.10.1" 80 | "@babel/helper-replace-supers" "^7.10.1" 81 | "@babel/helper-simple-access" "^7.10.1" 82 | "@babel/helper-split-export-declaration" "^7.10.1" 83 | "@babel/template" "^7.10.1" 84 | "@babel/types" "^7.10.1" 85 | lodash "^4.17.13" 86 | 87 | "@babel/helper-optimise-call-expression@^7.10.1": 88 | version "7.10.1" 89 | resolved "https://neo.jfrog.io/neo/api/npm/npm/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.10.1.tgz#b4a1f2561870ce1247ceddb02a3860fa96d72543" 90 | integrity sha1-tKHyVhhwzhJHzt2wKjhg+pbXJUM= 91 | dependencies: 92 | "@babel/types" "^7.10.1" 93 | 94 | "@babel/helper-replace-supers@^7.10.1": 95 | version "7.10.1" 96 | resolved "https://neo.jfrog.io/neo/api/npm/npm/@babel/helper-replace-supers/-/helper-replace-supers-7.10.1.tgz#ec6859d20c5d8087f6a2dc4e014db7228975f13d" 97 | integrity sha1-7GhZ0gxdgIf2otxOAU23Iol18T0= 98 | dependencies: 99 | "@babel/helper-member-expression-to-functions" "^7.10.1" 100 | "@babel/helper-optimise-call-expression" "^7.10.1" 101 | "@babel/traverse" "^7.10.1" 102 | "@babel/types" "^7.10.1" 103 | 104 | "@babel/helper-simple-access@^7.10.1": 105 | version "7.10.1" 106 | resolved "https://neo.jfrog.io/neo/api/npm/npm/@babel/helper-simple-access/-/helper-simple-access-7.10.1.tgz#08fb7e22ace9eb8326f7e3920a1c2052f13d851e" 107 | integrity sha1-CPt+Iqzp64Mm9+OSChwgUvE9hR4= 108 | dependencies: 109 | "@babel/template" "^7.10.1" 110 | "@babel/types" "^7.10.1" 111 | 112 | "@babel/helper-split-export-declaration@^7.10.1": 113 | version "7.10.1" 114 | resolved "https://neo.jfrog.io/neo/api/npm/npm/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.10.1.tgz#c6f4be1cbc15e3a868e4c64a17d5d31d754da35f" 115 | integrity sha1-xvS+HLwV46ho5MZKF9XTHXVNo18= 116 | dependencies: 117 | "@babel/types" "^7.10.1" 118 | 119 | "@babel/helper-validator-identifier@^7.10.1": 120 | version "7.10.1" 121 | resolved "https://neo.jfrog.io/neo/api/npm/npm/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.1.tgz#5770b0c1a826c4f53f5ede5e153163e0318e94b5" 122 | integrity sha1-V3CwwagmxPU/Xt5eFTFj4DGOlLU= 123 | 124 | "@babel/helpers@^7.10.1": 125 | version "7.10.1" 126 | resolved "https://neo.jfrog.io/neo/api/npm/npm/@babel/helpers/-/helpers-7.10.1.tgz#a6827b7cb975c9d9cef5fd61d919f60d8844a973" 127 | integrity sha1-poJ7fLl1ydnO9f1h2Rn2DYhEqXM= 128 | dependencies: 129 | "@babel/template" "^7.10.1" 130 | "@babel/traverse" "^7.10.1" 131 | "@babel/types" "^7.10.1" 132 | 133 | "@babel/highlight@^7.10.1": 134 | version "7.10.1" 135 | resolved "https://neo.jfrog.io/neo/api/npm/npm/@babel/highlight/-/highlight-7.10.1.tgz#841d098ba613ba1a427a2b383d79e35552c38ae0" 136 | integrity sha1-hB0Ji6YTuhpCeis4PXnjVVLDiuA= 137 | dependencies: 138 | "@babel/helper-validator-identifier" "^7.10.1" 139 | chalk "^2.0.0" 140 | js-tokens "^4.0.0" 141 | 142 | "@babel/parser@^7.10.1", "@babel/parser@^7.10.2": 143 | version "7.10.2" 144 | resolved "https://neo.jfrog.io/neo/api/npm/npm/@babel/parser/-/parser-7.10.2.tgz#871807f10442b92ff97e4783b9b54f6a0ca812d0" 145 | integrity sha1-hxgH8QRCuS/5fkeDubVPagyoEtA= 146 | 147 | "@babel/runtime@^7.9.6": 148 | version "7.11.2" 149 | resolved "https://neo.jfrog.io/neo/api/npm/npm/@babel/runtime/-/runtime-7.11.2.tgz#f549c13c754cc40b87644b9fa9f09a6a95fe0736" 150 | integrity sha1-9UnBPHVMxAuHZEufqfCaapX+BzY= 151 | dependencies: 152 | regenerator-runtime "^0.13.4" 153 | 154 | "@babel/template@^7.10.1": 155 | version "7.10.1" 156 | resolved "https://neo.jfrog.io/neo/api/npm/npm/@babel/template/-/template-7.10.1.tgz#e167154a94cb5f14b28dc58f5356d2162f539811" 157 | integrity sha1-4WcVSpTLXxSyjcWPU1bSFi9TmBE= 158 | dependencies: 159 | "@babel/code-frame" "^7.10.1" 160 | "@babel/parser" "^7.10.1" 161 | "@babel/types" "^7.10.1" 162 | 163 | "@babel/traverse@^7.10.1": 164 | version "7.10.1" 165 | resolved "https://neo.jfrog.io/neo/api/npm/npm/@babel/traverse/-/traverse-7.10.1.tgz#bbcef3031e4152a6c0b50147f4958df54ca0dd27" 166 | integrity sha1-u87zAx5BUqbAtQFH9JWN9Uyg3Sc= 167 | dependencies: 168 | "@babel/code-frame" "^7.10.1" 169 | "@babel/generator" "^7.10.1" 170 | "@babel/helper-function-name" "^7.10.1" 171 | "@babel/helper-split-export-declaration" "^7.10.1" 172 | "@babel/parser" "^7.10.1" 173 | "@babel/types" "^7.10.1" 174 | debug "^4.1.0" 175 | globals "^11.1.0" 176 | lodash "^4.17.13" 177 | 178 | "@babel/types@^7.10.1", "@babel/types@^7.10.2": 179 | version "7.10.2" 180 | resolved "https://neo.jfrog.io/neo/api/npm/npm/@babel/types/-/types-7.10.2.tgz#30283be31cad0dbf6fb00bd40641ca0ea675172d" 181 | integrity sha1-MCg74xytDb9vsAvUBkHKDqZ1Fy0= 182 | dependencies: 183 | "@babel/helper-validator-identifier" "^7.10.1" 184 | lodash "^4.17.13" 185 | to-fast-properties "^2.0.0" 186 | 187 | "@istanbuljs/load-nyc-config@^1.0.0": 188 | version "1.1.0" 189 | resolved "https://neo.jfrog.io/neo/api/npm/npm/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz#fd3db1d59ecf7cf121e80650bb86712f9b55eced" 190 | integrity sha1-/T2x1Z7PfPEh6AZQu4ZxL5tV7O0= 191 | dependencies: 192 | camelcase "^5.3.1" 193 | find-up "^4.1.0" 194 | get-package-type "^0.1.0" 195 | js-yaml "^3.13.1" 196 | resolve-from "^5.0.0" 197 | 198 | "@istanbuljs/schema@^0.1.2": 199 | version "0.1.2" 200 | resolved "https://neo.jfrog.io/neo/api/npm/npm/@istanbuljs/schema/-/schema-0.1.2.tgz#26520bf09abe4a5644cd5414e37125a8954241dd" 201 | integrity sha1-JlIL8Jq+SlZEzVQU43ElqJVCQd0= 202 | 203 | "@sinonjs/commons@^1.0.2", "@sinonjs/commons@^1.3.0": 204 | version "1.3.0" 205 | resolved "https://neo.jfrog.io/neo/api/npm/npm/@sinonjs/commons/-/commons-1.3.0.tgz#50a2754016b6f30a994ceda6d9a0a8c36adda849" 206 | integrity sha1-UKJ1QBa28wqZTO2m2aCow2rdqEk= 207 | dependencies: 208 | type-detect "4.0.8" 209 | 210 | "@sinonjs/formatio@^3.1.0": 211 | version "3.1.0" 212 | resolved "https://neo.jfrog.io/neo/api/npm/npm/@sinonjs/formatio/-/formatio-3.1.0.tgz#6ac9d1eb1821984d84c4996726e45d1646d8cce5" 213 | integrity sha1-asnR6xghmE2ExJlnJuRdFkbYzOU= 214 | dependencies: 215 | "@sinonjs/samsam" "^2 || ^3" 216 | 217 | "@sinonjs/samsam@^2 || ^3", "@sinonjs/samsam@^3.1.1": 218 | version "3.2.0" 219 | resolved "https://neo.jfrog.io/neo/api/npm/npm/@sinonjs/samsam/-/samsam-3.2.0.tgz#58c62b5f1f42e46d039d073d0ae2753da676bf0c" 220 | integrity sha1-WMYrXx9C5G0DnQc9CuJ1PaZ2vww= 221 | dependencies: 222 | "@sinonjs/commons" "^1.0.2" 223 | array-from "^2.1.1" 224 | lodash "^4.17.11" 225 | 226 | "@sinonjs/text-encoding@^0.7.1": 227 | version "0.7.1" 228 | resolved "https://neo.jfrog.io/neo/api/npm/npm/@sinonjs/text-encoding/-/text-encoding-0.7.1.tgz#8da5c6530915653f3a1f38fd5f101d8c3f8079c5" 229 | integrity sha1-jaXGUwkVZT86Hzj9XxAdjD+AecU= 230 | 231 | "@types/color-name@^1.1.1": 232 | version "1.1.1" 233 | resolved "https://neo.jfrog.io/neo/api/npm/npm/@types/color-name/-/color-name-1.1.1.tgz#1c1261bbeaa10a8055bbc5d8ab84b7b2afc846a0" 234 | integrity sha1-HBJhu+qhCoBVu8XYq4S3sq/IRqA= 235 | 236 | aggregate-error@^3.0.0: 237 | version "3.0.1" 238 | resolved "https://neo.jfrog.io/neo/api/npm/npm/aggregate-error/-/aggregate-error-3.0.1.tgz#db2fe7246e536f40d9b5442a39e117d7dd6a24e0" 239 | integrity sha1-2y/nJG5Tb0DZtUQqOeEX191qJOA= 240 | dependencies: 241 | clean-stack "^2.0.0" 242 | indent-string "^4.0.0" 243 | 244 | ansi-colors@3.2.3: 245 | version "3.2.3" 246 | resolved "https://neo.jfrog.io/neo/api/npm/npm/ansi-colors/-/ansi-colors-3.2.3.tgz#57d35b8686e851e2cc04c403f1c00203976a1813" 247 | integrity sha1-V9NbhoboUeLMBMQD8cACA5dqGBM= 248 | 249 | ansi-regex@^2.0.0: 250 | version "2.1.1" 251 | resolved "https://neo.jfrog.io/neo/api/npm/npm/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" 252 | integrity sha1-w7M6te42DYbg5ijwRorn7yfWVN8= 253 | 254 | ansi-regex@^3.0.0: 255 | version "3.0.0" 256 | resolved "https://neo.jfrog.io/neo/api/npm/npm/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" 257 | integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg= 258 | 259 | ansi-regex@^4.1.0: 260 | version "4.1.0" 261 | resolved "https://neo.jfrog.io/neo/api/npm/npm/ansi-regex/-/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997" 262 | integrity sha1-i5+PCM8ay4Q3Vqg5yox+MWjFGZc= 263 | 264 | ansi-regex@^5.0.0: 265 | version "5.0.0" 266 | resolved "https://neo.jfrog.io/neo/api/npm/npm/ansi-regex/-/ansi-regex-5.0.0.tgz#388539f55179bf39339c81af30a654d69f87cb75" 267 | integrity sha1-OIU59VF5vzkznIGvMKZU1p+Hy3U= 268 | 269 | ansi-styles@^3.2.0, ansi-styles@^3.2.1: 270 | version "3.2.1" 271 | resolved "https://neo.jfrog.io/neo/api/npm/npm/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" 272 | integrity sha1-QfuyAkPlCxK+DwS43tvwdSDOhB0= 273 | dependencies: 274 | color-convert "^1.9.0" 275 | 276 | ansi-styles@^4.0.0: 277 | version "4.2.1" 278 | resolved "https://neo.jfrog.io/neo/api/npm/npm/ansi-styles/-/ansi-styles-4.2.1.tgz#90ae75c424d008d2624c5bf29ead3177ebfcf359" 279 | integrity sha1-kK51xCTQCNJiTFvynq0xd+v881k= 280 | dependencies: 281 | "@types/color-name" "^1.1.1" 282 | color-convert "^2.0.1" 283 | 284 | anymatch@~3.1.1: 285 | version "3.1.1" 286 | resolved "https://neo.jfrog.io/neo/api/npm/npm/anymatch/-/anymatch-3.1.1.tgz#c55ecf02185e2469259399310c173ce31233b142" 287 | integrity sha1-xV7PAhheJGklk5kxDBc84xIzsUI= 288 | dependencies: 289 | normalize-path "^3.0.0" 290 | picomatch "^2.0.4" 291 | 292 | append-transform@^2.0.0: 293 | version "2.0.0" 294 | resolved "https://neo.jfrog.io/neo/api/npm/npm/append-transform/-/append-transform-2.0.0.tgz#99d9d29c7b38391e6f428d28ce136551f0b77e12" 295 | integrity sha1-mdnSnHs4OR5vQo0ozhNlUfC3fhI= 296 | dependencies: 297 | default-require-extensions "^3.0.0" 298 | 299 | archy@^1.0.0: 300 | version "1.0.0" 301 | resolved "https://neo.jfrog.io/neo/api/npm/npm/archy/-/archy-1.0.0.tgz#f9c8c13757cc1dd7bc379ac77b2c62a5c2868c40" 302 | integrity sha1-+cjBN1fMHde8N5rHeyxipcKGjEA= 303 | 304 | argparse@^1.0.7: 305 | version "1.0.10" 306 | resolved "https://neo.jfrog.io/neo/api/npm/npm/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" 307 | integrity sha1-vNZ5HqWuCXJeF+WtmIE0zUCz2RE= 308 | dependencies: 309 | sprintf-js "~1.0.2" 310 | 311 | array-from@^2.1.1: 312 | version "2.1.1" 313 | resolved "https://neo.jfrog.io/neo/api/npm/npm/array-from/-/array-from-2.1.1.tgz#cfe9d8c26628b9dc5aecc62a9f5d8f1f352c1195" 314 | integrity sha1-z+nYwmYoudxa7MYqn12PHzUsEZU= 315 | 316 | array-uniq@1.0.2: 317 | version "1.0.2" 318 | resolved "https://neo.jfrog.io/neo/api/npm/npm/array-uniq/-/array-uniq-1.0.2.tgz#5fcc373920775723cfd64d65c64bef53bf9eba6d" 319 | integrity sha1-X8w3OSB3VyPP1k1lxkvvU7+eum0= 320 | 321 | assertion-error@^1.1.0: 322 | version "1.1.0" 323 | resolved "https://neo.jfrog.io/neo/api/npm/npm/assertion-error/-/assertion-error-1.1.0.tgz#e60b6b0e8f301bd97e5375215bda406c85118c0b" 324 | integrity sha1-5gtrDo8wG9l+U3UhW9pAbIURjAs= 325 | 326 | balanced-match@^1.0.0: 327 | version "1.0.0" 328 | resolved "https://neo.jfrog.io/neo/api/npm/npm/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" 329 | integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c= 330 | 331 | binary-extensions@^2.0.0: 332 | version "2.0.0" 333 | resolved "https://neo.jfrog.io/neo/api/npm/npm/binary-extensions/-/binary-extensions-2.0.0.tgz#23c0df14f6a88077f5f986c0d167ec03c3d5537c" 334 | integrity sha1-I8DfFPaogHf1+YbA0WfsA8PVU3w= 335 | 336 | bluebird@^3.7.2: 337 | version "3.7.2" 338 | resolved "https://neo.jfrog.io/neo/api/npm/npm/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f" 339 | integrity sha1-nyKcFb4nJFT/qXOs4NvueaGww28= 340 | 341 | brace-expansion@^1.1.7: 342 | version "1.1.11" 343 | resolved "https://neo.jfrog.io/neo/api/npm/npm/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" 344 | integrity sha1-PH/L9SnYcibz0vUrlm/1Jx60Qd0= 345 | dependencies: 346 | balanced-match "^1.0.0" 347 | concat-map "0.0.1" 348 | 349 | braces@~3.0.2: 350 | version "3.0.2" 351 | resolved "https://neo.jfrog.io/neo/api/npm/npm/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" 352 | integrity sha1-NFThpGLujVmeI23zNs2epPiv4Qc= 353 | dependencies: 354 | fill-range "^7.0.1" 355 | 356 | browser-stdout@1.3.1: 357 | version "1.3.1" 358 | resolved "https://neo.jfrog.io/neo/api/npm/npm/browser-stdout/-/browser-stdout-1.3.1.tgz#baa559ee14ced73452229bad7326467c61fabd60" 359 | integrity sha1-uqVZ7hTO1zRSIputcyZGfGH6vWA= 360 | 361 | caching-transform@^4.0.0: 362 | version "4.0.0" 363 | resolved "https://neo.jfrog.io/neo/api/npm/npm/caching-transform/-/caching-transform-4.0.0.tgz#00d297a4206d71e2163c39eaffa8157ac0651f0f" 364 | integrity sha1-ANKXpCBtceIWPDnq/6gVesBlHw8= 365 | dependencies: 366 | hasha "^5.0.0" 367 | make-dir "^3.0.0" 368 | package-hash "^4.0.0" 369 | write-file-atomic "^3.0.0" 370 | 371 | camelcase@^5.0.0: 372 | version "5.0.0" 373 | resolved "https://neo.jfrog.io/neo/api/npm/npm/camelcase/-/camelcase-5.0.0.tgz#03295527d58bd3cd4aa75363f35b2e8d97be2f42" 374 | integrity sha1-AylVJ9WL081Kp1Nj81sujZe+L0I= 375 | 376 | camelcase@^5.3.1: 377 | version "5.3.1" 378 | resolved "https://neo.jfrog.io/neo/api/npm/npm/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" 379 | integrity sha1-48mzFWnhBoEd8kL3FXJaH0xJQyA= 380 | 381 | chai-as-promised@^7.1.1: 382 | version "7.1.1" 383 | resolved "https://neo.jfrog.io/neo/api/npm/npm/chai-as-promised/-/chai-as-promised-7.1.1.tgz#08645d825deb8696ee61725dbf590c012eb00ca0" 384 | integrity sha1-CGRdgl3rhpbuYXJdv1kMAS6wDKA= 385 | dependencies: 386 | check-error "^1.0.2" 387 | 388 | chai@^4.2.0: 389 | version "4.2.0" 390 | resolved "https://neo.jfrog.io/neo/api/npm/npm/chai/-/chai-4.2.0.tgz#760aa72cf20e3795e84b12877ce0e83737aa29e5" 391 | integrity sha1-dgqnLPION5XoSxKHfODoNzeqKeU= 392 | dependencies: 393 | assertion-error "^1.1.0" 394 | check-error "^1.0.2" 395 | deep-eql "^3.0.1" 396 | get-func-name "^2.0.0" 397 | pathval "^1.1.0" 398 | type-detect "^4.0.5" 399 | 400 | chalk@^2.0.0, chalk@^2.4.2: 401 | version "2.4.2" 402 | resolved "https://neo.jfrog.io/neo/api/npm/npm/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" 403 | integrity sha1-zUJUFnelQzPPVBpJEIwUMrRMlCQ= 404 | dependencies: 405 | ansi-styles "^3.2.1" 406 | escape-string-regexp "^1.0.5" 407 | supports-color "^5.3.0" 408 | 409 | check-error@^1.0.2: 410 | version "1.0.2" 411 | resolved "https://neo.jfrog.io/neo/api/npm/npm/check-error/-/check-error-1.0.2.tgz#574d312edd88bb5dd8912e9286dd6c0aed4aac82" 412 | integrity sha1-V00xLt2Iu13YkS6Sht1sCu1KrII= 413 | 414 | chokidar@3.3.0: 415 | version "3.3.0" 416 | resolved "https://neo.jfrog.io/neo/api/npm/npm/chokidar/-/chokidar-3.3.0.tgz#12c0714668c55800f659e262d4962a97faf554a6" 417 | integrity sha1-EsBxRmjFWAD2WeJi1JYql/r1VKY= 418 | dependencies: 419 | anymatch "~3.1.1" 420 | braces "~3.0.2" 421 | glob-parent "~5.1.0" 422 | is-binary-path "~2.1.0" 423 | is-glob "~4.0.1" 424 | normalize-path "~3.0.0" 425 | readdirp "~3.2.0" 426 | optionalDependencies: 427 | fsevents "~2.1.1" 428 | 429 | clean-stack@^2.0.0: 430 | version "2.2.0" 431 | resolved "https://neo.jfrog.io/neo/api/npm/npm/clean-stack/-/clean-stack-2.2.0.tgz#ee8472dbb129e727b31e8a10a427dee9dfe4008b" 432 | integrity sha1-7oRy27Ep5yezHooQpCfe6d/kAIs= 433 | 434 | cliui@^4.0.0: 435 | version "4.1.0" 436 | resolved "https://neo.jfrog.io/neo/api/npm/npm/cliui/-/cliui-4.1.0.tgz#348422dbe82d800b3022eef4f6ac10bf2e4d1b49" 437 | integrity sha1-NIQi2+gtgAswIu709qwQvy5NG0k= 438 | dependencies: 439 | string-width "^2.1.1" 440 | strip-ansi "^4.0.0" 441 | wrap-ansi "^2.0.0" 442 | 443 | cliui@^5.0.0: 444 | version "5.0.0" 445 | resolved "https://neo.jfrog.io/neo/api/npm/npm/cliui/-/cliui-5.0.0.tgz#deefcfdb2e800784aa34f46fa08e06851c7bbbc5" 446 | integrity sha1-3u/P2y6AB4SqNPRvoI4GhRx7u8U= 447 | dependencies: 448 | string-width "^3.1.0" 449 | strip-ansi "^5.2.0" 450 | wrap-ansi "^5.1.0" 451 | 452 | cliui@^6.0.0: 453 | version "6.0.0" 454 | resolved "https://neo.jfrog.io/neo/api/npm/npm/cliui/-/cliui-6.0.0.tgz#511d702c0c4e41ca156d7d0e96021f23e13225b1" 455 | integrity sha1-UR1wLAxOQcoVbX0OlgIfI+EyJbE= 456 | dependencies: 457 | string-width "^4.2.0" 458 | strip-ansi "^6.0.0" 459 | wrap-ansi "^6.2.0" 460 | 461 | code-point-at@^1.0.0: 462 | version "1.1.0" 463 | resolved "https://neo.jfrog.io/neo/api/npm/npm/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" 464 | integrity sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c= 465 | 466 | color-convert@^1.9.0: 467 | version "1.9.3" 468 | resolved "https://neo.jfrog.io/neo/api/npm/npm/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" 469 | integrity sha1-u3GFBpDh8TZWfeYp0tVHHe2kweg= 470 | dependencies: 471 | color-name "1.1.3" 472 | 473 | color-convert@^2.0.1: 474 | version "2.0.1" 475 | resolved "https://neo.jfrog.io/neo/api/npm/npm/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" 476 | integrity sha1-ctOmjVmMm9s68q0ehPIdiWq9TeM= 477 | dependencies: 478 | color-name "~1.1.4" 479 | 480 | color-name@1.1.3: 481 | version "1.1.3" 482 | resolved "https://neo.jfrog.io/neo/api/npm/npm/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" 483 | integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= 484 | 485 | color-name@~1.1.4: 486 | version "1.1.4" 487 | resolved "https://neo.jfrog.io/neo/api/npm/npm/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" 488 | integrity sha1-wqCah6y95pVD3m9j+jmVyCbFNqI= 489 | 490 | commondir@^1.0.1: 491 | version "1.0.1" 492 | resolved "https://neo.jfrog.io/neo/api/npm/npm/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b" 493 | integrity sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs= 494 | 495 | concat-map@0.0.1: 496 | version "0.0.1" 497 | resolved "https://neo.jfrog.io/neo/api/npm/npm/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" 498 | integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= 499 | 500 | convert-source-map@^1.7.0: 501 | version "1.7.0" 502 | resolved "https://neo.jfrog.io/neo/api/npm/npm/convert-source-map/-/convert-source-map-1.7.0.tgz#17a2cb882d7f77d3490585e2ce6c524424a3a442" 503 | integrity sha1-F6LLiC1/d9NJBYXizmxSRCSjpEI= 504 | dependencies: 505 | safe-buffer "~5.1.1" 506 | 507 | cross-spawn@^6.0.0: 508 | version "6.0.5" 509 | resolved "https://neo.jfrog.io/neo/api/npm/npm/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" 510 | integrity sha1-Sl7Hxk364iw6FBJNus3uhG2Ay8Q= 511 | dependencies: 512 | nice-try "^1.0.4" 513 | path-key "^2.0.1" 514 | semver "^5.5.0" 515 | shebang-command "^1.2.0" 516 | which "^1.2.9" 517 | 518 | cross-spawn@^7.0.0: 519 | version "7.0.3" 520 | resolved "https://neo.jfrog.io/neo/api/npm/npm/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" 521 | integrity sha1-9zqFudXUHQRVUcF34ogtSshXKKY= 522 | dependencies: 523 | path-key "^3.1.0" 524 | shebang-command "^2.0.0" 525 | which "^2.0.1" 526 | 527 | debug@3.2.6: 528 | version "3.2.6" 529 | resolved "https://neo.jfrog.io/neo/api/npm/npm/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b" 530 | integrity sha1-6D0X3hbYp++3cX7b5fsQE17uYps= 531 | dependencies: 532 | ms "^2.1.1" 533 | 534 | debug@^4.1.0, debug@^4.1.1: 535 | version "4.1.1" 536 | resolved "https://neo.jfrog.io/neo/api/npm/npm/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791" 537 | integrity sha1-O3ImAlUQnGtYnO4FDx1RYTlmR5E= 538 | dependencies: 539 | ms "^2.1.1" 540 | 541 | decamelize@^1.2.0: 542 | version "1.2.0" 543 | resolved "https://neo.jfrog.io/neo/api/npm/npm/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" 544 | integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA= 545 | 546 | deep-eql@^3.0.1: 547 | version "3.0.1" 548 | resolved "https://neo.jfrog.io/neo/api/npm/npm/deep-eql/-/deep-eql-3.0.1.tgz#dfc9404400ad1c8fe023e7da1df1c147c4b444df" 549 | integrity sha1-38lARACtHI/gI+faHfHBR8S0RN8= 550 | dependencies: 551 | type-detect "^4.0.0" 552 | 553 | default-require-extensions@^3.0.0: 554 | version "3.0.0" 555 | resolved "https://neo.jfrog.io/neo/api/npm/npm/default-require-extensions/-/default-require-extensions-3.0.0.tgz#e03f93aac9b2b6443fc52e5e4a37b3ad9ad8df96" 556 | integrity sha1-4D+TqsmytkQ/xS5eSjezrZrY35Y= 557 | dependencies: 558 | strip-bom "^4.0.0" 559 | 560 | define-properties@^1.1.2: 561 | version "1.1.3" 562 | resolved "https://neo.jfrog.io/neo/api/npm/npm/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1" 563 | integrity sha1-z4jabL7ib+bbcJT2HYcMvYTO6fE= 564 | dependencies: 565 | object-keys "^1.0.12" 566 | 567 | diff@3.5.0, diff@^3.5.0: 568 | version "3.5.0" 569 | resolved "https://neo.jfrog.io/neo/api/npm/npm/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12" 570 | integrity sha1-gAwN0eCov7yVg1wgKtIg/jF+WhI= 571 | 572 | dimsum@^0.2.2: 573 | version "0.2.2" 574 | resolved "https://neo.jfrog.io/neo/api/npm/npm/dimsum/-/dimsum-0.2.2.tgz#6c0b0469f19cf6979a8a0318948786a1ef2b4cdc" 575 | integrity sha1-bAsEafGc9peaigMYlIeGoe8rTNw= 576 | 577 | emoji-regex@^7.0.1: 578 | version "7.0.3" 579 | resolved "https://neo.jfrog.io/neo/api/npm/npm/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156" 580 | integrity sha1-kzoEBShgyF6DwSJHnEdIqOTHIVY= 581 | 582 | emoji-regex@^8.0.0: 583 | version "8.0.0" 584 | resolved "https://neo.jfrog.io/neo/api/npm/npm/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" 585 | integrity sha1-6Bj9ac5cz8tARZT4QpY79TFkzDc= 586 | 587 | end-of-stream@^1.1.0: 588 | version "1.4.1" 589 | resolved "https://neo.jfrog.io/neo/api/npm/npm/end-of-stream/-/end-of-stream-1.4.1.tgz#ed29634d19baba463b6ce6b80a37213eab71ec43" 590 | integrity sha1-7SljTRm6ukY7bOa4CjchPqtx7EM= 591 | dependencies: 592 | once "^1.4.0" 593 | 594 | es-abstract@^1.5.1: 595 | version "1.13.0" 596 | resolved "https://neo.jfrog.io/neo/api/npm/npm/es-abstract/-/es-abstract-1.13.0.tgz#ac86145fdd5099d8dd49558ccba2eaf9b88e24e9" 597 | integrity sha1-rIYUX91QmdjdSVWMy6Lq+biOJOk= 598 | dependencies: 599 | es-to-primitive "^1.2.0" 600 | function-bind "^1.1.1" 601 | has "^1.0.3" 602 | is-callable "^1.1.4" 603 | is-regex "^1.0.4" 604 | object-keys "^1.0.12" 605 | 606 | es-to-primitive@^1.2.0: 607 | version "1.2.0" 608 | resolved "https://neo.jfrog.io/neo/api/npm/npm/es-to-primitive/-/es-to-primitive-1.2.0.tgz#edf72478033456e8dda8ef09e00ad9650707f377" 609 | integrity sha1-7fckeAM0VujdqO8J4ArZZQcH83c= 610 | dependencies: 611 | is-callable "^1.1.4" 612 | is-date-object "^1.0.1" 613 | is-symbol "^1.0.2" 614 | 615 | es6-error@^4.0.1: 616 | version "4.1.1" 617 | resolved "https://neo.jfrog.io/neo/api/npm/npm/es6-error/-/es6-error-4.1.1.tgz#9e3af407459deed47e9a91f9b885a84eb05c561d" 618 | integrity sha1-njr0B0Wd7tR+mpH5uIWoTrBcVh0= 619 | 620 | es6-promise-pool@^2.5.0: 621 | version "2.5.0" 622 | resolved "https://neo.jfrog.io/neo/api/npm/npm/es6-promise-pool/-/es6-promise-pool-2.5.0.tgz#147c612b36b47f105027f9d2bf54a598a99d9ccb" 623 | integrity sha1-FHxhKza0fxBQJ/nSv1SlmKmdnMs= 624 | 625 | escape-string-regexp@1.0.5, escape-string-regexp@^1.0.5: 626 | version "1.0.5" 627 | resolved "https://neo.jfrog.io/neo/api/npm/npm/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" 628 | integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= 629 | 630 | esprima@^4.0.0: 631 | version "4.0.1" 632 | resolved "https://neo.jfrog.io/neo/api/npm/npm/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" 633 | integrity sha1-E7BM2z5sXRnfkatph6hpVhmwqnE= 634 | 635 | execa@^1.0.0: 636 | version "1.0.0" 637 | resolved "https://neo.jfrog.io/neo/api/npm/npm/execa/-/execa-1.0.0.tgz#c6236a5bb4df6d6f15e88e7f017798216749ddd8" 638 | integrity sha1-xiNqW7TfbW8V6I5/AXeYIWdJ3dg= 639 | dependencies: 640 | cross-spawn "^6.0.0" 641 | get-stream "^4.0.0" 642 | is-stream "^1.1.0" 643 | npm-run-path "^2.0.0" 644 | p-finally "^1.0.0" 645 | signal-exit "^3.0.0" 646 | strip-eof "^1.0.0" 647 | 648 | faker@^4.1.0: 649 | version "4.1.0" 650 | resolved "https://neo.jfrog.io/neo/api/npm/npm/faker/-/faker-4.1.0.tgz#1e45bbbecc6774b3c195fad2835109c6d748cc3f" 651 | integrity sha1-HkW7vsxndLPBlfrSg1EJxtdIzD8= 652 | 653 | fill-range@^7.0.1: 654 | version "7.0.1" 655 | resolved "https://neo.jfrog.io/neo/api/npm/npm/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" 656 | integrity sha1-GRmmp8df44ssfHflGYU12prN2kA= 657 | dependencies: 658 | to-regex-range "^5.0.1" 659 | 660 | find-cache-dir@^3.2.0: 661 | version "3.3.1" 662 | resolved "https://neo.jfrog.io/neo/api/npm/npm/find-cache-dir/-/find-cache-dir-3.3.1.tgz#89b33fad4a4670daa94f855f7fbe31d6d84fe880" 663 | integrity sha1-ibM/rUpGcNqpT4Vff74x1thP6IA= 664 | dependencies: 665 | commondir "^1.0.1" 666 | make-dir "^3.0.2" 667 | pkg-dir "^4.1.0" 668 | 669 | find-up@3.0.0, find-up@^3.0.0: 670 | version "3.0.0" 671 | resolved "https://neo.jfrog.io/neo/api/npm/npm/find-up/-/find-up-3.0.0.tgz#49169f1d7993430646da61ecc5ae355c21c97b73" 672 | integrity sha1-SRafHXmTQwZG2mHsxa41XCHJe3M= 673 | dependencies: 674 | locate-path "^3.0.0" 675 | 676 | find-up@^4.0.0, find-up@^4.1.0: 677 | version "4.1.0" 678 | resolved "https://neo.jfrog.io/neo/api/npm/npm/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19" 679 | integrity sha1-l6/n1s3AvFkoWEt8jXsW6KmqXRk= 680 | dependencies: 681 | locate-path "^5.0.0" 682 | path-exists "^4.0.0" 683 | 684 | flat@^4.1.0: 685 | version "4.1.0" 686 | resolved "https://neo.jfrog.io/neo/api/npm/npm/flat/-/flat-4.1.0.tgz#090bec8b05e39cba309747f1d588f04dbaf98db2" 687 | integrity sha1-CQvsiwXjnLowl0fx1YjwTbr5jbI= 688 | dependencies: 689 | is-buffer "~2.0.3" 690 | 691 | foreground-child@^2.0.0: 692 | version "2.0.0" 693 | resolved "https://neo.jfrog.io/neo/api/npm/npm/foreground-child/-/foreground-child-2.0.0.tgz#71b32800c9f15aa8f2f83f4a6bd9bff35d861a53" 694 | integrity sha1-cbMoAMnxWqjy+D9Ka9m/812GGlM= 695 | dependencies: 696 | cross-spawn "^7.0.0" 697 | signal-exit "^3.0.2" 698 | 699 | fromentries@^1.2.0: 700 | version "1.2.0" 701 | resolved "https://neo.jfrog.io/neo/api/npm/npm/fromentries/-/fromentries-1.2.0.tgz#e6aa06f240d6267f913cea422075ef88b63e7897" 702 | integrity sha1-5qoG8kDWJn+RPOpCIHXviLY+eJc= 703 | 704 | fs.realpath@^1.0.0: 705 | version "1.0.0" 706 | resolved "https://neo.jfrog.io/neo/api/npm/npm/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" 707 | integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= 708 | 709 | fsevents@~2.1.1: 710 | version "2.1.3" 711 | resolved "https://neo.jfrog.io/neo/api/npm/npm/fsevents/-/fsevents-2.1.3.tgz#fb738703ae8d2f9fe900c33836ddebee8b97f23e" 712 | integrity sha1-+3OHA66NL5/pAMM4Nt3r7ouX8j4= 713 | 714 | function-bind@^1.1.1: 715 | version "1.1.1" 716 | resolved "https://neo.jfrog.io/neo/api/npm/npm/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" 717 | integrity sha1-pWiZ0+o8m6uHS7l3O3xe3pL0iV0= 718 | 719 | generic-pool@^3.6.1: 720 | version "3.6.1" 721 | resolved "https://neo.jfrog.io/neo/api/npm/npm/generic-pool/-/generic-pool-3.6.1.tgz#a51a8439ee86f0bbcf100fc1db3f45c86289deb4" 722 | integrity sha1-pRqEOe6G8LvPEA/B2z9FyGKJ3rQ= 723 | 724 | gensync@^1.0.0-beta.1: 725 | version "1.0.0-beta.1" 726 | resolved "https://neo.jfrog.io/neo/api/npm/npm/gensync/-/gensync-1.0.0-beta.1.tgz#58f4361ff987e5ff6e1e7a210827aa371eaac269" 727 | integrity sha1-WPQ2H/mH5f9uHnohCCeqNx6qwmk= 728 | 729 | get-caller-file@^1.0.1: 730 | version "1.0.3" 731 | resolved "https://neo.jfrog.io/neo/api/npm/npm/get-caller-file/-/get-caller-file-1.0.3.tgz#f978fa4c90d1dfe7ff2d6beda2a515e713bdcf4a" 732 | integrity sha1-+Xj6TJDR3+f/LWvtoqUV5xO9z0o= 733 | 734 | get-caller-file@^2.0.1: 735 | version "2.0.5" 736 | resolved "https://neo.jfrog.io/neo/api/npm/npm/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" 737 | integrity sha1-T5RBKoLbMvNuOwuXQfipf+sDH34= 738 | 739 | get-func-name@^2.0.0: 740 | version "2.0.0" 741 | resolved "https://neo.jfrog.io/neo/api/npm/npm/get-func-name/-/get-func-name-2.0.0.tgz#ead774abee72e20409433a066366023dd6887a41" 742 | integrity sha1-6td0q+5y4gQJQzoGY2YCPdaIekE= 743 | 744 | get-package-type@^0.1.0: 745 | version "0.1.0" 746 | resolved "https://neo.jfrog.io/neo/api/npm/npm/get-package-type/-/get-package-type-0.1.0.tgz#8de2d803cff44df3bc6c456e6668b36c3926e11a" 747 | integrity sha1-jeLYA8/0TfO8bEVuZmizbDkm4Ro= 748 | 749 | get-stream@^4.0.0: 750 | version "4.1.0" 751 | resolved "https://neo.jfrog.io/neo/api/npm/npm/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5" 752 | integrity sha1-wbJVV189wh1Zv8ec09K0axw6VLU= 753 | dependencies: 754 | pump "^3.0.0" 755 | 756 | glob-parent@~5.1.0: 757 | version "5.1.1" 758 | resolved "https://neo.jfrog.io/neo/api/npm/npm/glob-parent/-/glob-parent-5.1.1.tgz#b6c1ef417c4e5663ea498f1c45afac6916bbc229" 759 | integrity sha1-tsHvQXxOVmPqSY8cRa+saRa7wik= 760 | dependencies: 761 | is-glob "^4.0.1" 762 | 763 | glob@7.1.3, glob@^7.1.3: 764 | version "7.1.3" 765 | resolved "https://neo.jfrog.io/neo/api/npm/npm/glob/-/glob-7.1.3.tgz#3960832d3f1574108342dafd3a67b332c0969df1" 766 | integrity sha1-OWCDLT8VdBCDQtr9OmezMsCWnfE= 767 | dependencies: 768 | fs.realpath "^1.0.0" 769 | inflight "^1.0.4" 770 | inherits "2" 771 | minimatch "^3.0.4" 772 | once "^1.3.0" 773 | path-is-absolute "^1.0.0" 774 | 775 | glob@^7.1.4, glob@^7.1.6: 776 | version "7.1.6" 777 | resolved "https://neo.jfrog.io/neo/api/npm/npm/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6" 778 | integrity sha1-FB8zuBp8JJLhJVlDB0gMRmeSeKY= 779 | dependencies: 780 | fs.realpath "^1.0.0" 781 | inflight "^1.0.4" 782 | inherits "2" 783 | minimatch "^3.0.4" 784 | once "^1.3.0" 785 | path-is-absolute "^1.0.0" 786 | 787 | globals@^11.1.0: 788 | version "11.11.0" 789 | resolved "https://neo.jfrog.io/neo/api/npm/npm/globals/-/globals-11.11.0.tgz#dcf93757fa2de5486fbeed7118538adf789e9c2e" 790 | integrity sha1-3Pk3V/ot5Uhvvu1xGFOK33ienC4= 791 | 792 | graceful-fs@^4.1.15: 793 | version "4.1.15" 794 | resolved "https://neo.jfrog.io/neo/api/npm/npm/graceful-fs/-/graceful-fs-4.1.15.tgz#ffb703e1066e8a0eeaa4c8b80ba9253eeefbfb00" 795 | integrity sha1-/7cD4QZuig7qpMi4C6klPu77+wA= 796 | 797 | growl@1.10.5: 798 | version "1.10.5" 799 | resolved "https://neo.jfrog.io/neo/api/npm/npm/growl/-/growl-1.10.5.tgz#f2735dc2283674fa67478b10181059355c369e5e" 800 | integrity sha1-8nNdwig2dPpnR4sQGBBZNVw2nl4= 801 | 802 | has-flag@^3.0.0: 803 | version "3.0.0" 804 | resolved "https://neo.jfrog.io/neo/api/npm/npm/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" 805 | integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= 806 | 807 | has-flag@^4.0.0: 808 | version "4.0.0" 809 | resolved "https://neo.jfrog.io/neo/api/npm/npm/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" 810 | integrity sha1-lEdx/ZyByBJlxNaUGGDaBrtZR5s= 811 | 812 | has-symbols@^1.0.0: 813 | version "1.0.0" 814 | resolved "https://neo.jfrog.io/neo/api/npm/npm/has-symbols/-/has-symbols-1.0.0.tgz#ba1a8f1af2a0fc39650f5c850367704122063b44" 815 | integrity sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q= 816 | 817 | has@^1.0.1, has@^1.0.3: 818 | version "1.0.3" 819 | resolved "https://neo.jfrog.io/neo/api/npm/npm/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" 820 | integrity sha1-ci18v8H2qoJB8W3YFOAR4fQeh5Y= 821 | dependencies: 822 | function-bind "^1.1.1" 823 | 824 | hasha@^5.0.0: 825 | version "5.2.0" 826 | resolved "https://neo.jfrog.io/neo/api/npm/npm/hasha/-/hasha-5.2.0.tgz#33094d1f69c40a4a6ac7be53d5fe3ff95a269e0c" 827 | integrity sha1-MwlNH2nECkpqx75T1f4/+Vomngw= 828 | dependencies: 829 | is-stream "^2.0.0" 830 | type-fest "^0.8.0" 831 | 832 | he@1.2.0: 833 | version "1.2.0" 834 | resolved "https://neo.jfrog.io/neo/api/npm/npm/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" 835 | integrity sha1-hK5l+n6vsWX922FWauFLrwVmTw8= 836 | 837 | html-escaper@^2.0.0: 838 | version "2.0.2" 839 | resolved "https://neo.jfrog.io/neo/api/npm/npm/html-escaper/-/html-escaper-2.0.2.tgz#dfd60027da36a36dfcbe236262c00a5822681453" 840 | integrity sha1-39YAJ9o2o238viNiYsAKWCJoFFM= 841 | 842 | imurmurhash@^0.1.4: 843 | version "0.1.4" 844 | resolved "https://neo.jfrog.io/neo/api/npm/npm/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" 845 | integrity sha1-khi5srkoojixPcT7a21XbyMUU+o= 846 | 847 | indent-string@^4.0.0: 848 | version "4.0.0" 849 | resolved "https://neo.jfrog.io/neo/api/npm/npm/indent-string/-/indent-string-4.0.0.tgz#624f8f4497d619b2d9768531d58f4122854d7251" 850 | integrity sha1-Yk+PRJfWGbLZdoUx1Y9BIoVNclE= 851 | 852 | inflight@^1.0.4: 853 | version "1.0.6" 854 | resolved "https://neo.jfrog.io/neo/api/npm/npm/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" 855 | integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= 856 | dependencies: 857 | once "^1.3.0" 858 | wrappy "1" 859 | 860 | inherits@2: 861 | version "2.0.3" 862 | resolved "https://neo.jfrog.io/neo/api/npm/npm/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" 863 | integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= 864 | 865 | invert-kv@^2.0.0: 866 | version "2.0.0" 867 | resolved "https://neo.jfrog.io/neo/api/npm/npm/invert-kv/-/invert-kv-2.0.0.tgz#7393f5afa59ec9ff5f67a27620d11c226e3eec02" 868 | integrity sha1-c5P1r6Weyf9fZ6J2INEcIm4+7AI= 869 | 870 | is-binary-path@~2.1.0: 871 | version "2.1.0" 872 | resolved "https://neo.jfrog.io/neo/api/npm/npm/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" 873 | integrity sha1-6h9/O4DwZCNug0cPhsCcJU+0Wwk= 874 | dependencies: 875 | binary-extensions "^2.0.0" 876 | 877 | is-buffer@~2.0.3: 878 | version "2.0.3" 879 | resolved "https://neo.jfrog.io/neo/api/npm/npm/is-buffer/-/is-buffer-2.0.3.tgz#4ecf3fcf749cbd1e472689e109ac66261a25e725" 880 | integrity sha1-Ts8/z3ScvR5HJonhCaxmJhol5yU= 881 | 882 | is-callable@^1.1.4: 883 | version "1.1.4" 884 | resolved "https://neo.jfrog.io/neo/api/npm/npm/is-callable/-/is-callable-1.1.4.tgz#1e1adf219e1eeb684d691f9d6a05ff0d30a24d75" 885 | integrity sha1-HhrfIZ4e62hNaR+dagX/DTCiTXU= 886 | 887 | is-date-object@^1.0.1: 888 | version "1.0.1" 889 | resolved "https://neo.jfrog.io/neo/api/npm/npm/is-date-object/-/is-date-object-1.0.1.tgz#9aa20eb6aeebbff77fbd33e74ca01b33581d3a16" 890 | integrity sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY= 891 | 892 | is-extglob@^2.1.1: 893 | version "2.1.1" 894 | resolved "https://neo.jfrog.io/neo/api/npm/npm/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" 895 | integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= 896 | 897 | is-fullwidth-code-point@^1.0.0: 898 | version "1.0.0" 899 | resolved "https://neo.jfrog.io/neo/api/npm/npm/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" 900 | integrity sha1-754xOG8DGn8NZDr4L95QxFfvAMs= 901 | dependencies: 902 | number-is-nan "^1.0.0" 903 | 904 | is-fullwidth-code-point@^2.0.0: 905 | version "2.0.0" 906 | resolved "https://neo.jfrog.io/neo/api/npm/npm/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" 907 | integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8= 908 | 909 | is-fullwidth-code-point@^3.0.0: 910 | version "3.0.0" 911 | resolved "https://neo.jfrog.io/neo/api/npm/npm/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" 912 | integrity sha1-8Rb4Bk/pCz94RKOJl8C3UFEmnx0= 913 | 914 | is-glob@^4.0.1, is-glob@~4.0.1: 915 | version "4.0.1" 916 | resolved "https://neo.jfrog.io/neo/api/npm/npm/is-glob/-/is-glob-4.0.1.tgz#7567dbe9f2f5e2467bc77ab83c4a29482407a5dc" 917 | integrity sha1-dWfb6fL14kZ7x3q4PEopSCQHpdw= 918 | dependencies: 919 | is-extglob "^2.1.1" 920 | 921 | is-number@^7.0.0: 922 | version "7.0.0" 923 | resolved "https://neo.jfrog.io/neo/api/npm/npm/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" 924 | integrity sha1-dTU0W4lnNNX4DE0GxQlVUnoU8Ss= 925 | 926 | is-regex@^1.0.4: 927 | version "1.0.4" 928 | resolved "https://neo.jfrog.io/neo/api/npm/npm/is-regex/-/is-regex-1.0.4.tgz#5517489b547091b0930e095654ced25ee97e9491" 929 | integrity sha1-VRdIm1RwkbCTDglWVM7SXul+lJE= 930 | dependencies: 931 | has "^1.0.1" 932 | 933 | is-stream@^1.1.0: 934 | version "1.1.0" 935 | resolved "https://neo.jfrog.io/neo/api/npm/npm/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" 936 | integrity sha1-EtSj3U5o4Lec6428hBc66A2RykQ= 937 | 938 | is-stream@^2.0.0: 939 | version "2.0.0" 940 | resolved "https://neo.jfrog.io/neo/api/npm/npm/is-stream/-/is-stream-2.0.0.tgz#bde9c32680d6fae04129d6ac9d921ce7815f78e3" 941 | integrity sha1-venDJoDW+uBBKdasnZIc54FfeOM= 942 | 943 | is-symbol@^1.0.2: 944 | version "1.0.2" 945 | resolved "https://neo.jfrog.io/neo/api/npm/npm/is-symbol/-/is-symbol-1.0.2.tgz#a055f6ae57192caee329e7a860118b497a950f38" 946 | integrity sha1-oFX2rlcZLK7jKeeoYBGLSXqVDzg= 947 | dependencies: 948 | has-symbols "^1.0.0" 949 | 950 | is-typedarray@^1.0.0: 951 | version "1.0.0" 952 | resolved "https://neo.jfrog.io/neo/api/npm/npm/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" 953 | integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo= 954 | 955 | is-windows@^1.0.2: 956 | version "1.0.2" 957 | resolved "https://neo.jfrog.io/neo/api/npm/npm/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" 958 | integrity sha1-0YUOuXkezRjmGCzhKjDzlmNLsZ0= 959 | 960 | isarray@0.0.1: 961 | version "0.0.1" 962 | resolved "https://neo.jfrog.io/neo/api/npm/npm/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" 963 | integrity sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8= 964 | 965 | isexe@^2.0.0: 966 | version "2.0.0" 967 | resolved "https://neo.jfrog.io/neo/api/npm/npm/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" 968 | integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= 969 | 970 | istanbul-lib-coverage@^3.0.0, istanbul-lib-coverage@^3.0.0-alpha.1: 971 | version "3.0.0" 972 | resolved "https://neo.jfrog.io/neo/api/npm/npm/istanbul-lib-coverage/-/istanbul-lib-coverage-3.0.0.tgz#f5944a37c70b550b02a78a5c3b2055b280cec8ec" 973 | integrity sha1-9ZRKN8cLVQsCp4pcOyBVsoDOyOw= 974 | 975 | istanbul-lib-hook@^3.0.0: 976 | version "3.0.0" 977 | resolved "https://neo.jfrog.io/neo/api/npm/npm/istanbul-lib-hook/-/istanbul-lib-hook-3.0.0.tgz#8f84c9434888cc6b1d0a9d7092a76d239ebf0cc6" 978 | integrity sha1-j4TJQ0iIzGsdCp1wkqdtI56/DMY= 979 | dependencies: 980 | append-transform "^2.0.0" 981 | 982 | istanbul-lib-instrument@^4.0.0: 983 | version "4.0.3" 984 | resolved "https://neo.jfrog.io/neo/api/npm/npm/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.3.tgz#873c6fff897450118222774696a3f28902d77c1d" 985 | integrity sha1-hzxv/4l0UBGCIndGlqPyiQLXfB0= 986 | dependencies: 987 | "@babel/core" "^7.7.5" 988 | "@istanbuljs/schema" "^0.1.2" 989 | istanbul-lib-coverage "^3.0.0" 990 | semver "^6.3.0" 991 | 992 | istanbul-lib-processinfo@^2.0.2: 993 | version "2.0.2" 994 | resolved "https://neo.jfrog.io/neo/api/npm/npm/istanbul-lib-processinfo/-/istanbul-lib-processinfo-2.0.2.tgz#e1426514662244b2f25df728e8fd1ba35fe53b9c" 995 | integrity sha1-4UJlFGYiRLLyXfco6P0bo1/lO5w= 996 | dependencies: 997 | archy "^1.0.0" 998 | cross-spawn "^7.0.0" 999 | istanbul-lib-coverage "^3.0.0-alpha.1" 1000 | make-dir "^3.0.0" 1001 | p-map "^3.0.0" 1002 | rimraf "^3.0.0" 1003 | uuid "^3.3.3" 1004 | 1005 | istanbul-lib-report@^3.0.0: 1006 | version "3.0.0" 1007 | resolved "https://neo.jfrog.io/neo/api/npm/npm/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz#7518fe52ea44de372f460a76b5ecda9ffb73d8a6" 1008 | integrity sha1-dRj+UupE3jcvRgp2tezan/tz2KY= 1009 | dependencies: 1010 | istanbul-lib-coverage "^3.0.0" 1011 | make-dir "^3.0.0" 1012 | supports-color "^7.1.0" 1013 | 1014 | istanbul-lib-source-maps@^4.0.0: 1015 | version "4.0.0" 1016 | resolved "https://neo.jfrog.io/neo/api/npm/npm/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.0.tgz#75743ce6d96bb86dc7ee4352cf6366a23f0b1ad9" 1017 | integrity sha1-dXQ85tlruG3H7kNSz2Nmoj8LGtk= 1018 | dependencies: 1019 | debug "^4.1.1" 1020 | istanbul-lib-coverage "^3.0.0" 1021 | source-map "^0.6.1" 1022 | 1023 | istanbul-reports@^3.0.2: 1024 | version "3.0.2" 1025 | resolved "https://neo.jfrog.io/neo/api/npm/npm/istanbul-reports/-/istanbul-reports-3.0.2.tgz#d593210e5000683750cb09fc0644e4b6e27fd53b" 1026 | integrity sha1-1ZMhDlAAaDdQywn8BkTktuJ/1Ts= 1027 | dependencies: 1028 | html-escaper "^2.0.0" 1029 | istanbul-lib-report "^3.0.0" 1030 | 1031 | js-tokens@^4.0.0: 1032 | version "4.0.0" 1033 | resolved "https://neo.jfrog.io/neo/api/npm/npm/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" 1034 | integrity sha1-GSA/tZmR35jjoocFDUZHzerzJJk= 1035 | 1036 | js-yaml@3.13.1: 1037 | version "3.13.1" 1038 | resolved "https://neo.jfrog.io/neo/api/npm/npm/js-yaml/-/js-yaml-3.13.1.tgz#aff151b30bfdfa8e49e05da22e7415e9dfa37847" 1039 | integrity sha1-r/FRswv9+o5J4F2iLnQV6d+jeEc= 1040 | dependencies: 1041 | argparse "^1.0.7" 1042 | esprima "^4.0.0" 1043 | 1044 | js-yaml@^3.13.1: 1045 | version "3.14.0" 1046 | resolved "https://neo.jfrog.io/neo/api/npm/npm/js-yaml/-/js-yaml-3.14.0.tgz#a7a34170f26a21bb162424d8adacb4113a69e482" 1047 | integrity sha1-p6NBcPJqIbsWJCTYray0ETpp5II= 1048 | dependencies: 1049 | argparse "^1.0.7" 1050 | esprima "^4.0.0" 1051 | 1052 | jsesc@^2.5.1: 1053 | version "2.5.2" 1054 | resolved "https://neo.jfrog.io/neo/api/npm/npm/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" 1055 | integrity sha1-gFZNLkg9rPbo7yCWUKZ98/DCg6Q= 1056 | 1057 | json5@^2.1.2: 1058 | version "2.1.3" 1059 | resolved "https://neo.jfrog.io/neo/api/npm/npm/json5/-/json5-2.1.3.tgz#c9b0f7fa9233bfe5807fe66fcf3a5617ed597d43" 1060 | integrity sha1-ybD3+pIzv+WAf+ZvzzpWF+1ZfUM= 1061 | dependencies: 1062 | minimist "^1.2.5" 1063 | 1064 | just-extend@^4.0.2: 1065 | version "4.0.2" 1066 | resolved "https://neo.jfrog.io/neo/api/npm/npm/just-extend/-/just-extend-4.0.2.tgz#f3f47f7dfca0f989c55410a7ebc8854b07108afc" 1067 | integrity sha1-8/R/ffyg+YnFVBCn68iFSwcQivw= 1068 | 1069 | lcid@^2.0.0: 1070 | version "2.0.0" 1071 | resolved "https://neo.jfrog.io/neo/api/npm/npm/lcid/-/lcid-2.0.0.tgz#6ef5d2df60e52f82eb228a4c373e8d1f397253cf" 1072 | integrity sha1-bvXS32DlL4LrIopMNz6NHzlyU88= 1073 | dependencies: 1074 | invert-kv "^2.0.0" 1075 | 1076 | locate-path@^3.0.0: 1077 | version "3.0.0" 1078 | resolved "https://neo.jfrog.io/neo/api/npm/npm/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e" 1079 | integrity sha1-2+w7OrdZdYBxtY/ln8QYca8hQA4= 1080 | dependencies: 1081 | p-locate "^3.0.0" 1082 | path-exists "^3.0.0" 1083 | 1084 | locate-path@^5.0.0: 1085 | version "5.0.0" 1086 | resolved "https://neo.jfrog.io/neo/api/npm/npm/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0" 1087 | integrity sha1-Gvujlq/WdqbUJQTQpno6frn2KqA= 1088 | dependencies: 1089 | p-locate "^4.1.0" 1090 | 1091 | lodash.flattendeep@^4.4.0: 1092 | version "4.4.0" 1093 | resolved "https://neo.jfrog.io/neo/api/npm/npm/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz#fb030917f86a3134e5bc9bec0d69e0013ddfedb2" 1094 | integrity sha1-+wMJF/hqMTTlvJvsDWngAT3f7bI= 1095 | 1096 | lodash@^4.17.11: 1097 | version "4.17.11" 1098 | resolved "https://neo.jfrog.io/neo/api/npm/npm/lodash/-/lodash-4.17.11.tgz#b39ea6229ef607ecd89e2c8df12536891cac9b8d" 1099 | integrity sha1-s56mIp72B+zYniyN8SU2iRysm40= 1100 | 1101 | lodash@^4.17.13, lodash@^4.17.15: 1102 | version "4.17.15" 1103 | resolved "https://neo.jfrog.io/neo/api/npm/npm/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548" 1104 | integrity sha1-tEf2ZwoEVbv+7dETku/zMOoJdUg= 1105 | 1106 | lodash@^4.17.20: 1107 | version "4.17.20" 1108 | resolved "https://neo.jfrog.io/neo/api/npm/npm/lodash/-/lodash-4.17.20.tgz#b44a9b6297bcb698f1c51a3545a2b3b368d59c52" 1109 | integrity sha1-tEqbYpe8tpjxxRo1RaKzs2jVnFI= 1110 | 1111 | log-symbols@3.0.0: 1112 | version "3.0.0" 1113 | resolved "https://neo.jfrog.io/neo/api/npm/npm/log-symbols/-/log-symbols-3.0.0.tgz#f3a08516a5dea893336a7dee14d18a1cfdab77c4" 1114 | integrity sha1-86CFFqXeqJMzan3uFNGKHP2rd8Q= 1115 | dependencies: 1116 | chalk "^2.4.2" 1117 | 1118 | lolex@^2.3.2: 1119 | version "2.7.5" 1120 | resolved "https://neo.jfrog.io/neo/api/npm/npm/lolex/-/lolex-2.7.5.tgz#113001d56bfc7e02d56e36291cc5c413d1aa0733" 1121 | integrity sha1-ETAB1Wv8fgLVbjYpHMXEE9GqBzM= 1122 | 1123 | lolex@^3.1.0: 1124 | version "3.1.0" 1125 | resolved "https://neo.jfrog.io/neo/api/npm/npm/lolex/-/lolex-3.1.0.tgz#1a7feb2fefd75b3e3a7f79f0e110d9476e294434" 1126 | integrity sha1-Gn/rL+/XWz46f3nw4RDZR24pRDQ= 1127 | 1128 | make-dir@^3.0.0, make-dir@^3.0.2: 1129 | version "3.1.0" 1130 | resolved "https://neo.jfrog.io/neo/api/npm/npm/make-dir/-/make-dir-3.1.0.tgz#415e967046b3a7f1d185277d84aa58203726a13f" 1131 | integrity sha1-QV6WcEazp/HRhSd9hKpYIDcmoT8= 1132 | dependencies: 1133 | semver "^6.0.0" 1134 | 1135 | map-age-cleaner@^0.1.1: 1136 | version "0.1.3" 1137 | resolved "https://neo.jfrog.io/neo/api/npm/npm/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz#7d583a7306434c055fe474b0f45078e6e1b4b92a" 1138 | integrity sha1-fVg6cwZDTAVf5HSw9FB45uG0uSo= 1139 | dependencies: 1140 | p-defer "^1.0.0" 1141 | 1142 | mem@^4.0.0: 1143 | version "4.1.0" 1144 | resolved "https://neo.jfrog.io/neo/api/npm/npm/mem/-/mem-4.1.0.tgz#aeb9be2d21f47e78af29e4ac5978e8afa2ca5b8a" 1145 | integrity sha1-rrm+LSH0fnivKeSsWXjor6LKW4o= 1146 | dependencies: 1147 | map-age-cleaner "^0.1.1" 1148 | mimic-fn "^1.0.0" 1149 | p-is-promise "^2.0.0" 1150 | 1151 | mimic-fn@^1.0.0: 1152 | version "1.2.0" 1153 | resolved "https://neo.jfrog.io/neo/api/npm/npm/mimic-fn/-/mimic-fn-1.2.0.tgz#820c86a39334640e99516928bd03fca88057d022" 1154 | integrity sha1-ggyGo5M0ZA6ZUWkovQP8qIBX0CI= 1155 | 1156 | minimatch@3.0.4, minimatch@^3.0.4: 1157 | version "3.0.4" 1158 | resolved "https://neo.jfrog.io/neo/api/npm/npm/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" 1159 | integrity sha1-UWbihkV/AzBgZL5Ul+jbsMPTIIM= 1160 | dependencies: 1161 | brace-expansion "^1.1.7" 1162 | 1163 | minimist@^1.2.5: 1164 | version "1.2.5" 1165 | resolved "https://neo.jfrog.io/neo/api/npm/npm/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" 1166 | integrity sha1-Z9ZgFLZqaoqqDAg8X9WN9OTpdgI= 1167 | 1168 | mkdirp@0.5.5: 1169 | version "0.5.5" 1170 | resolved "https://neo.jfrog.io/neo/api/npm/npm/mkdirp/-/mkdirp-0.5.5.tgz#d91cefd62d1436ca0f41620e251288d420099def" 1171 | integrity sha1-2Rzv1i0UNsoPQWIOJRKI1CAJne8= 1172 | dependencies: 1173 | minimist "^1.2.5" 1174 | 1175 | mocha@^7.2.0: 1176 | version "7.2.0" 1177 | resolved "https://neo.jfrog.io/neo/api/npm/npm/mocha/-/mocha-7.2.0.tgz#01cc227b00d875ab1eed03a75106689cfed5a604" 1178 | integrity sha1-AcwiewDYdase7QOnUQZonP7VpgQ= 1179 | dependencies: 1180 | ansi-colors "3.2.3" 1181 | browser-stdout "1.3.1" 1182 | chokidar "3.3.0" 1183 | debug "3.2.6" 1184 | diff "3.5.0" 1185 | escape-string-regexp "1.0.5" 1186 | find-up "3.0.0" 1187 | glob "7.1.3" 1188 | growl "1.10.5" 1189 | he "1.2.0" 1190 | js-yaml "3.13.1" 1191 | log-symbols "3.0.0" 1192 | minimatch "3.0.4" 1193 | mkdirp "0.5.5" 1194 | ms "2.1.1" 1195 | node-environment-flags "1.0.6" 1196 | object.assign "4.1.0" 1197 | strip-json-comments "2.0.1" 1198 | supports-color "6.0.0" 1199 | which "1.3.1" 1200 | wide-align "1.1.3" 1201 | yargs "13.3.2" 1202 | yargs-parser "13.1.2" 1203 | yargs-unparser "1.6.0" 1204 | 1205 | moment@^2.27.0: 1206 | version "2.27.0" 1207 | resolved "https://neo.jfrog.io/neo/api/npm/npm/moment/-/moment-2.27.0.tgz#8bff4e3e26a236220dfe3e36de756b6ebaa0105d" 1208 | integrity sha1-i/9OPiaiNiIN/j423nVrbrqgEF0= 1209 | 1210 | ms@2.1.1, ms@^2.1.1: 1211 | version "2.1.1" 1212 | resolved "https://neo.jfrog.io/neo/api/npm/npm/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a" 1213 | integrity sha1-MKWGTrPrsKZvLr5tcnrwagnYbgo= 1214 | 1215 | neo4j-driver@^4.1.1: 1216 | version "4.1.1" 1217 | resolved "https://neo.jfrog.io/neo/api/npm/npm/neo4j-driver/-/neo4j-driver-4.1.1.tgz#0d25de398256117b6088fc5e4466100ee4ae5f57" 1218 | integrity sha1-DSXeOYJWEXtgiPxeRGYQDuSuX1c= 1219 | dependencies: 1220 | "@babel/runtime" "^7.9.6" 1221 | rxjs "^6.5.5" 1222 | text-encoding-utf-8 "^1.0.2" 1223 | uri-js "^4.2.2" 1224 | 1225 | nice-try@^1.0.4: 1226 | version "1.0.5" 1227 | resolved "https://neo.jfrog.io/neo/api/npm/npm/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" 1228 | integrity sha1-ozeKdpbOfSI+iPybdkvX7xCJ42Y= 1229 | 1230 | nise@^1.4.10: 1231 | version "1.4.10" 1232 | resolved "https://neo.jfrog.io/neo/api/npm/npm/nise/-/nise-1.4.10.tgz#ae46a09a26436fae91a38a60919356ae6db143b6" 1233 | integrity sha1-rkagmiZDb66Ro4pgkZNWrm2xQ7Y= 1234 | dependencies: 1235 | "@sinonjs/formatio" "^3.1.0" 1236 | "@sinonjs/text-encoding" "^0.7.1" 1237 | just-extend "^4.0.2" 1238 | lolex "^2.3.2" 1239 | path-to-regexp "^1.7.0" 1240 | 1241 | node-environment-flags@1.0.6: 1242 | version "1.0.6" 1243 | resolved "https://neo.jfrog.io/neo/api/npm/npm/node-environment-flags/-/node-environment-flags-1.0.6.tgz#a30ac13621f6f7d674260a54dede048c3982c088" 1244 | integrity sha1-owrBNiH299Z0JgpU3t4EjDmCwIg= 1245 | dependencies: 1246 | object.getownpropertydescriptors "^2.0.3" 1247 | semver "^5.7.0" 1248 | 1249 | node-preload@^0.2.1: 1250 | version "0.2.1" 1251 | resolved "https://neo.jfrog.io/neo/api/npm/npm/node-preload/-/node-preload-0.2.1.tgz#c03043bb327f417a18fee7ab7ee57b408a144301" 1252 | integrity sha1-wDBDuzJ/QXoY/uerfuV7QIoUQwE= 1253 | dependencies: 1254 | process-on-spawn "^1.0.0" 1255 | 1256 | normalize-path@^3.0.0, normalize-path@~3.0.0: 1257 | version "3.0.0" 1258 | resolved "https://neo.jfrog.io/neo/api/npm/npm/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" 1259 | integrity sha1-Dc1p/yOhybEf0JeDFmRKA4ghamU= 1260 | 1261 | npm-run-path@^2.0.0: 1262 | version "2.0.2" 1263 | resolved "https://neo.jfrog.io/neo/api/npm/npm/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f" 1264 | integrity sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8= 1265 | dependencies: 1266 | path-key "^2.0.0" 1267 | 1268 | number-is-nan@^1.0.0: 1269 | version "1.0.1" 1270 | resolved "https://neo.jfrog.io/neo/api/npm/npm/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" 1271 | integrity sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0= 1272 | 1273 | nyc@^15.1.0: 1274 | version "15.1.0" 1275 | resolved "https://neo.jfrog.io/neo/api/npm/npm/nyc/-/nyc-15.1.0.tgz#1335dae12ddc87b6e249d5a1994ca4bdaea75f02" 1276 | integrity sha1-EzXa4S3ch7biSdWhmUykva6nXwI= 1277 | dependencies: 1278 | "@istanbuljs/load-nyc-config" "^1.0.0" 1279 | "@istanbuljs/schema" "^0.1.2" 1280 | caching-transform "^4.0.0" 1281 | convert-source-map "^1.7.0" 1282 | decamelize "^1.2.0" 1283 | find-cache-dir "^3.2.0" 1284 | find-up "^4.1.0" 1285 | foreground-child "^2.0.0" 1286 | get-package-type "^0.1.0" 1287 | glob "^7.1.6" 1288 | istanbul-lib-coverage "^3.0.0" 1289 | istanbul-lib-hook "^3.0.0" 1290 | istanbul-lib-instrument "^4.0.0" 1291 | istanbul-lib-processinfo "^2.0.2" 1292 | istanbul-lib-report "^3.0.0" 1293 | istanbul-lib-source-maps "^4.0.0" 1294 | istanbul-reports "^3.0.2" 1295 | make-dir "^3.0.0" 1296 | node-preload "^0.2.1" 1297 | p-map "^3.0.0" 1298 | process-on-spawn "^1.0.0" 1299 | resolve-from "^5.0.0" 1300 | rimraf "^3.0.0" 1301 | signal-exit "^3.0.2" 1302 | spawn-wrap "^2.0.0" 1303 | test-exclude "^6.0.0" 1304 | yargs "^15.0.2" 1305 | 1306 | object-keys@^1.0.11, object-keys@^1.0.12: 1307 | version "1.1.0" 1308 | resolved "https://neo.jfrog.io/neo/api/npm/npm/object-keys/-/object-keys-1.1.0.tgz#11bd22348dd2e096a045ab06f6c85bcc340fa032" 1309 | integrity sha1-Eb0iNI3S4JagRasG9shbzDQPoDI= 1310 | 1311 | object.assign@4.1.0: 1312 | version "4.1.0" 1313 | resolved "https://neo.jfrog.io/neo/api/npm/npm/object.assign/-/object.assign-4.1.0.tgz#968bf1100d7956bb3ca086f006f846b3bc4008da" 1314 | integrity sha1-lovxEA15Vrs8oIbwBvhGs7xACNo= 1315 | dependencies: 1316 | define-properties "^1.1.2" 1317 | function-bind "^1.1.1" 1318 | has-symbols "^1.0.0" 1319 | object-keys "^1.0.11" 1320 | 1321 | object.getownpropertydescriptors@^2.0.3: 1322 | version "2.0.3" 1323 | resolved "https://neo.jfrog.io/neo/api/npm/npm/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.0.3.tgz#8758c846f5b407adab0f236e0986f14b051caa16" 1324 | integrity sha1-h1jIRvW0B62rDyNuCYbxSwUcqhY= 1325 | dependencies: 1326 | define-properties "^1.1.2" 1327 | es-abstract "^1.5.1" 1328 | 1329 | once@^1.3.0, once@^1.3.1, once@^1.4.0: 1330 | version "1.4.0" 1331 | resolved "https://neo.jfrog.io/neo/api/npm/npm/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" 1332 | integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= 1333 | dependencies: 1334 | wrappy "1" 1335 | 1336 | os-locale@^3.0.0: 1337 | version "3.1.0" 1338 | resolved "https://neo.jfrog.io/neo/api/npm/npm/os-locale/-/os-locale-3.1.0.tgz#a802a6ee17f24c10483ab9935719cef4ed16bf1a" 1339 | integrity sha1-qAKm7hfyTBBIOrmTVxnO9O0Wvxo= 1340 | dependencies: 1341 | execa "^1.0.0" 1342 | lcid "^2.0.0" 1343 | mem "^4.0.0" 1344 | 1345 | p-defer@^1.0.0: 1346 | version "1.0.0" 1347 | resolved "https://neo.jfrog.io/neo/api/npm/npm/p-defer/-/p-defer-1.0.0.tgz#9f6eb182f6c9aa8cd743004a7d4f96b196b0fb0c" 1348 | integrity sha1-n26xgvbJqozXQwBKfU+WsZaw+ww= 1349 | 1350 | p-finally@^1.0.0: 1351 | version "1.0.0" 1352 | resolved "https://neo.jfrog.io/neo/api/npm/npm/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" 1353 | integrity sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4= 1354 | 1355 | p-is-promise@^2.0.0: 1356 | version "2.0.0" 1357 | resolved "https://neo.jfrog.io/neo/api/npm/npm/p-is-promise/-/p-is-promise-2.0.0.tgz#7554e3d572109a87e1f3f53f6a7d85d1b194f4c5" 1358 | integrity sha1-dVTj1XIQmofh8/U/an2F0bGU9MU= 1359 | 1360 | p-limit@^2.0.0: 1361 | version "2.1.0" 1362 | resolved "https://neo.jfrog.io/neo/api/npm/npm/p-limit/-/p-limit-2.1.0.tgz#1d5a0d20fb12707c758a655f6bbc4386b5930d68" 1363 | integrity sha1-HVoNIPsScHx1imVfa7xDhrWTDWg= 1364 | dependencies: 1365 | p-try "^2.0.0" 1366 | 1367 | p-limit@^2.2.0: 1368 | version "2.3.0" 1369 | resolved "https://neo.jfrog.io/neo/api/npm/npm/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" 1370 | integrity sha1-PdM8ZHohT9//2DWTPrCG2g3CHbE= 1371 | dependencies: 1372 | p-try "^2.0.0" 1373 | 1374 | p-locate@^3.0.0: 1375 | version "3.0.0" 1376 | resolved "https://neo.jfrog.io/neo/api/npm/npm/p-locate/-/p-locate-3.0.0.tgz#322d69a05c0264b25997d9f40cd8a891ab0064a4" 1377 | integrity sha1-Mi1poFwCZLJZl9n0DNiokasAZKQ= 1378 | dependencies: 1379 | p-limit "^2.0.0" 1380 | 1381 | p-locate@^4.1.0: 1382 | version "4.1.0" 1383 | resolved "https://neo.jfrog.io/neo/api/npm/npm/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07" 1384 | integrity sha1-o0KLtwiLOmApL2aRkni3wpetTwc= 1385 | dependencies: 1386 | p-limit "^2.2.0" 1387 | 1388 | p-map@^3.0.0: 1389 | version "3.0.0" 1390 | resolved "https://neo.jfrog.io/neo/api/npm/npm/p-map/-/p-map-3.0.0.tgz#d704d9af8a2ba684e2600d9a215983d4141a979d" 1391 | integrity sha1-1wTZr4orpoTiYA2aIVmD1BQal50= 1392 | dependencies: 1393 | aggregate-error "^3.0.0" 1394 | 1395 | p-try@^2.0.0: 1396 | version "2.0.0" 1397 | resolved "https://neo.jfrog.io/neo/api/npm/npm/p-try/-/p-try-2.0.0.tgz#85080bb87c64688fa47996fe8f7dfbe8211760b1" 1398 | integrity sha1-hQgLuHxkaI+keZb+j3376CEXYLE= 1399 | 1400 | package-hash@^4.0.0: 1401 | version "4.0.0" 1402 | resolved "https://neo.jfrog.io/neo/api/npm/npm/package-hash/-/package-hash-4.0.0.tgz#3537f654665ec3cc38827387fc904c163c54f506" 1403 | integrity sha1-NTf2VGZew8w4gnOH/JBMFjxU9QY= 1404 | dependencies: 1405 | graceful-fs "^4.1.15" 1406 | hasha "^5.0.0" 1407 | lodash.flattendeep "^4.4.0" 1408 | release-zalgo "^1.0.0" 1409 | 1410 | path-exists@^3.0.0: 1411 | version "3.0.0" 1412 | resolved "https://neo.jfrog.io/neo/api/npm/npm/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" 1413 | integrity sha1-zg6+ql94yxiSXqfYENe1mwEP1RU= 1414 | 1415 | path-exists@^4.0.0: 1416 | version "4.0.0" 1417 | resolved "https://neo.jfrog.io/neo/api/npm/npm/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" 1418 | integrity sha1-UTvb4tO5XXdi6METfvoZXGxhtbM= 1419 | 1420 | path-is-absolute@^1.0.0: 1421 | version "1.0.1" 1422 | resolved "https://neo.jfrog.io/neo/api/npm/npm/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" 1423 | integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= 1424 | 1425 | path-key@^2.0.0, path-key@^2.0.1: 1426 | version "2.0.1" 1427 | resolved "https://neo.jfrog.io/neo/api/npm/npm/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" 1428 | integrity sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A= 1429 | 1430 | path-key@^3.1.0: 1431 | version "3.1.1" 1432 | resolved "https://neo.jfrog.io/neo/api/npm/npm/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" 1433 | integrity sha1-WB9q3mWMu6ZaDTOA3ndTKVBU83U= 1434 | 1435 | path-parse@^1.0.6: 1436 | version "1.0.6" 1437 | resolved "https://neo.jfrog.io/neo/api/npm/npm/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c" 1438 | integrity sha1-1i27VnlAXXLEc37FhgDp3c8G0kw= 1439 | 1440 | path-to-regexp@^1.7.0: 1441 | version "1.7.0" 1442 | resolved "https://neo.jfrog.io/neo/api/npm/npm/path-to-regexp/-/path-to-regexp-1.7.0.tgz#59fde0f435badacba103a84e9d3bc64e96b9937d" 1443 | integrity sha1-Wf3g9DW62suhA6hOnTvGTpa5k30= 1444 | dependencies: 1445 | isarray "0.0.1" 1446 | 1447 | pathval@^1.1.0: 1448 | version "1.1.0" 1449 | resolved "https://neo.jfrog.io/neo/api/npm/npm/pathval/-/pathval-1.1.0.tgz#b942e6d4bde653005ef6b71361def8727d0645e0" 1450 | integrity sha1-uULm1L3mUwBe9rcTYd74cn0GReA= 1451 | 1452 | picomatch@^2.0.4: 1453 | version "2.2.2" 1454 | resolved "https://neo.jfrog.io/neo/api/npm/npm/picomatch/-/picomatch-2.2.2.tgz#21f333e9b6b8eaff02468f5146ea406d345f4dad" 1455 | integrity sha1-IfMz6ba46v8CRo9RRupAbTRfTa0= 1456 | 1457 | pkg-dir@^4.1.0: 1458 | version "4.2.0" 1459 | resolved "https://neo.jfrog.io/neo/api/npm/npm/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3" 1460 | integrity sha1-8JkTPfft5CLoHR2ESCcO6z5CYfM= 1461 | dependencies: 1462 | find-up "^4.0.0" 1463 | 1464 | process-on-spawn@^1.0.0: 1465 | version "1.0.0" 1466 | resolved "https://neo.jfrog.io/neo/api/npm/npm/process-on-spawn/-/process-on-spawn-1.0.0.tgz#95b05a23073d30a17acfdc92a440efd2baefdc93" 1467 | integrity sha1-lbBaIwc9MKF6z9ySpEDv0rrv3JM= 1468 | dependencies: 1469 | fromentries "^1.2.0" 1470 | 1471 | pump@^3.0.0: 1472 | version "3.0.0" 1473 | resolved "https://neo.jfrog.io/neo/api/npm/npm/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64" 1474 | integrity sha1-tKIRaBW94vTh6mAjVOjHVWUQemQ= 1475 | dependencies: 1476 | end-of-stream "^1.1.0" 1477 | once "^1.3.1" 1478 | 1479 | punycode@^2.1.0: 1480 | version "2.1.1" 1481 | resolved "https://neo.jfrog.io/neo/api/npm/npm/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" 1482 | integrity sha1-tYsBCsQMIsVldhbI0sLALHv0eew= 1483 | 1484 | randomstring@^1.1.5: 1485 | version "1.1.5" 1486 | resolved "https://neo.jfrog.io/neo/api/npm/npm/randomstring/-/randomstring-1.1.5.tgz#6df0628f75cbd5932930d9fe3ab4e956a18518c3" 1487 | integrity sha1-bfBij3XL1ZMpMNn+OrTpVqGFGMM= 1488 | dependencies: 1489 | array-uniq "1.0.2" 1490 | 1491 | readdirp@~3.2.0: 1492 | version "3.2.0" 1493 | resolved "https://neo.jfrog.io/neo/api/npm/npm/readdirp/-/readdirp-3.2.0.tgz#c30c33352b12c96dfb4b895421a49fd5a9593839" 1494 | integrity sha1-wwwzNSsSyW37S4lUIaSf1alZODk= 1495 | dependencies: 1496 | picomatch "^2.0.4" 1497 | 1498 | regenerator-runtime@^0.13.4: 1499 | version "0.13.7" 1500 | resolved "https://neo.jfrog.io/neo/api/npm/npm/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz#cac2dacc8a1ea675feaabaeb8ae833898ae46f55" 1501 | integrity sha1-ysLazIoepnX+qrrriugziYrkb1U= 1502 | 1503 | release-zalgo@^1.0.0: 1504 | version "1.0.0" 1505 | resolved "https://neo.jfrog.io/neo/api/npm/npm/release-zalgo/-/release-zalgo-1.0.0.tgz#09700b7e5074329739330e535c5a90fb67851730" 1506 | integrity sha1-CXALflB0Mpc5Mw5TXFqQ+2eFFzA= 1507 | dependencies: 1508 | es6-error "^4.0.1" 1509 | 1510 | require-directory@^2.1.1: 1511 | version "2.1.1" 1512 | resolved "https://neo.jfrog.io/neo/api/npm/npm/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" 1513 | integrity sha1-jGStX9MNqxyXbiNE/+f3kqam30I= 1514 | 1515 | require-main-filename@^1.0.1: 1516 | version "1.0.1" 1517 | resolved "https://neo.jfrog.io/neo/api/npm/npm/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1" 1518 | integrity sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE= 1519 | 1520 | require-main-filename@^2.0.0: 1521 | version "2.0.0" 1522 | resolved "https://neo.jfrog.io/neo/api/npm/npm/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b" 1523 | integrity sha1-0LMp7MfMD2Fkn2IhW+aa9UqomJs= 1524 | 1525 | resolve-from@^5.0.0: 1526 | version "5.0.0" 1527 | resolved "https://neo.jfrog.io/neo/api/npm/npm/resolve-from/-/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69" 1528 | integrity sha1-w1IlhD3493bfIcV1V7wIfp39/Gk= 1529 | 1530 | resolve@^1.3.2: 1531 | version "1.17.0" 1532 | resolved "https://neo.jfrog.io/neo/api/npm/npm/resolve/-/resolve-1.17.0.tgz#b25941b54968231cc2d1bb76a79cb7f2c0bf8444" 1533 | integrity sha1-sllBtUloIxzC0bt2p5y38sC/hEQ= 1534 | dependencies: 1535 | path-parse "^1.0.6" 1536 | 1537 | rimraf@^3.0.0: 1538 | version "3.0.2" 1539 | resolved "https://neo.jfrog.io/neo/api/npm/npm/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" 1540 | integrity sha1-8aVAK6YiCtUswSgrrBrjqkn9Bho= 1541 | dependencies: 1542 | glob "^7.1.3" 1543 | 1544 | rxjs@^6.5.5: 1545 | version "6.6.2" 1546 | resolved "https://neo.jfrog.io/neo/api/npm/npm/rxjs/-/rxjs-6.6.2.tgz#8096a7ac03f2cc4fe5860ef6e572810d9e01c0d2" 1547 | integrity sha1-gJanrAPyzE/lhg725XKBDZ4BwNI= 1548 | dependencies: 1549 | tslib "^1.9.0" 1550 | 1551 | safe-buffer@~5.1.1: 1552 | version "5.1.2" 1553 | resolved "https://neo.jfrog.io/neo/api/npm/npm/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" 1554 | integrity sha1-mR7GnSluAxN0fVm9/St0XDX4go0= 1555 | 1556 | semver@^5.4.1, semver@^5.7.0: 1557 | version "5.7.1" 1558 | resolved "https://neo.jfrog.io/neo/api/npm/npm/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" 1559 | integrity sha1-qVT5Ma66UI0we78Gnv8MAclhFvc= 1560 | 1561 | semver@^5.5.0: 1562 | version "5.6.0" 1563 | resolved "https://neo.jfrog.io/neo/api/npm/npm/semver/-/semver-5.6.0.tgz#7e74256fbaa49c75aa7c7a205cc22799cac80004" 1564 | integrity sha1-fnQlb7qknHWqfHogXMInmcrIAAQ= 1565 | 1566 | semver@^6.0.0, semver@^6.3.0: 1567 | version "6.3.0" 1568 | resolved "https://neo.jfrog.io/neo/api/npm/npm/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" 1569 | integrity sha1-7gpkyK9ejO6mdoexM3YeG+y9HT0= 1570 | 1571 | set-blocking@^2.0.0: 1572 | version "2.0.0" 1573 | resolved "https://neo.jfrog.io/neo/api/npm/npm/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" 1574 | integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc= 1575 | 1576 | shebang-command@^1.2.0: 1577 | version "1.2.0" 1578 | resolved "https://neo.jfrog.io/neo/api/npm/npm/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" 1579 | integrity sha1-RKrGW2lbAzmJaMOfNj/uXer98eo= 1580 | dependencies: 1581 | shebang-regex "^1.0.0" 1582 | 1583 | shebang-command@^2.0.0: 1584 | version "2.0.0" 1585 | resolved "https://neo.jfrog.io/neo/api/npm/npm/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" 1586 | integrity sha1-zNCvT4g1+9wmW4JGGq8MNmY/NOo= 1587 | dependencies: 1588 | shebang-regex "^3.0.0" 1589 | 1590 | shebang-regex@^1.0.0: 1591 | version "1.0.0" 1592 | resolved "https://neo.jfrog.io/neo/api/npm/npm/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" 1593 | integrity sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM= 1594 | 1595 | shebang-regex@^3.0.0: 1596 | version "3.0.0" 1597 | resolved "https://neo.jfrog.io/neo/api/npm/npm/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" 1598 | integrity sha1-rhbxZE2HPsrYQ7AwexQzYtTEIXI= 1599 | 1600 | signal-exit@^3.0.0, signal-exit@^3.0.2: 1601 | version "3.0.2" 1602 | resolved "https://neo.jfrog.io/neo/api/npm/npm/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" 1603 | integrity sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0= 1604 | 1605 | sinon@^7.2.4: 1606 | version "7.2.4" 1607 | resolved "https://neo.jfrog.io/neo/api/npm/npm/sinon/-/sinon-7.2.4.tgz#d834b9a38d8533b4ca3274a9a9ffa8e54c95d10c" 1608 | integrity sha1-2DS5o42FM7TKMnSpqf+o5UyV0Qw= 1609 | dependencies: 1610 | "@sinonjs/commons" "^1.3.0" 1611 | "@sinonjs/formatio" "^3.1.0" 1612 | "@sinonjs/samsam" "^3.1.1" 1613 | diff "^3.5.0" 1614 | lolex "^3.1.0" 1615 | nise "^1.4.10" 1616 | supports-color "^5.5.0" 1617 | 1618 | source-map@^0.5.0: 1619 | version "0.5.7" 1620 | resolved "https://neo.jfrog.io/neo/api/npm/npm/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" 1621 | integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= 1622 | 1623 | source-map@^0.6.1: 1624 | version "0.6.1" 1625 | resolved "https://neo.jfrog.io/neo/api/npm/npm/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" 1626 | integrity sha1-dHIq8y6WFOnCh6jQu95IteLxomM= 1627 | 1628 | spawn-wrap@^2.0.0: 1629 | version "2.0.0" 1630 | resolved "https://neo.jfrog.io/neo/api/npm/npm/spawn-wrap/-/spawn-wrap-2.0.0.tgz#103685b8b8f9b79771318827aa78650a610d457e" 1631 | integrity sha1-EDaFuLj5t5dxMYgnqnhlCmENRX4= 1632 | dependencies: 1633 | foreground-child "^2.0.0" 1634 | is-windows "^1.0.2" 1635 | make-dir "^3.0.0" 1636 | rimraf "^3.0.0" 1637 | signal-exit "^3.0.2" 1638 | which "^2.0.1" 1639 | 1640 | sprintf-js@~1.0.2: 1641 | version "1.0.3" 1642 | resolved "https://neo.jfrog.io/neo/api/npm/npm/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" 1643 | integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= 1644 | 1645 | string-width@^1.0.1: 1646 | version "1.0.2" 1647 | resolved "https://neo.jfrog.io/neo/api/npm/npm/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" 1648 | integrity sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M= 1649 | dependencies: 1650 | code-point-at "^1.0.0" 1651 | is-fullwidth-code-point "^1.0.0" 1652 | strip-ansi "^3.0.0" 1653 | 1654 | "string-width@^1.0.2 || 2", string-width@^2.0.0, string-width@^2.1.1: 1655 | version "2.1.1" 1656 | resolved "https://neo.jfrog.io/neo/api/npm/npm/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" 1657 | integrity sha1-q5Pyeo3BPSjKyBXEYhQ6bZASrp4= 1658 | dependencies: 1659 | is-fullwidth-code-point "^2.0.0" 1660 | strip-ansi "^4.0.0" 1661 | 1662 | string-width@^3.0.0, string-width@^3.1.0: 1663 | version "3.1.0" 1664 | resolved "https://neo.jfrog.io/neo/api/npm/npm/string-width/-/string-width-3.1.0.tgz#22767be21b62af1081574306f69ac51b62203961" 1665 | integrity sha1-InZ74htirxCBV0MG9prFG2IgOWE= 1666 | dependencies: 1667 | emoji-regex "^7.0.1" 1668 | is-fullwidth-code-point "^2.0.0" 1669 | strip-ansi "^5.1.0" 1670 | 1671 | string-width@^4.1.0, string-width@^4.2.0: 1672 | version "4.2.0" 1673 | resolved "https://neo.jfrog.io/neo/api/npm/npm/string-width/-/string-width-4.2.0.tgz#952182c46cc7b2c313d1596e623992bd163b72b5" 1674 | integrity sha1-lSGCxGzHssMT0VluYjmSvRY7crU= 1675 | dependencies: 1676 | emoji-regex "^8.0.0" 1677 | is-fullwidth-code-point "^3.0.0" 1678 | strip-ansi "^6.0.0" 1679 | 1680 | strip-ansi@^3.0.0, strip-ansi@^3.0.1: 1681 | version "3.0.1" 1682 | resolved "https://neo.jfrog.io/neo/api/npm/npm/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" 1683 | integrity sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8= 1684 | dependencies: 1685 | ansi-regex "^2.0.0" 1686 | 1687 | strip-ansi@^4.0.0: 1688 | version "4.0.0" 1689 | resolved "https://neo.jfrog.io/neo/api/npm/npm/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" 1690 | integrity sha1-qEeQIusaw2iocTibY1JixQXuNo8= 1691 | dependencies: 1692 | ansi-regex "^3.0.0" 1693 | 1694 | strip-ansi@^5.0.0, strip-ansi@^5.1.0, strip-ansi@^5.2.0: 1695 | version "5.2.0" 1696 | resolved "https://neo.jfrog.io/neo/api/npm/npm/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae" 1697 | integrity sha1-jJpTb+tq/JYr36WxBKUJHBrZwK4= 1698 | dependencies: 1699 | ansi-regex "^4.1.0" 1700 | 1701 | strip-ansi@^6.0.0: 1702 | version "6.0.0" 1703 | resolved "https://neo.jfrog.io/neo/api/npm/npm/strip-ansi/-/strip-ansi-6.0.0.tgz#0b1571dd7669ccd4f3e06e14ef1eed26225ae532" 1704 | integrity sha1-CxVx3XZpzNTz4G4U7x7tJiJa5TI= 1705 | dependencies: 1706 | ansi-regex "^5.0.0" 1707 | 1708 | strip-bom@^4.0.0: 1709 | version "4.0.0" 1710 | resolved "https://neo.jfrog.io/neo/api/npm/npm/strip-bom/-/strip-bom-4.0.0.tgz#9c3505c1db45bcedca3d9cf7a16f5c5aa3901878" 1711 | integrity sha1-nDUFwdtFvO3KPZz3oW9cWqOQGHg= 1712 | 1713 | strip-eof@^1.0.0: 1714 | version "1.0.0" 1715 | resolved "https://neo.jfrog.io/neo/api/npm/npm/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" 1716 | integrity sha1-u0P/VZim6wXYm1n80SnJgzE2Br8= 1717 | 1718 | strip-json-comments@2.0.1: 1719 | version "2.0.1" 1720 | resolved "https://neo.jfrog.io/neo/api/npm/npm/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" 1721 | integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo= 1722 | 1723 | supports-color@6.0.0: 1724 | version "6.0.0" 1725 | resolved "https://neo.jfrog.io/neo/api/npm/npm/supports-color/-/supports-color-6.0.0.tgz#76cfe742cf1f41bb9b1c29ad03068c05b4c0e40a" 1726 | integrity sha1-ds/nQs8fQbubHCmtAwaMBbTA5Ao= 1727 | dependencies: 1728 | has-flag "^3.0.0" 1729 | 1730 | supports-color@^5.3.0, supports-color@^5.5.0: 1731 | version "5.5.0" 1732 | resolved "https://neo.jfrog.io/neo/api/npm/npm/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" 1733 | integrity sha1-4uaaRKyHcveKHsCzW2id9lMO/I8= 1734 | dependencies: 1735 | has-flag "^3.0.0" 1736 | 1737 | supports-color@^7.1.0: 1738 | version "7.1.0" 1739 | resolved "https://neo.jfrog.io/neo/api/npm/npm/supports-color/-/supports-color-7.1.0.tgz#68e32591df73e25ad1c4b49108a2ec507962bfd1" 1740 | integrity sha1-aOMlkd9z4lrRxLSRCKLsUHliv9E= 1741 | dependencies: 1742 | has-flag "^4.0.0" 1743 | 1744 | test-exclude@^6.0.0: 1745 | version "6.0.0" 1746 | resolved "https://neo.jfrog.io/neo/api/npm/npm/test-exclude/-/test-exclude-6.0.0.tgz#04a8698661d805ea6fa293b6cb9e63ac044ef15e" 1747 | integrity sha1-BKhphmHYBepvopO2y55jrARO8V4= 1748 | dependencies: 1749 | "@istanbuljs/schema" "^0.1.2" 1750 | glob "^7.1.4" 1751 | minimatch "^3.0.4" 1752 | 1753 | text-encoding-utf-8@^1.0.2: 1754 | version "1.0.2" 1755 | resolved "https://neo.jfrog.io/neo/api/npm/npm/text-encoding-utf-8/-/text-encoding-utf-8-1.0.2.tgz#585b62197b0ae437e3c7b5d0af27ac1021e10d13" 1756 | integrity sha1-WFtiGXsK5Dfjx7XQryesECHhDRM= 1757 | 1758 | to-fast-properties@^2.0.0: 1759 | version "2.0.0" 1760 | resolved "https://neo.jfrog.io/neo/api/npm/npm/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" 1761 | integrity sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4= 1762 | 1763 | to-regex-range@^5.0.1: 1764 | version "5.0.1" 1765 | resolved "https://neo.jfrog.io/neo/api/npm/npm/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" 1766 | integrity sha1-FkjESq58jZiKMmAY7XL1tN0DkuQ= 1767 | dependencies: 1768 | is-number "^7.0.0" 1769 | 1770 | tslib@^1.9.0: 1771 | version "1.10.0" 1772 | resolved "https://neo.jfrog.io/neo/api/npm/npm/tslib/-/tslib-1.10.0.tgz#c3c19f95973fb0a62973fb09d90d961ee43e5c8a" 1773 | integrity sha1-w8GflZc/sKYpc/sJ2Q2WHuQ+XIo= 1774 | 1775 | type-detect@4.0.8, type-detect@^4.0.0, type-detect@^4.0.5: 1776 | version "4.0.8" 1777 | resolved "https://neo.jfrog.io/neo/api/npm/npm/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c" 1778 | integrity sha1-dkb7XxiHHPu3dJ5pvTmmOI63RQw= 1779 | 1780 | type-fest@^0.8.0: 1781 | version "0.8.1" 1782 | resolved "https://neo.jfrog.io/neo/api/npm/npm/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d" 1783 | integrity sha1-CeJJ696FHTseSNJ8EFREZn8XuD0= 1784 | 1785 | typedarray-to-buffer@^3.1.5: 1786 | version "3.1.5" 1787 | resolved "https://neo.jfrog.io/neo/api/npm/npm/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz#a97ee7a9ff42691b9f783ff1bc5112fe3fca9080" 1788 | integrity sha1-qX7nqf9CaRufeD/xvFES/j/KkIA= 1789 | dependencies: 1790 | is-typedarray "^1.0.0" 1791 | 1792 | uri-js@^4.2.2: 1793 | version "4.2.2" 1794 | resolved "https://neo.jfrog.io/neo/api/npm/npm/uri-js/-/uri-js-4.2.2.tgz#94c540e1ff772956e2299507c010aea6c8838eb0" 1795 | integrity sha1-lMVA4f93KVbiKZUHwBCupsiDjrA= 1796 | dependencies: 1797 | punycode "^2.1.0" 1798 | 1799 | uuid@^3.3.2: 1800 | version "3.3.2" 1801 | resolved "https://neo.jfrog.io/neo/api/npm/npm/uuid/-/uuid-3.3.2.tgz#1b4af4955eb3077c501c23872fc6513811587131" 1802 | integrity sha1-G0r0lV6zB3xQHCOHL8ZROBFYcTE= 1803 | 1804 | uuid@^3.3.3: 1805 | version "3.4.0" 1806 | resolved "https://neo.jfrog.io/neo/api/npm/npm/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee" 1807 | integrity sha1-sj5DWK+oogL+ehAK8fX4g/AgB+4= 1808 | 1809 | which-module@^2.0.0: 1810 | version "2.0.0" 1811 | resolved "https://neo.jfrog.io/neo/api/npm/npm/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" 1812 | integrity sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho= 1813 | 1814 | which@1.3.1, which@^1.2.9: 1815 | version "1.3.1" 1816 | resolved "https://neo.jfrog.io/neo/api/npm/npm/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" 1817 | integrity sha1-pFBD1U9YBTFtqNYvn1CRjT2nCwo= 1818 | dependencies: 1819 | isexe "^2.0.0" 1820 | 1821 | which@^2.0.1: 1822 | version "2.0.2" 1823 | resolved "https://neo.jfrog.io/neo/api/npm/npm/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" 1824 | integrity sha1-fGqN0KY2oDJ+ELWckobu6T8/UbE= 1825 | dependencies: 1826 | isexe "^2.0.0" 1827 | 1828 | wide-align@1.1.3: 1829 | version "1.1.3" 1830 | resolved "https://neo.jfrog.io/neo/api/npm/npm/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457" 1831 | integrity sha1-rgdOa9wMFKQx6ATmJFScYzsABFc= 1832 | dependencies: 1833 | string-width "^1.0.2 || 2" 1834 | 1835 | wrap-ansi@^2.0.0: 1836 | version "2.1.0" 1837 | resolved "https://neo.jfrog.io/neo/api/npm/npm/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85" 1838 | integrity sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU= 1839 | dependencies: 1840 | string-width "^1.0.1" 1841 | strip-ansi "^3.0.1" 1842 | 1843 | wrap-ansi@^5.1.0: 1844 | version "5.1.0" 1845 | resolved "https://neo.jfrog.io/neo/api/npm/npm/wrap-ansi/-/wrap-ansi-5.1.0.tgz#1fd1f67235d5b6d0fee781056001bfb694c03b09" 1846 | integrity sha1-H9H2cjXVttD+54EFYAG/tpTAOwk= 1847 | dependencies: 1848 | ansi-styles "^3.2.0" 1849 | string-width "^3.0.0" 1850 | strip-ansi "^5.0.0" 1851 | 1852 | wrap-ansi@^6.2.0: 1853 | version "6.2.0" 1854 | resolved "https://neo.jfrog.io/neo/api/npm/npm/wrap-ansi/-/wrap-ansi-6.2.0.tgz#e9393ba07102e6c91a3b221478f0257cd2856e53" 1855 | integrity sha1-6Tk7oHEC5skaOyIUePAlfNKFblM= 1856 | dependencies: 1857 | ansi-styles "^4.0.0" 1858 | string-width "^4.1.0" 1859 | strip-ansi "^6.0.0" 1860 | 1861 | wrappy@1: 1862 | version "1.0.2" 1863 | resolved "https://neo.jfrog.io/neo/api/npm/npm/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" 1864 | integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= 1865 | 1866 | write-file-atomic@^3.0.0: 1867 | version "3.0.3" 1868 | resolved "https://neo.jfrog.io/neo/api/npm/npm/write-file-atomic/-/write-file-atomic-3.0.3.tgz#56bd5c5a5c70481cd19c571bd39ab965a5de56e8" 1869 | integrity sha1-Vr1cWlxwSBzRnFcb05q5ZaXeVug= 1870 | dependencies: 1871 | imurmurhash "^0.1.4" 1872 | is-typedarray "^1.0.0" 1873 | signal-exit "^3.0.2" 1874 | typedarray-to-buffer "^3.1.5" 1875 | 1876 | "y18n@^3.2.1 || ^4.0.0", y18n@^4.0.0: 1877 | version "4.0.0" 1878 | resolved "https://neo.jfrog.io/neo/api/npm/npm/y18n/-/y18n-4.0.0.tgz#95ef94f85ecc81d007c264e190a120f0a3c8566b" 1879 | integrity sha1-le+U+F7MgdAHwmThkKEg8KPIVms= 1880 | 1881 | yargs-parser@13.1.2, yargs-parser@^13.1.2: 1882 | version "13.1.2" 1883 | resolved "https://neo.jfrog.io/neo/api/npm/npm/yargs-parser/-/yargs-parser-13.1.2.tgz#130f09702ebaeef2650d54ce6e3e5706f7a4fb38" 1884 | integrity sha1-Ew8JcC667vJlDVTObj5XBvek+zg= 1885 | dependencies: 1886 | camelcase "^5.0.0" 1887 | decamelize "^1.2.0" 1888 | 1889 | yargs-parser@^11.1.1: 1890 | version "11.1.1" 1891 | resolved "https://neo.jfrog.io/neo/api/npm/npm/yargs-parser/-/yargs-parser-11.1.1.tgz#879a0865973bca9f6bab5cbdf3b1c67ec7d3bcf4" 1892 | integrity sha1-h5oIZZc7yp9rq1y987HGfsfTvPQ= 1893 | dependencies: 1894 | camelcase "^5.0.0" 1895 | decamelize "^1.2.0" 1896 | 1897 | yargs-parser@^18.1.1: 1898 | version "18.1.3" 1899 | resolved "https://neo.jfrog.io/neo/api/npm/npm/yargs-parser/-/yargs-parser-18.1.3.tgz#be68c4975c6b2abf469236b0c870362fab09a7b0" 1900 | integrity sha1-vmjEl1xrKr9GkjawyHA2L6sJp7A= 1901 | dependencies: 1902 | camelcase "^5.0.0" 1903 | decamelize "^1.2.0" 1904 | 1905 | yargs-unparser@1.6.0: 1906 | version "1.6.0" 1907 | resolved "https://neo.jfrog.io/neo/api/npm/npm/yargs-unparser/-/yargs-unparser-1.6.0.tgz#ef25c2c769ff6bd09e4b0f9d7c605fb27846ea9f" 1908 | integrity sha1-7yXCx2n/a9CeSw+dfGBfsnhG6p8= 1909 | dependencies: 1910 | flat "^4.1.0" 1911 | lodash "^4.17.15" 1912 | yargs "^13.3.0" 1913 | 1914 | yargs@13.3.2, yargs@^13.3.0: 1915 | version "13.3.2" 1916 | resolved "https://neo.jfrog.io/neo/api/npm/npm/yargs/-/yargs-13.3.2.tgz#ad7ffefec1aa59565ac915f82dccb38a9c31a2dd" 1917 | integrity sha1-rX/+/sGqWVZayRX4Lcyzipwxot0= 1918 | dependencies: 1919 | cliui "^5.0.0" 1920 | find-up "^3.0.0" 1921 | get-caller-file "^2.0.1" 1922 | require-directory "^2.1.1" 1923 | require-main-filename "^2.0.0" 1924 | set-blocking "^2.0.0" 1925 | string-width "^3.0.0" 1926 | which-module "^2.0.0" 1927 | y18n "^4.0.0" 1928 | yargs-parser "^13.1.2" 1929 | 1930 | yargs@^12.0.5: 1931 | version "12.0.5" 1932 | resolved "https://neo.jfrog.io/neo/api/npm/npm/yargs/-/yargs-12.0.5.tgz#05f5997b609647b64f66b81e3b4b10a368e7ad13" 1933 | integrity sha1-BfWZe2CWR7ZPZrgeO0sQo2jnrRM= 1934 | dependencies: 1935 | cliui "^4.0.0" 1936 | decamelize "^1.2.0" 1937 | find-up "^3.0.0" 1938 | get-caller-file "^1.0.1" 1939 | os-locale "^3.0.0" 1940 | require-directory "^2.1.1" 1941 | require-main-filename "^1.0.1" 1942 | set-blocking "^2.0.0" 1943 | string-width "^2.0.0" 1944 | which-module "^2.0.0" 1945 | y18n "^3.2.1 || ^4.0.0" 1946 | yargs-parser "^11.1.1" 1947 | 1948 | yargs@^15.0.2: 1949 | version "15.3.1" 1950 | resolved "https://neo.jfrog.io/neo/api/npm/npm/yargs/-/yargs-15.3.1.tgz#9505b472763963e54afe60148ad27a330818e98b" 1951 | integrity sha1-lQW0cnY5Y+VK/mAUitJ6MwgY6Ys= 1952 | dependencies: 1953 | cliui "^6.0.0" 1954 | decamelize "^1.2.0" 1955 | find-up "^4.1.0" 1956 | get-caller-file "^2.0.1" 1957 | require-directory "^2.1.1" 1958 | require-main-filename "^2.0.0" 1959 | set-blocking "^2.0.0" 1960 | string-width "^4.2.0" 1961 | which-module "^2.0.0" 1962 | y18n "^4.0.0" 1963 | yargs-parser "^18.1.1" 1964 | --------------------------------------------------------------------------------