├── .gitignore ├── .vscode └── settings.json ├── README.md ├── async-control-flow-patterns-es6-beyond ├── generators │ ├── async-control-flow.js │ ├── iterators.js │ ├── notes.md │ ├── passing-values-generator.js │ ├── producer-consumer-pattern.js │ └── thunks.js └── promises │ ├── approach2-library.js │ ├── notes.md │ └── promisifying.js ├── async-control-flow-patterns-with-callbacks ├── callback-hell.md └── concurrency.md ├── design-patterns ├── adapter.md ├── command │ ├── client.js │ ├── command.js │ ├── invoker.js │ └── target.js ├── composition-proxy.js ├── config.js ├── decorator.md ├── factory.md ├── logging-proxy.js ├── middleware │ ├── client.js │ ├── jsonMiddleware.js │ ├── server.js │ └── zmqMiddleware.js ├── observable-pattern.js ├── profiler.js ├── proxy.md ├── revealing-constructor.md ├── roee.js ├── state.md ├── strategy.md ├── template.md └── videogame.js ├── messaging-integration-patterns ├── amqp-chat │ ├── app.js │ ├── historySvc.js │ ├── msgHistory │ │ ├── 000005.log │ │ ├── CURRENT │ │ ├── LOCK │ │ ├── LOG │ │ ├── LOG.old │ │ └── MANIFEST-000004 │ └── www │ │ └── index.html ├── notes.md ├── paralell-pipelines │ ├── sink.js │ ├── ventilator.js │ └── worker.js └── real-time-chat │ ├── app.js │ ├── p2p.js │ ├── redis.js │ └── www │ └── index.html ├── node.js-eseential-patterns ├── eventEmitter-vs-callback.md ├── io.md ├── misc.md ├── modules.md ├── observer-pattern │ ├── basic.js │ └── observable.js └── substack-pattern │ ├── code.js │ └── logger.js ├── package.json ├── scalability-architectural-patterns ├── cloning │ ├── app.js │ └── clusteredApp.js ├── cluster-vs-reverse-proxy.md ├── dinamic-load-balancer │ ├── README.md │ ├── app.js │ └── loadBalancer.js ├── requests-http-balancer-multiple-servers │ ├── balancedRequest.js │ └── client.js └── zero-downtime-cluster │ ├── app.js │ └── clusteredApp.js ├── streams ├── archive.js ├── back-pressure.js ├── checkUrls.js ├── combinedStreams.js ├── demultiplexer-server.js ├── flowing.js ├── generateData.js ├── gzip-buffer.js ├── gzip-streams.js ├── multiplexer-client.js ├── non-flowing.js ├── notes.md ├── parallelStream.js ├── randomString.js ├── replace.js ├── sequential-execution.js ├── stderr.log ├── stdout.log ├── toFileStream.js ├── transformStream.js └── writable-server.js ├── yarn-error.log └── yarn.lock /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "workbench.colorCustomizations": {} 3 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Node JS Design Patterns 2 | 3 | Highlights and code chunks 4 | 5 | Quokka.js usage is advised to run code snippets in the IDE -------------------------------------------------------------------------------- /async-control-flow-patterns-es6-beyond/generators/async-control-flow.js: -------------------------------------------------------------------------------- 1 | const fs = require("fs"); 2 | 3 | function asyncFlow(generatorFn) { 4 | function callback(err) { 5 | if (err) { 6 | return generator.throw(err); 7 | } 8 | const results = [].slice.call(arguments, 1); 9 | //Callback is called after every execution and is the one who goes for the next iteration 10 | generator.next(results.length > 1 ? results : results[0]); 11 | } 12 | const generator = generatorFn(callback); 13 | generator.next(); 14 | } 15 | 16 | function* cloneGen(callback) { 17 | const fileName = "README.md"; 18 | const myself = yield fs.readFile(fileName, "utf8", callback); 19 | yield fs.writeFile(`clone_of_${fileName}`, myself, callback); 20 | console.log("Clone created"); 21 | } 22 | 23 | asyncFlow(cloneGen); 24 | -------------------------------------------------------------------------------- /async-control-flow-patterns-es6-beyond/generators/iterators.js: -------------------------------------------------------------------------------- 1 | function* iteratorGenerator(arr) { 2 | for (let i = 0; i < arr.length; i++) { 3 | yield arr[i]; 4 | } 5 | } 6 | 7 | const numbers = new Array(10).fill().map((value, index) => index + 1); 8 | const iterator = iteratorGenerator(numbers); 9 | let currentItem = iterator.next(); 10 | while (!currentItem.done) { 11 | console.log(currentItem); 12 | currentItem = iterator.next(); 13 | } 14 | -------------------------------------------------------------------------------- /async-control-flow-patterns-es6-beyond/generators/notes.md: -------------------------------------------------------------------------------- 1 | ### Thunks 2 | 3 | A thunk used in the generator-based control flow is just a function that partially applies all the arguments of the original function except the callback. The return value is another function that only accepts the callback as an argument. E.g.: the thunkified version of `fs.readFile()` would be as follows: 4 | 5 | ```js 6 | function readFileThunk(filename, options){ 7 | return function(callback){ 8 | fs.readFile(filename, options, callback) 9 | } 10 | } 11 | ``` 12 | 13 | It allows to run async functions in a generator synchronously, like an async await and with a sequential execution. 14 | 15 | 16 | ### Paralell execution 17 | 18 | Generators are fine for sequential, but they cant be used to parallelize execution. The workaround is using callbacks or promises using `co` library. 19 | 20 | 21 | ### Generator-to-thunk pattern 22 | 23 | It converts a generator to a thunk in order to be able to run it in parallel or utilize it for taking advantage of other callback or promise-based control flow algorithms. 24 | 25 | 26 | ### Limited parallel execution 27 | 28 | There are several options. Based on the previous, you can also use a Queue (callback or promise-based), async+thunkify, `co-limiter` library or implement a custom algorithm. -------------------------------------------------------------------------------- /async-control-flow-patterns-es6-beyond/generators/passing-values-generator.js: -------------------------------------------------------------------------------- 1 | function* twoWay() { 2 | const arg = yield "Pow"; 3 | return yield Math.pow(arg, arg); 4 | } 5 | 6 | const callPow = twoWay(); 7 | console.log(callPow.next()); 8 | console.log(callPow.next(4)); 9 | 10 | // We can also use a throw 11 | 12 | const callPow2 = twoWay(); 13 | console.log(callPow2.next()); 14 | callPow2.throw(new Error("Forced error")); 15 | -------------------------------------------------------------------------------- /async-control-flow-patterns-es6-beyond/generators/producer-consumer-pattern.js: -------------------------------------------------------------------------------- 1 | /** 2 | * In the TaskQueue class, the workers have the role of consumers 3 | * while whoever uses pushTask() can be considered a producer. 4 | * This pattern shows us how a generator can be very similar to 5 | * a thread (or a process). 6 | */ 7 | 8 | const co = require("co"); 9 | 10 | class TaskQueue { 11 | constructor(concurrency) { 12 | this.concurrency = concurrency; 13 | this.running = 0; 14 | this.taskQueue = []; 15 | this.consumerQueue = []; 16 | this.spawnWorkers(concurrency); 17 | } 18 | pushTask(task) { 19 | if (this.consumerQueue.length !== 0) { 20 | this.consumerQueue.shift()(null, task); 21 | } else { 22 | this.taskQueue.push(task); 23 | } 24 | } 25 | 26 | spawnWorkers(concurrency) { 27 | const self = this; 28 | for (let i = 0; i < concurrency; i++) { 29 | // wrapping with co to run in parallel 30 | co(function*() { 31 | while (true) { 32 | const task = yield self.nextTask(); 33 | yield task; 34 | } 35 | }); 36 | } 37 | } 38 | 39 | nextTask() { 40 | return callback => { 41 | if (this.taskQueue.length !== 0) { 42 | return callback(null, this.taskQueue.shift()); 43 | } 44 | //if no tasks in the queue we push the callback 45 | // so the worker will be in idle mode 46 | this.consumerQueue.push(callback); 47 | }; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /async-control-flow-patterns-es6-beyond/generators/thunks.js: -------------------------------------------------------------------------------- 1 | const fs = require("fs"); 2 | 3 | function asyncFlowWithThunk(generatorFn) { 4 | function callback(err) { 5 | if (err) { 6 | return generator.throw(err); 7 | } 8 | const results = [].slice.call(arguments, 1); 9 | const thunk = generator.next(results.length > 1 ? results : results[0]) 10 | .value; 11 | thunk && thunk(callback); 12 | } 13 | const generator = generatorFn(callback); 14 | const thunk = generator.next().value; 15 | thunk && thunk(callback); 16 | } 17 | 18 | function* cloneGen(callback) { 19 | const fileName = "README.md"; 20 | const myself = yield fs.readFile(fileName, "utf8", callback); 21 | yield fs.writeFile(`clone_of_${fileName}`, myself, callback); 22 | console.log("Clone created"); 23 | } 24 | 25 | asyncFlowWithThunk(cloneGen); 26 | -------------------------------------------------------------------------------- /async-control-flow-patterns-es6-beyond/promises/approach2-library.js: -------------------------------------------------------------------------------- 1 | function asyncdivision(dividend, divisor, callback) { 2 | return new Promise((resolve, reject) => { 3 | process.nextTick(() => { 4 | const result = dividend / divisor; 5 | if (isNaN(result) || !Number.isFinite(result)) { 6 | const error = new Error("Invalid operands"); 7 | if (callback) { 8 | callback(error); 9 | } 10 | return reject(error); 11 | } 12 | if (callback) { 13 | callback(null, result); 14 | } 15 | return resolve(result); 16 | }); 17 | }); 18 | } 19 | 20 | // No callback case 21 | 22 | let result; 23 | asyncdivision(4, 2) 24 | .then(value => { 25 | console.log(value); 26 | result = value; 27 | }) 28 | .catch(err => console.log(err)); 29 | 30 | // With callback 31 | 32 | asyncdivision(4, 2, (error, value) => { 33 | if (error) { 34 | console.log(error); 35 | return; 36 | } 37 | console.log(value); 38 | result = value; 39 | }); 40 | 41 | // Error management 42 | 43 | asyncdivision(4, 0) 44 | .then(value => { 45 | console.log(value); 46 | result = value; 47 | }) 48 | .catch(err => console.log(err)); 49 | 50 | asyncdivision(4, 0, (error, value) => { 51 | if (error) { 52 | console.log(error); 53 | return; 54 | } 55 | console.log(value); 56 | result = value; 57 | }); 58 | 59 | module.exports = asyncdivision; 60 | -------------------------------------------------------------------------------- /async-control-flow-patterns-es6-beyond/promises/notes.md: -------------------------------------------------------------------------------- 1 | * `then()` synchronously returns a promise 2 | * A thenable is a promise-like object with a `then()` method. This term is used to indicate a promise that is foreign to the particular promise implementation in use. 3 | * `onFulfilled` and `onRejected`are invoked asynchronously 4 | * If a throw is called from `onFulfilled` or `onRejected` handler, the promise returned by `then()` will be automatically reject, with the exception thrown as the rejection reason. It means that with promises, errors will propagate through the chain. 5 | 6 | ## ES6 Promises 7 | 8 | ### Static methods if the Promise object 9 | 10 | * `Promise.resolve(obj)`: Creates a new promise from a thenable or a value 11 | * `Promise.reject(err)`: Creates a promise that rejects with err as a reason 12 | * `Promise.all(iterable)`: Creates a promise that fulfills with an iterable of fulfillment values when every item in the iterable object fulfills, and rejects with the first rejectio reason if any item rejects. Each item in the iterable object can be a promise, a generic thenable or a value 13 | * `Promise.race(iterable)`: Returns a promise that resolves or rejects as soon as one of the promises in the iterable resolves or rejects with value mor reason from that promise. 14 | 15 | ### Methods of promise instance: 16 | 17 | * `promise.then(onFullfilled,onRejected)`: Essential method of a promise 18 | * `promise.catch(onRejected)`: This is just syntactic sugar for `promise.then(onFullfilled,onRejected)` 19 | 20 | ### Sequential iteration pattern 21 | 22 | It dinamically builds a chain of promises using a loop. 23 | 24 | Standard: 25 | 26 | ```js 27 | let tasks = [...] 28 | let promise = Promise.resolve(); // empty promise as entry point 29 | tasks.forEach(task => { 30 | promise = promise.then(()=> task()) 31 | }) 32 | promise.then(()=>{ 33 | // ... All Tasks completed 34 | }) 35 | ``` 36 | 37 | Compact mode: 38 | 39 | ```js 40 | let tasks = [...] 41 | let promise = tasks.reduce((acc, task) => ( 42 | prev.then(() => task()) 43 | ), Promise.resolve()) 44 | promise.then(()=>{ 45 | // ... All Tasks completed 46 | }) 47 | ``` 48 | 49 | 50 | ### Paralell execution 51 | 52 | Just using `Promise.all([task1, task2, task3])` 53 | 54 | ### Limited paralell execution 55 | 56 | There isnt a native way in ES6 to limit the number of concurrent tasks. 57 | It's similar that with callbacks but switching them for `then` 58 | 59 | 60 | ### Callback vs Promises in public APIs 61 | 62 | #### Approach 1 63 | 64 | Offering a simple API that is only based on callbacks and leave the developer the option to promisifythe exposed functions if needed. 65 | 66 | #### Approach 2 67 | 68 | It also offers a callback-oriented API, but it makes the callback argument optional. Whenever the callback is passed as an argument , the function will behave normally, executing the callback on completion or on failure. 69 | When the callback is not passed, the function will inmediatelly return a Promise object. 70 | It combines callbacks and Promises without the need of promisifying. 71 | 72 | Check example in approach2-library.js -------------------------------------------------------------------------------- /async-control-flow-patterns-es6-beyond/promises/promisifying.js: -------------------------------------------------------------------------------- 1 | function promisify(callbackBasedApi) { 2 | return function promisified() { 3 | // promisified version of callbackBasedApi 4 | const args = [].slice.call(arguments); 5 | return new Promise((resolve, reject) => { 6 | args.push((err, result) => { 7 | if (err) { 8 | return reject(err); 9 | } 10 | if (arguments.length <= 2) { 11 | resolve(result); 12 | } else { 13 | resolve([].slice.call(arguments, 1)); 14 | } 15 | }); 16 | callbackBasedApi.apply(null, args); 17 | }); 18 | }; 19 | } 20 | 21 | const fs = require("fs"); 22 | const fileName = "README.md"; 23 | 24 | // Standard 25 | const readFile = fs.readFile; 26 | readFile(fileName, (err, data) => { 27 | if (err) { 28 | console.log(err); 29 | return; 30 | } 31 | console.log(data); 32 | return; 33 | }); 34 | 35 | // Promisified 36 | const readFilePromisified = promisify(fs.readFile); 37 | readFilePromisified(fileName) //returns the promise 38 | .then(value => { 39 | console.log(typeof value); 40 | return value; 41 | }) 42 | .then(value => { 43 | console.log(value); 44 | }) 45 | .catch(err => { 46 | console.log(err); 47 | }); 48 | 49 | // Failing case 50 | readFilePromisified(`${fileName}2`) 51 | .then(value => { 52 | console.log(typeof value); 53 | return value; 54 | }) 55 | .then(value => { 56 | console.log(value); 57 | }) 58 | .catch(err => { 59 | console.log(err); 60 | }); 61 | -------------------------------------------------------------------------------- /async-control-flow-patterns-with-callbacks/callback-hell.md: -------------------------------------------------------------------------------- 1 | ### Callback Hell and closures 2 | 3 | * One of the most severe and well-recognized anti-patterns in node and JS in general 4 | * Making bad use of closures can lead to incredibly bad code 5 | * Chained callbacks in a same function is really hard to read 6 | * Substitute with asynchronous code 7 | 8 | 9 | ### Typical example 10 | 11 | ```js 12 | asyncFoo(err => { 13 | asyncFoo2(err => { 14 | asyncFoo3(err => { 15 | ... 16 | }) 17 | }) 18 | }) 19 | ``` 20 | 21 | * It's called pyramid of doom and the most evident problem is the poor readability. Also the overlapping of variables used in different nested levels. 22 | * Closures are good in performance ways but can cause memory leaks very hard to identify because we shouldn't forget that any context referenced by an active closure is retained from garbage collection. 23 | 24 | 25 | ### Callback discipline 26 | 27 | * You should exit ASAP using `return` instead executing only the callback 28 | * Avoid completing `if...else` statements 29 | * Keep using modularity to have simpler and shorter functions 30 | * Use named functions instead so much arrow functions. It will keep a more clear code and a better stack trace 31 | 32 | 33 | ### Sequential execution 34 | 35 | There are different variations of the flow: 36 | 37 | * Executing a set of known tasks in squence, without chaining or propagating results. It passes the callback through the tasks. 38 | * Using the output of a task as the input for the next. Also known as chaining, pipeline or waterfall. 39 | * Iterating over a collection while running an async task on each element, one after the other. 40 | 41 | ### Sequential iteration pattern 42 | 43 | ```js 44 | function iterate(index){ 45 | if(index === tasks.length){ 46 | // The return here is crucial to avoid the function to keep running 47 | return finish(); 48 | } 49 | const task = tasks[index]; 50 | task(function(){ 51 | iterate(index + 1); 52 | }) 53 | } 54 | 55 | function finish(){ 56 | // iteration completed 57 | } 58 | iterate(0); 59 | ``` 60 | 61 | NOTE: This type of algorithm becomes really recursive if `task` is a synchronous operation. In such a case, the stack won't unwind at every cicle and there might be a risk of itting the maximum call stack size limit. 62 | 63 | * This is a very powerful pattern that can be adapted to several situations -------------------------------------------------------------------------------- /async-control-flow-patterns-with-callbacks/concurrency.md: -------------------------------------------------------------------------------- 1 | * Even being single thread, node can achieve concurrency, thanks to the non-blocking nature 2 | * A task gives control back to the event loop when it requests a new async operation allowing the event loop to execute another task. That's concurreny 3 | * Synchronous (blocking) operations can not run concurrently in node, unless is interleaved with an async operation or deferred 4 | * Running multiple asyn tasks in parallel is in straightforward and cheap in terms of resources. This is one of the most strengths of node. 5 | 6 | 7 | ### Paralell Execution pattern 8 | 9 | ```js 10 | const tasks = [...] 11 | let completed = 0; 12 | tasks.forEach( 13 | task => { 14 | task(()=>{ 15 | if(++completed === tasks.length){ 16 | finish() 17 | } 18 | }) 19 | } 20 | ) 21 | 22 | function finish(){ 23 | // all the tasks completed ... 24 | } 25 | ``` 26 | 27 | - Run a set of async tasks in parallel by spawning them all at once, and then wait for all ofthem to complete by counting the number of times their callbacks are invoked 28 | 29 | 30 | ### Race condition issues 31 | 32 | * Problem: The root of the problem is the delay between the invocation of an async operation and the notification of its result. It can lead in data corruption and are very hard to debug. E.g.: Tasks that are downloading files and 2 of them are equal. It 'd download the file twice. 33 | * Solution: Mapping tasks before running to avoid duplications or collisions. 34 | 35 | 36 | ### Limited Parallel execution pattern 37 | 38 | * Spawning paralell tasks without control can lead to an excessive load, like running out of resources. It can also create a DoS attack vulnerability. 39 | 40 | ```js 41 | const js = ... 42 | let concurrency = 2, running = 0, completed = 0, index = 0; 43 | function next(){ 44 | while(running < concurrency && index < tasks.length){ 45 | task = tasks[index++] 46 | task(()=>{ 47 | if(completed === tasks.length){ 48 | return finish() 49 | } 50 | completed++; 51 | running--; 52 | next() 53 | }) 54 | running ++; 55 | } 56 | } 57 | next() 58 | funcion finish(){ 59 | // all tasks finished 60 | } 61 | ``` 62 | 63 | * Queues are good to manage parallel execution 64 | 65 | 66 | TIP: `async` library of node is useful for this patterns. -------------------------------------------------------------------------------- /design-patterns/adapter.md: -------------------------------------------------------------------------------- 1 | ## Adapter pattern 2 | 3 | It allows us to access the functionallity of an object so it can be used by components expecting a different interface. 4 | The most common implementation technique is composition, where the methods of the adapter provides a bridge to the methods of the adaptee. 5 | Example: bridging `readFile` and `writeFile` with `db.get` and `db.put` respectively. -------------------------------------------------------------------------------- /design-patterns/command/client.js: -------------------------------------------------------------------------------- 1 | const Invoker = require("./invoker"); 2 | const createSendStatusCmd = require("./command"); 3 | const statusUpdateService = require("./target"); 4 | 5 | const invoker = new Invoker(); 6 | const command = createSendStatusCmd(statusUpdateService, "Hi!"); 7 | 8 | function test() { 9 | invoker.run(command); 10 | invoker.undo(); 11 | invoker.delay(command, 1000 * 60 * 60); 12 | invoker.runRemotely(command); 13 | } 14 | 15 | test(); 16 | -------------------------------------------------------------------------------- /design-patterns/command/command.js: -------------------------------------------------------------------------------- 1 | function createSendStatusCmd(service, status) { 2 | let postId = null; 3 | const command = () => { 4 | postId = service.sendUpdate(status); 5 | }; 6 | command.undo = () => { 7 | if (postId) { 8 | service.destroyUpdate(postId); 9 | postId = null; 10 | } 11 | }; 12 | command.serialize = () => { 13 | return { type: "status", action: "post", status: status }; 14 | }; 15 | return command; 16 | } 17 | 18 | module.exports = createSendStatusCmd; 19 | -------------------------------------------------------------------------------- /design-patterns/command/invoker.js: -------------------------------------------------------------------------------- 1 | class Invoker { 2 | constructor() { 3 | this.history = []; 4 | } 5 | run(cmd) { 6 | this.history.push(cmd); 7 | cmd(); 8 | console.log("Command executed", cmd.serialize()); 9 | } 10 | 11 | delay(cmd, delay) { 12 | setTimeout(() => { 13 | this.run(cmd); 14 | }, delay); 15 | } 16 | 17 | undo() { 18 | const cmd = this.history.pop(); 19 | cmd.undo(); 20 | console.log("Command undone", cmd.serialize()); 21 | } 22 | 23 | runRemotely(cmd) { 24 | request.post( 25 | "http://localhost:7000/cmd", 26 | { json: cmd.serialize() }, 27 | err => { 28 | console.log("Command executed remotely", cmd.serialize()); 29 | } 30 | ); 31 | } 32 | } 33 | 34 | module.exports = Invoker; 35 | -------------------------------------------------------------------------------- /design-patterns/command/target.js: -------------------------------------------------------------------------------- 1 | const statusUpdateService = { 2 | statusUpdates: {}, 3 | sendUpdate: function(status) { 4 | console.log("Status sent: " + status); 5 | let id = Math.floor(Math.random() * 1000000); 6 | statusUpdateService.statusUpdates[id] = status; 7 | return id; 8 | }, 9 | destroyUpdate: id => { 10 | console.log("Status removed: " + id); 11 | delete statusUpdateService.statusUpdates[id]; 12 | } 13 | }; 14 | 15 | module.exports = statusUpdateService; 16 | -------------------------------------------------------------------------------- /design-patterns/composition-proxy.js: -------------------------------------------------------------------------------- 1 | function createProxy(subject) { 2 | const proto = Object.getPrototypeOf(subject); 3 | 4 | function Proxy(subject) { 5 | this.subject = subject; 6 | } 7 | 8 | Proxy.prototype = Object.create(proto); 9 | 10 | //proxied method 11 | Proxy.prototype.hello = function() { 12 | return `${this.subject.hello()} world!`; 13 | }; 14 | 15 | //delegated method 16 | Proxy.prototype.goodbye = function() { 17 | return this.subject.goodbye.apply(this.subject, arguments); 18 | }; 19 | 20 | return new Proxy(subject); 21 | } 22 | 23 | // or 24 | 25 | function createProxy(subject) { 26 | return { 27 | // proxied method 28 | hello: () => `${subject.hello()} world!`, 29 | // delegated method 30 | goodby: () => subject.goodbye.apply(subject, arguments) 31 | }; 32 | } 33 | -------------------------------------------------------------------------------- /design-patterns/config.js: -------------------------------------------------------------------------------- 1 | const fs = require("fs"); 2 | const ini = require("ini"); 3 | const objectPath = require("object-path"); 4 | 5 | class Config { 6 | constructor(strategy) { 7 | this.data = {}; 8 | this.strategy = strategy; 9 | } 10 | get(path) { 11 | return objectPath.get(this.data, path); 12 | } 13 | 14 | set(path, value) { 15 | return objectPath.set(this.data, path, value); 16 | } 17 | 18 | read(file) { 19 | console.log(`Deserializing to ${file}`); 20 | this.data = this.strategy.deserialize(fs.readFileSync(file, "utf-8")); 21 | } 22 | 23 | save(file) { 24 | console.log(`Serializing to ${file}`); 25 | fs.writeFileSync(file, this.strategy.serialize(this.data)); 26 | } 27 | } 28 | 29 | const jsonStrategies = { 30 | serialize: data => JSON.stringify(data, null, " "), 31 | deserialize: data => JSON.parse(data) 32 | }; 33 | 34 | const iniStrategies = { 35 | serialize: data => ini.stringify(data), 36 | deserialize: data => ini.parse(data) 37 | }; 38 | 39 | const jsonConfig = new Config(jsonStrategies); 40 | jsonConfig.read("package.json"); 41 | jsonConfig.set("test.nodejs", "design patterns"); 42 | jsonConfig.save("new.json"); 43 | 44 | const iniConfig = new Config(iniStrategies); 45 | iniConfig.read("package.json"); 46 | iniConfig.set("test.nodejs", "design patterns INI"); 47 | iniConfig.save("new.ini"); 48 | -------------------------------------------------------------------------------- /design-patterns/decorator.md: -------------------------------------------------------------------------------- 1 | ## Decorator 2 | 3 | Similar to proxy, butinstead of enhacing or modyfing the behavior, it augments with new functionalities. 4 | 5 | Techniques: 6 | 7 | - Composition: 8 | 9 | ```js 10 | function decorate(component) { 11 | const proto = Object.getPrototypeOf(component); 12 | function Decorator(component) { 13 | this.component = component; 14 | } 15 | Decorator.prototype = Object.create(proto); 16 | 17 | // new method 18 | Decorator.prototype.greetings = () => "Hi!"; 19 | 20 | // delegated method 21 | Decorator.prototype.hello = () => 22 | this.component.apply(this.component, arguments); 23 | 24 | return new Decorator(component); 25 | } 26 | ``` 27 | 28 | - Object augmentation 29 | 30 | ```js 31 | function decorate(component) { 32 | // new method 33 | component.greetings = () => "Hi"; 34 | return component; 35 | } 36 | ``` 37 | -------------------------------------------------------------------------------- /design-patterns/factory.md: -------------------------------------------------------------------------------- 1 | ## Factory pattern 2 | 3 | A factory allow us to separate the object creation from its implementation. 4 | 5 | ```js 6 | function createImage(name){ 7 | return new Image(name) 8 | } 9 | const image = createImage("photo.png") 10 | ``` 11 | 12 | `new` binds our code to a particular type. A factory instead give us more flexibility. For example if we want to reactor the `Image` class in the preceding example. Splitting into some functions, one for each image type. 13 | 14 | ## Enforce encapsulation 15 | 16 | Factory can be used as encapsulation (or information hiding) mechanism due to closures. 17 | 18 | ```js 19 | function createPerson(){ 20 | const privateProperties = {} 21 | const person = { 22 | setName: name => { 23 | if (!name) throw new Error("Error") 24 | privateProperties.name = name 25 | }, 26 | getName: ()=>{ 27 | return privateProperties.name; 28 | } 29 | } 30 | 31 | person.setName(name) 32 | return person; 33 | } 34 | ``` 35 | 36 | Full example: profiler.js 37 | 38 | ## Composable factory functions 39 | 40 | Example using `stampit`: videogame.js 41 | 42 | Other libraries to create factories: 43 | - Dnode 44 | - Restify 45 | 46 | -------------------------------------------------------------------------------- /design-patterns/logging-proxy.js: -------------------------------------------------------------------------------- 1 | function createLoggingWritable(writableOrig) { 2 | const proto = Object.getPrototypeOf(writableOrig); 3 | function LoggingWritable(writableOrig) { 4 | this.writableOrig = writableOrig; 5 | } 6 | LoggingWritable.prototype = Object.create(proto); 7 | 8 | // Overwrite write method 9 | LoggingWritable.prototype.write = function(chunk, encoding, callback) { 10 | if (!callback && typeof encoding === "function") { 11 | callback = encoding; 12 | encoding = undefined; 13 | } 14 | console.log("Writing", chunk); 15 | return this.writableOrig.write(chunk, encoding, function() { 16 | console.log("Finished writing", chunk); 17 | callback && callback(); 18 | }); 19 | }; 20 | 21 | // Delegated methods, not overwritten 22 | LoggingWritable.prototype.on = function() { 23 | return this.writableOrig.on.apply(this.writableOrig, arguments); 24 | }; 25 | LoggingWritable.prototype.end = function() { 26 | return this.writableOrig.end.apply(this.writableOrig, arguments); 27 | }; 28 | 29 | return new LoggingWritable(writableOrig); 30 | } 31 | 32 | const fs = require("fs"); 33 | 34 | const writable = fs.createWriteStream("test.txt"); 35 | const writableProxy = createLoggingWritable(writable); 36 | writableProxy.write("First Chunk"); 37 | writableProxy.write("Second Chunk"); 38 | writableProxy.write("Third Chunk"); 39 | writable.write("Not logged"); 40 | writableProxy.end(); 41 | -------------------------------------------------------------------------------- /design-patterns/middleware/client.js: -------------------------------------------------------------------------------- 1 | const zmq = require("zeromq"); 2 | const ZmqMiddlewareManager = require("./zmqMiddleware"); 3 | const jsonMiddleware = require("./jsonMiddleware"); 4 | const request = zmq.socket("req"); 5 | 6 | async function run() { 7 | await request.connect("tcp://127.0.0.1:7000"); 8 | 9 | const zmqm = new ZmqMiddlewareManager(request); 10 | zmqm.use(jsonMiddleware.json()); 11 | 12 | zmqm.use({ 13 | inbound: function(message, next) { 14 | console.log("Echoed back: ", message.data); 15 | next(); 16 | } 17 | }); 18 | 19 | setInterval(() => { 20 | zmqm.send({ action: "ping", echo: Date.now() }); 21 | }, 1000); 22 | } 23 | 24 | run(); 25 | -------------------------------------------------------------------------------- /design-patterns/middleware/jsonMiddleware.js: -------------------------------------------------------------------------------- 1 | const jsonMiddleware = () => ({ 2 | /** 3 | * Deserializes JSON 4 | * @param {Object} message 5 | * @param {Function} next 6 | */ 7 | inboud: function(message, next) { 8 | message.data = JSON.parse(message.data.toString()); 9 | next(); 10 | }, 11 | /** 12 | * Serializes JSON 13 | * @param {Object} message 14 | * @param {Function} next 15 | */ 16 | outbound: function(message, next) { 17 | message.data = new Buffer(JSON.stringify(message.data)); 18 | next(); 19 | } 20 | }); 21 | 22 | module.exports.json = jsonMiddleware; 23 | -------------------------------------------------------------------------------- /design-patterns/middleware/server.js: -------------------------------------------------------------------------------- 1 | const zmq = require("zeromq"); 2 | const ZmqMiddlewareManager = require("./zmqMiddleware"); 3 | const jsonMiddleware = require("./jsonMiddleware"); 4 | const reply = zmq.socket("rep"); 5 | 6 | async function run() { 7 | await reply.bind("tcp://127.0.0.1:7000"); 8 | const zmqm = new ZmqMiddlewareManager(reply); 9 | zmqm.use(jsonMiddleware.json()); 10 | 11 | zmqm.use({ 12 | inbound: function(message, next) { 13 | console.log("Received: ", message.data); 14 | if (message.data.action === "ping") { 15 | this.send({ action: "pong", echo: message.data.echo }); 16 | } 17 | next(); 18 | } 19 | }); 20 | } 21 | 22 | run(); 23 | -------------------------------------------------------------------------------- /design-patterns/middleware/zmqMiddleware.js: -------------------------------------------------------------------------------- 1 | class ZmqMiddlewareManager { 2 | constructor(socket) { 3 | this.socket = socket; 4 | // Two empty lists that will contain middleware functions 5 | this.inboundMiddleware = []; 6 | this.outboundMiddleware = []; 7 | // Starts listening 8 | socket.on("message", message => { 9 | this.executeMiddleware(this.inboundMiddleware, { 10 | data: message 11 | }); 12 | }); 13 | } 14 | 15 | /** 16 | * Executes the middleware when a new message 17 | * is sent through the socket 18 | * @param {*} data 19 | */ 20 | send(data) { 21 | const message = { 22 | data 23 | }; 24 | this.executeMiddleware(this.outboundMiddleware, message, () => { 25 | this.socket.send(message.data); 26 | }); 27 | } 28 | 29 | /** 30 | * Appends middleware functions to pipelines 31 | * @param {Array} middleware 32 | */ 33 | use(middleware) { 34 | if (middleware.inboud) { 35 | this.inboundMiddleware.push(middleware.inboud); 36 | } 37 | if (middleware.outbound) { 38 | this.outboundMiddleware.unshift(middleware.outbound); 39 | } 40 | } 41 | 42 | /** 43 | * Executes the middleware functions 44 | * 45 | * @param {Array} middleware 46 | * @param {*} arg 47 | * @param {Function} finish 48 | */ 49 | executeMiddleware(middleware, arg, finish) { 50 | function iterator(index) { 51 | if (index === middleware.length) { 52 | return finish && finish(); 53 | } 54 | middleware[index].call(this, arg, err => { 55 | if (err) { 56 | return console.error(`There was an error: ${err.message}`); 57 | } 58 | iterator.call(this, ++index); 59 | }); 60 | } 61 | iterator.call(this, 0); 62 | } 63 | } 64 | 65 | module.exports = ZmqMiddlewareManager; 66 | -------------------------------------------------------------------------------- /design-patterns/observable-pattern.js: -------------------------------------------------------------------------------- 1 | const EventEmitter = require("events").EventEmitter; 2 | 3 | class Pizza extends EventEmitter { 4 | constructor(size = 1) { 5 | super(); 6 | this.ovenTime = this._ovenTime(size); 7 | this.maxIngredients = this._maxIngredients(size); 8 | this.ingredients = []; 9 | this.timeToReleasePizza = 5; 10 | } 11 | 12 | /** 13 | * Static function that returns size types 14 | */ 15 | static sizes() { 16 | return { 17 | individual: 1, 18 | medium: 2, 19 | familiar: 3 20 | }; 21 | } 22 | 23 | /** 24 | * Max pizza ingredients by size 25 | * @param {Number} size 26 | * @returns {Number} 27 | */ 28 | _maxIngredients(size) { 29 | return size * 3; 30 | } 31 | 32 | /** 33 | * Oven time by size 34 | * @param {Number} size 35 | * @returns {Number} 36 | */ 37 | _ovenTime(size) { 38 | return 5 + size * 2; 39 | } 40 | 41 | /** 42 | * Checks if max number of ingredients was reached 43 | * @returns {Boolean} 44 | */ 45 | _isMaxIngredientsReached() { 46 | return this.ingredients.length === this.maxIngredients; 47 | } 48 | 49 | /** 50 | * Adds and ingredient to pizza if max was 51 | * not reached and emits events in both cases 52 | * @param {String} ingredient 53 | * @returns {Pizza} 54 | */ 55 | add(ingredient) { 56 | if (!this._isMaxIngredientsReached()) { 57 | this.ingredients.push(ingredient); 58 | this.emit("ingredientAdded", ingredient); 59 | } else { 60 | this.emit("maxIngredientsReached"); 61 | } 62 | return this; 63 | } 64 | 65 | /** 66 | * Removes and ingredient from the pizza if founf 67 | * and emits events in both cases 68 | * @param {String} ingredient 69 | * @returns {Pizza} 70 | */ 71 | remove(ingredient) { 72 | const ingredientToRemove = this.ingredients.indexOf(ingredient); 73 | if (ingredientToRemove !== -1) { 74 | this.ingredients.splice(ingredientToRemove, 1); 75 | this.emit("ingredientRemoved", ingredient); 76 | } else { 77 | this.emit("errorRemovingIngredient", ingredient); 78 | } 79 | return this; 80 | } 81 | 82 | /** 83 | * It starts the timer once the oven time is passed, 84 | * the pizza has to be released (clearing interval) 85 | * in an specific amount of time to avoid charring 86 | * @returns {Pizza} 87 | */ 88 | cook() { 89 | this.emit("cookStarted"); 90 | setTimeout(() => { 91 | const releasePizza = setTimeout(() => { 92 | this.emit("charredPizza"); 93 | }, this.timeToReleasePizza); 94 | this.emit("cookFinished", releasePizza); 95 | }, this.ovenTime); 96 | 97 | return this; 98 | } 99 | } 100 | 101 | const createMediumPizza = () => { 102 | const pizza = new Pizza(Pizza.sizes().medium); 103 | pizza 104 | .on("ingredientAdded", ing => console.log(`${ing} added`)) 105 | .on("maxIngredientsReached", ing => 106 | console.log(`Max ingredients (${pizza.maxIngredients}) reached`) 107 | ) 108 | .on("ingredientRemoved", ing => console.log(`${ing} removed`)) 109 | .on("errorRemovingIngredient", ing => 110 | console.log(`Can not remove ${ing} because is not in the pizza`) 111 | ) 112 | .on("cookStarted", () => console.log("Pizza is in the oven.")) 113 | .on("cookFinished", release => { 114 | console.log(`Pizza is ready to release.`); 115 | clearTimeout(release); 116 | console.info("Pizza was released!"); 117 | }) 118 | .add("Tomato") 119 | .add("Mushrooms") 120 | .add("Scarmoza") 121 | .add("Bone") 122 | .remove("Bone") 123 | .add("Pepper") 124 | .remove("Peper") 125 | .add("Onion") 126 | .add("Pepperoni") 127 | .add("Oregano") 128 | .cook(); 129 | }; 130 | 131 | const createSmallPizza = () => { 132 | const pizzaSmall = new Pizza(Pizza.sizes().small); 133 | pizzaSmall 134 | .on("cookFinished", () => { 135 | console.log(`PizzaSmall is ready to release.`); 136 | // no clearing interval of release 137 | }) 138 | .on("cookStarted", () => console.log("PizzaSmall is in the oven")) 139 | .on("charredPizza", () => 140 | console.error("OOPS! The PizzaSmall is charred...") 141 | ) 142 | .add("mozzarella") 143 | .add("Meat") 144 | .cook(); 145 | }; 146 | 147 | //createMediumPizza(); 148 | createSmallPizza(); 149 | -------------------------------------------------------------------------------- /design-patterns/profiler.js: -------------------------------------------------------------------------------- 1 | class Profiler { 2 | constructor(label) { 3 | this.label = label; 4 | this.lastTime = null; 5 | } 6 | start() { 7 | this.lastTime = process.hrtime(); 8 | } 9 | end() { 10 | const diff = process.hrtime(this.lastTime); 11 | console.log( 12 | `Timer ${this.label} took ${diff[0]} seconds and ${diff[1]} ns` 13 | ); 14 | } 15 | } 16 | 17 | function createProfiler(label) { 18 | if (process.env.NODE_ENV === "development") { 19 | return new Profiler(label); 20 | } else if (process.env.NODE_ENV === "production") { 21 | // we dont want logging in prod 22 | // so thanks to dynamic typing 23 | // we can do duck typing here 24 | return { 25 | start: () => {}, 26 | end: () => {} 27 | }; 28 | } else { 29 | throw new Error("Env not set"); 30 | } 31 | } 32 | 33 | function getRandomArray(len) { 34 | const p = createProfiler(`Generating a ${len} items long array`); 35 | p.start(); 36 | const arr = [].fill(null, len); 37 | for (let i = 0; i < arr; i++) { 38 | arr[i] = Math.random(); 39 | } 40 | p.end(); 41 | } 42 | 43 | process.env.NODE_ENV = "development"; 44 | getRandomArray(1e6); 45 | console.log("Done"); 46 | 47 | module.exports = createProfiler; 48 | -------------------------------------------------------------------------------- /design-patterns/proxy.md: -------------------------------------------------------------------------------- 1 | # Proxy pattern 2 | 3 | A Proxy (or middleware) is an object that controls the access to another object, called subject. 4 | Proxy and subject have an identical interface. 5 | The proxy pattern involves wrapping actual instances of the subject, thus preserving its state. 6 | It's useful for several circumstances like the folowwing: 7 | - Data validation 8 | - Security 9 | - Caching 10 | - Lazy load 11 | - Logging 12 | - Remote objects 13 | 14 | ## Techniques for implementing 15 | 16 | - Object composition: composition-proxy.js 17 | - Object augmentation (or monkey patching) is probably the most pragmatic way of proxying individual methods of an object and consists of modifying the subject directly by replacing a method with its proxied implementation. Example: 18 | ```js 19 | function createProxy(subject){ 20 | const helloOrig = subject.hello; 21 | subject.hello = () => `${helloOrig.call(this)} world!` 22 | return subject; 23 | } 24 | ``` 25 | 26 | ## Logging writable stream 27 | 28 | Example: logging-proxy.js 29 | 30 | ## Proxy ES6 31 | 32 | ```js 33 | const scientist = { 34 | name: 'nikola', 35 | surname: 'tesla' 36 | } 37 | const uppercaseScientist = new Proxy(scientist, { 38 | get: (target, property) => target[property].toUpperCase() 39 | }) 40 | 41 | console.log(uppercaseScientist.name, uppercaseScientist.surname) 42 | // prints NIKOLA TESLA 43 | ``` 44 | 45 | It allows developers to intercept access to generic attributes in target object 46 | 47 | Another clarifying example 48 | 49 | ```js 50 | const evenNumbers = new Proxy([], { 51 | get: (target, index) => index * 2, 52 | has: (target, number) => number % 2 === 0 53 | }) 54 | 55 | console.log(2 in evenNumbers) // true 56 | console.log(5 in evenNumbers) // false 57 | console.log(evenNumbers[7]) // 14 58 | ``` -------------------------------------------------------------------------------- /design-patterns/revealing-constructor.md: -------------------------------------------------------------------------------- 1 | ## Revealing contstructor 2 | 3 | Used by some core libraries such as `Promise` 4 | 5 | ```js 6 | const promise = new Promise((resolve, reject) => { 7 | // ... 8 | }) 9 | ``` 10 | 11 | It accepts a function in the constructor, which is called the *executor function*. It serves a mechanism to expose `resolve` and `reject` to change the internal state, which are the only public code, and the only that is able to change the internal state. Once the object is constructed it can be passed around safely. 12 | 13 | Example: roee.js 14 | 15 | Apart of promise it's hard to find common use cases like `Promise` 16 | -------------------------------------------------------------------------------- /design-patterns/roee.js: -------------------------------------------------------------------------------- 1 | const EventEmitter = require("events"); 2 | 3 | class Roee extends EventEmitter { 4 | constructor(executor) { 5 | super(); 6 | const emit = this.emit.bind(this); 7 | // emit can only be used with the executor 8 | this.emit = undefined; 9 | executor(emit); 10 | } 11 | } 12 | 13 | const ticker = new Roee(emit => { 14 | let tickCount = 0; 15 | setInterval(() => emit("tick", tickCount++), 1000); 16 | }); 17 | 18 | ticker.on("tick", count => console.log(count, "Tick")); 19 | 20 | // ticker.emit is undefined 21 | // ticker.emit("Something",{}) also fails 22 | -------------------------------------------------------------------------------- /design-patterns/state.md: -------------------------------------------------------------------------------- 1 | ## State 2 | 3 | State is a variation of the *Strategy pattern* where the strategy changes depending on the state of the context and in the other pattern the strategy doesnt change in the lifespan of the context. -------------------------------------------------------------------------------- /design-patterns/strategy.md: -------------------------------------------------------------------------------- 1 | ## Strategy 2 | 3 | It enables an object called *context* to support variations in its logic by extracting the variable parts into separate, interchangeable objects called strategies. 4 | 5 | Particularly useful in all those situations where supporting variations of an algorithm requires complex conditional logic like lots of `if..else` or `switch`. Or mixing together different algorithms of the same family. 6 | 7 | ### Multi-format configuration objects 8 | 9 | Example: config.js 10 | Having different strategies to serialize and deserialize. -------------------------------------------------------------------------------- /design-patterns/template.md: -------------------------------------------------------------------------------- 1 | ## Template 2 | 3 | Consists on defining an abstract pseudo class that represents the skeleton of an algortihm, where some of its steps are left undefined. 4 | Sublcasses can then fill the gaps in the algorithm by implementing the missing steps, called *template methods* -------------------------------------------------------------------------------- /design-patterns/videogame.js: -------------------------------------------------------------------------------- 1 | const stampit = require("stampit"); 2 | 3 | // Base character 4 | const character = stampit().props({ 5 | name: "anonymous", 6 | lifePoints: 100, 7 | x: 0, 8 | y: 0 9 | }); 10 | 11 | // Behaviors 12 | const mover = stampit().methods({ 13 | move(xIncr, yIncr) { 14 | this.x += xIncr; 15 | this.y += yIncr; 16 | console.log(`${this.name} moved to [${this.x}, ${this.y}]`); 17 | } 18 | }); 19 | 20 | const slasher = stampit().methods({ 21 | slash(direction) { 22 | console.log(`${this.name} slashed to the ${direction}`); 23 | } 24 | }); 25 | 26 | const shooter = stampit() 27 | .props({ 28 | bullets: 6 29 | }) 30 | .methods({ 31 | shoot(direction) { 32 | if (this.bullets > 0) { 33 | --this.bullets; 34 | console.log(`${this.name} shoot to the ${direction}`); 35 | } else { 36 | console.log(`${this.name} is out of bullets`); 37 | } 38 | } 39 | }); 40 | 41 | // Characters 42 | 43 | const runner = stampit.compose( 44 | character, 45 | mover 46 | ); 47 | const samurai = stampit.compose( 48 | character, 49 | mover, 50 | slasher 51 | ); 52 | const sniper = stampit.compose( 53 | character, 54 | shooter 55 | ); 56 | const gunslinger = stampit.compose( 57 | character, 58 | mover, 59 | shooter 60 | ); 61 | const westernSamurai = stampit.compose( 62 | gunslinger, 63 | samurai 64 | ); 65 | 66 | // Instance 67 | 68 | const gojiro = new westernSamurai(); 69 | gojiro.name = "Pepe"; 70 | gojiro.move(1, 3); 71 | gojiro.slash("right"); 72 | gojiro.move(7, 2); 73 | gojiro.shoot("left"); 74 | gojiro.shoot("front"); 75 | gojiro.shoot("back"); 76 | gojiro.shoot("right"); 77 | gojiro.shoot("left"); 78 | gojiro.shoot("front"); 79 | gojiro.shoot("back"); 80 | gojiro.shoot("right"); // Out of bullets 81 | -------------------------------------------------------------------------------- /messaging-integration-patterns/amqp-chat/app.js: -------------------------------------------------------------------------------- 1 | // Requirement: Having a rabbit running on local environment 2 | 3 | const WebSocketServer = require("ws").Server; 4 | const server = require("http").createServer( 5 | require("ecstatic")({ root: `${__dirname}/www` }) 6 | ); 7 | const level = require("level"); 8 | const timestamp = require("monotonic-timestamp"); 9 | const JSONStream = require("JSONStream"); 10 | const amqp = require("amqplib"); 11 | const db = level("./msgHistory"); 12 | 13 | const port = process.argv[2] || 8080; 14 | 15 | let channel, queue; 16 | 17 | amqp 18 | // Establish connection with amqp broker (Rabbit) 19 | .connect("amqp://localhost") 20 | // And create channel 21 | .then(conn => conn.createChannel()) 22 | .then(ch => { 23 | channel = ch; 24 | // Set up fanout exchange, named chat. 25 | return channel.assertExchange("chat", "fanout"); 26 | }) 27 | .then(() => channel.assertQueue(`chat_srv_${port}`, { exclusive: true })) 28 | .then(q => { 29 | queue = q.queue; 30 | // Bind queue to the chat exchange 31 | return channel.bindQueue(queue, "chat"); 32 | }) 33 | .catch(err => console.log(err)); 34 | 35 | const ws = new WebSocketServer({ server: server }); 36 | 37 | ws.on("connection", ws => { 38 | console.log("Client connected"); 39 | ws.on("message", msg => { 40 | console.log(`Message: ${msg}`); 41 | channel.publish("chat", "", new Buffer(msg)); 42 | }); 43 | }); 44 | 45 | server.listen(port); 46 | -------------------------------------------------------------------------------- /messaging-integration-patterns/amqp-chat/historySvc.js: -------------------------------------------------------------------------------- 1 | const level = require("level"); 2 | const timestamp = require("monotonic-timestamp"); 3 | const JSONStream = require("JSONStream"); 4 | const amqp = require("amqplib"); 5 | const db = level("./msgHistory"); 6 | 7 | require("http") 8 | .createServer((req, res) => { 9 | res.writeHead(200); 10 | db.createValueStream() 11 | .pipe(JSONStream.stringify()) 12 | .pipe(res); 13 | }) 14 | .listen(8090); 15 | 16 | let channel, queue; 17 | 18 | amqp 19 | // Establish connection with amqp broker (Rabbit) 20 | .connect("amqp://localhost") 21 | // And create channel 22 | .then(conn => conn.createChannel()) 23 | .then(ch => { 24 | channel = ch; 25 | // Set up fanout exchange, named chat. 26 | return channel.assertExchange("chat", "fanout"); 27 | }) 28 | .then(() => channel.assertQueue("chat_history")) 29 | // Create queue, durable by default 30 | .then(q => { 31 | queue = q.queue; 32 | // Bind queue to the chat exchange 33 | return channel.bindQueue(queue, "chat"); 34 | }) 35 | .then(() => { 36 | // Listen for messages 37 | return channel.consume(queue, msg => { 38 | const content = msg.content.toString(); 39 | console.log(`Saving message: ${content}`); 40 | // Store in history db 41 | db.put(timestamp(), content, err => { 42 | // If the ACK (acknowledgment) is not received by the broker, the message is kept in the queue for being processed again. 43 | if (!err) channel.ack(msg); 44 | }); 45 | }); 46 | }) 47 | .catch(err => console.log(err)); 48 | -------------------------------------------------------------------------------- /messaging-integration-patterns/amqp-chat/msgHistory/000005.log: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boxgames1/nodejs-patterns/42599ea94e07d9847ecdf8c9f56a08bacbdc5439/messaging-integration-patterns/amqp-chat/msgHistory/000005.log -------------------------------------------------------------------------------- /messaging-integration-patterns/amqp-chat/msgHistory/CURRENT: -------------------------------------------------------------------------------- 1 | MANIFEST-000004 2 | -------------------------------------------------------------------------------- /messaging-integration-patterns/amqp-chat/msgHistory/LOCK: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boxgames1/nodejs-patterns/42599ea94e07d9847ecdf8c9f56a08bacbdc5439/messaging-integration-patterns/amqp-chat/msgHistory/LOCK -------------------------------------------------------------------------------- /messaging-integration-patterns/amqp-chat/msgHistory/LOG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boxgames1/nodejs-patterns/42599ea94e07d9847ecdf8c9f56a08bacbdc5439/messaging-integration-patterns/amqp-chat/msgHistory/LOG -------------------------------------------------------------------------------- /messaging-integration-patterns/amqp-chat/msgHistory/LOG.old: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boxgames1/nodejs-patterns/42599ea94e07d9847ecdf8c9f56a08bacbdc5439/messaging-integration-patterns/amqp-chat/msgHistory/LOG.old -------------------------------------------------------------------------------- /messaging-integration-patterns/amqp-chat/msgHistory/MANIFEST-000004: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boxgames1/nodejs-patterns/42599ea94e07d9847ecdf8c9f56a08bacbdc5439/messaging-integration-patterns/amqp-chat/msgHistory/MANIFEST-000004 -------------------------------------------------------------------------------- /messaging-integration-patterns/amqp-chat/www/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 15 | 16 | 17 | Messages: 18 |
19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /messaging-integration-patterns/notes.md: -------------------------------------------------------------------------------- 1 | ## Types of messages 2 | 3 | - Command Message: Like command pattern. E.g.: HTTP request 4 | - Event Message: E.g.: domain event 5 | - Document Message: Message doesn't contain information that tells the receiver what to do with the data, by other hand is not associated with a particular occurrence, with something that happened. 6 | 7 | ## Durable suscribers 8 | 9 | A subscriber that is able to always reliably receive all the messages, even those sent whenit's not listening for them, is called a *durable subscriber*. 10 | The MQTT protocol defines a level of Quality of Service (QoS) for themessages exchanged between the sender and receiver: 11 | 12 | - QoS0, at most once 13 | - QoS1, at least once 14 | - QoS2, exactly once 15 | 16 | 17 | ## AMQP (Advanced Message Queuing Protocol) 18 | 19 | Three essential components: 20 | 21 | - Queue: Data structure that can be *durable*, *exclusive* or *auto-delete* 22 | - Exchange: Where the message is published. Implementing algorithms can be *direct exchange*, *topic exchange* or *fanout exchange* 23 | - Binding: This is the link between exchanges and queues. It also defines therouting key or the pattern used to filter the messages that arrive from theexchange 24 | 25 | These components are managed by a broker, which exposes an API for creating andmanipulating them. 26 | In AMQP, the durable subscriber pattern can be obtained by creating any type of queue that is not exclusive or auto-delete 27 | 28 | 29 | ## Pipelines and task distribution patterns 30 | 31 | The idea is to have a messaging pattern that allows us to spread tasks across multiple machines. These tasks might be individual chunks of work or pieces of a bigger task split using a divide and conquer technique 32 | What we need instead is a message distribution pattern similar to a load balancer, that dispatches each message to a different consumer (also called worker, in this case). In the messaging system terminology, this pattern is known as competing consumers, fanout distribution, or *ventilator* 33 | 34 | Here, consumers connect to producer. 35 | Distribution (fan-out or *ventilator*) sends messages through a series of pipelines to be received by an aggregation (fan-in or *sink*) 36 | 37 | ## Competing consumers pattern 38 | 39 | When a broker balances the load of messages received across all the consumers of the key. 40 | 41 | ## Return address pattern 42 | 43 | The correlation identifier is the fundamental pattern for creating a request/reply communication on top of a one-way channel; however, it's not enough when our messaging architecture has more than one channel or queue, or when there can be potentially more than one requestor. In these situations, in addition to a correlation ID, we also need to know the return address, a piece of information which allows the replier to send the response back to the original sender of the request. 44 | 45 | In AMQP, the return address is the queue where the requestor is listening for incoming replies. Because the response is meant to be received by only one requestor, it's important that the queue is private and not shared across different consumers -------------------------------------------------------------------------------- /messaging-integration-patterns/paralell-pipelines/sink.js: -------------------------------------------------------------------------------- 1 | const zmq = require("zeromq"); 2 | const sink = zmq.socket("pull"); 3 | 4 | sink.bindSync("tcp://*:5017"); 5 | 6 | sink.on("message", buffer => { 7 | console.log("Message from worker: ", buffer.toString()); 8 | }); 9 | -------------------------------------------------------------------------------- /messaging-integration-patterns/paralell-pipelines/ventilator.js: -------------------------------------------------------------------------------- 1 | const zmq = require("zeromq"); 2 | const variationsStream = require("variations-stream"); 3 | 4 | const alphabet = "abcdefghijklmnopqrstuvwxyz"; 5 | const BATCH_SIZE = 10000; 6 | const maxLength = process.argv[2]; 7 | const searchHash = process.argv[3]; 8 | 9 | // Create PUSH socket and bind to 5000 port 10 | const ventilator = zmq.socket("push"); 11 | ventilator.bindSync("tcp://*:5000"); 12 | let batch = []; 13 | 14 | variationsStream(alphabet, maxLength) 15 | .on("data", combination => { 16 | console.log(combination); 17 | 18 | batch.push(combination); 19 | // Group the generated variations in batches of 10,000 items 20 | if (batch.length === BATCH_SIZE) { 21 | const msg = { searchHash: searchHash, variations: batch }; 22 | // Send task object to the next available worker 23 | ventilator.send(JSON.stringify(msg)); 24 | batch = []; 25 | } 26 | }) 27 | .on("end", () => { 28 | //send remaining combinations 29 | const msg = { searchHash: searchHash, variations: batch }; 30 | ventilator.send(JSON.stringify(msg)); 31 | }); 32 | 33 | /** 34 | * To run: 35 | * node worker 36 | * node worker 37 | * node worker 38 | * node sink 39 | * node ventilator [chars] [searchSHA1] 40 | */ 41 | -------------------------------------------------------------------------------- /messaging-integration-patterns/paralell-pipelines/worker.js: -------------------------------------------------------------------------------- 1 | // This represents a transient node in the architecture 2 | const zmq = require("zeromq"); 3 | const crypto = require("crypto"); 4 | const fromVentilator = zmq.socket("pull"); 5 | const toSink = zmq.socket("push"); 6 | 7 | // Sockets will connect to a remote node 8 | // instead of listening for the incoming connections 9 | fromVentilator.connect("tcp://localhost:5016"); // PULL socket 10 | toSink.connect("tcp://localhost:5017"); // PUSH socket 11 | 12 | fromVentilator.on("message", buffer => { 13 | // For each message received, it iterates over the batch of words it contains, 14 | // then for each word it calculates the SHA1 checksum and tries to match it 15 | // against searchHash passed with the message. 16 | // When a match is found, the result is forwarded to the sink 17 | 18 | const msg = JSON.parse(buffer); 19 | const variations = msg.variations; 20 | variations.forEach(word => { 21 | console.log(`Processing: ${word}`); 22 | const shasum = crypto.createHash("sha1"); 23 | shasum.update(word); 24 | const digest = shasum.digest("hex"); 25 | if (digest === msg.searchHash) { 26 | console.log(`Found! => ${word}`); 27 | toSink.send(`Found! ${digest} => ${word}`); 28 | } 29 | }); 30 | }); 31 | -------------------------------------------------------------------------------- /messaging-integration-patterns/real-time-chat/app.js: -------------------------------------------------------------------------------- 1 | const WebSocketServer = require("ws").Server; 2 | 3 | /** 4 | * create an HTTP server and attach middleware 5 | * called ecstatic to serve static files. 6 | * This is needed to serve the client-side resources 7 | * of our application (JS and CSS) 8 | */ 9 | const server = require("http").createServer( 10 | require("ecstatic")({ root: `${__dirname}/www` }) 11 | ); 12 | 13 | // Create WS and attach to server 14 | const wss = new WebSocketServer({ server: server }); 15 | 16 | // Listen connection event 17 | wss.on("connection", ws => { 18 | console.log("Client connected"); 19 | // Listen for new messages 20 | ws.on("message", msg => { 21 | console.log(`Message: ${msg}`); 22 | // and send to connected clients 23 | broadcast(msg); 24 | }); 25 | }); 26 | 27 | /** 28 | * Iterate through clients and send passed msg 29 | */ 30 | const broadcast = msg => { 31 | wss.clients.forEach(client => { 32 | client.send(msg); 33 | }); 34 | }; 35 | 36 | server.listen(process.argv[2] || 8080); 37 | -------------------------------------------------------------------------------- /messaging-integration-patterns/real-time-chat/p2p.js: -------------------------------------------------------------------------------- 1 | const args = require("minimist")(process.argv.slice(2)); 2 | const zmq = require("zeromq"); 3 | const WebSocketServer = require("ws").Server; 4 | 5 | const pubSocket = zmq.socket("pub"); // PUB socket 6 | pubSocket.bind(`tcp://127.0.0.1:${args["pub"]}`); // Binded to passed port as arg 7 | 8 | const subSocket = zmq.socket("sub"); // SUB socket 9 | const subPorts = [].concat(args["sub"]); // Get SUB ports from args 10 | subPorts.forEach(p => { 11 | console.log(`Subscribing to ${p}`); 12 | // Connect SUB ports to the PUB sockets of the other instances of our application 13 | subSocket.connect(`tcp://127.0.0.1:${p}`); 14 | }); 15 | 16 | const server = require("http").createServer( 17 | require("ecstatic")({ root: `${__dirname}/www` }) 18 | ); 19 | 20 | const ws = new WebSocketServer({ server: server }); 21 | 22 | // Set chat as filter 23 | subSocket.subscribe("chat"); 24 | 25 | ws.on("message", msg => { 26 | // When a new message is received by our WebSocket, 27 | // we broadcast it to all the connected clients 28 | console.log(`Message: ${msg}`); 29 | broadcast(msg); 30 | // we also publish it through our PUB socket using chat as aprefix followed by a space, 31 | // so the message will be published to all the 32 | // subscriptions using chat as a filter 33 | pubSocket.send(`chat ${msg}`); 34 | }); 35 | 36 | subSocket.on("message", msg => { 37 | // We start listening for messages that arrive at our SUB socket, 38 | // we do some simple parsing of the message to remove the chat prefix, 39 | // and then we broadcast it to all the clients connected to the current WebSocket server 40 | console.log(`From other server: ${msg}`); 41 | broadcast(msg.toString().split(" ")[1]); 42 | }); 43 | 44 | const broadcast = msg => { 45 | wss.clients.forEach(client => { 46 | client.send(msg); 47 | }); 48 | }; 49 | 50 | server.listen(args["http"] || 8080); 51 | 52 | /* Run this file with 3 instances: 53 | * node p2p --http 8080 --pub 5000 --sub 5001 --sub 5002 54 | * node p2p --http 8081 --pub 5001 --sub 5000 --sub 5002 55 | * node p2p --http 8082 --pub 5002 --sub 5000 --sub 5001 56 | */ 57 | -------------------------------------------------------------------------------- /messaging-integration-patterns/real-time-chat/redis.js: -------------------------------------------------------------------------------- 1 | const WebSocketServer = require("ws").Server; 2 | const redis = require("redis"); 3 | const redisSub = redis.createClient(); //Sub connection 4 | const redisPub = redis.createClient(); // Pub connection 5 | 6 | const server = require("http").createServer( 7 | require("ecstatic")({ root: `${__dirname}/www` }) 8 | ); 9 | 10 | const wss = new WebSocketServer({ server: server }); 11 | 12 | wss.on("connection", ws => { 13 | console.log("Client connected"); 14 | ws.on("message", msg => { 15 | console.log(`Message: ${msg}`); 16 | // When a new message is received from a connected client, we publish a message in the chat_messages channel. 17 | // We don't directly broadcast the message to clients because the server is subscribed to the same channel 18 | // so it will come back to us through Redis. 19 | redisPub.publish("chat_messages", msg); 20 | }); 21 | }); 22 | 23 | // Server is suscribed to chat_messages channel 24 | redisSub.subscribe("chat_messages"); 25 | 26 | // Listens messages and broadcasts it to all clients 27 | redisSub.on("message", (channel, msg) => { 28 | wss.clients.forEach(client => { 29 | client.send(msg); 30 | }); 31 | }); 32 | 33 | server.listen(process.argv[2] || 8080); 34 | -------------------------------------------------------------------------------- /messaging-integration-patterns/real-time-chat/www/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 15 | 16 | 17 | Messages: 18 |
19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /node.js-eseential-patterns/eventEmitter-vs-callback.md: -------------------------------------------------------------------------------- 1 | ### Event emitter versus callbacks 2 | 3 | * The general differentiating rules is semantic: callbacks should be used when a result must be returned in an async way; events should instead be used when there is a need to communicate that something just happened 4 | * A callback is expected to be called only once 5 | 6 | * Pattern. Create a function that accepts a callback and returns EventEmitter. Thus, providing a siimple and clear entry point for the main functionallity, while emitting more fine-grained events using EventEmitter. -------------------------------------------------------------------------------- /node.js-eseential-patterns/io.md: -------------------------------------------------------------------------------- 1 | `process.tick(function)` 2 | Defers the execution of a function until the next pass of the event loop. It takes a callback as an argument and pushes it to the top of the event queue, in front of any pending I/O event, and returns inmediately. The callback will be invoked as soon as the event loop runs again. It has danger if has the chance of cut a recursive call 3 | 4 | 5 | `setInmediate(function)` 6 | Similar to the previous, but with the difference that with this, the execution is queued behind any I/O event that is already in the queue 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /node.js-eseential-patterns/misc.md: -------------------------------------------------------------------------------- 1 | * Set a try-catch surrounding a function call instead the definition of the function will not work and is an anti-pattern 2 | * CPS = Continuation Passing Style. A way to pass callbacks through functions to concatenate calls 3 | -------------------------------------------------------------------------------- /node.js-eseential-patterns/modules.md: -------------------------------------------------------------------------------- 1 | * Revealing module pattern: Export as functions in an object to closure parts of the module and avoid expostion of the exterior 2 | * Polluting the global scope is considered bad practice and nullifies the advantge if having module system. So, use it only if you really know what you are doing 3 | * module.exports is for assign while exports is to access a property of it -------------------------------------------------------------------------------- /node.js-eseential-patterns/observer-pattern/basic.js: -------------------------------------------------------------------------------- 1 | /** 2 | * In OOP it requires interfaces. In node is much simpler. 3 | * It comes in the core with the EventEmitter class 4 | */ 5 | 6 | const EventEmitter = require("events").EventEmitter; 7 | const fs = require("fs"); 8 | 9 | const findPattern = (files, regex) => { 10 | const emitter = new EventEmitter(); 11 | files.forEach(file => { 12 | fs.readFile(file, "utf8", (err, content) => { 13 | /** 14 | * Cannot just throw exceptions when an error occurs, 15 | * the convention is to emmit a special event called error 16 | * and to pass an Error object as arg 17 | */ 18 | if (err) return emitter.emit("error", err); 19 | emitter.emit("fileread", file); 20 | let match; 21 | if ((match = content.match(regex))) 22 | match.forEach(elem => emitter.emit("found", file, elem)); 23 | }); 24 | }); 25 | return emitter; 26 | }; 27 | 28 | const file = "README.md"; 29 | const regex = /.*?# Node.*?/; 30 | 31 | findPattern([file], regex) 32 | .on("fileread", file => console.log("file was read: ", file)) 33 | .on("found", (file, match) => console.log("file was found: ", file, match)) 34 | .on("err", err => console.log("error was found: ", err)); 35 | -------------------------------------------------------------------------------- /node.js-eseential-patterns/observer-pattern/observable.js: -------------------------------------------------------------------------------- 1 | /** 2 | * In OOP it requires interfaces. In node is much simpler. 3 | * It comes in the core with the EventEmitter class 4 | */ 5 | 6 | const EventEmitter = require("events").EventEmitter; 7 | const fs = require("fs"); 8 | 9 | class FindPattern extends EventEmitter { 10 | constructor(regex) { 11 | super(); 12 | this.regex = regex; 13 | this.files = []; 14 | } 15 | addFile(file) { 16 | this.files.push(file); 17 | return this; // this is needed to allow chaining 18 | } 19 | 20 | find() { 21 | this.files.forEach(file => { 22 | fs.readFile(file, "utf8", (err, content) => { 23 | if (err) return this.emit("error", err); 24 | this.emit("fileread", file); 25 | let match; 26 | if ((match = content.match(this.regex))) { 27 | match.forEach(elem => this.emit("found", file, elem)); 28 | } 29 | }); 30 | }); 31 | return this; // this is needed to allow chaining 32 | } 33 | } 34 | 35 | const file = "README.md"; 36 | const regex = /.*?# Node.*?/; 37 | 38 | const findPatternObj = new FindPattern(regex); 39 | 40 | findPatternObj 41 | .addFile(file) 42 | .find() 43 | .on("fileread", file => console.log("file was read: ", file)) 44 | .on("found", (file, match) => console.log("file was found: ", file, match)) 45 | .on("err", err => console.log("error was found: ", err)); 46 | -------------------------------------------------------------------------------- /node.js-eseential-patterns/substack-pattern/code.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Substack pattern: Expose the main functionallity 3 | * of a module by exporting only one function. 4 | * Use the exported function as a namespace to 5 | * expose any auxiliary functionallity. 6 | */ 7 | 8 | const logger = require("./logger"); 9 | 10 | logger("bla bla bla"); 11 | logger.verbose("bla bla bla"); 12 | -------------------------------------------------------------------------------- /node.js-eseential-patterns/substack-pattern/logger.js: -------------------------------------------------------------------------------- 1 | module.exports = msg => console.log(msg); 2 | module.exports.verbose = msg => console.log(`verbose: ${msg}`); 3 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "devDependencies": { 3 | "chance": "^1.0.18", 4 | "mkdirp": "^0.5.1" 5 | }, 6 | "dependencies": { 7 | "JSONStream": "^1.3.5", 8 | "amqplib": "^0.5.5", 9 | "child_process": "^1.0.2", 10 | "combine": "^0.1.4", 11 | "consul": "^0.36.0", 12 | "crypto": "^1.0.1", 13 | "ecstatic": "^4.1.2", 14 | "forever": "^1.0.0", 15 | "from2-array": "^0.0.4", 16 | "http-proxy": "^1.18.0", 17 | "ini": "^1.3.5", 18 | "level": "^6.0.0", 19 | "minimist": "^1.2.0", 20 | "monotonic-timestamp": "^0.0.9", 21 | "multipipe": "^3.0.1", 22 | "object-path": "^0.11.4", 23 | "portfinder": "^1.0.25", 24 | "redis": "^2.8.0", 25 | "request": "^2.88.0", 26 | "split": "^1.0.1", 27 | "stampit": "^4.2.0", 28 | "through2": "^3.0.1", 29 | "variations-stream": "^0.1.3", 30 | "ws": "^7.2.0", 31 | "zeromq": "^5.2.0" 32 | }, 33 | "scripts": { 34 | "consul": "consul agent -dev" 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /scalability-architectural-patterns/cloning/app.js: -------------------------------------------------------------------------------- 1 | const http = require("http"); 2 | const pid = process.pid; 3 | 4 | http 5 | .createServer((req, res) => { 6 | for (let i = 1e7; i > 0; i--) {} 7 | console.log(`Handling request from from ${pid}`); 8 | res.end(`Hello from ${pid}`); 9 | }) 10 | .listen(8080, () => { 11 | console.log(`Started ${pid}`); 12 | }); 13 | // Random error 14 | /* setTimeout(() => { 15 | throw new Error("Oops"); 16 | }, Math.ceil(Math.random() * 3) * 1000); */ 17 | // execute siege -c200 -t10S http://localhost:8080 from CLI 18 | -------------------------------------------------------------------------------- /scalability-architectural-patterns/cloning/clusteredApp.js: -------------------------------------------------------------------------------- 1 | const cluster = require("cluster"); 2 | const os = require("os"); 3 | 4 | // Only fork into workers the master thread 5 | if (cluster.isMaster) { 6 | const cpus = os.cpus().length; 7 | console.log(`Clustering to ${cpus} CPUs`); 8 | for (let i = 0; i < cpus; i++) { 9 | // Create one worker by CPU 10 | // Each worker will have his own event loop, memory space and loaded modules 11 | cluster.fork(); 12 | } 13 | cluster.on("exit", (worker, code) => { 14 | // worker finished because of an error 15 | if (code !== 0 && !worker.exitedAfterDisconnect) { 16 | console.log("Worker crashed. Starting a new one"); 17 | cluster.fork(); 18 | } 19 | }); 20 | //signal of workers restart 21 | process.on("SIGUSR2", () => { 22 | const workers = Object.keys(cluster.workers); 23 | console.log("workers: ", workers); 24 | 25 | //recursive function over workers 26 | function restartWorker(i) { 27 | if (i >= workers.length) return; 28 | const worker = cluster.workers[workers[i]]; 29 | console.log(`Stopping worker: ${worker.process.pid}`); 30 | worker.disconnect(); // disconnect task 31 | worker.on("exit", () => { 32 | if (!worker.exitedAfterDisconnect) return; 33 | // when the worker was disconnected we can start a new one 34 | const newWorker = cluster.fork(); 35 | newWorker.on("listening", () => { 36 | // once the new worker is listerning we can restart the next worker 37 | restartWorker(i + 1); 38 | }); 39 | }); 40 | } 41 | restartWorker(0); 42 | }); 43 | } else { 44 | // Workers will enter app 45 | require("./app"); 46 | } 47 | -------------------------------------------------------------------------------- /scalability-architectural-patterns/cluster-vs-reverse-proxy.md: -------------------------------------------------------------------------------- 1 | For a Node.js application, there are many reasons to choose this approach in place of the cluster module: 2 | 3 | - A reverse proxy can distribute the load across several machines, not just several processes 4 | - The most popular reverse proxies on the market support sticky load balancing 5 | - A reverse proxy can route a request to any available server, regardless of its programming language or platform 6 | - We can choose more powerful load balancing algorithms 7 | - Many reverse proxies also offer other services such as URL rewrites, caching, SSL termination point, or even the functionality of fully-fledged web servers that can be used, for example, to serve static files 8 | 9 | That said, the *cluster module could also be easily combined with a reverse proxy* if necessary; for example, using * cluster to scale vertically * inside a single machine and then using the *reverse proxy to scale horizontally* across different nodes. 10 | 11 | _Pattern_ 12 | Use a reverse proxy to balance the load of an application across multiple instances running on different ports or machines. -------------------------------------------------------------------------------- /scalability-architectural-patterns/dinamic-load-balancer/README.md: -------------------------------------------------------------------------------- 1 | To run it: 2 | 3 | - You need to have installed `forever` as global dependency 4 | - Start the service registry: `yarn consul` 5 | - Spawn some instances of the services: 6 | - `forever start app.js api-service` 7 | - `forever start app.js api-service` 8 | - `forever start app.js api-service` 9 | - `forever start app.js webapp-service` 10 | - `forever start app.js webapp-service` 11 | 12 | 13 | If we run `curl localhost:8080/api` several time we should be receiving messages from different servers. It means that the balancer is distributing the load correctly. -------------------------------------------------------------------------------- /scalability-architectural-patterns/dinamic-load-balancer/app.js: -------------------------------------------------------------------------------- 1 | const http = require("http"); 2 | const pid = process.pid; 3 | const consul = require("consul")(); 4 | const portfinder = require("portfinder"); 5 | const serviceType = process.argv[2]; 6 | portfinder.getPort((err, port) => { 7 | const serviceId = serviceType + port; 8 | // Register new service in the registry 9 | consul.agent.service.register( 10 | { 11 | id: serviceId, 12 | name: serviceType, 13 | address: "localhost", 14 | port: port, 15 | tags: [serviceType] 16 | }, 17 | () => { 18 | // Function to remove the service from registry 19 | const unregisterService = err => { 20 | consul.agent.service.deregister(serviceId, () => { 21 | process.exit(err ? 1 : 0); 22 | }); 23 | }; 24 | // Call cleanup function on exit 25 | process.on("exit", unregisterService); 26 | process.on("SIGINT", unregisterService); 27 | process.on("uncaughtException", unregisterService); 28 | // Start server 29 | http 30 | .createServer((req, res) => { 31 | for (let i = 1e7; i > 0; i--) {} 32 | console.log(`Handling request from ${pid}`); 33 | res.end(`${serviceType} response from ${pid}\n`); 34 | }) 35 | .listen(port, () => { 36 | console.log(`Started ${serviceType} (${pid}) on port ${port}`); 37 | }); 38 | } 39 | ); 40 | }); 41 | -------------------------------------------------------------------------------- /scalability-architectural-patterns/dinamic-load-balancer/loadBalancer.js: -------------------------------------------------------------------------------- 1 | const http = require("http"); 2 | const httpProxy = require("http-proxy"); 3 | const consul = require("consul")(); 4 | 5 | const proxy = httpProxy.createProxyServer({}); 6 | 7 | const routing = [ 8 | { 9 | path: "/api", 10 | service: "api-service", 11 | index: 0 12 | }, 13 | { 14 | path: "/", 15 | service: "webapp-service", 16 | index: 0 17 | } 18 | ]; 19 | 20 | http 21 | .createServer((req, res) => { 22 | let route; 23 | routing.some(entry => { 24 | // Match URL against route table 25 | route = entry; 26 | //Starts with the route path? 27 | return req.url.indexOf(route.path) === 0; 28 | }); 29 | // Get list of servers 30 | consul.agent.service.list((err, services) => { 31 | const servers = []; 32 | // Filter services by tag of the required service 33 | Object.keys(services).filter(id => { 34 | if (services[id].Tags.indexOf(route.service) > -1) { 35 | servers.push(`http://${services[id].Address}:${services[id].Port}`); 36 | } 37 | }); 38 | // If no servers found with the tag, an error is thrown 39 | if (!servers.length) { 40 | res.writeHead(502); 41 | return res.end("Bad gateway"); 42 | } 43 | // Update route index pointing to the next server, following a round robin approach 44 | route.index = (route.index + 1) % servers.length; 45 | // Select that server 46 | proxy.web(req, res, { target: servers[route.index] }); 47 | }); 48 | }) 49 | .listen(8080, () => console.log("Load balancer started on port 8080")); 50 | -------------------------------------------------------------------------------- /scalability-architectural-patterns/requests-http-balancer-multiple-servers/balancedRequest.js: -------------------------------------------------------------------------------- 1 | const http = require("http"); 2 | const servers = [ 3 | { host: "localhost", port: "8004" }, 4 | { host: "localhost", port: "8003" } 5 | ]; 6 | 7 | let i = 0; 8 | 9 | module.exports = (options, callback) => { 10 | i = (i + 1) % servers.length; 11 | options.hostname = servers[i].host; 12 | options.port = servers[i].port; 13 | // Wrap original http.request to override hostname and port using round robin algorithm 14 | return http.request(options, callback); 15 | }; 16 | -------------------------------------------------------------------------------- /scalability-architectural-patterns/requests-http-balancer-multiple-servers/client.js: -------------------------------------------------------------------------------- 1 | const request = require("./balancedRequest"); 2 | 3 | for (let i = 10; i >= 0; i--) { 4 | request({ method: "GET", path: "/" }, res => { 5 | let str = ""; 6 | res 7 | .on("data", chunk => { 8 | str += chunk; 9 | }) 10 | .on("end", () => { 11 | console.log(str); 12 | }); 13 | }).end(); 14 | } 15 | 16 | /** 17 | * To run. 18 | * Go to dinamic-load-balancer and execute: 19 | * node app 8003 20 | * node app 8004 21 | * Then in this folder execute: 22 | * node client 23 | * 24 | * You should notice how each request goes to a different server 25 | * 26 | * This is feasable without a reverse proxy and can be optimized adding a service registry 27 | */ 28 | -------------------------------------------------------------------------------- /scalability-architectural-patterns/zero-downtime-cluster/app.js: -------------------------------------------------------------------------------- 1 | const http = require("http"); 2 | const pid = process.pid; 3 | 4 | http 5 | .createServer((req, res) => { 6 | for (let i = 1e7; i > 0; i--) {} 7 | console.log(`Handling request from from ${pid}`); 8 | res.end(`Hello from ${pid}`); 9 | }) 10 | .listen(8080, () => { 11 | console.log(`Started ${pid}`); 12 | }); 13 | -------------------------------------------------------------------------------- /scalability-architectural-patterns/zero-downtime-cluster/clusteredApp.js: -------------------------------------------------------------------------------- 1 | const cluster = require("cluster"); 2 | const os = require("os"); 3 | 4 | // Only fork into workers the master thread 5 | if (cluster.isMaster) { 6 | const cpus = os.cpus().length; 7 | console.log(`Clustering to ${cpus} CPUs`); 8 | for (let i = 0; i < cpus; i++) { 9 | // Create one worker by CPU 10 | // Each worker will have his own event loop, memory space and loaded modules 11 | cluster.fork(); 12 | } 13 | cluster.on("exit", (worker, code) => { 14 | // worker finished because of an error 15 | if (code !== 0 && !worker.exitedAfterDisconnect) { 16 | console.log("Worker crashed. Starting a new one"); 17 | cluster.fork(); 18 | } 19 | }); 20 | //signal of workers restart 21 | process.on("SIGUSR2", () => { 22 | const workers = Object.keys(cluster.workers); 23 | console.log("workers: ", workers); 24 | 25 | //recursive function over workers 26 | const restartWorker = workerIndex => { 27 | if (workerIndex >= workers.length) return; 28 | const worker = cluster.workers[workers[workerIndex]]; 29 | console.log(`Stopping worker: ${worker.process.pid}`); 30 | worker.disconnect(); // disconnect task 31 | worker.on("exit", () => { 32 | if (!worker.exitedAfterDisconnect) return; 33 | // when the worker was disconnected we can start a new one 34 | const newWorker = cluster.fork(); 35 | newWorker.on("listening", () => { 36 | // once the new worker is listerning we can restart the next worker 37 | restartWorker(workerIndex + 1); 38 | }); 39 | }); 40 | }; 41 | restartWorker(0); 42 | }); 43 | } else { 44 | // Workers will enter app 45 | require("./app"); 46 | } 47 | 48 | /** 49 | * node clusteredApp 50 | * ps af to find the master process 51 | * kill -SIGUSR2 52 | * execute siege -c200 -t10S http://localhost:8080 from CLI to check load 53 | */ 54 | -------------------------------------------------------------------------------- /streams/archive.js: -------------------------------------------------------------------------------- 1 | const fs = require("fs"); 2 | const combine = require("multipipe"); 3 | 4 | const compresssAndEncryptStream = require("./combinedStreams") 5 | .compressAndEncrypt; 6 | 7 | combine( 8 | fs 9 | .createReadStream(process.argv[3]) 10 | .pipe(compresssAndEncryptStream(process.argv[2])) 11 | .pipe(fs.createWriteStream(process.argv[3] + ".gz.enc")) 12 | ).on("error", err => console.log(err)); 13 | 14 | // 2 run in the CLI: node archive [password] file.txt 15 | -------------------------------------------------------------------------------- /streams/back-pressure.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Usage: 3 | * curl localhost:8082 4 | * or 5 | * entering localhost:8082 in the browser 6 | */ 7 | 8 | const Chance = require("chance"); 9 | const http = require("http"); 10 | 11 | const chance = new Chance(); 12 | 13 | http 14 | .createServer((req, res) => { 15 | res.writeHead(200, { "Content-Type": "text/plain" }); 16 | function generateMore() { 17 | while (chance.bool({ likelihood: 95 })) { 18 | let shouldContinue = res.write( 19 | chance.string({ length: 16 * 1024 - 1 }) 20 | ); 21 | if (!shouldContinue) { 22 | console.log("backpressure"); 23 | return res.once("drain", generateMore); 24 | } 25 | } 26 | res.end("\nThe end \n", () => { 27 | console.log("All data was sent"); 28 | }); 29 | } 30 | generateMore(); 31 | }) 32 | .listen("8082", () => { 33 | console.log("Listening on 8082"); 34 | }); 35 | -------------------------------------------------------------------------------- /streams/checkUrls.js: -------------------------------------------------------------------------------- 1 | const fs = require("fs"); 2 | const split = require("split"); 3 | const request = require("request"); 4 | const ParallelStream = require("./parallelStream"); 5 | 6 | fs.createReadStream(process.argv[2]) 7 | .pipe(split()) 8 | .pipe( 9 | new ParallelStream((url, enc, push, done) => { 10 | if (!url) return done && done(); 11 | request.head(url, (err, response) => { 12 | push(`${url} is ${err ? "down" : "up"} \n`); 13 | done && done(); 14 | }); 15 | }) 16 | ) 17 | .pipe(fs.createWriteStream("results.txt")) 18 | .on("finish", () => console.log("All urls were checked")); 19 | 20 | // Execution in CLI: node checkUrls urlList.txt 21 | // Results order should be different in each execution 22 | // as they are async sequential jobs. 23 | -------------------------------------------------------------------------------- /streams/combinedStreams.js: -------------------------------------------------------------------------------- 1 | const zlib = require("zlib"); 2 | const crypto = require("crypto"); 3 | const combine = require("combine"); 4 | 5 | // This will act as black-boxes 6 | module.exports.compressAndEncrypt = password => 7 | combine(zlib.createGzip(), crypto.createCipher("aes192", password)); 8 | 9 | module.exports.decryptAndDecompress = password => 10 | combine(crypto.createDecipher("aes192", password), zlib.createGunzip()); 11 | -------------------------------------------------------------------------------- /streams/demultiplexer-server.js: -------------------------------------------------------------------------------- 1 | const net = require("net"); 2 | const fs = require("fs"); 3 | 4 | const demultiplexChannel = (source, destinations) => { 5 | let currentChannel = null; 6 | let currentLength = null; 7 | source 8 | .on("readable", () => { 9 | let chunk; 10 | if (currentChannel === null) { 11 | chunk = source.read(1); 12 | currentChannel = chunk && chunk.readUInt8(0); 13 | } 14 | if (currentLength === null) { 15 | chunk = source.read(4); 16 | currentLength = chunk && chunk.readUInt32BE(0); 17 | } 18 | chunk = source.read(currentLength); 19 | if (chunk === null) return; 20 | console.log("received poacket from: " + currentChannel); 21 | destinations[currentChannel].write(chunk); 22 | currentChannel = null; 23 | currentLength = null; 24 | }) 25 | .on("end", () => { 26 | destinations.forEach(dest => dest.end()); 27 | console.log("Source channel closed"); 28 | }); 29 | }; 30 | 31 | net 32 | .createServer(socket => { 33 | const stdoutStream = fs.createWriteStream("stdout.log"); 34 | const stderrStream = fs.createWriteStream("stderr.log"); 35 | demultiplexChannel(socket, [stdoutStream, stderrStream]); 36 | }) 37 | .listen(3000, () => console.log("Server started")); 38 | 39 | // 2 run in CLI: node demultiplexer-server.js 40 | -------------------------------------------------------------------------------- /streams/flowing.js: -------------------------------------------------------------------------------- 1 | process.stdin 2 | .on("data", chunk => { 3 | console.log("New data available"); 4 | console.log(`Chunk read: ${chunk.length} ${chunk.toString()}`); 5 | }) 6 | .on("end", () => { 7 | process.stdout.write("End of stream"); 8 | }); 9 | -------------------------------------------------------------------------------- /streams/generateData.js: -------------------------------------------------------------------------------- 1 | console.log("out1"); 2 | console.log("out2"); 3 | console.error("err1"); 4 | console.log("out3"); 5 | console.error("err2"); 6 | -------------------------------------------------------------------------------- /streams/gzip-buffer.js: -------------------------------------------------------------------------------- 1 | const fs = require("fs"); 2 | const zlib = require("zlib"); 3 | const file = "README.md"; // Select a file over 1GB 4 | 5 | fs.readFile(file, (err, buffer) => { 6 | if (err) console.log(err); 7 | zlib.gzip(buffer, (err, buffer) => { 8 | if (err) console.log(err); 9 | fs.writeFile(`${file}.gz`, buffer, err => { 10 | if (err) console.log(err); 11 | console.log("successfully compressed"); 12 | }); 13 | }); 14 | }); 15 | -------------------------------------------------------------------------------- /streams/gzip-streams.js: -------------------------------------------------------------------------------- 1 | const fs = require("fs"); 2 | const zlib = require("zlib"); 3 | const file = "README.md"; // Select a file over 1GB 4 | 5 | fs.createReadStream(file) 6 | .pipe(zlib.createGzip()) 7 | .pipe(fs.createWriteStream(`${file}.gz`)) 8 | .on("finish", () => console.log("Successfully compressed")); 9 | -------------------------------------------------------------------------------- /streams/multiplexer-client.js: -------------------------------------------------------------------------------- 1 | const child_process = require("child_process"); 2 | const net = require("net"); 3 | 4 | const multiplexChannels = (sources, destination) => { 5 | let totalChannels = sources.length; 6 | 7 | for (let i = 0; i < sources.length; i++) { 8 | sources[i] 9 | .on("readable", function() { 10 | let chunk; 11 | while ((chunk = this.read()) !== null) { 12 | const outBuff = new Buffer(1 + 4 + chunk.length); 13 | outBuff.writeUIint8(i, 0); 14 | outBuff.writeUIint32BE(chunk.length, 1); 15 | chunk.copy(outBuff, 5); 16 | console.log("Sending packet to channel:" + i); 17 | destination.write(outBuff); 18 | } 19 | }) 20 | .on("end", () => { 21 | if (--totalChannels === 0) { 22 | destination.end(); 23 | } 24 | }); 25 | } 26 | }; 27 | 28 | const socket = net.connect(3000, () => { 29 | const child = child_process.fork(process.argv[2], process.argv.slice[3], { 30 | silent: true 31 | }); 32 | multiplexChannels([child.stdout, child.stderr], socket); 33 | }); 34 | 35 | // 2 run in CLI: node multiplexer-client.js generateData.js 36 | -------------------------------------------------------------------------------- /streams/non-flowing.js: -------------------------------------------------------------------------------- 1 | process.stdin 2 | .on("readable", () => { 3 | let chunk; 4 | console.log("New data available"); 5 | while ((chunk = process.stdin.read()) !== null) { 6 | console.log(`Chunk read: ${chunk.length} ${chunk.toString()}`); 7 | } 8 | }) 9 | .on("end", () => { 10 | process.stdout.write("End of stream"); 11 | }); 12 | -------------------------------------------------------------------------------- /streams/notes.md: -------------------------------------------------------------------------------- 1 | ### Buffers vs Streams 2 | 3 | - Buffers only send the data once are chunks are collected 4 | - Streams send data once received even if isn't the entire piece. 5 | 6 | Adavantages of streams over Buffers: 7 | 8 | - Spatial efficiency 9 | 10 | V8 Buffers can not be bigger than 1GB, so you can run out of memory loading big files if using Buffers. 11 | See gzip example 12 | 13 | - Time efficiency 14 | 15 | For combined operations, with buffers you need to finish the forst one to start the sencond, while with Streams you can start the second operation once you receive the first chunk. 16 | 17 | - Composability 18 | 19 | Using `pipe()` streams allows to connect the different processing units, each responsible for one single responsibility. 20 | Streams have a uniform interface. The only prerequisite is that the next stream in the pipeline has to support the data type produced by the previous stream 21 | 22 | ## Anatomy 23 | 24 | Every stream in node is an implementation of one of the four base abstract classes availabel in the node core: 25 | 26 | - stream.Readable 27 | - stream.Writable 28 | - stream.Duplex 29 | - stream.Transform 30 | 31 | Each one is also an instance of `EventEmitter`. Streams can produce severak types of event, such as `end`, when a readable stream has finished reading, or `error`when goes wrong. 32 | 33 | Two modes: 34 | 35 | - Binary mode: Data streamed in form of chunk, such as buffers or strings. 36 | - Object mode: Where the streaming data is treated as a sequence of discrete objects (allowing to use almost any JS value). 37 | 38 | ### Redable streams 39 | 40 | It represents a source of data. 41 | Two ways of reading: 42 | 43 | - Non-flowing mode 44 | 45 | Attaching a listener to the readable event that signals the availability of new data to read 46 | See non-flowing.js 47 | 48 | - Flowing mode 49 | 50 | Attaching a listener to the data event. Doesn't use `read()`, but it's pushed to the data as soon as it arrives. 51 | 52 | 53 | ### Implementing Readable Streams 54 | 55 | `read()` is called by the stream consumers 56 | `_read()` must be implemented by a stream subclass and should be never called directly. Underscore indicates that is a private method. 57 | 58 | Example: randomString.js 59 | 60 | ### Writable streams 61 | 62 | It uses `write()` to write and `end()` to signal that no more data will be written 63 | 64 | Example: writable-server.js 65 | 66 | 67 | ### Backpressure 68 | 69 | Streams can also suffer from botttlenecks, where data is written faster than the stream can consume it. 70 | To solve it, you should buffer the incoming data. 71 | `writable.write()` will return false when the internal buffer exceeds the `highWaterMark` limit. It indicates that the applicatioon should stop writting. 72 | When the buffer is emptied, the drain event is emitted, communicating that it's safe to start writting again. 73 | This mechanism is called * back-pressure * 74 | Can be also used in readable streams. 75 | 76 | Example: back-pressure.js 77 | 78 | ### Implementing Writable Streams 79 | 80 | `writer()` is called by the stream consumers 81 | `_writer()` must be implemented by a stream subclass. 82 | 83 | Example: toFileStream.js 84 | 85 | 86 | ### Duplex Stream 87 | 88 | - Readable + Writable. 89 | - Network sockets for example. 90 | - Inherits the methods of both parent classes. 91 | - Use `read()` and `write()` 92 | - `readable` and `drain events` 93 | - New option. `allowHalfOpen` (defaults to true) that if set to false will cause both parts to end if only one of them does. 94 | 95 | 96 | ### Transform Streams 97 | 98 | - Special type of duplex streams to handle data transformations 99 | - In a duplex, there isn't an intermediate relationship between the parts, but Transform, applies some type of transformation to each chunk of data received from Writable. 100 | - Two different methods: `_transform()` and `flush()` 101 | 102 | Example: transformStream.js 103 | 104 | 105 | ### Connecting streams with pipes 106 | 107 | - They work like the pipe operator in UNIX. E.g.: `echo blahblah | sed s/bla/blo/g` 108 | - In streams: `readable.pipe(writable, [options])` It gets the output of the readable stream and pumps up into the writable stream. 109 | - Writable also ends when readable emits his `end()` event (unless `{end: false}` is specified in the options) 110 | - Piping two streams together will create a *suction* which allow the data to flow and there is no need to control the back-presure anymore as it's automatically taken care of. 111 | 112 | Example: replace.js 113 | 114 | - Error events are not propagated automatically through the pipeline. In the following example we'll only catch errors from the `stream2` 115 | 116 | ```js 117 | stream1 118 | .pipe(stream2) 119 | .on('error', () => {}) 120 | ``` 121 | 122 | ### Unordered parallel execution 123 | 124 | Parallel streams cannot be used when the order in which the data is processed is important. 125 | 126 | Example: parallelStream.js and checkUrls.js 127 | 128 | 129 | ### Unordered limitedparallel execution 130 | 131 | Similar to the previous but adding concurrency contorl. 132 | 133 | 134 | ### Ordered parallel execution 135 | 136 | When unordered are not acceptable, we should use other techniques that involve the use of buffer to reoprder chunks whil emitted. 137 | NPM package `through2-parallel` is specific for this purpose 138 | 139 | 140 | ### Combined streams 141 | 142 | - When writting into a combined streams, we are writing into the first stream of the pipeline. 143 | - When reading into a combined streams, we are reading from the last stream of the pipeline. 144 | - It has to capture every error in the pipeline as they are not propagated. 145 | 146 | Example: combinedStreams.js/archive.js -------------------------------------------------------------------------------- /streams/parallelStream.js: -------------------------------------------------------------------------------- 1 | const stream = require("stream"); 2 | 3 | class ParallelStrem extends stream.Transform { 4 | constructor(userTransform) { 5 | super({ objectMode: true }); 6 | this.userTransform = userTransform; 7 | this.running = 0; 8 | this.terminateCallback = null; 9 | } 10 | 11 | _transform(chunk, enc, done) { 12 | this.running++; 13 | this.userTransform(chunk, enc, this.push.bind(this)); 14 | this._onComplete.bind(this); 15 | done(); 16 | } 17 | 18 | _flush(done) { 19 | if (this.running > 0) this.terminateCallback = done; 20 | else done(); 21 | } 22 | 23 | _onComplete(err) { 24 | this.running--; 25 | if (err) return this.emit("error", err); 26 | if (this.running === 0) this.terminateCallback && this.terminateCallback(); 27 | } 28 | } 29 | 30 | module.exports = ParallelStrem; 31 | -------------------------------------------------------------------------------- /streams/randomString.js: -------------------------------------------------------------------------------- 1 | const stream = require("stream"); 2 | const Chance = require("chance"); 3 | 4 | const chance = new Chance(); 5 | 6 | class RandomString extends stream.Readable { 7 | constructor(options) { 8 | super(options); 9 | } 10 | 11 | // size is an advisory parameter 12 | _read(size) { 13 | const chunk = chance.string(); 14 | console.log(`Pushing chunk of size ${chunk.length}`); 15 | this.push(chunk, "utf8"); 16 | if (chance.bool({ likelihood: 5 })) { 17 | this.push(null); 18 | } 19 | } 20 | } 21 | 22 | const randomString = new RandomString(); 23 | 24 | randomString.on("readable", () => { 25 | let chunk; 26 | while ((chunk = randomString.read()) !== null) { 27 | console.log(`Chunk received: ${chunk.length}`); 28 | } 29 | }); 30 | 31 | randomString.on("data", chunk => { 32 | console.log(chunk.toString()); 33 | }); 34 | -------------------------------------------------------------------------------- /streams/replace.js: -------------------------------------------------------------------------------- 1 | const ReplaceStream = require("./transformStream"); 2 | 3 | process.stdin 4 | .pipe(new ReplaceStream(process.argv[2], process.argv[3])) 5 | .pipe(process.stdout); 6 | 7 | /* In console: 8 | echo Hello World! | node replace World Node.js 9 | */ 10 | -------------------------------------------------------------------------------- /streams/sequential-execution.js: -------------------------------------------------------------------------------- 1 | const fromArray = require("from2-array"); 2 | const through = require("through2"); 3 | const fs = require("fs"); 4 | 5 | const concatFiles = (destination, files, callback) => { 6 | const destStream = fs.createWriteStream(destination); 7 | fromArray 8 | .obj(files) 9 | .pipe( 10 | through.obj((file, enc, done) => { 11 | const src = fs.createReadStream(file); 12 | src.pipe( 13 | destStream, 14 | { end: false } 15 | ); 16 | src.on("end", done); 17 | }) 18 | ) 19 | .on("finish", () => { 20 | destStream.end(); 21 | callback(); 22 | }); 23 | }; 24 | 25 | concatFiles("concat.txt", ["README.md", ".gitignore", "package.json"], () => 26 | console.log("Files concatenated successfully") 27 | ); 28 | -------------------------------------------------------------------------------- /streams/stderr.log: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boxgames1/nodejs-patterns/42599ea94e07d9847ecdf8c9f56a08bacbdc5439/streams/stderr.log -------------------------------------------------------------------------------- /streams/stdout.log: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boxgames1/nodejs-patterns/42599ea94e07d9847ecdf8c9f56a08bacbdc5439/streams/stdout.log -------------------------------------------------------------------------------- /streams/toFileStream.js: -------------------------------------------------------------------------------- 1 | const stream = require("stream"); 2 | const fs = require("fs"); 3 | const path = require("path"); 4 | const mkdirp = require("mkdirp"); 5 | 6 | class ToFileStream extends stream.Writable { 7 | constructor() { 8 | super({ 9 | objectMode: true 10 | }); 11 | } 12 | 13 | _write(chunk, encoding, callback) { 14 | mkdirp(path.dirname(chunk.path), err => { 15 | if (err) return callback(err); 16 | fs.writeFile(chunk.path, chunk.content, callback); 17 | }); 18 | } 19 | } 20 | 21 | const toFileStream = new ToFileStream(); 22 | 23 | toFileStream.write({ 24 | path: "file", 25 | content: "Helloooooooooooo Dolly" 26 | }); 27 | toFileStream.write({ 28 | path: "file2", 29 | content: "Fire in the hol3" 30 | }); 31 | toFileStream.write({ 32 | path: "file3", 33 | content: "Streamssss in the night" 34 | }); 35 | 36 | toFileStream.end(() => console.log("AllFiles created")); 37 | -------------------------------------------------------------------------------- /streams/transformStream.js: -------------------------------------------------------------------------------- 1 | const stream = require("stream"); 2 | 3 | class ReplaceStream extends stream.Transform { 4 | constructor(searchString, replaceString) { 5 | super(); 6 | this.searchString = searchString; 7 | this.replaceString = replaceString; 8 | this.tailPiece = ""; 9 | } 10 | _transform(chunk, encoding, callback) { 11 | const pieces = (this.tailPiece + chunk).split(this.searchString); 12 | const lastPiece = pieces[pieces.length - 1]; 13 | const tailPieceLen = this.searchString.length - 1; 14 | 15 | this.tailPiece = lastPiece.slice(-tailPieceLen); 16 | pieces[pieces.length - 1] = lastPiece.slice(0, -tailPieceLen); 17 | 18 | this.push(pieces.join(this.replaceString)); 19 | } 20 | 21 | _flush(callback) { 22 | this.push(this.tailPiece); 23 | callback(); 24 | } 25 | } 26 | 27 | /* Example with Quokka 28 | const rs = new ReplaceStream("World", "Node.js"); 29 | rs.on("data", chunk => console.log(chunk.toString())); 30 | rs.write( 31 | "hello Wdedw dewd ewdew wedew dew dwed World edw dewdew wWorld ewdw edwe" 32 | ); 33 | rs.end(); 34 | */ 35 | 36 | module.exports = ReplaceStream; 37 | -------------------------------------------------------------------------------- /streams/writable-server.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Usage: 3 | * curl localhost:8080 4 | * or 5 | * entering localhost:8080 in the browser 6 | */ 7 | 8 | const Chance = require("chance"); 9 | const http = require("http"); 10 | 11 | const chance = new Chance(); 12 | 13 | http 14 | .createServer((req, res) => { 15 | res.writeHead(200, { "Content-Type": "text/plain" }); 16 | while (chance.bool({ likelihood: 95 })) { 17 | res.write(chance.string() + "\n"); 18 | } 19 | res.end("\nThe end \n"); 20 | res.on("finish", () => { 21 | console.log("All data was sent"); 22 | }); 23 | }) 24 | .listen("8080", () => { 25 | console.log("Listening on 8080"); 26 | }); 27 | -------------------------------------------------------------------------------- /yarn-error.log: -------------------------------------------------------------------------------- 1 | Arguments: 2 | /home/oli/.nvm/versions/node/v10.3.0/bin/node /usr/share/yarn/bin/yarn.js add level monotonic-timestamp JSONStream amqlib 3 | 4 | PATH: 5 | /home/oli/bin:/home/oli/.local/bin:/home/oli/.nvm/versions/node/v10.3.0/bin:/home/oli/bin:/home/oli/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin:/home/oli/Android/Sdk/tools:/home/oli/Android/Sdk/tools/bin:/home/oli/Android/Sdk/platform-tools:/home/oli/Android/Sdk/emulator:/home/oli/Android/Sdk/tools:/home/oli/Android/Sdk/tools/bin:/home/oli/Android/Sdk/platform-tools:/home/oli/Android/Sdk/emulator 6 | 7 | Yarn version: 8 | 1.15.2 9 | 10 | Node version: 11 | 10.3.0 12 | 13 | Platform: 14 | linux x64 15 | 16 | Trace: 17 | Error: https://registry.npmjs.org/amqlib: Not found 18 | at Request.params.callback [as _callback] (/usr/share/yarn/lib/cli.js:66058:18) 19 | at Request.self.callback (/usr/share/yarn/lib/cli.js:129541:22) 20 | at Request.emit (events.js:182:13) 21 | at Request. (/usr/share/yarn/lib/cli.js:130513:10) 22 | at Request.emit (events.js:182:13) 23 | at IncomingMessage. (/usr/share/yarn/lib/cli.js:130435:12) 24 | at Object.onceWrapper (events.js:273:13) 25 | at IncomingMessage.emit (events.js:187:15) 26 | at endReadableNT (_stream_readable.js:1090:12) 27 | at process._tickCallback (internal/process/next_tick.js:63:19) 28 | 29 | npm manifest: 30 | { 31 | "devDependencies": { 32 | "chance": "^1.0.18", 33 | "mkdirp": "^0.5.1" 34 | }, 35 | "dependencies": { 36 | "child_process": "^1.0.2", 37 | "combine": "^0.1.4", 38 | "consul": "^0.36.0", 39 | "crypto": "^1.0.1", 40 | "ecstatic": "^4.1.2", 41 | "forever": "^1.0.0", 42 | "from2-array": "^0.0.4", 43 | "http-proxy": "^1.18.0", 44 | "ini": "^1.3.5", 45 | "minimist": "^1.2.0", 46 | "multipipe": "^3.0.1", 47 | "object-path": "^0.11.4", 48 | "portfinder": "^1.0.25", 49 | "redis": "^2.8.0", 50 | "request": "^2.88.0", 51 | "split": "^1.0.1", 52 | "stampit": "^4.2.0", 53 | "through2": "^3.0.1", 54 | "ws": "^7.2.0", 55 | "zeromq": "^5.2.0" 56 | }, 57 | "scripts": { 58 | "consul": "consul agent -dev" 59 | } 60 | } 61 | 62 | yarn manifest: 63 | No manifest 64 | 65 | Lockfile: 66 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 67 | # yarn lockfile v1 68 | 69 | 70 | abbrev@1: 71 | version "1.1.1" 72 | resolved "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" 73 | integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q== 74 | 75 | ajv@^6.5.5: 76 | version "6.10.2" 77 | resolved "https://registry.npmjs.org/ajv/-/ajv-6.10.2.tgz#d3cea04d6b017b2894ad69040fec8b623eb4bd52" 78 | integrity sha512-TXtUUEYHuaTEbLZWIKUr5pmBuhDLy+8KYtPYdcV8qC+pOZL+NKqYwvWSRrVXHn+ZmRRAu8vJTAznH7Oag6RVRw== 79 | dependencies: 80 | fast-deep-equal "^2.0.1" 81 | fast-json-stable-stringify "^2.0.0" 82 | json-schema-traverse "^0.4.1" 83 | uri-js "^4.2.2" 84 | 85 | ansi-regex@^2.0.0: 86 | version "2.1.1" 87 | resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" 88 | integrity sha1-w7M6te42DYbg5ijwRorn7yfWVN8= 89 | 90 | ansi-regex@^3.0.0: 91 | version "3.0.0" 92 | resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" 93 | integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg= 94 | 95 | anymatch@^1.3.0: 96 | version "1.3.2" 97 | resolved "https://registry.npmjs.org/anymatch/-/anymatch-1.3.2.tgz#553dcb8f91e3c889845dfdba34c77721b90b9d7a" 98 | integrity sha512-0XNayC8lTHQ2OI8aljNCN3sSx6hsr/1+rlcDAotXJR7C1oZZHCNsfpbKwMjRA3Uqb5tF1Rae2oloTr4xpq+WjA== 99 | dependencies: 100 | micromatch "^2.1.5" 101 | normalize-path "^2.0.0" 102 | 103 | aproba@^1.0.3: 104 | version "1.2.0" 105 | resolved "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" 106 | integrity sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw== 107 | 108 | are-we-there-yet@~1.1.2: 109 | version "1.1.5" 110 | resolved "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz#4b35c2944f062a8bfcda66410760350fe9ddfc21" 111 | integrity sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w== 112 | dependencies: 113 | delegates "^1.0.0" 114 | readable-stream "^2.0.6" 115 | 116 | arguments@>=1.0.0: 117 | version "1.0.0" 118 | resolved "https://registry.npmjs.org/arguments/-/arguments-1.0.0.tgz#d4c63864545501e916f55b5179d1d1b1c41a45ad" 119 | integrity sha1-1MY4ZFRVAekW9VtRedHRscQaRa0= 120 | 121 | arr-diff@^2.0.0: 122 | version "2.0.0" 123 | resolved "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz#8f3b827f955a8bd669697e4a4256ac3ceae356cf" 124 | integrity sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8= 125 | dependencies: 126 | arr-flatten "^1.0.1" 127 | 128 | arr-diff@^4.0.0: 129 | version "4.0.0" 130 | resolved "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520" 131 | integrity sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA= 132 | 133 | arr-flatten@^1.0.1, arr-flatten@^1.1.0: 134 | version "1.1.0" 135 | resolved "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1" 136 | integrity sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg== 137 | 138 | arr-union@^3.1.0: 139 | version "3.1.0" 140 | resolved "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4" 141 | integrity sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ= 142 | 143 | array-unique@^0.2.1: 144 | version "0.2.1" 145 | resolved "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz#a1d97ccafcbc2625cc70fadceb36a50c58b01a53" 146 | integrity sha1-odl8yvy8JiXMcPrc6zalDFiwGlM= 147 | 148 | array-unique@^0.3.2: 149 | version "0.3.2" 150 | resolved "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428" 151 | integrity sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg= 152 | 153 | asn1@~0.2.3: 154 | version "0.2.4" 155 | resolved "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz#8d2475dfab553bb33e77b54e59e880bb8ce23136" 156 | integrity sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg== 157 | dependencies: 158 | safer-buffer "~2.1.0" 159 | 160 | assert-plus@1.0.0, assert-plus@^1.0.0: 161 | version "1.0.0" 162 | resolved "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" 163 | integrity sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU= 164 | 165 | assign-symbols@^1.0.0: 166 | version "1.0.0" 167 | resolved "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367" 168 | integrity sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c= 169 | 170 | async-each@^1.0.0: 171 | version "1.0.3" 172 | resolved "https://registry.npmjs.org/async-each/-/async-each-1.0.3.tgz#b727dbf87d7651602f06f4d4ac387f47d91b0cbf" 173 | integrity sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ== 174 | 175 | async-limiter@^1.0.0: 176 | version "1.0.1" 177 | resolved "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz#dd379e94f0db8310b08291f9d64c3209766617fd" 178 | integrity sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ== 179 | 180 | async@0.2.9: 181 | version "0.2.9" 182 | resolved "https://registry.npmjs.org/async/-/async-0.2.9.tgz#df63060fbf3d33286a76aaf6d55a2986d9ff8619" 183 | integrity sha1-32MGD789Myhqdqr21Vophtn/hhk= 184 | 185 | async@0.2.x, async@~0.2.9: 186 | version "0.2.10" 187 | resolved "https://registry.npmjs.org/async/-/async-0.2.10.tgz#b6bbe0b0674b9d719708ca38de8c237cb526c3d1" 188 | integrity sha1-trvgsGdLnXGXCMo43owjfLUmw9E= 189 | 190 | async@^2.6.2: 191 | version "2.6.3" 192 | resolved "https://registry.npmjs.org/async/-/async-2.6.3.tgz#d72625e2344a3656e3a3ad4fa749fa83299d82ff" 193 | integrity sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg== 194 | dependencies: 195 | lodash "^4.17.14" 196 | 197 | async@~0.9.0: 198 | version "0.9.2" 199 | resolved "https://registry.npmjs.org/async/-/async-0.9.2.tgz#aea74d5e61c1f899613bf64bda66d4c78f2fd17d" 200 | integrity sha1-rqdNXmHB+JlhO/ZL2mbUx48v0X0= 201 | 202 | asynckit@^0.4.0: 203 | version "0.4.0" 204 | resolved "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" 205 | integrity sha1-x57Zf380y48robyXkLzDZkdLS3k= 206 | 207 | atob@^2.1.1: 208 | version "2.1.2" 209 | resolved "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9" 210 | integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg== 211 | 212 | aws-sign2@~0.7.0: 213 | version "0.7.0" 214 | resolved "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8" 215 | integrity sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg= 216 | 217 | aws4@^1.8.0: 218 | version "1.8.0" 219 | resolved "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz#f0e003d9ca9e7f59c7a508945d7b2ef9a04a542f" 220 | integrity sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ== 221 | 222 | balanced-match@^1.0.0: 223 | version "1.0.0" 224 | resolved "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" 225 | integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c= 226 | 227 | base@^0.11.1: 228 | version "0.11.2" 229 | resolved "https://registry.npmjs.org/base/-/base-0.11.2.tgz#7bde5ced145b6d551a90db87f83c558b4eb48a8f" 230 | integrity sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg== 231 | dependencies: 232 | cache-base "^1.0.1" 233 | class-utils "^0.3.5" 234 | component-emitter "^1.2.1" 235 | define-property "^1.0.0" 236 | isobject "^3.0.1" 237 | mixin-deep "^1.2.0" 238 | pascalcase "^0.1.1" 239 | 240 | bcrypt-pbkdf@^1.0.0: 241 | version "1.0.2" 242 | resolved "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz#a4301d389b6a43f9b67ff3ca11a3f6637e360e9e" 243 | integrity sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4= 244 | dependencies: 245 | tweetnacl "^0.14.3" 246 | 247 | binary-extensions@^1.0.0: 248 | version "1.13.1" 249 | resolved "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz#598afe54755b2868a5330d2aff9d4ebb53209b65" 250 | integrity sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw== 251 | 252 | bl@^3.0.0: 253 | version "3.0.0" 254 | resolved "https://registry.npmjs.org/bl/-/bl-3.0.0.tgz#3611ec00579fd18561754360b21e9f784500ff88" 255 | integrity sha512-EUAyP5UHU5hxF8BPT0LKW8gjYLhq1DQIcneOX/pL/m2Alo+OYDQAJlHq+yseMP50Os2nHXOSic6Ss3vSQeyf4A== 256 | dependencies: 257 | readable-stream "^3.0.1" 258 | 259 | brace-expansion@^1.1.7: 260 | version "1.1.11" 261 | resolved "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" 262 | integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== 263 | dependencies: 264 | balanced-match "^1.0.0" 265 | concat-map "0.0.1" 266 | 267 | braces@^1.8.2: 268 | version "1.8.5" 269 | resolved "https://registry.npmjs.org/braces/-/braces-1.8.5.tgz#ba77962e12dff969d6b76711e914b737857bf6a7" 270 | integrity sha1-uneWLhLf+WnWt2cR6RS3N4V79qc= 271 | dependencies: 272 | expand-range "^1.8.1" 273 | preserve "^0.2.0" 274 | repeat-element "^1.1.2" 275 | 276 | braces@^2.3.1: 277 | version "2.3.2" 278 | resolved "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz#5979fd3f14cd531565e5fa2df1abfff1dfaee729" 279 | integrity sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w== 280 | dependencies: 281 | arr-flatten "^1.1.0" 282 | array-unique "^0.3.2" 283 | extend-shallow "^2.0.1" 284 | fill-range "^4.0.0" 285 | isobject "^3.0.1" 286 | repeat-element "^1.1.2" 287 | snapdragon "^0.8.1" 288 | snapdragon-node "^2.0.1" 289 | split-string "^3.0.2" 290 | to-regex "^3.0.1" 291 | 292 | broadway@~0.3.2, broadway@~0.3.6: 293 | version "0.3.6" 294 | resolved "https://registry.npmjs.org/broadway/-/broadway-0.3.6.tgz#7dbef068b954b7907925fd544963b578a902ba7a" 295 | integrity sha1-fb7waLlUt5B5Jf1USWO1eKkCuno= 296 | dependencies: 297 | cliff "0.1.9" 298 | eventemitter2 "0.4.14" 299 | nconf "0.6.9" 300 | utile "0.2.1" 301 | winston "0.8.0" 302 | 303 | cache-base@^1.0.1: 304 | version "1.0.1" 305 | resolved "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz#0a7f46416831c8b662ee36fe4e7c59d76f666ab2" 306 | integrity sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ== 307 | dependencies: 308 | collection-visit "^1.0.0" 309 | component-emitter "^1.2.1" 310 | get-value "^2.0.6" 311 | has-value "^1.0.0" 312 | isobject "^3.0.1" 313 | set-value "^2.0.0" 314 | to-object-path "^0.3.0" 315 | union-value "^1.0.0" 316 | unset-value "^1.0.0" 317 | 318 | caller@~0.0.1: 319 | version "0.0.1" 320 | resolved "https://registry.npmjs.org/caller/-/caller-0.0.1.tgz#f37a1d6ea10e829d94721ae29a90bb4fb52ab767" 321 | integrity sha1-83odbqEOgp2UchrimpC7T7Uqt2c= 322 | dependencies: 323 | tape "~2.3.2" 324 | 325 | caseless@~0.12.0: 326 | version "0.12.0" 327 | resolved "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" 328 | integrity sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw= 329 | 330 | chance@^1.0.18: 331 | version "1.1.3" 332 | resolved "https://registry.npmjs.org/chance/-/chance-1.1.3.tgz#414f08634ee479c7a316b569050ea20751b82dd3" 333 | integrity sha512-XeJsdoVAzDb1WRPRuMBesRSiWpW1uNTo5Fd7mYxPJsAfgX71+jfuCOHOdbyBz2uAUZ8TwKcXgWk3DMedFfJkbg== 334 | 335 | charset@^1.0.1: 336 | version "1.0.1" 337 | resolved "https://registry.npmjs.org/charset/-/charset-1.0.1.tgz#8d59546c355be61049a8fa9164747793319852bd" 338 | integrity sha512-6dVyOOYjpfFcL1Y4qChrAoQLRHvj2ziyhcm0QJlhOcAhykL/k1kTUPbeo+87MNRTRdk2OIIsIXbuF3x2wi5EXg== 339 | 340 | child_process@^1.0.2: 341 | version "1.0.2" 342 | resolved "https://registry.npmjs.org/child_process/-/child_process-1.0.2.tgz#b1f7e7fc73d25e7fd1d455adc94e143830182b5a" 343 | integrity sha1-sffn/HPSXn/R1FWtyU4UODAYK1o= 344 | 345 | chokidar@^1.0.1: 346 | version "1.7.0" 347 | resolved "https://registry.npmjs.org/chokidar/-/chokidar-1.7.0.tgz#798e689778151c8076b4b360e5edd28cda2bb468" 348 | integrity sha1-eY5ol3gVHIB2tLNg5e3SjNortGg= 349 | dependencies: 350 | anymatch "^1.3.0" 351 | async-each "^1.0.0" 352 | glob-parent "^2.0.0" 353 | inherits "^2.0.1" 354 | is-binary-path "^1.0.0" 355 | is-glob "^2.0.0" 356 | path-is-absolute "^1.0.0" 357 | readdirp "^2.0.0" 358 | optionalDependencies: 359 | fsevents "^1.0.0" 360 | 361 | chownr@^1.1.1: 362 | version "1.1.3" 363 | resolved "https://registry.npmjs.org/chownr/-/chownr-1.1.3.tgz#42d837d5239688d55f303003a508230fa6727142" 364 | integrity sha512-i70fVHhmV3DtTl6nqvZOnIjbY0Pe4kAUjwHj8z0zAdgBtYrJyYwLKCCuRBQ5ppkyL0AkN7HKRnETdmdp1zqNXw== 365 | 366 | class-utils@^0.3.5: 367 | version "0.3.6" 368 | resolved "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463" 369 | integrity sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg== 370 | dependencies: 371 | arr-union "^3.1.0" 372 | define-property "^0.2.5" 373 | isobject "^3.0.0" 374 | static-extend "^0.1.1" 375 | 376 | cliff@0.1.9: 377 | version "0.1.9" 378 | resolved "https://registry.npmjs.org/cliff/-/cliff-0.1.9.tgz#a211e09c6a3de3ba1af27d049d301250d18812bc" 379 | integrity sha1-ohHgnGo947oa8n0EnTASUNGIErw= 380 | dependencies: 381 | colors "0.x.x" 382 | eyes "0.1.x" 383 | winston "0.8.x" 384 | 385 | cliff@~0.1.9: 386 | version "0.1.10" 387 | resolved "https://registry.npmjs.org/cliff/-/cliff-0.1.10.tgz#53be33ea9f59bec85609ee300ac4207603e52013" 388 | integrity sha1-U74z6p9ZvshWCe4wCsQgdgPlIBM= 389 | dependencies: 390 | colors "~1.0.3" 391 | eyes "~0.1.8" 392 | winston "0.8.x" 393 | 394 | clone@^1.0.2: 395 | version "1.0.4" 396 | resolved "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz#da309cc263df15994c688ca902179ca3c7cd7c7e" 397 | integrity sha1-2jCcwmPfFZlMaIypAheco8fNfH4= 398 | 399 | code-point-at@^1.0.0: 400 | version "1.1.0" 401 | resolved "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" 402 | integrity sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c= 403 | 404 | collection-visit@^1.0.0: 405 | version "1.0.0" 406 | resolved "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz#4bc0373c164bc3291b4d368c829cf1a80a59dca0" 407 | integrity sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA= 408 | dependencies: 409 | map-visit "^1.0.0" 410 | object-visit "^1.0.0" 411 | 412 | colors@0.6.x, colors@0.x.x, colors@~0.6.2: 413 | version "0.6.2" 414 | resolved "https://registry.npmjs.org/colors/-/colors-0.6.2.tgz#2423fe6678ac0c5dae8852e5d0e5be08c997abcc" 415 | integrity sha1-JCP+ZnisDF2uiFLl0OW+CMmXq8w= 416 | 417 | colors@^1.1.2: 418 | version "1.4.0" 419 | resolved "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz#c50491479d4c1bdaed2c9ced32cf7c7dc2360f78" 420 | integrity sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA== 421 | 422 | colors@~1.0.3: 423 | version "1.0.3" 424 | resolved "https://registry.npmjs.org/colors/-/colors-1.0.3.tgz#0433f44d809680fdeb60ed260f1b0c262e82a40b" 425 | integrity sha1-BDP0TYCWgP3rYO0mDxsMJi6CpAs= 426 | 427 | combine@^0.1.4: 428 | version "0.1.4" 429 | resolved "https://registry.npmjs.org/combine/-/combine-0.1.4.tgz#c1a23db416623ffa5fdcd6711695ce1511c91351" 430 | integrity sha1-waI9tBZiP/pf3NZxFpXOFRHJE1E= 431 | dependencies: 432 | arguments ">=1.0.0" 433 | 434 | combined-stream@^1.0.6, combined-stream@~1.0.6: 435 | version "1.0.8" 436 | resolved "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" 437 | integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== 438 | dependencies: 439 | delayed-stream "~1.0.0" 440 | 441 | component-emitter@^1.2.1: 442 | version "1.3.0" 443 | resolved "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0" 444 | integrity sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg== 445 | 446 | concat-map@0.0.1: 447 | version "0.0.1" 448 | resolved "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" 449 | integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= 450 | 451 | console-control-strings@^1.0.0, console-control-strings@~1.1.0: 452 | version "1.1.0" 453 | resolved "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" 454 | integrity sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4= 455 | 456 | consul@^0.36.0: 457 | version "0.36.0" 458 | resolved "https://registry.npmjs.org/consul/-/consul-0.36.0.tgz#d1eff5aafe94eec36a05efb15618c8d39ef1e405" 459 | integrity sha512-1ISrujwQt9eCUM6Sl/TQEt3uE9Cn3glho2n/B8KD+XuEcoe/9fUWu9mhsKaRFB+DOKv3qtTwEDLfJBR0YOlS6g== 460 | dependencies: 461 | papi "^0.29.0" 462 | 463 | copy-descriptor@^0.1.0: 464 | version "0.1.1" 465 | resolved "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" 466 | integrity sha1-Z29us8OZl8LuGsOpJP1hJHSPV40= 467 | 468 | core-util-is@1.0.2, core-util-is@~1.0.0: 469 | version "1.0.2" 470 | resolved "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" 471 | integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac= 472 | 473 | crypto@^1.0.1: 474 | version "1.0.1" 475 | resolved "https://registry.npmjs.org/crypto/-/crypto-1.0.1.tgz#2af1b7cad8175d24c8a1b0778255794a21803037" 476 | integrity sha512-VxBKmeNcqQdiUQUW2Tzq0t377b54N2bMtXO/qiLa+6eRRmmC4qT3D4OnTGoT/U6O9aklQ/jTwbOtRMTTY8G0Ig== 477 | 478 | cycle@1.0.x: 479 | version "1.0.3" 480 | resolved "https://registry.npmjs.org/cycle/-/cycle-1.0.3.tgz#21e80b2be8580f98b468f379430662b046c34ad2" 481 | integrity sha1-IegLK+hYD5i0aPN5QwZisEbDStI= 482 | 483 | dashdash@^1.12.0: 484 | version "1.14.1" 485 | resolved "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" 486 | integrity sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA= 487 | dependencies: 488 | assert-plus "^1.0.0" 489 | 490 | debug@^2.2.0, debug@^2.3.3: 491 | version "2.6.9" 492 | resolved "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" 493 | integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== 494 | dependencies: 495 | ms "2.0.0" 496 | 497 | debug@^3.0.0, debug@^3.1.1, debug@^3.2.6: 498 | version "3.2.6" 499 | resolved "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b" 500 | integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ== 501 | dependencies: 502 | ms "^2.1.1" 503 | 504 | decode-uri-component@^0.2.0: 505 | version "0.2.0" 506 | resolved "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545" 507 | integrity sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU= 508 | 509 | decompress-response@^4.2.0: 510 | version "4.2.1" 511 | resolved "https://registry.npmjs.org/decompress-response/-/decompress-response-4.2.1.tgz#414023cc7a302da25ce2ec82d0d5238ccafd8986" 512 | integrity sha512-jOSne2qbyE+/r8G1VU+G/82LBs2Fs4LAsTiLSHOCOMZQl2OKZ6i8i4IyHemTe+/yIXOtTcRQMzPcgyhoFlqPkw== 513 | dependencies: 514 | mimic-response "^2.0.0" 515 | 516 | deep-equal@*: 517 | version "1.1.1" 518 | resolved "https://registry.npmjs.org/deep-equal/-/deep-equal-1.1.1.tgz#b5c98c942ceffaf7cb051e24e1434a25a2e6076a" 519 | integrity sha512-yd9c5AdiqVcR+JjcwUQb9DkhJc8ngNr0MahEBGvDiJw8puWab2yZlh+nkasOnZP+EGTAP6rRp2JzJhJZzvNF8g== 520 | dependencies: 521 | is-arguments "^1.0.4" 522 | is-date-object "^1.0.1" 523 | is-regex "^1.0.4" 524 | object-is "^1.0.1" 525 | object-keys "^1.1.1" 526 | regexp.prototype.flags "^1.2.0" 527 | 528 | deep-equal@~0.1.0: 529 | version "0.1.2" 530 | resolved "https://registry.npmjs.org/deep-equal/-/deep-equal-0.1.2.tgz#b246c2b80a570a47c11be1d9bd1070ec878b87ce" 531 | integrity sha1-skbCuApXCkfBG+HZvRBw7IeLh84= 532 | 533 | deep-equal@~0.2.1: 534 | version "0.2.2" 535 | resolved "https://registry.npmjs.org/deep-equal/-/deep-equal-0.2.2.tgz#84b745896f34c684e98f2ce0e42abaf43bba017d" 536 | integrity sha1-hLdFiW80xoTpjyzg5Cq69Du6AX0= 537 | 538 | deep-extend@^0.6.0: 539 | version "0.6.0" 540 | resolved "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" 541 | integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA== 542 | 543 | define-properties@^1.1.2: 544 | version "1.1.3" 545 | resolved "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1" 546 | integrity sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ== 547 | dependencies: 548 | object-keys "^1.0.12" 549 | 550 | define-property@^0.2.5: 551 | version "0.2.5" 552 | resolved "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz#c35b1ef918ec3c990f9a5bc57be04aacec5c8116" 553 | integrity sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY= 554 | dependencies: 555 | is-descriptor "^0.1.0" 556 | 557 | define-property@^1.0.0: 558 | version "1.0.0" 559 | resolved "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz#769ebaaf3f4a63aad3af9e8d304c9bbe79bfb0e6" 560 | integrity sha1-dp66rz9KY6rTr56NMEybvnm/sOY= 561 | dependencies: 562 | is-descriptor "^1.0.0" 563 | 564 | define-property@^2.0.2: 565 | version "2.0.2" 566 | resolved "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz#d459689e8d654ba77e02a817f8710d702cb16e9d" 567 | integrity sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ== 568 | dependencies: 569 | is-descriptor "^1.0.2" 570 | isobject "^3.0.1" 571 | 572 | defined@~0.0.0: 573 | version "0.0.0" 574 | resolved "https://registry.npmjs.org/defined/-/defined-0.0.0.tgz#f35eea7d705e933baf13b2f03b3f83d921403b3e" 575 | integrity sha1-817qfXBekzuvE7LwOz+D2SFAOz4= 576 | 577 | delayed-stream@~1.0.0: 578 | version "1.0.0" 579 | resolved "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" 580 | integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk= 581 | 582 | delegates@^1.0.0: 583 | version "1.0.0" 584 | resolved "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" 585 | integrity sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o= 586 | 587 | detect-libc@^1.0.2, detect-libc@^1.0.3: 588 | version "1.0.3" 589 | resolved "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" 590 | integrity sha1-+hN8S9aY7fVc1c0CrFWfkaTEups= 591 | 592 | director@1.2.7: 593 | version "1.2.7" 594 | resolved "https://registry.npmjs.org/director/-/director-1.2.7.tgz#bfd3741075fd7fb1a5b2e13658c5f4bec77736f3" 595 | integrity sha1-v9N0EHX9f7GlsuE2WMX0vsd3NvM= 596 | 597 | double-ended-queue@^2.1.0-0: 598 | version "2.1.0-0" 599 | resolved "https://registry.npmjs.org/double-ended-queue/-/double-ended-queue-2.1.0-0.tgz#103d3527fd31528f40188130c841efdd78264e5c" 600 | integrity sha1-ED01J/0xUo9AGIEwyEHv3XgmTlw= 601 | 602 | duplexer2@^0.1.2: 603 | version "0.1.4" 604 | resolved "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz#8b12dab878c0d69e3e7891051662a32fc6bddcc1" 605 | integrity sha1-ixLauHjA1p4+eJEFFmKjL8a93ME= 606 | dependencies: 607 | readable-stream "^2.0.2" 608 | 609 | ecc-jsbn@~0.1.1: 610 | version "0.1.2" 611 | resolved "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9" 612 | integrity sha1-OoOpBOVDUyh4dMVkt1SThoSamMk= 613 | dependencies: 614 | jsbn "~0.1.0" 615 | safer-buffer "^2.1.0" 616 | 617 | ecstatic@^4.1.2: 618 | version "4.1.2" 619 | resolved "https://registry.npmjs.org/ecstatic/-/ecstatic-4.1.2.tgz#3afbe29849b32bc2a1f8a90f67e01dc048c7ad40" 620 | integrity sha512-lnrAOpU2f7Ra8dm1pW0D1ucyUxQIEk8RjFrvROg1YqCV0ueVu9hzgiSEbSyROqXDDiHREdqC4w3AwOTb23P4UQ== 621 | dependencies: 622 | charset "^1.0.1" 623 | he "^1.1.1" 624 | mime "^2.4.1" 625 | minimist "^1.1.0" 626 | on-finished "^2.3.0" 627 | url-join "^4.0.0" 628 | 629 | ee-first@1.1.1: 630 | version "1.1.1" 631 | resolved "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" 632 | integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0= 633 | 634 | end-of-stream@^1.1.0, end-of-stream@^1.4.1: 635 | version "1.4.4" 636 | resolved "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0" 637 | integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q== 638 | dependencies: 639 | once "^1.4.0" 640 | 641 | event-stream@~0.5: 642 | version "0.5.3" 643 | resolved "https://registry.npmjs.org/event-stream/-/event-stream-0.5.3.tgz#b77b9309f7107addfeab63f0c0eafd8db0bd8c1c" 644 | integrity sha1-t3uTCfcQet3+q2PwwOr9jbC9jBw= 645 | dependencies: 646 | optimist "0.2" 647 | 648 | eventemitter2@0.4.14, eventemitter2@~0.4.14: 649 | version "0.4.14" 650 | resolved "https://registry.npmjs.org/eventemitter2/-/eventemitter2-0.4.14.tgz#8f61b75cde012b2e9eb284d4545583b5643b61ab" 651 | integrity sha1-j2G3XN4BKy6esoTUVFWDtWQ7Yas= 652 | 653 | eventemitter3@^4.0.0: 654 | version "4.0.0" 655 | resolved "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.0.tgz#d65176163887ee59f386d64c82610b696a4a74eb" 656 | integrity sha512-qerSRB0p+UDEssxTtm6EDKcE7W4OaoisfIMl4CngyEhjpYglocpNg6UEqCvemdGhosAsg4sO2dXJOdyBifPGCg== 657 | 658 | expand-brackets@^0.1.4: 659 | version "0.1.5" 660 | resolved "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz#df07284e342a807cd733ac5af72411e581d1177b" 661 | integrity sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s= 662 | dependencies: 663 | is-posix-bracket "^0.1.0" 664 | 665 | expand-brackets@^2.1.4: 666 | version "2.1.4" 667 | resolved "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz#b77735e315ce30f6b6eff0f83b04151a22449622" 668 | integrity sha1-t3c14xXOMPa27/D4OwQVGiJEliI= 669 | dependencies: 670 | debug "^2.3.3" 671 | define-property "^0.2.5" 672 | extend-shallow "^2.0.1" 673 | posix-character-classes "^0.1.0" 674 | regex-not "^1.0.0" 675 | snapdragon "^0.8.1" 676 | to-regex "^3.0.1" 677 | 678 | expand-range@^1.8.1: 679 | version "1.8.2" 680 | resolved "https://registry.npmjs.org/expand-range/-/expand-range-1.8.2.tgz#a299effd335fe2721ebae8e257ec79644fc85337" 681 | integrity sha1-opnv/TNf4nIeuujiV+x5ZE/IUzc= 682 | dependencies: 683 | fill-range "^2.1.0" 684 | 685 | expand-template@^2.0.3: 686 | version "2.0.3" 687 | resolved "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz#6e14b3fcee0f3a6340ecb57d2e8918692052a47c" 688 | integrity sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg== 689 | 690 | extend-shallow@^2.0.1: 691 | version "2.0.1" 692 | resolved "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f" 693 | integrity sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8= 694 | dependencies: 695 | is-extendable "^0.1.0" 696 | 697 | extend-shallow@^3.0.0, extend-shallow@^3.0.2: 698 | version "3.0.2" 699 | resolved "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz#26a71aaf073b39fb2127172746131c2704028db8" 700 | integrity sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg= 701 | dependencies: 702 | assign-symbols "^1.0.0" 703 | is-extendable "^1.0.1" 704 | 705 | extend@~3.0.2: 706 | version "3.0.2" 707 | resolved "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" 708 | integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== 709 | 710 | extglob@^0.3.1: 711 | version "0.3.2" 712 | resolved "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz#2e18ff3d2f49ab2765cec9023f011daa8d8349a1" 713 | integrity sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE= 714 | dependencies: 715 | is-extglob "^1.0.0" 716 | 717 | extglob@^2.0.4: 718 | version "2.0.4" 719 | resolved "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz#ad00fe4dc612a9232e8718711dc5cb5ab0285543" 720 | integrity sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw== 721 | dependencies: 722 | array-unique "^0.3.2" 723 | define-property "^1.0.0" 724 | expand-brackets "^2.1.4" 725 | extend-shallow "^2.0.1" 726 | fragment-cache "^0.2.1" 727 | regex-not "^1.0.0" 728 | snapdragon "^0.8.1" 729 | to-regex "^3.0.1" 730 | 731 | extsprintf@1.3.0: 732 | version "1.3.0" 733 | resolved "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05" 734 | integrity sha1-lpGEQOMEGnpBT4xS48V06zw+HgU= 735 | 736 | extsprintf@^1.2.0: 737 | version "1.4.0" 738 | resolved "https://registry.npmjs.org/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f" 739 | integrity sha1-4mifjzVvrWLMplo6kcXfX5VRaS8= 740 | 741 | eyes@0.1.x, eyes@~0.1.8: 742 | version "0.1.8" 743 | resolved "https://registry.npmjs.org/eyes/-/eyes-0.1.8.tgz#62cf120234c683785d902348a800ef3e0cc20bc0" 744 | integrity sha1-Ys8SAjTGg3hdkCNIqADvPgzCC8A= 745 | 746 | fast-deep-equal@^2.0.1: 747 | version "2.0.1" 748 | resolved "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz#7b05218ddf9667bf7f370bf7fdb2cb15fdd0aa49" 749 | integrity sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk= 750 | 751 | fast-json-stable-stringify@^2.0.0: 752 | version "2.0.0" 753 | resolved "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2" 754 | integrity sha1-1RQsDK7msRifh9OnYREGT4bIu/I= 755 | 756 | filename-regex@^2.0.0: 757 | version "2.0.1" 758 | resolved "https://registry.npmjs.org/filename-regex/-/filename-regex-2.0.1.tgz#c1c4b9bee3e09725ddb106b75c1e301fe2f18b26" 759 | integrity sha1-wcS5vuPglyXdsQa3XB4wH+LxiyY= 760 | 761 | fill-range@^2.1.0: 762 | version "2.2.4" 763 | resolved "https://registry.npmjs.org/fill-range/-/fill-range-2.2.4.tgz#eb1e773abb056dcd8df2bfdf6af59b8b3a936565" 764 | integrity sha512-cnrcCbj01+j2gTG921VZPnHbjmdAf8oQV/iGeV2kZxGSyfYjjTyY79ErsK1WJWMpw6DaApEX72binqJE+/d+5Q== 765 | dependencies: 766 | is-number "^2.1.0" 767 | isobject "^2.0.0" 768 | randomatic "^3.0.0" 769 | repeat-element "^1.1.2" 770 | repeat-string "^1.5.2" 771 | 772 | fill-range@^4.0.0: 773 | version "4.0.0" 774 | resolved "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz#d544811d428f98eb06a63dc402d2403c328c38f7" 775 | integrity sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc= 776 | dependencies: 777 | extend-shallow "^2.0.1" 778 | is-number "^3.0.0" 779 | repeat-string "^1.6.1" 780 | to-regex-range "^2.1.0" 781 | 782 | flatiron@~0.4.2: 783 | version "0.4.3" 784 | resolved "https://registry.npmjs.org/flatiron/-/flatiron-0.4.3.tgz#248cf79a3da7d7dc379e2a11c92a2719cbb540f6" 785 | integrity sha1-JIz3mj2n19w3nioRySonGcu1QPY= 786 | dependencies: 787 | broadway "~0.3.2" 788 | director "1.2.7" 789 | optimist "0.6.0" 790 | prompt "0.2.14" 791 | 792 | follow-redirects@^1.0.0: 793 | version "1.9.0" 794 | resolved "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.9.0.tgz#8d5bcdc65b7108fe1508649c79c12d732dcedb4f" 795 | integrity sha512-CRcPzsSIbXyVDl0QI01muNDu69S8trU4jArW9LpOt2WtC6LyUJetcIrmfHsRBx7/Jb6GHJUiuqyYxPooFfNt6A== 796 | dependencies: 797 | debug "^3.0.0" 798 | 799 | for-in@^1.0.1, for-in@^1.0.2: 800 | version "1.0.2" 801 | resolved "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" 802 | integrity sha1-gQaNKVqBQuwKxybG4iAMMPttXoA= 803 | 804 | for-own@^0.1.4: 805 | version "0.1.5" 806 | resolved "https://registry.npmjs.org/for-own/-/for-own-0.1.5.tgz#5265c681a4f294dabbf17c9509b6763aa84510ce" 807 | integrity sha1-UmXGgaTylNq78XyVCbZ2OqhFEM4= 808 | dependencies: 809 | for-in "^1.0.1" 810 | 811 | forever-agent@~0.6.1: 812 | version "0.6.1" 813 | resolved "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" 814 | integrity sha1-+8cfDEGt6zf5bFd60e1C2P2sypE= 815 | 816 | forever-monitor@~1.7.0: 817 | version "1.7.1" 818 | resolved "https://registry.npmjs.org/forever-monitor/-/forever-monitor-1.7.1.tgz#5d820f4a3a78db2d81ae2671f158b9e86a091bb8" 819 | integrity sha1-XYIPSjp42y2BriZx8Vi56GoJG7g= 820 | dependencies: 821 | broadway "~0.3.6" 822 | chokidar "^1.0.1" 823 | minimatch "~3.0.2" 824 | ps-tree "0.0.x" 825 | utile "~0.2.1" 826 | 827 | forever@^1.0.0: 828 | version "1.0.0" 829 | resolved "https://registry.npmjs.org/forever/-/forever-1.0.0.tgz#d6dc092da8e44da838318fabe45205b191f2a094" 830 | integrity sha512-ZaNWo5aMdtfui5GZWxaPcmFPW/TaaJZgGE0/p47lhn0FGRhFehuG338zuUURIqjn0dZEmgNPUAahZMOdykEAiw== 831 | dependencies: 832 | async "~0.2.9" 833 | cliff "~0.1.9" 834 | clone "^1.0.2" 835 | colors "~0.6.2" 836 | flatiron "~0.4.2" 837 | forever-monitor "~1.7.0" 838 | mkdirp "0.x.x" 839 | nconf "~0.6.9" 840 | nssocket "~0.5.1" 841 | object-assign "^3.0.0" 842 | optimist "~0.6.0" 843 | path-is-absolute "~1.0.0" 844 | prettyjson "^1.1.2" 845 | shush "^1.0.0" 846 | utile "~0.3.0" 847 | winston "~0.8.1" 848 | 849 | form-data@~2.3.2: 850 | version "2.3.3" 851 | resolved "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6" 852 | integrity sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ== 853 | dependencies: 854 | asynckit "^0.4.0" 855 | combined-stream "^1.0.6" 856 | mime-types "^2.1.12" 857 | 858 | fragment-cache@^0.2.1: 859 | version "0.2.1" 860 | resolved "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz#4290fad27f13e89be7f33799c6bc5a0abfff0d19" 861 | integrity sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk= 862 | dependencies: 863 | map-cache "^0.2.2" 864 | 865 | from2-array@^0.0.4: 866 | version "0.0.4" 867 | resolved "https://registry.npmjs.org/from2-array/-/from2-array-0.0.4.tgz#eafc16b65f6e2719bcd57fdc1869005ac1332cd6" 868 | integrity sha1-6vwWtl9uJxm81X/cGGkAWsEzLNY= 869 | dependencies: 870 | from2 "^2.0.3" 871 | 872 | from2@^2.0.3: 873 | version "2.3.0" 874 | resolved "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz#8bfb5502bde4a4d36cfdeea007fcca21d7e382af" 875 | integrity sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8= 876 | dependencies: 877 | inherits "^2.0.1" 878 | readable-stream "^2.0.0" 879 | 880 | fs-constants@^1.0.0: 881 | version "1.0.0" 882 | resolved "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz#6be0de9be998ce16af8afc24497b9ee9b7ccd9ad" 883 | integrity sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow== 884 | 885 | fs-minipass@^1.2.5: 886 | version "1.2.7" 887 | resolved "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.7.tgz#ccff8570841e7fe4265693da88936c55aed7f7c7" 888 | integrity sha512-GWSSJGFy4e9GUeCcbIkED+bgAoFyj7XF1mV8rma3QW4NIqX9Kyx79N/PF61H5udOV3aY1IaMLs6pGbH71nlCTA== 889 | dependencies: 890 | minipass "^2.6.0" 891 | 892 | fs.realpath@^1.0.0: 893 | version "1.0.0" 894 | resolved "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" 895 | integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= 896 | 897 | fsevents@^1.0.0: 898 | version "1.2.9" 899 | resolved "https://registry.npmjs.org/fsevents/-/fsevents-1.2.9.tgz#3f5ed66583ccd6f400b5a00db6f7e861363e388f" 900 | integrity sha512-oeyj2H3EjjonWcFjD5NvZNE9Rqe4UW+nQBU2HNeKw0koVLEFIhtyETyAakeAM3de7Z/SW5kcA+fZUait9EApnw== 901 | dependencies: 902 | nan "^2.12.1" 903 | node-pre-gyp "^0.12.0" 904 | 905 | function-bind@^1.1.1: 906 | version "1.1.1" 907 | resolved "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" 908 | integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== 909 | 910 | gauge@~2.7.3: 911 | version "2.7.4" 912 | resolved "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7" 913 | integrity sha1-LANAXHU4w51+s3sxcCLjJfsBi/c= 914 | dependencies: 915 | aproba "^1.0.3" 916 | console-control-strings "^1.0.0" 917 | has-unicode "^2.0.0" 918 | object-assign "^4.1.0" 919 | signal-exit "^3.0.0" 920 | string-width "^1.0.1" 921 | strip-ansi "^3.0.1" 922 | wide-align "^1.1.0" 923 | 924 | get-value@^2.0.3, get-value@^2.0.6: 925 | version "2.0.6" 926 | resolved "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28" 927 | integrity sha1-3BXKHGcjh8p2vTesCjlbogQqLCg= 928 | 929 | getpass@^0.1.1: 930 | version "0.1.7" 931 | resolved "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa" 932 | integrity sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo= 933 | dependencies: 934 | assert-plus "^1.0.0" 935 | 936 | github-from-package@0.0.0: 937 | version "0.0.0" 938 | resolved "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz#97fb5d96bfde8973313f20e8288ef9a167fa64ce" 939 | integrity sha1-l/tdlr/eiXMxPyDoKI75oWf6ZM4= 940 | 941 | glob-base@^0.3.0: 942 | version "0.3.0" 943 | resolved "https://registry.npmjs.org/glob-base/-/glob-base-0.3.0.tgz#dbb164f6221b1c0b1ccf82aea328b497df0ea3c4" 944 | integrity sha1-27Fk9iIbHAscz4Kuoyi0l98Oo8Q= 945 | dependencies: 946 | glob-parent "^2.0.0" 947 | is-glob "^2.0.0" 948 | 949 | glob-parent@^2.0.0: 950 | version "2.0.0" 951 | resolved "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz#81383d72db054fcccf5336daa902f182f6edbb28" 952 | integrity sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg= 953 | dependencies: 954 | is-glob "^2.0.0" 955 | 956 | glob@^7.1.3: 957 | version "7.1.6" 958 | resolved "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6" 959 | integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA== 960 | dependencies: 961 | fs.realpath "^1.0.0" 962 | inflight "^1.0.4" 963 | inherits "2" 964 | minimatch "^3.0.4" 965 | once "^1.3.0" 966 | path-is-absolute "^1.0.0" 967 | 968 | graceful-fs@^4.1.11: 969 | version "4.2.3" 970 | resolved "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz#4a12ff1b60376ef09862c2093edd908328be8423" 971 | integrity sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ== 972 | 973 | har-schema@^2.0.0: 974 | version "2.0.0" 975 | resolved "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92" 976 | integrity sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI= 977 | 978 | har-validator@~5.1.0: 979 | version "5.1.3" 980 | resolved "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz#1ef89ebd3e4996557675eed9893110dc350fa080" 981 | integrity sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g== 982 | dependencies: 983 | ajv "^6.5.5" 984 | har-schema "^2.0.0" 985 | 986 | has-unicode@^2.0.0: 987 | version "2.0.1" 988 | resolved "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" 989 | integrity sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk= 990 | 991 | has-value@^0.3.1: 992 | version "0.3.1" 993 | resolved "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz#7b1f58bada62ca827ec0a2078025654845995e1f" 994 | integrity sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8= 995 | dependencies: 996 | get-value "^2.0.3" 997 | has-values "^0.1.4" 998 | isobject "^2.0.0" 999 | 1000 | has-value@^1.0.0: 1001 | version "1.0.0" 1002 | resolved "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz#18b281da585b1c5c51def24c930ed29a0be6b177" 1003 | integrity sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc= 1004 | dependencies: 1005 | get-value "^2.0.6" 1006 | has-values "^1.0.0" 1007 | isobject "^3.0.0" 1008 | 1009 | has-values@^0.1.4: 1010 | version "0.1.4" 1011 | resolved "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz#6d61de95d91dfca9b9a02089ad384bff8f62b771" 1012 | integrity sha1-bWHeldkd/Km5oCCJrThL/49it3E= 1013 | 1014 | has-values@^1.0.0: 1015 | version "1.0.0" 1016 | resolved "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz#95b0b63fec2146619a6fe57fe75628d5a39efe4f" 1017 | integrity sha1-lbC2P+whRmGab+V/51Yo1aOe/k8= 1018 | dependencies: 1019 | is-number "^3.0.0" 1020 | kind-of "^4.0.0" 1021 | 1022 | has@^1.0.1: 1023 | version "1.0.3" 1024 | resolved "https://registry.npmjs.org/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" 1025 | integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== 1026 | dependencies: 1027 | function-bind "^1.1.1" 1028 | 1029 | he@^1.1.1: 1030 | version "1.2.0" 1031 | resolved "https://registry.npmjs.org/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" 1032 | integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== 1033 | 1034 | http-proxy@^1.18.0: 1035 | version "1.18.0" 1036 | resolved "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.0.tgz#dbe55f63e75a347db7f3d99974f2692a314a6a3a" 1037 | integrity sha512-84I2iJM/n1d4Hdgc6y2+qY5mDaz2PUVjlg9znE9byl+q0uC3DeByqBGReQu5tpLK0TAqTIXScRUV+dg7+bUPpQ== 1038 | dependencies: 1039 | eventemitter3 "^4.0.0" 1040 | follow-redirects "^1.0.0" 1041 | requires-port "^1.0.0" 1042 | 1043 | http-signature@~1.2.0: 1044 | version "1.2.0" 1045 | resolved "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1" 1046 | integrity sha1-muzZJRFHcvPZW2WmCruPfBj7rOE= 1047 | dependencies: 1048 | assert-plus "^1.0.0" 1049 | jsprim "^1.2.2" 1050 | sshpk "^1.7.0" 1051 | 1052 | i@0.3.x: 1053 | version "0.3.6" 1054 | resolved "https://registry.npmjs.org/i/-/i-0.3.6.tgz#d96c92732076f072711b6b10fd7d4f65ad8ee23d" 1055 | integrity sha1-2WyScyB28HJxG2sQ/X1PZa2O4j0= 1056 | 1057 | iconv-lite@^0.4.4: 1058 | version "0.4.24" 1059 | resolved "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" 1060 | integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== 1061 | dependencies: 1062 | safer-buffer ">= 2.1.2 < 3" 1063 | 1064 | ignore-walk@^3.0.1: 1065 | version "3.0.3" 1066 | resolved "https://registry.npmjs.org/ignore-walk/-/ignore-walk-3.0.3.tgz#017e2447184bfeade7c238e4aefdd1e8f95b1e37" 1067 | integrity sha512-m7o6xuOaT1aqheYHKf8W6J5pYH85ZI9w077erOzLje3JsB1gkafkAhHHY19dqjulgIZHFm32Cp5uNZgcQqdJKw== 1068 | dependencies: 1069 | minimatch "^3.0.4" 1070 | 1071 | inflight@^1.0.4: 1072 | version "1.0.6" 1073 | resolved "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" 1074 | integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= 1075 | dependencies: 1076 | once "^1.3.0" 1077 | wrappy "1" 1078 | 1079 | inherits@2, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.1, inherits@~2.0.3: 1080 | version "2.0.4" 1081 | resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" 1082 | integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== 1083 | 1084 | ini@1.x.x, ini@^1.3.5, ini@~1.3.0: 1085 | version "1.3.5" 1086 | resolved "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927" 1087 | integrity sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw== 1088 | 1089 | is-accessor-descriptor@^0.1.6: 1090 | version "0.1.6" 1091 | resolved "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz#a9e12cb3ae8d876727eeef3843f8a0897b5c98d6" 1092 | integrity sha1-qeEss66Nh2cn7u84Q/igiXtcmNY= 1093 | dependencies: 1094 | kind-of "^3.0.2" 1095 | 1096 | is-accessor-descriptor@^1.0.0: 1097 | version "1.0.0" 1098 | resolved "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz#169c2f6d3df1f992618072365c9b0ea1f6878656" 1099 | integrity sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ== 1100 | dependencies: 1101 | kind-of "^6.0.0" 1102 | 1103 | is-arguments@^1.0.4: 1104 | version "1.0.4" 1105 | resolved "https://registry.npmjs.org/is-arguments/-/is-arguments-1.0.4.tgz#3faf966c7cba0ff437fb31f6250082fcf0448cf3" 1106 | integrity sha512-xPh0Rmt8NE65sNzvyUmWgI1tz3mKq74lGA0mL8LYZcoIzKOzDh6HmrYm3d18k60nHerC8A9Km8kYu87zfSFnLA== 1107 | 1108 | is-binary-path@^1.0.0: 1109 | version "1.0.1" 1110 | resolved "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz#75f16642b480f187a711c814161fd3a4a7655898" 1111 | integrity sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg= 1112 | dependencies: 1113 | binary-extensions "^1.0.0" 1114 | 1115 | is-buffer@^1.1.5: 1116 | version "1.1.6" 1117 | resolved "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" 1118 | integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== 1119 | 1120 | is-data-descriptor@^0.1.4: 1121 | version "0.1.4" 1122 | resolved "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56" 1123 | integrity sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y= 1124 | dependencies: 1125 | kind-of "^3.0.2" 1126 | 1127 | is-data-descriptor@^1.0.0: 1128 | version "1.0.0" 1129 | resolved "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz#d84876321d0e7add03990406abbbbd36ba9268c7" 1130 | integrity sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ== 1131 | dependencies: 1132 | kind-of "^6.0.0" 1133 | 1134 | is-date-object@^1.0.1: 1135 | version "1.0.1" 1136 | resolved "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.1.tgz#9aa20eb6aeebbff77fbd33e74ca01b33581d3a16" 1137 | integrity sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY= 1138 | 1139 | is-descriptor@^0.1.0: 1140 | version "0.1.6" 1141 | resolved "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz#366d8240dde487ca51823b1ab9f07a10a78251ca" 1142 | integrity sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg== 1143 | dependencies: 1144 | is-accessor-descriptor "^0.1.6" 1145 | is-data-descriptor "^0.1.4" 1146 | kind-of "^5.0.0" 1147 | 1148 | is-descriptor@^1.0.0, is-descriptor@^1.0.2: 1149 | version "1.0.2" 1150 | resolved "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz#3b159746a66604b04f8c81524ba365c5f14d86ec" 1151 | integrity sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg== 1152 | dependencies: 1153 | is-accessor-descriptor "^1.0.0" 1154 | is-data-descriptor "^1.0.0" 1155 | kind-of "^6.0.2" 1156 | 1157 | is-dotfile@^1.0.0: 1158 | version "1.0.3" 1159 | resolved "https://registry.npmjs.org/is-dotfile/-/is-dotfile-1.0.3.tgz#a6a2f32ffd2dfb04f5ca25ecd0f6b83cf798a1e1" 1160 | integrity sha1-pqLzL/0t+wT1yiXs0Pa4PPeYoeE= 1161 | 1162 | is-equal-shallow@^0.1.3: 1163 | version "0.1.3" 1164 | resolved "https://registry.npmjs.org/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz#2238098fc221de0bcfa5d9eac4c45d638aa1c534" 1165 | integrity sha1-IjgJj8Ih3gvPpdnqxMRdY4qhxTQ= 1166 | dependencies: 1167 | is-primitive "^2.0.0" 1168 | 1169 | is-extendable@^0.1.0, is-extendable@^0.1.1: 1170 | version "0.1.1" 1171 | resolved "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" 1172 | integrity sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik= 1173 | 1174 | is-extendable@^1.0.1: 1175 | version "1.0.1" 1176 | resolved "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz#a7470f9e426733d81bd81e1155264e3a3507cab4" 1177 | integrity sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA== 1178 | dependencies: 1179 | is-plain-object "^2.0.4" 1180 | 1181 | is-extglob@^1.0.0: 1182 | version "1.0.0" 1183 | resolved "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz#ac468177c4943405a092fc8f29760c6ffc6206c0" 1184 | integrity sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA= 1185 | 1186 | is-fullwidth-code-point@^1.0.0: 1187 | version "1.0.0" 1188 | resolved "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" 1189 | integrity sha1-754xOG8DGn8NZDr4L95QxFfvAMs= 1190 | dependencies: 1191 | number-is-nan "^1.0.0" 1192 | 1193 | is-fullwidth-code-point@^2.0.0: 1194 | version "2.0.0" 1195 | resolved "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" 1196 | integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8= 1197 | 1198 | is-glob@^2.0.0, is-glob@^2.0.1: 1199 | version "2.0.1" 1200 | resolved "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz#d096f926a3ded5600f3fdfd91198cb0888c2d863" 1201 | integrity sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM= 1202 | dependencies: 1203 | is-extglob "^1.0.0" 1204 | 1205 | is-number@^2.1.0: 1206 | version "2.1.0" 1207 | resolved "https://registry.npmjs.org/is-number/-/is-number-2.1.0.tgz#01fcbbb393463a548f2f466cce16dece49db908f" 1208 | integrity sha1-Afy7s5NGOlSPL0ZszhbezknbkI8= 1209 | dependencies: 1210 | kind-of "^3.0.2" 1211 | 1212 | is-number@^3.0.0: 1213 | version "3.0.0" 1214 | resolved "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195" 1215 | integrity sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU= 1216 | dependencies: 1217 | kind-of "^3.0.2" 1218 | 1219 | is-number@^4.0.0: 1220 | version "4.0.0" 1221 | resolved "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz#0026e37f5454d73e356dfe6564699867c6a7f0ff" 1222 | integrity sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ== 1223 | 1224 | is-plain-object@^2.0.3, is-plain-object@^2.0.4: 1225 | version "2.0.4" 1226 | resolved "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677" 1227 | integrity sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og== 1228 | dependencies: 1229 | isobject "^3.0.1" 1230 | 1231 | is-posix-bracket@^0.1.0: 1232 | version "0.1.1" 1233 | resolved "https://registry.npmjs.org/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz#3334dc79774368e92f016e6fbc0a88f5cd6e6bc4" 1234 | integrity sha1-MzTceXdDaOkvAW5vvAqI9c1ua8Q= 1235 | 1236 | is-primitive@^2.0.0: 1237 | version "2.0.0" 1238 | resolved "https://registry.npmjs.org/is-primitive/-/is-primitive-2.0.0.tgz#207bab91638499c07b2adf240a41a87210034575" 1239 | integrity sha1-IHurkWOEmcB7Kt8kCkGochADRXU= 1240 | 1241 | is-regex@^1.0.4: 1242 | version "1.0.4" 1243 | resolved "https://registry.npmjs.org/is-regex/-/is-regex-1.0.4.tgz#5517489b547091b0930e095654ced25ee97e9491" 1244 | integrity sha1-VRdIm1RwkbCTDglWVM7SXul+lJE= 1245 | dependencies: 1246 | has "^1.0.1" 1247 | 1248 | is-typedarray@~1.0.0: 1249 | version "1.0.0" 1250 | resolved "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" 1251 | integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo= 1252 | 1253 | is-windows@^1.0.2: 1254 | version "1.0.2" 1255 | resolved "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" 1256 | integrity sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA== 1257 | 1258 | isarray@1.0.0, isarray@~1.0.0: 1259 | version "1.0.0" 1260 | resolved "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" 1261 | integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= 1262 | 1263 | isobject@^2.0.0: 1264 | version "2.1.0" 1265 | resolved "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" 1266 | integrity sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk= 1267 | dependencies: 1268 | isarray "1.0.0" 1269 | 1270 | isobject@^3.0.0, isobject@^3.0.1: 1271 | version "3.0.1" 1272 | resolved "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" 1273 | integrity sha1-TkMekrEalzFjaqH5yNHMvP2reN8= 1274 | 1275 | isstream@0.1.x, isstream@~0.1.2: 1276 | version "0.1.2" 1277 | resolved "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" 1278 | integrity sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo= 1279 | 1280 | jsbn@~0.1.0: 1281 | version "0.1.1" 1282 | resolved "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" 1283 | integrity sha1-peZUwuWi3rXyAdls77yoDA7y9RM= 1284 | 1285 | json-schema-traverse@^0.4.1: 1286 | version "0.4.1" 1287 | resolved "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" 1288 | integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== 1289 | 1290 | json-schema@0.2.3: 1291 | version "0.2.3" 1292 | resolved "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" 1293 | integrity sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM= 1294 | 1295 | json-stringify-safe@~5.0.1: 1296 | version "5.0.1" 1297 | resolved "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" 1298 | integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus= 1299 | 1300 | jsonify@~0.0.0: 1301 | version "0.0.0" 1302 | resolved "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73" 1303 | integrity sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM= 1304 | 1305 | jsprim@^1.2.2: 1306 | version "1.4.1" 1307 | resolved "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2" 1308 | integrity sha1-MT5mvB5cwG5Di8G3SZwuXFastqI= 1309 | dependencies: 1310 | assert-plus "1.0.0" 1311 | extsprintf "1.3.0" 1312 | json-schema "0.2.3" 1313 | verror "1.10.0" 1314 | 1315 | kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0: 1316 | version "3.2.2" 1317 | resolved "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" 1318 | integrity sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ= 1319 | dependencies: 1320 | is-buffer "^1.1.5" 1321 | 1322 | kind-of@^4.0.0: 1323 | version "4.0.0" 1324 | resolved "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz#20813df3d712928b207378691a45066fae72dd57" 1325 | integrity sha1-IIE989cSkosgc3hpGkUGb65y3Vc= 1326 | dependencies: 1327 | is-buffer "^1.1.5" 1328 | 1329 | kind-of@^5.0.0: 1330 | version "5.1.0" 1331 | resolved "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz#729c91e2d857b7a419a1f9aa65685c4c33f5845d" 1332 | integrity sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw== 1333 | 1334 | kind-of@^6.0.0, kind-of@^6.0.2: 1335 | version "6.0.2" 1336 | resolved "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz#01146b36a6218e64e58f3a8d66de5d7fc6f6d051" 1337 | integrity sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA== 1338 | 1339 | lazy@~1.0.11: 1340 | version "1.0.11" 1341 | resolved "https://registry.npmjs.org/lazy/-/lazy-1.0.11.tgz#daa068206282542c088288e975c297c1ae77b690" 1342 | integrity sha1-2qBoIGKCVCwIgojpdcKXwa53tpA= 1343 | 1344 | lodash@^4.17.14: 1345 | version "4.17.15" 1346 | resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548" 1347 | integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A== 1348 | 1349 | map-cache@^0.2.2: 1350 | version "0.2.2" 1351 | resolved "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf" 1352 | integrity sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8= 1353 | 1354 | map-visit@^1.0.0: 1355 | version "1.0.0" 1356 | resolved "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz#ecdca8f13144e660f1b5bd41f12f3479d98dfb8f" 1357 | integrity sha1-7Nyo8TFE5mDxtb1B8S80edmN+48= 1358 | dependencies: 1359 | object-visit "^1.0.0" 1360 | 1361 | math-random@^1.0.1: 1362 | version "1.0.4" 1363 | resolved "https://registry.npmjs.org/math-random/-/math-random-1.0.4.tgz#5dd6943c938548267016d4e34f057583080c514c" 1364 | integrity sha512-rUxjysqif/BZQH2yhd5Aaq7vXMSx9NdEsQcyA07uEzIvxgI7zIr33gGsh+RU0/XjmQpCW7RsVof1vlkvQVCK5A== 1365 | 1366 | micromatch@^2.1.5: 1367 | version "2.3.11" 1368 | resolved "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz#86677c97d1720b363431d04d0d15293bd38c1565" 1369 | integrity sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU= 1370 | dependencies: 1371 | arr-diff "^2.0.0" 1372 | array-unique "^0.2.1" 1373 | braces "^1.8.2" 1374 | expand-brackets "^0.1.4" 1375 | extglob "^0.3.1" 1376 | filename-regex "^2.0.0" 1377 | is-extglob "^1.0.0" 1378 | is-glob "^2.0.1" 1379 | kind-of "^3.0.2" 1380 | normalize-path "^2.0.1" 1381 | object.omit "^2.0.0" 1382 | parse-glob "^3.0.4" 1383 | regex-cache "^0.4.2" 1384 | 1385 | micromatch@^3.1.10: 1386 | version "3.1.10" 1387 | resolved "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23" 1388 | integrity sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg== 1389 | dependencies: 1390 | arr-diff "^4.0.0" 1391 | array-unique "^0.3.2" 1392 | braces "^2.3.1" 1393 | define-property "^2.0.2" 1394 | extend-shallow "^3.0.2" 1395 | extglob "^2.0.4" 1396 | fragment-cache "^0.2.1" 1397 | kind-of "^6.0.2" 1398 | nanomatch "^1.2.9" 1399 | object.pick "^1.3.0" 1400 | regex-not "^1.0.0" 1401 | snapdragon "^0.8.1" 1402 | to-regex "^3.0.2" 1403 | 1404 | mime-db@1.42.0: 1405 | version "1.42.0" 1406 | resolved "https://registry.npmjs.org/mime-db/-/mime-db-1.42.0.tgz#3e252907b4c7adb906597b4b65636272cf9e7bac" 1407 | integrity sha512-UbfJCR4UAVRNgMpfImz05smAXK7+c+ZntjaA26ANtkXLlOe947Aag5zdIcKQULAiF9Cq4WxBi9jUs5zkA84bYQ== 1408 | 1409 | mime-types@^2.1.12, mime-types@~2.1.19: 1410 | version "2.1.25" 1411 | resolved "https://registry.npmjs.org/mime-types/-/mime-types-2.1.25.tgz#39772d46621f93e2a80a856c53b86a62156a6437" 1412 | integrity sha512-5KhStqB5xpTAeGqKBAMgwaYMnQik7teQN4IAzC7npDv6kzeU6prfkR67bc87J1kWMPGkoaZSq1npmexMgkmEVg== 1413 | dependencies: 1414 | mime-db "1.42.0" 1415 | 1416 | mime@^2.4.1: 1417 | version "2.4.4" 1418 | resolved "https://registry.npmjs.org/mime/-/mime-2.4.4.tgz#bd7b91135fc6b01cde3e9bae33d659b63d8857e5" 1419 | integrity sha512-LRxmNwziLPT828z+4YkNzloCFC2YM4wrB99k+AV5ZbEyfGNWfG8SO1FUXLmLDBSo89NrJZ4DIWeLjy1CHGhMGA== 1420 | 1421 | mimic-response@^2.0.0: 1422 | version "2.0.0" 1423 | resolved "https://registry.npmjs.org/mimic-response/-/mimic-response-2.0.0.tgz#996a51c60adf12cb8a87d7fb8ef24c2f3d5ebb46" 1424 | integrity sha512-8ilDoEapqA4uQ3TwS0jakGONKXVJqpy+RpM+3b7pLdOjghCrEiGp9SRkFbUHAmZW9vdnrENWHjaweIoTIJExSQ== 1425 | 1426 | minimatch@^3.0.4, minimatch@~3.0.2: 1427 | version "3.0.4" 1428 | resolved "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" 1429 | integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== 1430 | dependencies: 1431 | brace-expansion "^1.1.7" 1432 | 1433 | minimist@0.0.8: 1434 | version "0.0.8" 1435 | resolved "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" 1436 | integrity sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0= 1437 | 1438 | minimist@^1.1.0, minimist@^1.2.0: 1439 | version "1.2.0" 1440 | resolved "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" 1441 | integrity sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ= 1442 | 1443 | minimist@~0.0.1: 1444 | version "0.0.10" 1445 | resolved "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz#de3f98543dbf96082be48ad1a0c7cda836301dcf" 1446 | integrity sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8= 1447 | 1448 | minipass@^2.6.0, minipass@^2.8.6, minipass@^2.9.0: 1449 | version "2.9.0" 1450 | resolved "https://registry.npmjs.org/minipass/-/minipass-2.9.0.tgz#e713762e7d3e32fed803115cf93e04bca9fcc9a6" 1451 | integrity sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg== 1452 | dependencies: 1453 | safe-buffer "^5.1.2" 1454 | yallist "^3.0.0" 1455 | 1456 | minizlib@^1.2.1: 1457 | version "1.3.3" 1458 | resolved "https://registry.npmjs.org/minizlib/-/minizlib-1.3.3.tgz#2290de96818a34c29551c8a8d301216bd65a861d" 1459 | integrity sha512-6ZYMOEnmVsdCeTJVE0W9ZD+pVnE8h9Hma/iOwwRDsdQoePpoX56/8B6z3P9VNwppJuBKNRuFDRNRqRWexT9G9Q== 1460 | dependencies: 1461 | minipass "^2.9.0" 1462 | 1463 | mixin-deep@^1.2.0: 1464 | version "1.3.2" 1465 | resolved "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz#1120b43dc359a785dce65b55b82e257ccf479566" 1466 | integrity sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA== 1467 | dependencies: 1468 | for-in "^1.0.2" 1469 | is-extendable "^1.0.1" 1470 | 1471 | mkdirp@0.x.x, mkdirp@^0.5.0, mkdirp@^0.5.1: 1472 | version "0.5.1" 1473 | resolved "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" 1474 | integrity sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM= 1475 | dependencies: 1476 | minimist "0.0.8" 1477 | 1478 | ms@2.0.0: 1479 | version "2.0.0" 1480 | resolved "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" 1481 | integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= 1482 | 1483 | ms@^2.1.1: 1484 | version "2.1.2" 1485 | resolved "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" 1486 | integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== 1487 | 1488 | multipipe@^3.0.1: 1489 | version "3.0.1" 1490 | resolved "https://registry.npmjs.org/multipipe/-/multipipe-3.0.1.tgz#54bae8f676ac8970b63dc79caddfe5f4ef819091" 1491 | integrity sha512-/++nApZuuB9M6TmYV7SDVl2ogDnXxYXjFiHzYxuHeqYEYVOXtIDNFp/cw+CZuhPghr0IA/qMEeed/38ZLk6s9Q== 1492 | dependencies: 1493 | duplexer2 "^0.1.2" 1494 | object-assign "^4.1.0" 1495 | 1496 | mute-stream@~0.0.4: 1497 | version "0.0.8" 1498 | resolved "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz#1630c42b2251ff81e2a283de96a5497ea92e5e0d" 1499 | integrity sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA== 1500 | 1501 | nan@^2.12.1, nan@^2.14.0: 1502 | version "2.14.0" 1503 | resolved "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz#7818f722027b2459a86f0295d434d1fc2336c52c" 1504 | integrity sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg== 1505 | 1506 | nanomatch@^1.2.9: 1507 | version "1.2.13" 1508 | resolved "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119" 1509 | integrity sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA== 1510 | dependencies: 1511 | arr-diff "^4.0.0" 1512 | array-unique "^0.3.2" 1513 | define-property "^2.0.2" 1514 | extend-shallow "^3.0.2" 1515 | fragment-cache "^0.2.1" 1516 | is-windows "^1.0.2" 1517 | kind-of "^6.0.2" 1518 | object.pick "^1.3.0" 1519 | regex-not "^1.0.0" 1520 | snapdragon "^0.8.1" 1521 | to-regex "^3.0.1" 1522 | 1523 | napi-build-utils@^1.0.1: 1524 | version "1.0.1" 1525 | resolved "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.1.tgz#1381a0f92c39d66bf19852e7873432fc2123e508" 1526 | integrity sha512-boQj1WFgQH3v4clhu3mTNfP+vOBxorDlE8EKiMjUlLG3C4qAESnn9AxIOkFgTR2c9LtzNjPrjS60cT27ZKBhaA== 1527 | 1528 | nconf@0.6.9, nconf@~0.6.9: 1529 | version "0.6.9" 1530 | resolved "https://registry.npmjs.org/nconf/-/nconf-0.6.9.tgz#9570ef15ed6f9ae6b2b3c8d5e71b66d3193cd661" 1531 | integrity sha1-lXDvFe1vmuays8jV5xtm0xk81mE= 1532 | dependencies: 1533 | async "0.2.9" 1534 | ini "1.x.x" 1535 | optimist "0.6.0" 1536 | 1537 | ncp@0.4.x: 1538 | version "0.4.2" 1539 | resolved "https://registry.npmjs.org/ncp/-/ncp-0.4.2.tgz#abcc6cbd3ec2ed2a729ff6e7c1fa8f01784a8574" 1540 | integrity sha1-q8xsvT7C7Spyn/bnwfqPAXhKhXQ= 1541 | 1542 | ncp@1.0.x: 1543 | version "1.0.1" 1544 | resolved "https://registry.npmjs.org/ncp/-/ncp-1.0.1.tgz#d15367e5cb87432ba117d2bf80fdf45aecfb4246" 1545 | integrity sha1-0VNn5cuHQyuhF9K/gP30Wuz7QkY= 1546 | 1547 | needle@^2.2.1: 1548 | version "2.4.0" 1549 | resolved "https://registry.npmjs.org/needle/-/needle-2.4.0.tgz#6833e74975c444642590e15a750288c5f939b57c" 1550 | integrity sha512-4Hnwzr3mi5L97hMYeNl8wRW/Onhy4nUKR/lVemJ8gJedxxUyBLm9kkrDColJvoSfwi0jCNhD+xCdOtiGDQiRZg== 1551 | dependencies: 1552 | debug "^3.2.6" 1553 | iconv-lite "^0.4.4" 1554 | sax "^1.2.4" 1555 | 1556 | node-abi@^2.7.0: 1557 | version "2.12.0" 1558 | resolved "https://registry.npmjs.org/node-abi/-/node-abi-2.12.0.tgz#40e9cfabdda1837863fa825e7dfa0b15686adf6f" 1559 | integrity sha512-VhPBXCIcvmo/5K8HPmnWJyyhvgKxnHTUMXR/XwGHV68+wrgkzST4UmQrY/XszSWA5dtnXpNp528zkcyJ/pzVcw== 1560 | dependencies: 1561 | semver "^5.4.1" 1562 | 1563 | node-pre-gyp@^0.12.0: 1564 | version "0.12.0" 1565 | resolved "https://registry.npmjs.org/node-pre-gyp/-/node-pre-gyp-0.12.0.tgz#39ba4bb1439da030295f899e3b520b7785766149" 1566 | integrity sha512-4KghwV8vH5k+g2ylT+sLTjy5wmUOb9vPhnM8NHvRf9dHmnW/CndrFXy2aRPaPST6dugXSdHXfeaHQm77PIz/1A== 1567 | dependencies: 1568 | detect-libc "^1.0.2" 1569 | mkdirp "^0.5.1" 1570 | needle "^2.2.1" 1571 | nopt "^4.0.1" 1572 | npm-packlist "^1.1.6" 1573 | npmlog "^4.0.2" 1574 | rc "^1.2.7" 1575 | rimraf "^2.6.1" 1576 | semver "^5.3.0" 1577 | tar "^4" 1578 | 1579 | noop-logger@^0.1.1: 1580 | version "0.1.1" 1581 | resolved "https://registry.npmjs.org/noop-logger/-/noop-logger-0.1.1.tgz#94a2b1633c4f1317553007d8966fd0e841b6a4c2" 1582 | integrity sha1-lKKxYzxPExdVMAfYlm/Q6EG2pMI= 1583 | 1584 | nopt@^4.0.1: 1585 | version "4.0.1" 1586 | resolved "https://registry.npmjs.org/nopt/-/nopt-4.0.1.tgz#d0d4685afd5415193c8c7505602d0d17cd64474d" 1587 | integrity sha1-0NRoWv1UFRk8jHUFYC0NF81kR00= 1588 | dependencies: 1589 | abbrev "1" 1590 | osenv "^0.1.4" 1591 | 1592 | normalize-path@^2.0.0, normalize-path@^2.0.1: 1593 | version "2.1.1" 1594 | resolved "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9" 1595 | integrity sha1-GrKLVW4Zg2Oowab35vogE3/mrtk= 1596 | dependencies: 1597 | remove-trailing-separator "^1.0.1" 1598 | 1599 | npm-bundled@^1.0.1: 1600 | version "1.0.6" 1601 | resolved "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.0.6.tgz#e7ba9aadcef962bb61248f91721cd932b3fe6bdd" 1602 | integrity sha512-8/JCaftHwbd//k6y2rEWp6k1wxVfpFzB6t1p825+cUb7Ym2XQfhwIC5KwhrvzZRJu+LtDE585zVaS32+CGtf0g== 1603 | 1604 | npm-packlist@^1.1.6: 1605 | version "1.4.6" 1606 | resolved "https://registry.npmjs.org/npm-packlist/-/npm-packlist-1.4.6.tgz#53ba3ed11f8523079f1457376dd379ee4ea42ff4" 1607 | integrity sha512-u65uQdb+qwtGvEJh/DgQgW1Xg7sqeNbmxYyrvlNznaVTjV3E5P6F/EFjM+BVHXl7JJlsdG8A64M0XI8FI/IOlg== 1608 | dependencies: 1609 | ignore-walk "^3.0.1" 1610 | npm-bundled "^1.0.1" 1611 | 1612 | npmlog@^4.0.1, npmlog@^4.0.2: 1613 | version "4.1.2" 1614 | resolved "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b" 1615 | integrity sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg== 1616 | dependencies: 1617 | are-we-there-yet "~1.1.2" 1618 | console-control-strings "~1.1.0" 1619 | gauge "~2.7.3" 1620 | set-blocking "~2.0.0" 1621 | 1622 | nssocket@~0.5.1: 1623 | version "0.5.3" 1624 | resolved "https://registry.npmjs.org/nssocket/-/nssocket-0.5.3.tgz#883ca2ec605f5ed64a4d5190b2625401928f8f8d" 1625 | integrity sha1-iDyi7GBfXtZKTVGQsmJUAZKPj40= 1626 | dependencies: 1627 | eventemitter2 "~0.4.14" 1628 | lazy "~1.0.11" 1629 | 1630 | number-is-nan@^1.0.0: 1631 | version "1.0.1" 1632 | resolved "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" 1633 | integrity sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0= 1634 | 1635 | oauth-sign@~0.9.0: 1636 | version "0.9.0" 1637 | resolved "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455" 1638 | integrity sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ== 1639 | 1640 | object-assign@^3.0.0: 1641 | version "3.0.0" 1642 | resolved "https://registry.npmjs.org/object-assign/-/object-assign-3.0.0.tgz#9bedd5ca0897949bca47e7ff408062d549f587f2" 1643 | integrity sha1-m+3VygiXlJvKR+f/QIBi1Un1h/I= 1644 | 1645 | object-assign@^4.1.0: 1646 | version "4.1.1" 1647 | resolved "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" 1648 | integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= 1649 | 1650 | object-copy@^0.1.0: 1651 | version "0.1.0" 1652 | resolved "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz#7e7d858b781bd7c991a41ba975ed3812754e998c" 1653 | integrity sha1-fn2Fi3gb18mRpBupde04EnVOmYw= 1654 | dependencies: 1655 | copy-descriptor "^0.1.0" 1656 | define-property "^0.2.5" 1657 | kind-of "^3.0.3" 1658 | 1659 | object-is@^1.0.1: 1660 | version "1.0.1" 1661 | resolved "https://registry.npmjs.org/object-is/-/object-is-1.0.1.tgz#0aa60ec9989a0b3ed795cf4d06f62cf1ad6539b6" 1662 | integrity sha1-CqYOyZiaCz7Xlc9NBvYs8a1lObY= 1663 | 1664 | object-keys@^1.0.12, object-keys@^1.1.1: 1665 | version "1.1.1" 1666 | resolved "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" 1667 | integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== 1668 | 1669 | object-path@^0.11.4: 1670 | version "0.11.4" 1671 | resolved "https://registry.npmjs.org/object-path/-/object-path-0.11.4.tgz#370ae752fbf37de3ea70a861c23bba8915691949" 1672 | integrity sha1-NwrnUvvzfePqcKhhwju6iRVpGUk= 1673 | 1674 | object-visit@^1.0.0: 1675 | version "1.0.1" 1676 | resolved "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz#f79c4493af0c5377b59fe39d395e41042dd045bb" 1677 | integrity sha1-95xEk68MU3e1n+OdOV5BBC3QRbs= 1678 | dependencies: 1679 | isobject "^3.0.0" 1680 | 1681 | object.omit@^2.0.0: 1682 | version "2.0.1" 1683 | resolved "https://registry.npmjs.org/object.omit/-/object.omit-2.0.1.tgz#1a9c744829f39dbb858c76ca3579ae2a54ebd1fa" 1684 | integrity sha1-Gpx0SCnznbuFjHbKNXmuKlTr0fo= 1685 | dependencies: 1686 | for-own "^0.1.4" 1687 | is-extendable "^0.1.1" 1688 | 1689 | object.pick@^1.3.0: 1690 | version "1.3.0" 1691 | resolved "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz#87a10ac4c1694bd2e1cbf53591a66141fb5dd747" 1692 | integrity sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c= 1693 | dependencies: 1694 | isobject "^3.0.1" 1695 | 1696 | on-finished@^2.3.0: 1697 | version "2.3.0" 1698 | resolved "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" 1699 | integrity sha1-IPEzZIGwg811M3mSoWlxqi2QaUc= 1700 | dependencies: 1701 | ee-first "1.1.1" 1702 | 1703 | once@^1.3.0, once@^1.3.1, once@^1.4.0: 1704 | version "1.4.0" 1705 | resolved "https://registry.npmjs.org/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" 1706 | integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= 1707 | dependencies: 1708 | wrappy "1" 1709 | 1710 | optimist@0.2: 1711 | version "0.2.8" 1712 | resolved "https://registry.npmjs.org/optimist/-/optimist-0.2.8.tgz#e981ab7e268b457948593b55674c099a815cac31" 1713 | integrity sha1-6YGrfiaLRXlIWTtVZ0wJmoFcrDE= 1714 | dependencies: 1715 | wordwrap ">=0.0.1 <0.1.0" 1716 | 1717 | optimist@0.6.0: 1718 | version "0.6.0" 1719 | resolved "https://registry.npmjs.org/optimist/-/optimist-0.6.0.tgz#69424826f3405f79f142e6fc3d9ae58d4dbb9200" 1720 | integrity sha1-aUJIJvNAX3nxQub8PZrljU27kgA= 1721 | dependencies: 1722 | minimist "~0.0.1" 1723 | wordwrap "~0.0.2" 1724 | 1725 | optimist@~0.6.0: 1726 | version "0.6.1" 1727 | resolved "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz#da3ea74686fa21a19a111c326e90eb15a0196686" 1728 | integrity sha1-2j6nRob6IaGaERwybpDrFaAZZoY= 1729 | dependencies: 1730 | minimist "~0.0.1" 1731 | wordwrap "~0.0.2" 1732 | 1733 | os-homedir@^1.0.0: 1734 | version "1.0.2" 1735 | resolved "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" 1736 | integrity sha1-/7xJiDNuDoM94MFox+8VISGqf7M= 1737 | 1738 | os-tmpdir@^1.0.0: 1739 | version "1.0.2" 1740 | resolved "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" 1741 | integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ= 1742 | 1743 | osenv@^0.1.4: 1744 | version "0.1.5" 1745 | resolved "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz#85cdfafaeb28e8677f416e287592b5f3f49ea410" 1746 | integrity sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g== 1747 | dependencies: 1748 | os-homedir "^1.0.0" 1749 | os-tmpdir "^1.0.0" 1750 | 1751 | papi@^0.29.0: 1752 | version "0.29.1" 1753 | resolved "https://registry.npmjs.org/papi/-/papi-0.29.1.tgz#7373e2c527f5117d61fd2a0e6c6b1dd72bf7f180" 1754 | integrity sha512-Y9ipSMfWuuVFO3zY9PlxOmEg+bQ7CeJ28sa9/a0veYNynLf9fwjR3+3fld5otEy7okUaEOUuCHVH62MyTmACXQ== 1755 | 1756 | parse-glob@^3.0.4: 1757 | version "3.0.4" 1758 | resolved "https://registry.npmjs.org/parse-glob/-/parse-glob-3.0.4.tgz#b2c376cfb11f35513badd173ef0bb6e3a388391c" 1759 | integrity sha1-ssN2z7EfNVE7rdFz7wu246OIORw= 1760 | dependencies: 1761 | glob-base "^0.3.0" 1762 | is-dotfile "^1.0.0" 1763 | is-extglob "^1.0.0" 1764 | is-glob "^2.0.0" 1765 | 1766 | pascalcase@^0.1.1: 1767 | version "0.1.1" 1768 | resolved "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14" 1769 | integrity sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ= 1770 | 1771 | path-is-absolute@^1.0.0, path-is-absolute@~1.0.0: 1772 | version "1.0.1" 1773 | resolved "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" 1774 | integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= 1775 | 1776 | performance-now@^2.1.0: 1777 | version "2.1.0" 1778 | resolved "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" 1779 | integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns= 1780 | 1781 | pkginfo@0.3.x: 1782 | version "0.3.1" 1783 | resolved "https://registry.npmjs.org/pkginfo/-/pkginfo-0.3.1.tgz#5b29f6a81f70717142e09e765bbeab97b4f81e21" 1784 | integrity sha1-Wyn2qB9wcXFC4J52W76rl7T4HiE= 1785 | 1786 | pkginfo@0.x.x: 1787 | version "0.4.1" 1788 | resolved "https://registry.npmjs.org/pkginfo/-/pkginfo-0.4.1.tgz#b5418ef0439de5425fc4995042dced14fb2a84ff" 1789 | integrity sha1-tUGO8EOd5UJfxJlQQtztFPsqhP8= 1790 | 1791 | portfinder@^1.0.25: 1792 | version "1.0.25" 1793 | resolved "https://registry.npmjs.org/portfinder/-/portfinder-1.0.25.tgz#254fd337ffba869f4b9d37edc298059cb4d35eca" 1794 | integrity sha512-6ElJnHBbxVA1XSLgBp7G1FiCkQdlqGzuF7DswL5tcea+E8UpuvPU7beVAjjRwCioTS9ZluNbu+ZyRvgTsmqEBg== 1795 | dependencies: 1796 | async "^2.6.2" 1797 | debug "^3.1.1" 1798 | mkdirp "^0.5.1" 1799 | 1800 | posix-character-classes@^0.1.0: 1801 | version "0.1.1" 1802 | resolved "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" 1803 | integrity sha1-AerA/jta9xoqbAL+q7jB/vfgDqs= 1804 | 1805 | prebuild-install@^5.3.2: 1806 | version "5.3.3" 1807 | resolved "https://registry.npmjs.org/prebuild-install/-/prebuild-install-5.3.3.tgz#ef4052baac60d465f5ba6bf003c9c1de79b9da8e" 1808 | integrity sha512-GV+nsUXuPW2p8Zy7SarF/2W/oiK8bFQgJcncoJ0d7kRpekEA0ftChjfEaF9/Y+QJEc/wFR7RAEa8lYByuUIe2g== 1809 | dependencies: 1810 | detect-libc "^1.0.3" 1811 | expand-template "^2.0.3" 1812 | github-from-package "0.0.0" 1813 | minimist "^1.2.0" 1814 | mkdirp "^0.5.1" 1815 | napi-build-utils "^1.0.1" 1816 | node-abi "^2.7.0" 1817 | noop-logger "^0.1.1" 1818 | npmlog "^4.0.1" 1819 | pump "^3.0.0" 1820 | rc "^1.2.7" 1821 | simple-get "^3.0.3" 1822 | tar-fs "^2.0.0" 1823 | tunnel-agent "^0.6.0" 1824 | which-pm-runs "^1.0.0" 1825 | 1826 | preserve@^0.2.0: 1827 | version "0.2.0" 1828 | resolved "https://registry.npmjs.org/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b" 1829 | integrity sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks= 1830 | 1831 | prettyjson@^1.1.2: 1832 | version "1.2.1" 1833 | resolved "https://registry.npmjs.org/prettyjson/-/prettyjson-1.2.1.tgz#fcffab41d19cab4dfae5e575e64246619b12d289" 1834 | integrity sha1-/P+rQdGcq0365eV15kJGYZsS0ok= 1835 | dependencies: 1836 | colors "^1.1.2" 1837 | minimist "^1.2.0" 1838 | 1839 | process-nextick-args@~2.0.0: 1840 | version "2.0.1" 1841 | resolved "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" 1842 | integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== 1843 | 1844 | prompt@0.2.14: 1845 | version "0.2.14" 1846 | resolved "https://registry.npmjs.org/prompt/-/prompt-0.2.14.tgz#57754f64f543fd7b0845707c818ece618f05ffdc" 1847 | integrity sha1-V3VPZPVD/XsIRXB8gY7OYY8F/9w= 1848 | dependencies: 1849 | pkginfo "0.x.x" 1850 | read "1.0.x" 1851 | revalidator "0.1.x" 1852 | utile "0.2.x" 1853 | winston "0.8.x" 1854 | 1855 | ps-tree@0.0.x: 1856 | version "0.0.3" 1857 | resolved "https://registry.npmjs.org/ps-tree/-/ps-tree-0.0.3.tgz#dbf8d752a7fe22fa7d58635689499610e9276ddc" 1858 | integrity sha1-2/jXUqf+Ivp9WGNWiUmWEOknbdw= 1859 | dependencies: 1860 | event-stream "~0.5" 1861 | 1862 | psl@^1.1.24: 1863 | version "1.4.0" 1864 | resolved "https://registry.npmjs.org/psl/-/psl-1.4.0.tgz#5dd26156cdb69fa1fdb8ab1991667d3f80ced7c2" 1865 | integrity sha512-HZzqCGPecFLyoRj5HLfuDSKYTJkAfB5thKBIkRHtGjWwY7p1dAyveIbXIq4tO0KYfDF2tHqPUgY9SDnGm00uFw== 1866 | 1867 | pump@^3.0.0: 1868 | version "3.0.0" 1869 | resolved "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64" 1870 | integrity sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww== 1871 | dependencies: 1872 | end-of-stream "^1.1.0" 1873 | once "^1.3.1" 1874 | 1875 | punycode@^1.4.1: 1876 | version "1.4.1" 1877 | resolved "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" 1878 | integrity sha1-wNWmOycYgArY4esPpSachN1BhF4= 1879 | 1880 | punycode@^2.1.0: 1881 | version "2.1.1" 1882 | resolved "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" 1883 | integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== 1884 | 1885 | qs@~6.5.2: 1886 | version "6.5.2" 1887 | resolved "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36" 1888 | integrity sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA== 1889 | 1890 | randomatic@^3.0.0: 1891 | version "3.1.1" 1892 | resolved "https://registry.npmjs.org/randomatic/-/randomatic-3.1.1.tgz#b776efc59375984e36c537b2f51a1f0aff0da1ed" 1893 | integrity sha512-TuDE5KxZ0J461RVjrJZCJc+J+zCkTb1MbH9AQUq68sMhOMcy9jLcb3BrZKgp9q9Ncltdg4QVqWrH02W2EFFVYw== 1894 | dependencies: 1895 | is-number "^4.0.0" 1896 | kind-of "^6.0.0" 1897 | math-random "^1.0.1" 1898 | 1899 | rc@^1.2.7: 1900 | version "1.2.8" 1901 | resolved "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed" 1902 | integrity sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw== 1903 | dependencies: 1904 | deep-extend "^0.6.0" 1905 | ini "~1.3.0" 1906 | minimist "^1.2.0" 1907 | strip-json-comments "~2.0.1" 1908 | 1909 | read@1.0.x: 1910 | version "1.0.7" 1911 | resolved "https://registry.npmjs.org/read/-/read-1.0.7.tgz#b3da19bd052431a97671d44a42634adf710b40c4" 1912 | integrity sha1-s9oZvQUkMal2cdRKQmNK33ELQMQ= 1913 | dependencies: 1914 | mute-stream "~0.0.4" 1915 | 1916 | "readable-stream@2 || 3", readable-stream@^3.0.1, readable-stream@^3.1.1: 1917 | version "3.4.0" 1918 | resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-3.4.0.tgz#a51c26754658e0a3c21dbf59163bd45ba6f447fc" 1919 | integrity sha512-jItXPLmrSR8jmTRmRWJXCnGJsfy85mB3Wd/uINMXA65yrnFo0cPClFIUWzo2najVNSl+mx7/4W8ttlLWJe99pQ== 1920 | dependencies: 1921 | inherits "^2.0.3" 1922 | string_decoder "^1.1.1" 1923 | util-deprecate "^1.0.1" 1924 | 1925 | readable-stream@^2.0.0, readable-stream@^2.0.2, readable-stream@^2.0.6: 1926 | version "2.3.6" 1927 | resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf" 1928 | integrity sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw== 1929 | dependencies: 1930 | core-util-is "~1.0.0" 1931 | inherits "~2.0.3" 1932 | isarray "~1.0.0" 1933 | process-nextick-args "~2.0.0" 1934 | safe-buffer "~5.1.1" 1935 | string_decoder "~1.1.1" 1936 | util-deprecate "~1.0.1" 1937 | 1938 | readdirp@^2.0.0: 1939 | version "2.2.1" 1940 | resolved "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz#0e87622a3325aa33e892285caf8b4e846529a525" 1941 | integrity sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ== 1942 | dependencies: 1943 | graceful-fs "^4.1.11" 1944 | micromatch "^3.1.10" 1945 | readable-stream "^2.0.2" 1946 | 1947 | redis-commands@^1.2.0: 1948 | version "1.5.0" 1949 | resolved "https://registry.npmjs.org/redis-commands/-/redis-commands-1.5.0.tgz#80d2e20698fe688f227127ff9e5164a7dd17e785" 1950 | integrity sha512-6KxamqpZ468MeQC3bkWmCB1fp56XL64D4Kf0zJSwDZbVLLm7KFkoIcHrgRvQ+sk8dnhySs7+yBg94yIkAK7aJg== 1951 | 1952 | redis-parser@^2.6.0: 1953 | version "2.6.0" 1954 | resolved "https://registry.npmjs.org/redis-parser/-/redis-parser-2.6.0.tgz#52ed09dacac108f1a631c07e9b69941e7a19504b" 1955 | integrity sha1-Uu0J2srBCPGmMcB+m2mUHnoZUEs= 1956 | 1957 | redis@^2.8.0: 1958 | version "2.8.0" 1959 | resolved "https://registry.npmjs.org/redis/-/redis-2.8.0.tgz#202288e3f58c49f6079d97af7a10e1303ae14b02" 1960 | integrity sha512-M1OkonEQwtRmZv4tEWF2VgpG0JWJ8Fv1PhlgT5+B+uNq2cA3Rt1Yt/ryoR+vQNOQcIEgdCdfH0jr3bDpihAw1A== 1961 | dependencies: 1962 | double-ended-queue "^2.1.0-0" 1963 | redis-commands "^1.2.0" 1964 | redis-parser "^2.6.0" 1965 | 1966 | regex-cache@^0.4.2: 1967 | version "0.4.4" 1968 | resolved "https://registry.npmjs.org/regex-cache/-/regex-cache-0.4.4.tgz#75bdc58a2a1496cec48a12835bc54c8d562336dd" 1969 | integrity sha512-nVIZwtCjkC9YgvWkpM55B5rBhBYRZhAaJbgcFYXXsHnbZ9UZI9nnVWYZpBlCqv9ho2eZryPnWrZGsOdPwVWXWQ== 1970 | dependencies: 1971 | is-equal-shallow "^0.1.3" 1972 | 1973 | regex-not@^1.0.0, regex-not@^1.0.2: 1974 | version "1.0.2" 1975 | resolved "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz#1f4ece27e00b0b65e0247a6810e6a85d83a5752c" 1976 | integrity sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A== 1977 | dependencies: 1978 | extend-shallow "^3.0.2" 1979 | safe-regex "^1.1.0" 1980 | 1981 | regexp.prototype.flags@^1.2.0: 1982 | version "1.2.0" 1983 | resolved "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.2.0.tgz#6b30724e306a27833eeb171b66ac8890ba37e41c" 1984 | integrity sha512-ztaw4M1VqgMwl9HlPpOuiYgItcHlunW0He2fE6eNfT6E/CF2FtYi9ofOYe4mKntstYk0Fyh/rDRBdS3AnxjlrA== 1985 | dependencies: 1986 | define-properties "^1.1.2" 1987 | 1988 | remove-trailing-separator@^1.0.1: 1989 | version "1.1.0" 1990 | resolved "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef" 1991 | integrity sha1-wkvOKig62tW8P1jg1IJJuSN52O8= 1992 | 1993 | repeat-element@^1.1.2: 1994 | version "1.1.3" 1995 | resolved "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz#782e0d825c0c5a3bb39731f84efee6b742e6b1ce" 1996 | integrity sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g== 1997 | 1998 | repeat-string@^1.5.2, repeat-string@^1.6.1: 1999 | version "1.6.1" 2000 | resolved "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" 2001 | integrity sha1-jcrkcOHIirwtYA//Sndihtp15jc= 2002 | 2003 | request@^2.88.0: 2004 | version "2.88.0" 2005 | resolved "https://registry.npmjs.org/request/-/request-2.88.0.tgz#9c2fca4f7d35b592efe57c7f0a55e81052124fef" 2006 | integrity sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg== 2007 | dependencies: 2008 | aws-sign2 "~0.7.0" 2009 | aws4 "^1.8.0" 2010 | caseless "~0.12.0" 2011 | combined-stream "~1.0.6" 2012 | extend "~3.0.2" 2013 | forever-agent "~0.6.1" 2014 | form-data "~2.3.2" 2015 | har-validator "~5.1.0" 2016 | http-signature "~1.2.0" 2017 | is-typedarray "~1.0.0" 2018 | isstream "~0.1.2" 2019 | json-stringify-safe "~5.0.1" 2020 | mime-types "~2.1.19" 2021 | oauth-sign "~0.9.0" 2022 | performance-now "^2.1.0" 2023 | qs "~6.5.2" 2024 | safe-buffer "^5.1.2" 2025 | tough-cookie "~2.4.3" 2026 | tunnel-agent "^0.6.0" 2027 | uuid "^3.3.2" 2028 | 2029 | requires-port@^1.0.0: 2030 | version "1.0.0" 2031 | resolved "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" 2032 | integrity sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8= 2033 | 2034 | resolve-url@^0.2.1: 2035 | version "0.2.1" 2036 | resolved "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" 2037 | integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo= 2038 | 2039 | resumer@~0.0.0: 2040 | version "0.0.0" 2041 | resolved "https://registry.npmjs.org/resumer/-/resumer-0.0.0.tgz#f1e8f461e4064ba39e82af3cdc2a8c893d076759" 2042 | integrity sha1-8ej0YeQGS6Oegq883CqMiT0HZ1k= 2043 | dependencies: 2044 | through "~2.3.4" 2045 | 2046 | ret@~0.1.10: 2047 | version "0.1.15" 2048 | resolved "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc" 2049 | integrity sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg== 2050 | 2051 | revalidator@0.1.x: 2052 | version "0.1.8" 2053 | resolved "https://registry.npmjs.org/revalidator/-/revalidator-0.1.8.tgz#fece61bfa0c1b52a206bd6b18198184bdd523a3b" 2054 | integrity sha1-/s5hv6DBtSoga9axgZgYS91SOjs= 2055 | 2056 | rimraf@2.x.x, rimraf@^2.6.1: 2057 | version "2.7.1" 2058 | resolved "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec" 2059 | integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w== 2060 | dependencies: 2061 | glob "^7.1.3" 2062 | 2063 | safe-buffer@^5.0.1, safe-buffer@^5.1.2, safe-buffer@~5.2.0: 2064 | version "5.2.0" 2065 | resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz#b74daec49b1148f88c64b68d49b1e815c1f2f519" 2066 | integrity sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg== 2067 | 2068 | safe-buffer@~5.1.0, safe-buffer@~5.1.1: 2069 | version "5.1.2" 2070 | resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" 2071 | integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== 2072 | 2073 | safe-regex@^1.1.0: 2074 | version "1.1.0" 2075 | resolved "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz#40a3669f3b077d1e943d44629e157dd48023bf2e" 2076 | integrity sha1-QKNmnzsHfR6UPURinhV91IAjvy4= 2077 | dependencies: 2078 | ret "~0.1.10" 2079 | 2080 | "safer-buffer@>= 2.1.2 < 3", safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0: 2081 | version "2.1.2" 2082 | resolved "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" 2083 | integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== 2084 | 2085 | sax@^1.2.4: 2086 | version "1.2.4" 2087 | resolved "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" 2088 | integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== 2089 | 2090 | semver@^5.3.0, semver@^5.4.1: 2091 | version "5.7.1" 2092 | resolved "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" 2093 | integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== 2094 | 2095 | set-blocking@~2.0.0: 2096 | version "2.0.0" 2097 | resolved "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" 2098 | integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc= 2099 | 2100 | set-value@^2.0.0, set-value@^2.0.1: 2101 | version "2.0.1" 2102 | resolved "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz#a18d40530e6f07de4228c7defe4227af8cad005b" 2103 | integrity sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw== 2104 | dependencies: 2105 | extend-shallow "^2.0.1" 2106 | is-extendable "^0.1.1" 2107 | is-plain-object "^2.0.3" 2108 | split-string "^3.0.1" 2109 | 2110 | shush@^1.0.0: 2111 | version "1.0.0" 2112 | resolved "https://registry.npmjs.org/shush/-/shush-1.0.0.tgz#c27415a9e458f2fed39b27cf8eb37c003782b431" 2113 | integrity sha1-wnQVqeRY8v7TmyfPjrN8ADeCtDE= 2114 | dependencies: 2115 | caller "~0.0.1" 2116 | strip-json-comments "~0.1.1" 2117 | 2118 | signal-exit@^3.0.0: 2119 | version "3.0.2" 2120 | resolved "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" 2121 | integrity sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0= 2122 | 2123 | simple-concat@^1.0.0: 2124 | version "1.0.0" 2125 | resolved "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.0.tgz#7344cbb8b6e26fb27d66b2fc86f9f6d5997521c6" 2126 | integrity sha1-c0TLuLbib7J9ZrL8hvn21Zl1IcY= 2127 | 2128 | simple-get@^3.0.3: 2129 | version "3.1.0" 2130 | resolved "https://registry.npmjs.org/simple-get/-/simple-get-3.1.0.tgz#b45be062435e50d159540b576202ceec40b9c6b3" 2131 | integrity sha512-bCR6cP+aTdScaQCnQKbPKtJOKDp/hj9EDLJo3Nw4y1QksqaovlW/bnptB6/c1e+qmNIDHRK+oXFDdEqBT8WzUA== 2132 | dependencies: 2133 | decompress-response "^4.2.0" 2134 | once "^1.3.1" 2135 | simple-concat "^1.0.0" 2136 | 2137 | snapdragon-node@^2.0.1: 2138 | version "2.1.1" 2139 | resolved "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b" 2140 | integrity sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw== 2141 | dependencies: 2142 | define-property "^1.0.0" 2143 | isobject "^3.0.0" 2144 | snapdragon-util "^3.0.1" 2145 | 2146 | snapdragon-util@^3.0.1: 2147 | version "3.0.1" 2148 | resolved "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz#f956479486f2acd79700693f6f7b805e45ab56e2" 2149 | integrity sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ== 2150 | dependencies: 2151 | kind-of "^3.2.0" 2152 | 2153 | snapdragon@^0.8.1: 2154 | version "0.8.2" 2155 | resolved "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz#64922e7c565b0e14204ba1aa7d6964278d25182d" 2156 | integrity sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg== 2157 | dependencies: 2158 | base "^0.11.1" 2159 | debug "^2.2.0" 2160 | define-property "^0.2.5" 2161 | extend-shallow "^2.0.1" 2162 | map-cache "^0.2.2" 2163 | source-map "^0.5.6" 2164 | source-map-resolve "^0.5.0" 2165 | use "^3.1.0" 2166 | 2167 | source-map-resolve@^0.5.0: 2168 | version "0.5.2" 2169 | resolved "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.2.tgz#72e2cc34095543e43b2c62b2c4c10d4a9054f259" 2170 | integrity sha512-MjqsvNwyz1s0k81Goz/9vRBe9SZdB09Bdw+/zYyO+3CuPk6fouTaxscHkgtE8jKvf01kVfl8riHzERQ/kefaSA== 2171 | dependencies: 2172 | atob "^2.1.1" 2173 | decode-uri-component "^0.2.0" 2174 | resolve-url "^0.2.1" 2175 | source-map-url "^0.4.0" 2176 | urix "^0.1.0" 2177 | 2178 | source-map-url@^0.4.0: 2179 | version "0.4.0" 2180 | resolved "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3" 2181 | integrity sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM= 2182 | 2183 | source-map@^0.5.6: 2184 | version "0.5.7" 2185 | resolved "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" 2186 | integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= 2187 | 2188 | split-string@^3.0.1, split-string@^3.0.2: 2189 | version "3.1.0" 2190 | resolved "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2" 2191 | integrity sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw== 2192 | dependencies: 2193 | extend-shallow "^3.0.0" 2194 | 2195 | split@^1.0.1: 2196 | version "1.0.1" 2197 | resolved "https://registry.npmjs.org/split/-/split-1.0.1.tgz#605bd9be303aa59fb35f9229fbea0ddec9ea07d9" 2198 | integrity sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg== 2199 | dependencies: 2200 | through "2" 2201 | 2202 | sshpk@^1.7.0: 2203 | version "1.16.1" 2204 | resolved "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz#fb661c0bef29b39db40769ee39fa70093d6f6877" 2205 | integrity sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg== 2206 | dependencies: 2207 | asn1 "~0.2.3" 2208 | assert-plus "^1.0.0" 2209 | bcrypt-pbkdf "^1.0.0" 2210 | dashdash "^1.12.0" 2211 | ecc-jsbn "~0.1.1" 2212 | getpass "^0.1.1" 2213 | jsbn "~0.1.0" 2214 | safer-buffer "^2.0.2" 2215 | tweetnacl "~0.14.0" 2216 | 2217 | stack-trace@0.0.x: 2218 | version "0.0.10" 2219 | resolved "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz#547c70b347e8d32b4e108ea1a2a159e5fdde19c0" 2220 | integrity sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA= 2221 | 2222 | stampit@^4.2.0: 2223 | version "4.3.0" 2224 | resolved "https://registry.npmjs.org/stampit/-/stampit-4.3.0.tgz#0190574151f83280114aa928e96708690359cfaa" 2225 | integrity sha512-Ea8dBId0WFjmFzd2OO8RPOssNbfBApASwPTMdH83uc2mIQPS0v6JSX0rfvb2cUXIYDarjH5DPpeTA07brAe9cA== 2226 | 2227 | static-extend@^0.1.1: 2228 | version "0.1.2" 2229 | resolved "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6" 2230 | integrity sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY= 2231 | dependencies: 2232 | define-property "^0.2.5" 2233 | object-copy "^0.1.0" 2234 | 2235 | string-width@^1.0.1: 2236 | version "1.0.2" 2237 | resolved "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" 2238 | integrity sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M= 2239 | dependencies: 2240 | code-point-at "^1.0.0" 2241 | is-fullwidth-code-point "^1.0.0" 2242 | strip-ansi "^3.0.0" 2243 | 2244 | "string-width@^1.0.2 || 2": 2245 | version "2.1.1" 2246 | resolved "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" 2247 | integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw== 2248 | dependencies: 2249 | is-fullwidth-code-point "^2.0.0" 2250 | strip-ansi "^4.0.0" 2251 | 2252 | string_decoder@^1.1.1: 2253 | version "1.3.0" 2254 | resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" 2255 | integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== 2256 | dependencies: 2257 | safe-buffer "~5.2.0" 2258 | 2259 | string_decoder@~1.1.1: 2260 | version "1.1.1" 2261 | resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" 2262 | integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== 2263 | dependencies: 2264 | safe-buffer "~5.1.0" 2265 | 2266 | strip-ansi@^3.0.0, strip-ansi@^3.0.1: 2267 | version "3.0.1" 2268 | resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" 2269 | integrity sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8= 2270 | dependencies: 2271 | ansi-regex "^2.0.0" 2272 | 2273 | strip-ansi@^4.0.0: 2274 | version "4.0.0" 2275 | resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" 2276 | integrity sha1-qEeQIusaw2iocTibY1JixQXuNo8= 2277 | dependencies: 2278 | ansi-regex "^3.0.0" 2279 | 2280 | strip-json-comments@~0.1.1: 2281 | version "0.1.3" 2282 | resolved "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-0.1.3.tgz#164c64e370a8a3cc00c9e01b539e569823f0ee54" 2283 | integrity sha1-Fkxk43Coo8wAyeAbU55WmCPw7lQ= 2284 | 2285 | strip-json-comments@~2.0.1: 2286 | version "2.0.1" 2287 | resolved "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" 2288 | integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo= 2289 | 2290 | tape@~2.3.2: 2291 | version "2.3.3" 2292 | resolved "https://registry.npmjs.org/tape/-/tape-2.3.3.tgz#2e7ce0a31df09f8d6851664a71842e0ca5057af7" 2293 | integrity sha1-Lnzgox3wn41oUWZKcYQuDKUFevc= 2294 | dependencies: 2295 | deep-equal "~0.1.0" 2296 | defined "~0.0.0" 2297 | inherits "~2.0.1" 2298 | jsonify "~0.0.0" 2299 | resumer "~0.0.0" 2300 | through "~2.3.4" 2301 | 2302 | tar-fs@^2.0.0: 2303 | version "2.0.0" 2304 | resolved "https://registry.npmjs.org/tar-fs/-/tar-fs-2.0.0.tgz#677700fc0c8b337a78bee3623fdc235f21d7afad" 2305 | integrity sha512-vaY0obB6Om/fso8a8vakQBzwholQ7v5+uy+tF3Ozvxv1KNezmVQAiWtcNmMHFSFPqL3dJA8ha6gdtFbfX9mcxA== 2306 | dependencies: 2307 | chownr "^1.1.1" 2308 | mkdirp "^0.5.1" 2309 | pump "^3.0.0" 2310 | tar-stream "^2.0.0" 2311 | 2312 | tar-stream@^2.0.0: 2313 | version "2.1.0" 2314 | resolved "https://registry.npmjs.org/tar-stream/-/tar-stream-2.1.0.tgz#d1aaa3661f05b38b5acc9b7020efdca5179a2cc3" 2315 | integrity sha512-+DAn4Nb4+gz6WZigRzKEZl1QuJVOLtAwwF+WUxy1fJ6X63CaGaUAxJRD2KEn1OMfcbCjySTYpNC6WmfQoIEOdw== 2316 | dependencies: 2317 | bl "^3.0.0" 2318 | end-of-stream "^1.4.1" 2319 | fs-constants "^1.0.0" 2320 | inherits "^2.0.3" 2321 | readable-stream "^3.1.1" 2322 | 2323 | tar@^4: 2324 | version "4.4.13" 2325 | resolved "https://registry.npmjs.org/tar/-/tar-4.4.13.tgz#43b364bc52888d555298637b10d60790254ab525" 2326 | integrity sha512-w2VwSrBoHa5BsSyH+KxEqeQBAllHhccyMFVHtGtdMpF4W7IRWfZjFiQceJPChOeTsSDVUpER2T8FA93pr0L+QA== 2327 | dependencies: 2328 | chownr "^1.1.1" 2329 | fs-minipass "^1.2.5" 2330 | minipass "^2.8.6" 2331 | minizlib "^1.2.1" 2332 | mkdirp "^0.5.0" 2333 | safe-buffer "^5.1.2" 2334 | yallist "^3.0.3" 2335 | 2336 | through2@^3.0.1: 2337 | version "3.0.1" 2338 | resolved "https://registry.npmjs.org/through2/-/through2-3.0.1.tgz#39276e713c3302edf9e388dd9c812dd3b825bd5a" 2339 | integrity sha512-M96dvTalPT3YbYLaKaCuwu+j06D/8Jfib0o/PxbVt6Amhv3dUAtW6rTV1jPgJSBG83I/e04Y6xkVdVhSRhi0ww== 2340 | dependencies: 2341 | readable-stream "2 || 3" 2342 | 2343 | through@2, through@~2.3.4: 2344 | version "2.3.8" 2345 | resolved "https://registry.npmjs.org/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" 2346 | integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU= 2347 | 2348 | to-object-path@^0.3.0: 2349 | version "0.3.0" 2350 | resolved "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz#297588b7b0e7e0ac08e04e672f85c1f4999e17af" 2351 | integrity sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68= 2352 | dependencies: 2353 | kind-of "^3.0.2" 2354 | 2355 | to-regex-range@^2.1.0: 2356 | version "2.1.1" 2357 | resolved "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz#7c80c17b9dfebe599e27367e0d4dd5590141db38" 2358 | integrity sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg= 2359 | dependencies: 2360 | is-number "^3.0.0" 2361 | repeat-string "^1.6.1" 2362 | 2363 | to-regex@^3.0.1, to-regex@^3.0.2: 2364 | version "3.0.2" 2365 | resolved "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz#13cfdd9b336552f30b51f33a8ae1b42a7a7599ce" 2366 | integrity sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw== 2367 | dependencies: 2368 | define-property "^2.0.2" 2369 | extend-shallow "^3.0.2" 2370 | regex-not "^1.0.2" 2371 | safe-regex "^1.1.0" 2372 | 2373 | tough-cookie@~2.4.3: 2374 | version "2.4.3" 2375 | resolved "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz#53f36da3f47783b0925afa06ff9f3b165280f781" 2376 | integrity sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ== 2377 | dependencies: 2378 | psl "^1.1.24" 2379 | punycode "^1.4.1" 2380 | 2381 | tunnel-agent@^0.6.0: 2382 | version "0.6.0" 2383 | resolved "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" 2384 | integrity sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0= 2385 | dependencies: 2386 | safe-buffer "^5.0.1" 2387 | 2388 | tweetnacl@^0.14.3, tweetnacl@~0.14.0: 2389 | version "0.14.5" 2390 | resolved "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" 2391 | integrity sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q= 2392 | 2393 | union-value@^1.0.0: 2394 | version "1.0.1" 2395 | resolved "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz#0b6fe7b835aecda61c6ea4d4f02c14221e109847" 2396 | integrity sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg== 2397 | dependencies: 2398 | arr-union "^3.1.0" 2399 | get-value "^2.0.6" 2400 | is-extendable "^0.1.1" 2401 | set-value "^2.0.1" 2402 | 2403 | unset-value@^1.0.0: 2404 | version "1.0.0" 2405 | resolved "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz#8376873f7d2335179ffb1e6fc3a8ed0dfc8ab559" 2406 | integrity sha1-g3aHP30jNRef+x5vw6jtDfyKtVk= 2407 | dependencies: 2408 | has-value "^0.3.1" 2409 | isobject "^3.0.0" 2410 | 2411 | uri-js@^4.2.2: 2412 | version "4.2.2" 2413 | resolved "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz#94c540e1ff772956e2299507c010aea6c8838eb0" 2414 | integrity sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ== 2415 | dependencies: 2416 | punycode "^2.1.0" 2417 | 2418 | urix@^0.1.0: 2419 | version "0.1.0" 2420 | resolved "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72" 2421 | integrity sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI= 2422 | 2423 | url-join@^4.0.0: 2424 | version "4.0.1" 2425 | resolved "https://registry.npmjs.org/url-join/-/url-join-4.0.1.tgz#b642e21a2646808ffa178c4c5fda39844e12cde7" 2426 | integrity sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA== 2427 | 2428 | use@^3.1.0: 2429 | version "3.1.1" 2430 | resolved "https://registry.npmjs.org/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f" 2431 | integrity sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ== 2432 | 2433 | util-deprecate@^1.0.1, util-deprecate@~1.0.1: 2434 | version "1.0.2" 2435 | resolved "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" 2436 | integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= 2437 | 2438 | utile@0.2.1, utile@0.2.x, utile@~0.2.1: 2439 | version "0.2.1" 2440 | resolved "https://registry.npmjs.org/utile/-/utile-0.2.1.tgz#930c88e99098d6220834c356cbd9a770522d90d7" 2441 | integrity sha1-kwyI6ZCY1iIINMNWy9mncFItkNc= 2442 | dependencies: 2443 | async "~0.2.9" 2444 | deep-equal "*" 2445 | i "0.3.x" 2446 | mkdirp "0.x.x" 2447 | ncp "0.4.x" 2448 | rimraf "2.x.x" 2449 | 2450 | utile@~0.3.0: 2451 | version "0.3.0" 2452 | resolved "https://registry.npmjs.org/utile/-/utile-0.3.0.tgz#1352c340eb820e4d8ddba039a4fbfaa32ed4ef3a" 2453 | integrity sha1-E1LDQOuCDk2N26A5pPv6oy7U7zo= 2454 | dependencies: 2455 | async "~0.9.0" 2456 | deep-equal "~0.2.1" 2457 | i "0.3.x" 2458 | mkdirp "0.x.x" 2459 | ncp "1.0.x" 2460 | rimraf "2.x.x" 2461 | 2462 | uuid@^3.3.2: 2463 | version "3.3.3" 2464 | resolved "https://registry.npmjs.org/uuid/-/uuid-3.3.3.tgz#4568f0216e78760ee1dbf3a4d2cf53e224112866" 2465 | integrity sha512-pW0No1RGHgzlpHJO1nsVrHKpOEIxkGg1xB+v0ZmdNH5OAeAwzAVrCnI2/6Mtx+Uys6iaylxa+D3g4j63IKKjSQ== 2466 | 2467 | verror@1.10.0: 2468 | version "1.10.0" 2469 | resolved "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400" 2470 | integrity sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA= 2471 | dependencies: 2472 | assert-plus "^1.0.0" 2473 | core-util-is "1.0.2" 2474 | extsprintf "^1.2.0" 2475 | 2476 | which-pm-runs@^1.0.0: 2477 | version "1.0.0" 2478 | resolved "https://registry.npmjs.org/which-pm-runs/-/which-pm-runs-1.0.0.tgz#670b3afbc552e0b55df6b7780ca74615f23ad1cb" 2479 | integrity sha1-Zws6+8VS4LVd9rd4DKdGFfI60cs= 2480 | 2481 | wide-align@^1.1.0: 2482 | version "1.1.3" 2483 | resolved "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457" 2484 | integrity sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA== 2485 | dependencies: 2486 | string-width "^1.0.2 || 2" 2487 | 2488 | winston@0.8.0: 2489 | version "0.8.0" 2490 | resolved "https://registry.npmjs.org/winston/-/winston-0.8.0.tgz#61d0830fa699706212206b0a2b5ca69a93043668" 2491 | integrity sha1-YdCDD6aZcGISIGsKK1ymmpMENmg= 2492 | dependencies: 2493 | async "0.2.x" 2494 | colors "0.6.x" 2495 | cycle "1.0.x" 2496 | eyes "0.1.x" 2497 | pkginfo "0.3.x" 2498 | stack-trace "0.0.x" 2499 | 2500 | winston@0.8.x, winston@~0.8.1: 2501 | version "0.8.3" 2502 | resolved "https://registry.npmjs.org/winston/-/winston-0.8.3.tgz#64b6abf4cd01adcaefd5009393b1d8e8bec19db0" 2503 | integrity sha1-ZLar9M0Brcrv1QCTk7HY6L7BnbA= 2504 | dependencies: 2505 | async "0.2.x" 2506 | colors "0.6.x" 2507 | cycle "1.0.x" 2508 | eyes "0.1.x" 2509 | isstream "0.1.x" 2510 | pkginfo "0.3.x" 2511 | stack-trace "0.0.x" 2512 | 2513 | "wordwrap@>=0.0.1 <0.1.0", wordwrap@~0.0.2: 2514 | version "0.0.3" 2515 | resolved "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz#a3d5da6cd5c0bc0008d37234bbaf1bed63059107" 2516 | integrity sha1-o9XabNXAvAAI03I0u68b7WMFkQc= 2517 | 2518 | wrappy@1: 2519 | version "1.0.2" 2520 | resolved "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" 2521 | integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= 2522 | 2523 | ws@^7.2.0: 2524 | version "7.2.0" 2525 | resolved "https://registry.npmjs.org/ws/-/ws-7.2.0.tgz#422eda8c02a4b5dba7744ba66eebbd84bcef0ec7" 2526 | integrity sha512-+SqNqFbwTm/0DC18KYzIsMTnEWpLwJsiasW/O17la4iDRRIO9uaHbvKiAS3AHgTiuuWerK/brj4O6MYZkei9xg== 2527 | dependencies: 2528 | async-limiter "^1.0.0" 2529 | 2530 | yallist@^3.0.0, yallist@^3.0.3: 2531 | version "3.1.1" 2532 | resolved "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" 2533 | integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== 2534 | 2535 | zeromq@^5.2.0: 2536 | version "5.2.0" 2537 | resolved "https://registry.npmjs.org/zeromq/-/zeromq-5.2.0.tgz#92eed6baeee5167977e51a2e2360b2c29a3b39fd" 2538 | integrity sha512-qsckhCmrg6et6zrAJytC971SSN/4iLxKgkXK1Wqn2Gij5KXMY+TA+3cy/iFwehaWdU5usg5HNOOgaBdjSqtCVw== 2539 | dependencies: 2540 | nan "^2.14.0" 2541 | prebuild-install "^5.3.2" 2542 | --------------------------------------------------------------------------------