├── .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 |
--------------------------------------------------------------------------------