diff --git a/README.md b/README.md index 0623b54..1861b4d 100644 --- a/README.md +++ b/README.md @@ -21,13 +21,15 @@ See [node-hid's compiling from source instructions](https://github.com/node-hid/ ## Usage ```javascript -var Blink1 = require('node-blink1'); +const Blink1 = require('node-blink1'); ``` Get list of blink(1) devices connected: +* Returns an array of serial numbers + ```javascript -Blink1.devices(); // returns array of serial numbers +Blink1.devices(); ``` Create blink(1) object without serial number, uses first device: @@ -39,95 +41,244 @@ var blink1 = new Blink1(); Create blink(1) object with serial number, to get list of serial numbers use `Blink1.devices()`: +* Accepts an optional Serial Number parameter + ```javascript var blink1 = new Blink1(serialNumber); ``` +### rgbcolor package usage + +This blink1 package natively supports the [rgbcolor package](https://www.npmjs.com/package/rgbcolor). It is not required if you just pass an object containing RGB properties. At any point you see `new Color()` in the example code below, you can replace it with an RGB color object as shown: + +```javascript +// An example color object for the color red +var red = { + r: 255, + g: 0, + b: 0 +}; + +// An few example rgbcolor objects for the color red +const Color = require('rgbcolor'); +var red = new Color('red'); +var red = new Color('rgb(255,0,0)'); +var red = new Color('#FF0000'); +var red = new Color('#F00'); +``` + ### Get version +* Accepts an optional callback function parameter +* Returns Promise; automatically calls optional callback + ```javascript -blink1.version(callback(version)); +blink1.version([callback]).then*(version => { + console.log("Version:", version); +}); ``` ### Set colors -Fade to RGB, optional callback called after `fadeMillis` ms: +Fade to RGB, returns Promise after `delay` ms: + +* Accepts an object containing: + - Required RGBColor object + - Optional delay in ms + - Optional index 0 - 2 (only Mk2 supported) + - Optional callback function +* Returns Promise; automatically calls optional callback ```javascript -blink1.fadeToRGB(fadeMillis, r, g, b, [callback]); // r, g, b: 0 - 255 +const Color = require('rgbcolor'); +let blinkObject = { + color : new Color('orange'), + delay : 1000, + index : 0, + callback : () => {} +}; +blink1.fadeToRGB(blinkObject); +``` + +#### Extended Fade example + +Because most functions return promises, you can now chain actions together. + +This example will cause the device to fade to red over 2.5s, once complete, the device will then fade to green over another 2.5s. -blink1.fadeToRGB(fadeMillis, r, g, b, [index, callback]); // r, g, b: 0 - 255 - // index (mk2 only): 0 - 2 +```javascript +const Color = require('rgbcolor'); +let blinkObject = { + delay : 2500, + color : new Color('red') +}; +blink1.fadeToRGB(blinkObject).then(({red, green, blue}) => { + let blinkObject = { + delay : 2500, + color : new Color('green') + }; + blink1.fadeToRGB(blinkObject); +}); ``` -Set RGB: +Set RGB, returns Promise: + +* Accepts a required RGBColor object +* Accepts an optional callback function +* Returns Promise; automatically calls optional callback ```javascript -blink1.setRGB(r, g, b, [callback]); // r, g, b: 0 - 255 +const Color = require('rgbcolor'); +blink1.setRGB(new Color('red')[, callback]); ``` -Get RGB (mk2 only): +Get current RGB (mk2 only): + +* Accepts an optional index (default is 0) +* Accepts an optional callback function +* Returns Promise; automatically calls optional callback ```javascript -blink1.rgb([index,] callback(r, g, b)); +blink1.getRGB([index][, callback]); ``` +### Turn device off + Off: +* Accepts an optional callback function +* Returns Promise; automatically calls optional callback + ```javascript blink1.off([callback]); ``` ### Other methods -Set server down (enable, disable), optional callback called after `millis` ms: +#### enableServerDown() & disableServerDown() + +Set server down (enable, disable) after `delay` ms: + +* Accepts required delay in ms +* Accepts an optional callback function +* Returns Promise; automatically calls optional callback ```javascript -blink1.enableServerDown(millis, [callback]); // tickle +blink1.enableServerDown(delay[, callback]); // tickle -blink1.disableServerDown(millis, [callback]); // off +blink1.disableServerDown(delay[, callback]); // off ``` +#### play() + Play (start playing the pattern lines at the specified position): +* Accepts required play position +* Accepts an optional callback function +* Returns Promise; automatically calls optional callback + ```javascript -blink1.play(position, [callback]); +blink1.play(position[, callback]); ``` +#### playLoop() + Play Loop (start playing a subset of the pattern lines at specified start and end positions. Specifying count = 0 will loop pattern forever): +* Accepts an object containing: + - Required start position + - Required end position + - Required count + - Optional callback function +* Returns Promise; automatically calls optional callback + ```javascript -blink1.playLoop(startPosition, endPosition, count, [callback]); +let blinkObject = { + start : 1, + end : 2, + count : 2, + callback : () => {} +}; +blink1.playLoop(blinkObject); ``` +#### pause() + Pause (stop playing the pattern line): +* Accepts an optional callback function +* Returns Promise; automatically calls optional callback + ```javascript blink1.pause([callback]); ``` +#### writePatternLine() + Write pattern line (set the parameters for a pattern line, at the specified position): +* Accepts an object containing: + - Required RGBColor object + - Required delay in ms + - Required position + - Optional callback function +* Returns Promise; automatically calls optional callback + ```javascript -blink1.writePatternLine(fadeMillis, r, g, b, position, [callback]) // r, g, b: 0 - 255 +const Color = require('rgbcolor'); +let blinkObject = { + color : new Color('red'), + delay : 100, + position : 2, + callback : () => {} +}; +blink1.writePatternLine(blinkObject); ```` A simple example of this, used to flash red on & off is: ```javascript -blink1.writePatternLine(200, 255, 0, 0, 0); -blink1.writePatternLine(200, 0, 0, 0, 1); +const Color = require('rgbcolor'); +let blinkObject = { + delay : 200, + color : new Color('red') + position : 0 +}; +let blinkObject2 = { + delay : 200, + color : new Color('black') + position : 1 +}; +blink1.writePatternLine(blinkObject); +blink1.writePatternLine(blinkObject2); blink1.play(0); ``` +#### readPatternLine() + Read pattern line (at the position): +* Accepts a required position +* Accepts an optional callback function +* Returns Promise; automatically calls optional callback + ```javascript -blink1.readPatternLine(position, [callback]) +blink1.readPatternLine(position[, callback]).then(({ + color, + delay +}) => { + // readPatternLine values +}); ``` +#### close() + Close (the underlying HID device): +* Accepts an optional callback function +* Returns Promise; automatically calls optional callback + + ```javascript blink1.close([callback]); ``` diff --git a/base.js b/base.js new file mode 100644 index 0000000..da05b04 --- /dev/null +++ b/base.js @@ -0,0 +1,76 @@ +const HID = require('node-hid'); +const _ = require('lodash'); + +/********** + * CONFIG * + **********/ + +const VENDOR_ID = 0x27B8; +const PRODUCT_ID = 0x01ED; + +const REPORT_ID = 1; +const REPORT_LENGTH = 9; + +class Blink1_Base { + constructor(serialNumber) { + let blink1HIDdevices = Blink1_Base._blink1HIDdevices(); + + if (blink1HIDdevices.length === 0) { + throw new Error('No blink(1)\'s could be found'); + } + + var blink1HIDdevicePath = null; + + if (serialNumber === undefined) { + serialNumber = blink1HIDdevices[0].serialNumber; + } + + _.find(blink1HIDdevices, (blink1HIDdevice) => { + if (serialNumber === blink1HIDdevice.serialNumber) { + blink1HIDdevicePath = blink1HIDdevice.path; + } + + return (blink1HIDdevicePath !== null); + }); + + if (blink1HIDdevicePath === null) { + throw new Error('No blink(1)\'s with serial number ' + serialNumber + ' could be found'); + } + + this.serialNumber = serialNumber; + this.hidDevice = new HID.HID(blink1HIDdevicePath); + } + + static _blink1HIDdevices() { + return HID.devices(VENDOR_ID, PRODUCT_ID); + }; + + static devices() { + return _.map(Blink1_Base._blink1HIDdevices(), ({ serialNumber }) => serialNumber); + }; + + // Hardware API + + _sendCommand(/* command [, args ...]*/) { + var featureReport = [REPORT_ID, 0, 0, 0, 0, 0, 0, 0, 0]; + + _.forEach(arguments, (argument, k) => { + if (k === 0) { + featureReport[1] = argument.charCodeAt(0); + return; + } + + featureReport[k + 1] = argument; + }); + + this.hidDevice.sendFeatureReport(featureReport); + } + + _readResponse() { + return new Promise((resolve, reject) => { + resolve(this.hidDevice.getFeatureReport(REPORT_ID, REPORT_LENGTH)); + }); + } +} + +module.exports = Blink1_Base; diff --git a/blink1.js b/blink1.js index ae09bbc..c3c774e 100644 --- a/blink1.js +++ b/blink1.js @@ -1,321 +1,314 @@ -var HID = require('node-hid'); +const Color = require('rgbcolor'); +const Blink1_Validators = require('./validators'); -var VENDOR_ID = 0x27B8; -var PRODUCT_ID = 0x01ED; - -var REPORT_ID = 1; -var REPORT_LENGTH = 9; - -var _blink1HIDdevices = function() { - return HID.devices(VENDOR_ID, PRODUCT_ID); -}; - -var devices = function() { - var serialNumbers = []; - - _blink1HIDdevices().forEach(function(device) { - serialNumbers.push(device.serialNumber); - }); - - return serialNumbers; -}; - -function Blink1(serialNumber) { - var blink1HIDdevices = _blink1HIDdevices(); - - if (blink1HIDdevices.length === 0) { - throw new Error('No blink(1)\'s could be found'); - } - - var blink1HIDdevicePath = null; - - if (serialNumber === undefined) { - serialNumber = blink1HIDdevices[0].serialNumber; - } - - blink1HIDdevices.some(function(blink1HIDdevice) { - if (serialNumber === blink1HIDdevice.serialNumber) { - blink1HIDdevicePath = blink1HIDdevice.path; +class Blink1 extends Blink1_Validators { + constructor(serialNumber) { + super(serialNumber); } - return (blink1HIDdevicePath !== null); - }); - - if (blink1HIDdevicePath === null) { - throw new Error('No blink(1)\'s with serial number ' + serialNumber + ' could be found'); - } - - this.serialNumber = serialNumber; - this.hidDevice = new HID.HID(blink1HIDdevicePath); -} - -Blink1.prototype._sendCommand = function(/* command [, args ...]*/) { - var featureReport = [REPORT_ID, 0, 0, 0, 0, 0, 0, 0, 0]; - - featureReport[1] = arguments[0].charCodeAt(0); - - for (var i = 1; i < arguments.length; i++) { - featureReport[i + 1] = arguments[i]; - } + // API - this.hidDevice.sendFeatureReport(featureReport); -}; + version(callback = () => {}) { + const promise = new Promise((resolve, reject) => { + try { + this._isValidCallback(callback); + } catch(error) { + reject(error); + } -Blink1.prototype._isValidCallback = function(callback) { - return (typeof callback === 'function'); -}; + this._sendCommand('v'); -Blink1.prototype._validateNumber = function(number, name, min, max) { - if (typeof number !== 'number') { - throw new Error(name + ' must be a number'); - } + this._readResponse().then(response => { + resolve(String.fromCharCode(response[3]) + '.' + String.fromCharCode(response[4])); + }); + }); - if (number < min || number > max) { - throw new Error(name + ' must be between ' + min + ' and ' + max); - } -}; - -Blink1.prototype._validateAddress = function(address) { - this._validateNumber(address, 'address', 0, 0xffff); -}; - -Blink1.prototype._validateValue = function(value) { - this._validateNumber(value, 'value', 0, 0xff); -}; - -Blink1.prototype._validateCount = function(value) { - this._validateNumber(value, 'count', 0, 0xff); -}; - -Blink1.prototype._validateFadeMillis = function(fadeMillis) { - this._validateNumber(fadeMillis, 'fadeMillis', 0, 0x9FFF6); -}; - -Blink1.prototype._validateRGB = function(r, g, b) { - this._validateNumber(r, 'r', 0, 0xff); - this._validateNumber(g, 'g', 0, 0xff); - this._validateNumber(b, 'b', 0, 0xff); -}; - -Blink1.prototype._validateMillis = function(millis) { - this._validateNumber(millis, 'millis', 0, 0x9FFF6); -}; - -Blink1.prototype._validatePosition = function(position) { - this._validateNumber(position, 'position', 0, 11); -}; - -Blink1.prototype._validateIndex = function(index) { - this._validateNumber(index, 'index', 0, 2); -}; - -Blink1.prototype._readResponse = function(callback) { - if (this._isValidCallback(callback)) { - callback.apply(this, [this.hidDevice.getFeatureReport(REPORT_ID, REPORT_LENGTH)]); - } -}; - -Blink1.prototype.version = function(callback) { - this._sendCommand('v'); - - this._readResponse(function(response) { - var version = String.fromCharCode(response[3]) + '.' + String.fromCharCode(response[4]); - - if(this._isValidCallback(callback)) { - callback(version); + return this._returnCallbackPromise(promise, callback); } - }); -}; -Blink1.prototype.eeRead = function(address, callback) { - this._validateAddress(address); + eeRead(address, callback = () => {}) { + const promise = new Promise((resolve, reject) => { + try { + this._validateAddress(address); + this._isValidCallback(callback); + } catch(error) { + reject(error); + } - this._sendCommand('e', address); + this._sendCommand('e', address); - this._readResponse(function(response) { - var value = response[3]; + this._readResponse().then(response => { + resolve(response[3]); + }); + }); - if(this._isValidCallback(callback)) { - callback(value); + return this._returnCallbackPromise(promise, callback); } - }); -}; - -Blink1.prototype.eeWrite = function(address, value, callback) { - this._validateAddress(address); - this._validateValue(value); - - this._sendCommand('E', address, value); - - if(this._isValidCallback(callback)) { - callback(); - } -}; -Blink1.prototype.degamma = function(n) { - return Math.floor(((1 << Math.floor(n / 32)) - 1) + - Math.floor((1 << Math.floor(n / 32)) * Math.floor((n % 32) + 1) + 15) / 32); -}; + eeWrite(address, value, callback = () => {}) { + const promise = new Promise((resolve, reject) => { + try { + this._validateAddress(address); + this._validateValue(value); + this._isValidCallback(callback); + } catch(error) { + reject(error); + } + this._sendCommand('E', address, value); -Blink1.prototype.fadeToRGB = function(fadeMillis, r, g, b, index, callback) { - this._validateFadeMillis(fadeMillis); - this._validateRGB(r, g, b); + this._readResponse().then(() => { + resolve(); + }); + }); - var dms = fadeMillis / 10; - - if (this._isValidCallback(index)) { - // backwards compatible API, no index - callback = index; - index = 0; - } else if (index === undefined) { - index = 0; - } - - this._validateIndex(index); - - this._sendCommand('c', this.degamma(r), this.degamma(g), this.degamma(b), dms >> 8, dms % 0xff, index); - - if(this._isValidCallback(callback)) { - setTimeout(callback, fadeMillis); - } -}; - -Blink1.prototype.setRGB = function(r, g, b, callback) { - this._validateRGB(r, g, b); - - this._sendCommand('n', this.degamma(r), this.degamma(g), this.degamma(b)); - - if(this._isValidCallback(callback)) { - callback(); - } -}; - - -Blink1.prototype.off = function(callback) { - this.setRGB(0, 0, 0, callback); -}; - -Blink1.prototype.rgb = function(index, callback) { - if (this._isValidCallback(index)) { - callback = index; - index = 0; - } else if (index === undefined) { - index = 0; - } - - this._sendCommand('r', index, 0, 0, 0, 0, index); - - this._readResponse(function(response) { - var r = response[2]; - var g = response[3]; - var b = response[4]; - - if(this._isValidCallback(callback)) { - callback(r, g, b); + return this._returnCallbackPromise(promise, callback); } - }); -}; - -Blink1.prototype._serverDown = function(on, millis, callback) { - var dms = millis / 10; - - this._sendCommand('D', on, dms >> 8, dms % 0xff); - if(this._isValidCallback(callback)) { - setTimeout(callback, millis); - } -}; - -Blink1.prototype.enableServerDown = function(millis, callback) { - this._validateMillis(millis); + degamma(n) { + // Allow pass-through r,g,b values + if (!this.doDegamma) { + return n; + } + + return Math.floor( + ((1 << Math.floor(n / 32)) - 1) + + Math.floor( + (1 << Math.floor(n / 32)) * Math.floor((n % 32) + 1) + 15 + ) / 32); + } - this._serverDown(1, millis, callback); -}; + fadeToRGB({ + delay, + color, + index = 0, + callback = () => {} + }) { + const promise = new Promise((resolve, reject) => { + try { + this._validateFadeMillis(delay); + this._validateRGB(color); + this._validateIndex(index); + this._isValidCallback(callback); + } catch(error) { + reject(error); + } + + let dms = delay / 10; + this._sendCommand('c', this.degamma(color.r), this.degamma(color.g), this.degamma(color.b), dms >> 8, dms % 0xff, index); + + setTimeout(() => resolve({ + color, + index + }), delay); + }); + + return this._returnCallbackPromise(promise, callback); + } -Blink1.prototype.disableServerDown = function(millis, callback) { - this._validateMillis(millis); + setRGB(color, callback = () => {}) { + const promise = new Promise((resolve, reject) => { + try { + this._validateRGB(color); + this._isValidCallback(callback); + } catch(error) { + reject(error); + } - this._serverDown(0, millis, callback); -}; + this._sendCommand('n', this.degamma(color.r), this.degamma(color.g), this.degamma(color.b)); + resolve(color); + }); -Blink1.prototype._play = function(play, position, callback) { - this._sendCommand('p', play, position); + return this._returnCallbackPromise(promise, callback); + } - if(this._isValidCallback(callback)) { - callback(); - } -}; + off(callback = () => {}) { + const promise = new Promise((resolve, reject) => { + try { + this._isValidCallback(callback); + } catch(error) { + reject(error); + } -Blink1.prototype.play = function(position, callback) { - this._validatePosition(position); + this.setRGB(new Color('black')).then(response => { + resolve(response); + }); + }); - this._play(1, position, callback); -}; + return this._returnCallbackPromise(promise, callback); + } -Blink1.prototype._playLoop = function(play, position, endPosition, count, callback) { - this._sendCommand('p', play, position, endPosition, count); + getRGB(index = 0, callback = () => {}) { + const promise = new Promise((resolve, reject) => { + try { + this._isValidCallback(callback); + } catch(error) { + reject(error); + } - if(this._isValidCallback(callback)) { - callback(); - } -}; + this._sendCommand('r', index, 0, 0, 0, 0, index); -Blink1.prototype.playLoop = function(startPosition, endPosition, count, callback) { - this._validatePosition(startPosition); - this._validatePosition(endPosition); - this._validateCount(count); + this._readResponse().then(response => { + resolve(new Color('rgb('+response[2]+','+response[3]+','+response[4]+')')); + }); + }); - this._playLoop(1, startPosition, endPosition, count, callback); -}; + return this._returnCallbackPromise(promise, callback); + } -Blink1.prototype.pause = function(callback) { - this._play(0, 0, callback); -}; + enableServerDown(delay, callback = () => {}) { + const promise = new Promise((resolve, reject) => { + try { + this._validateMillis(delay); + this._isValidCallback(callback); + } catch(error) { + reject(error); + } + + this._serverDown(1, delay).then(response => { + resolve(); + }); + }); + + return this._returnCallbackPromise(promise, callback); + } -Blink1.prototype.writePatternLine = function(fadeMillis, r, g, b, position, callback) { - this._validateFadeMillis(fadeMillis); - this._validateRGB(r, g, b); - this._validatePosition(position); + disableServerDown(delay, callback = () => {}) { + const promise = new Promise((resolve, reject) => { + try { + this._validateMillis(delay); + this._isValidCallback(callback); + } catch(error) { + reject(error); + } + + this._serverDown(0, delay).then(response => { + resolve(); + }); + }); + + return this._returnCallbackPromise(promise, callback); + } - var dms = fadeMillis / 10; + play(position, callback = () => {}) { + const promise = new Promise((resolve, reject) => { + try { + this._validatePosition(position); + this._isValidCallback(callback); + } catch(error) { + reject(error); + } + + this._play(1, position).then(response => { + resolve(); + }); + }); + + return this._returnCallbackPromise(promise, callback); + } - this._sendCommand('P', this.degamma(r), this.degamma(g), this.degamma(b), dms >> 8, dms % 0xff, position, 0); + playLoop({ + start, + end, + count, + callback = () => {} + }) { + const promise = new Promise((resolve, reject) => { + try { + this._validatePosition(start); + this._validatePosition(end); + this._validateCount(count); + this._isValidCallback(callback); + } catch(error) { + reject(error); + } + + this._playLoop(1, start, end, count).then(() => { + resolve(); + }).catch(error => { + reject(error); + }); + }); + + return this._returnCallbackPromise(promise, callback); + } - if(this._isValidCallback(callback)) { - callback(); - } -}; + pause(callback = () => {}) { + const promise = new Promise((resolve, reject) => { + try { + this._isValidCallback(callback); + } catch(error) { + reject(error); + } -Blink1.prototype.readPatternLine = function(position, callback) { - this._validatePosition(position); + this._play(0, 0).then(() => { + resolve(); + }); + }); - this._sendCommand('R', 0, 0, 0, 0, 0, position, 0); + return this._returnCallbackPromise(promise, callback); + } - this._readResponse(function(response) { - var value = { - r: response[2], - g: response[3], - b: response[4], - fadeMillis: ((response[5] << 8) + (response[6] & 0xff)) * 10 - }; + writePatternLine({ + delay, + color, + position, + callback = () => {} + }) { + const promise = new Promise((resolve, reject) => { + try { + this._validateFadeMillis(delay); + this._validateRGB(color); + this._validatePosition(position); + this._isValidCallback(callback); + } catch(error) { + reject(error); + } + + let dms = delay / 10; + this._sendCommand('P', this.degamma(color.r), this.degamma(color.g), this.degamma(color.b), dms >> 8, dms % 0xff, position, 0); + resolve(); + }); + + return this._returnCallbackPromise(promise, callback); + } - if(this._isValidCallback(callback)) { - callback(value); + readPatternLine(position, callback = () => {}) { + const promise = new Promise((resolve, reject) => { + try { + this._validatePosition(position); + this._isValidCallback(callback); + } catch(error) { + reject(error); + } + + this._sendCommand('R', 0, 0, 0, 0, 0, position, 0); + + this._readResponse().then(response => { + resolve({ + color: new Color('rgb('+response[2]+','+response[3]+','+response[4]+')'), + delay : ((response[5] << 8) + (response[6] & 0xff)) * 10 + }); + }); + }); + + return this._returnCallbackPromise(promise, callback); } - }); -}; -Blink1.prototype.close = function(callback) { - this.hidDevice.close(); + close(callback = () => {}) { + const promise = new Promise((resolve, reject) => { + try { + this._isValidCallback(callback); + } catch(error) { + reject(error); + } - if(this._isValidCallback(callback)) { - callback(); - } -}; + this.hidDevice.close(); + resolve(); + }); -Blink1.devices = devices; + return this._returnCallbackPromise(promise, callback); + } +} module.exports = Blink1; -module.exports.Blink1 = Blink1; // backwards compatibility with older version - diff --git a/examples/cops.js b/examples/cops.js new file mode 100644 index 0000000..3697522 --- /dev/null +++ b/examples/cops.js @@ -0,0 +1,25 @@ +const Blink1 = require('../blink1'); +const Color = require('rgbcolor'); + +let d = Blink1.devices()[0]; +let b = new Blink1(d); +callTheCops({r: 255, g: 0, b: 0}, 1); +callTheCops({r: 0, g: 0, b: 255}, 2); + +function callTheCops(color, index) { + b.fadeToRGB({ + color, + delay: 100, + index, + callback: (data) => { + console.log("finished", data); + } + }).then(data => { + if (data.color.r == 255) { + newColor = {r: 0, g: 0, b: 255}; + } else { + newColor = {r: 255, g: 0, b: 0}; + } + callTheCops(newColor, index); + }); +} diff --git a/helpers.js b/helpers.js new file mode 100644 index 0000000..8bc8a2c --- /dev/null +++ b/helpers.js @@ -0,0 +1,50 @@ +const Blink1_Base = require('./base'); + +class Blink1_Helpers extends Blink1_Base { + constructor(serialNumber) { + super(serialNumber); + } + + // Helpers + + _returnCallbackPromise(promise, callback) { + try { + this._isValidCallback(callback); + } catch(error) { + return promise; + } + + promise.then(callback); + return promise; + } + + _serverDown(on, delay) { + return new Promise(resolve => { + let dms = delay / 10; + this._sendCommand('D', on, dms >> 8, dms % 0xff); + + setTimeout(resolve, delay); + }); + } + + _play(play, position) { + return new Promise(resolve => { + this._sendCommand('p', play, position); + resolve(); + }); + } + + _playLoop({ + play, + start, + end, + count + }) { + return new Promise(resolve => { + this._sendCommand('p', play, start, end, count); + resolve(); + }); + } +} + +module.exports = Blink1_Helpers; diff --git a/package.json b/package.json index 56e229f..f800a06 100644 --- a/package.json +++ b/package.json @@ -19,15 +19,17 @@ "blink(1)", "blink1" ], - "dependencies": { - "node-hid": "~0.5.0" - }, "devDependencies": { - "jshint": "latest", - "mocha": "latest", - "should": "latest", - "mockery": "latest", - "async": "~0.9.0" + "async": "^2.6.0", + "jshint": "^2.9.5", + "mocha": "^5.0.0", + "mockery": "^2.1.0", + "should": "^13.2.1" + }, + "dependencies": { + "lodash": "^4.17.4", + "node-hid": "^0.7.2", + "rgbcolor": "^1.0.1" }, "scripts": { "pretest": "jshint *.js", diff --git a/unit-tests.js b/unit-tests.js index c1bb408..7367582 100644 --- a/unit-tests.js +++ b/unit-tests.js @@ -1,8 +1,9 @@ +var Color = require('rgbcolor'); var should = require('should'); var mockery = require('mockery'); -describe('blink(1)', function() { +describe('blink(1)', () => { var BLINK1_SRC_PATH = './blink1'; var VENDOR_ID = 0x27B8; @@ -78,24 +79,24 @@ describe('blink(1)', function() { sentFeatureReport = null; }); - describe('#devices', function() { + describe('#devices', () => { - it('should return no serial numbers when there are no blink(1) HID devices', function() { + it('should return no serial numbers when there are no blink(1) HID devices', () => { mockHIDdevices = []; Blink1.devices().should.have.length(0); }); - it('should return two serial numbers when there are two blink(1) HID devices', function() { + it('should return two serial numbers when there are two blink(1) HID devices', () => { mockHIDdevices = [MOCK_HID_DEVICE_1, MOCK_HID_DEVICE_2]; Blink1.devices().should.eql([MOCK_HID_DEVICE_1_SERIAL_NUMBER, MOCK_HID_DEVICE_2_SERIAL_NUMBER]); }); }); - describe('#Blink1', function() { + describe('#Blink1', () => { - it('should throw an error when there are no blink(1) HID devices', function() { + it('should reject (catch) promise when there are no blink(1) HID devices', () => { mockHIDdevices = []; (function(){ @@ -103,13 +104,13 @@ describe('blink(1)', function() { }).should.throwError('No blink(1)\'s could be found'); }); - it('should not throw an error when there are blink(1) HID devices', function() { + it('should not throw an error when there are blink(1) HID devices', () => { mockHIDdevices = [MOCK_HID_DEVICE_1]; new Blink1(); }); - it('should throw an error when there are no blink(1) HID devices with the supplied serial number', function() { + it('should reject (catch) promise when there are no blink(1) HID devices with the supplied serial number', () => { mockHIDdevices = [MOCK_HID_DEVICE_1]; (function(){ @@ -117,27 +118,27 @@ describe('blink(1)', function() { }).should.throwError('No blink(1)\'s with serial number ' + MOCK_HID_DEVICE_2_SERIAL_NUMBER + ' could be found'); }); - it('should not throw an error when there are blink(1) HID devices with the supplied serial number', function() { + it('should not throw an error when there are blink(1) HID devices with the supplied serial number', () => { mockHIDdevices = [MOCK_HID_DEVICE_1]; new Blink1(MOCK_HID_DEVICE_1_SERIAL_NUMBER); }); - it('should store correct serial number', function() { + it('should store correct serial number', () => { mockHIDdevices = [MOCK_HID_DEVICE_1]; var blink1 = new Blink1(MOCK_HID_DEVICE_1_SERIAL_NUMBER); blink1.serialNumber.should.eql(MOCK_HID_DEVICE_1_SERIAL_NUMBER); }); - it('should select first blink(1) HID device when no serial number is supplied', function() { + it('should select first blink(1) HID device when no serial number is supplied', () => { mockHIDdevices = [MOCK_HID_DEVICE_1, MOCK_HID_DEVICE_2]; var blink1 = new Blink1(); blink1.serialNumber.should.eql(MOCK_HID_DEVICE_1_SERIAL_NUMBER); }); - it('should open correct HID device path', function() { + it('should open correct HID device path', () => { mockHIDdevices = [MOCK_HID_DEVICE_1, MOCK_HID_DEVICE_2]; var blink1 = new Blink1(MOCK_HID_DEVICE_1_SERIAL_NUMBER); @@ -158,7 +159,7 @@ describe('blink(1)', function() { blink1 = null; }; - describe('#Blink1.version', function() { + describe('#Blink1.version', () => { beforeEach(function() { setupBlink1(); @@ -167,28 +168,28 @@ describe('blink(1)', function() { }); afterEach(teardownBlink1); - it('should send version feature report', function() { + it('should send version feature report', () => { blink1.version(); sentFeatureReport.should.eql([FEATURE_REPORT_ID, 0x76, 0, 0, 0, 0, 0, 0, 0]); }); - it('should call back with version', function(done) { - blink1.version(function(version) { + it('should resolve promise with version', (done) => { + blink1.version().then(version => { done(); }); }); - it('should call back with correct version', function(done) { + it('should resolve promise with correct version', (done) => { - blink1.version(function(version) { + blink1.version().then(version => { version.should.eql('1.0'); done(); }); }); }); - describe('#Blink1.eeRead', function() { + describe('#Blink1.eeRead', () => { var ADDRESS = 1; var VALUE = 5; @@ -200,46 +201,52 @@ describe('blink(1)', function() { }); afterEach(teardownBlink1); - it('should throw an error when address is not a number', function() { + it('should reject (catch) promise when address is not a number', () => { (function(){ - blink1.eeRead('Bad address'); - }).should.throwError('address must be a number'); + blink1.eeRead('Bad address').catch((error) => { + error.should.eql("Bad address must be a number") + }); + }) }); - it('should throw an error when address is less than 0', function() { + it('should reject (catch) promise when address is less than 0', () => { (function(){ - blink1.eeRead(-1); - }).should.throwError('address must be between 0 and 65535'); + blink1.eeRead(-1).catch((error) => { + error.should.eql("address must be between 0 and 65535") + }); + }) }); - it('should throw an error when address is greater than 65535', function() { + it('should reject (catch) promise when address is greater than 65535', () => { (function(){ - blink1.eeRead(65536); - }).should.throwError('address must be between 0 and 65535'); + blink1.eeRead(65536).catch((error) => { + error.should.eql("address must be between 0 and 65535") + }); + }) }); - it('should send eeread feature report', function() { + it('should send eeread feature report', () => { blink1.eeRead(ADDRESS); sentFeatureReport.should.eql([FEATURE_REPORT_ID, 0x65, 1, 0, 0, 0, 0, 0, 0]); }); - it('should call back with value', function(done) { - blink1.eeRead(ADDRESS, function(value) { + it('should resolve promise with value', (done) => { + blink1.eeRead(ADDRESS).then(value => { done(); }); }); - it('should call back with correct value', function(done) { + it('should resolve promise with correct value', (done) => { - blink1.eeRead(ADDRESS, function(value) { + blink1.eeRead(ADDRESS).then(value => { value.should.eql(VALUE); done(); }); }); }); - describe('#Blink1.eeWrite', function() { + describe('#Blink1.eeWrite', () => { var ADDRESS = 1; var VALUE = 5; @@ -247,54 +254,68 @@ describe('blink(1)', function() { beforeEach(setupBlink1); afterEach(teardownBlink1); - it('should throw an error when address is not a number', function() { + it('should reject (catch) promise when address is not a number', () => { (function(){ - blink1.eeWrite('Bad address', VALUE); - }).should.throwError('address must be a number'); + blink1.eeWrite('Bad address', VALUE).catch(error => { + error.should.eql("bad address must be a number"); + }); + }) }); - it('should throw an error when address is less than 0', function() { + it('should reject (catch) promise when address is less than 0', () => { (function(){ - blink1.eeWrite(-1, VALUE); - }).should.throwError('address must be between 0 and 65535'); + blink1.eeWrite(-1, VALUE).catch(error => { + error.should.eql("address must be between 0 and 65535"); + }); + }) }); - it('should throw an error when address is greater than 65535', function() { + it('should reject (catch) promise when address is greater than 65535', () => { (function(){ - blink1.eeWrite(65536, VALUE); - }).should.throwError('address must be between 0 and 65535'); + blink1.eeWrite(65536, VALUE).catch(error => { + error.should.eql("address must be between 0 and 65535"); + }); + }) }); - it('should throw an error when value is not a number', function() { + it('should reject (catch) promise when value is not a number', () => { (function(){ - blink1.eeWrite(ADDRESS, 'Bad value'); - }).should.throwError('value must be a number'); + blink1.eeWrite(ADDRESS, 'Bad value').catch(error => { + error.should.eql("Bad value must be a number"); + }); + }) }); - it('should throw an error when value is less than 0', function() { + it('should reject (catch) promise when value is less than 0', () => { (function(){ - blink1.eeWrite(ADDRESS, -1); - }).should.throwError('value must be between 0 and 255'); + blink1.eeWrite(ADDRESS, -1).catch(error => { + error.should.eql("value must be between 0 and 255"); + }); + }) }); - it('should throw an error when value is greater than 255', function() { + it('should reject (catch) promise when value is greater than 255', () => { (function(){ - blink1.eeWrite(ADDRESS, 256); - }).should.throwError('value must be between 0 and 255'); + blink1.eeWrite(ADDRESS, 256).catch(error => { + error.should.eql("value must be between 0 and 255"); + }); + }) }); - it('should send eewrite feature report', function() { + it('should send eewrite feature report', () => { blink1.eeWrite(ADDRESS, VALUE); sentFeatureReport.should.eql([FEATURE_REPORT_ID, 0x45, ADDRESS, VALUE, 0, 0, 0, 0, 0]); }); - it('should call back', function(done) { - blink1.eeWrite(ADDRESS, VALUE, done); + it('should resolve promise', (done) => { + blink1.eeWrite(ADDRESS, VALUE).then(() => { + done(); + }); }); }); - describe('#Blink1.fadeToRGB', function() { + describe('#Blink1.fadeToRGB', () => { var FADE_MILLIS = 10; var R = 10; var G = 20; @@ -304,112 +325,202 @@ describe('blink(1)', function() { beforeEach(setupBlink1); afterEach(teardownBlink1); - it('should throw an error when fadeMillis is not a number', function() { + it('should reject (catch) promise when fadeMillis is not a number', () => { (function(){ - blink1.fadeToRGB('Bad fadeMillis', R, G, B); - }).should.throwError('fadeMillis must be a number'); + blink1.fadeToRGB({ + delay : 'Bad fadeMillis', + color : new Color('rgb('+R+','+G+','+B+')') + }).catch(error => { + error.should.eql("fadeMillis must be a number"); + }); + }); }); - it('should throw an error when fadeMillis is less than 0', function() { + it('should reject (catch) promise when fadeMillis is less than 0', () => { (function(){ - blink1.fadeToRGB(-1, R, G, B); - }).should.throwError('fadeMillis must be between 0 and 655350'); + blink1.fadeToRGB({ + delay : -1, + color : new Color('rgb('+R+','+G+','+B+')') + }).catch(error => { + error.should.eql("fadeMillis must be between 0 and 655350"); + }); + }); }); - it('should throw an error when fadeMillis is greater than 655350', function() { + it('should reject (catch) promise when fadeMillis is greater than 655350', () => { (function(){ - blink1.fadeToRGB(655351, R, G, B); - }).should.throwError('fadeMillis must be between 0 and 655350'); + blink1.fadeToRGB({ + delay : 655351, + color : new Color('rgb('+R+','+G+','+B+')') + }).catch(error => { + error.should.eql("fadeMillis must be between 0 and 655350"); + }); + }); }); - it('should throw an error when r is not a number', function() { + it('should reject (catch) promise when r is not a number', () => { (function(){ - blink1.fadeToRGB(FADE_MILLIS, 'Bad r', G, B); - }).should.throwError('r must be a number'); + blink1.fadeToRGB({ + delay : FADE_MILLIS, + color : new Color('rgb('+R+','+G+','+B+')') + }).catch(error => { + error.should.eql("r must be a number"); + }); + }); }); - it('should throw an error when r is less than 0', function() { + it('should reject (catch) promise when r is less than 0', () => { (function(){ - blink1.fadeToRGB(FADE_MILLIS, -1, G, B); - }).should.throwError('r must be between 0 and 255'); + blink1.fadeToRGB({ + delay : FADE_MILLIS, + color : new Color('rgb('+-1+','+G+','+B+')') + }).catch(error => { + error.should.eql("r must be between 0 and 255"); + }); + }); }); - it('should throw an error when r is greater than 255', function() { + it('should reject (catch) promise when r is greater than 255', () => { (function(){ - blink1.fadeToRGB(FADE_MILLIS, 256, G, B); - }).should.throwError('r must be between 0 and 255'); + blink1.fadeToRGB({ + delay : FADE_MILLIS, + color : new Color('rgb('+256+','+G+','+B+')') + }).catch(error => { + error.should.eql("r must be between 0 and 255"); + }); + }); }); - it('should throw an error when g is not a number', function() { + it('should reject (catch) promise when g is not a number', () => { (function(){ - blink1.fadeToRGB(FADE_MILLIS, R, 'Bad g', B); - }).should.throwError('g must be a number'); + blink1.fadeToRGB({ + delay : FADE_MILLIS, + color : new Color('rgb('+R+',Bad g,'+B+')') + }).catch(error => { + error.should.eql("g must be a number"); + }); + }); }); - it('should throw an error when g is less than 0', function() { + it('should reject (catch) promise when g is less than 0', () => { (function(){ - blink1.fadeToRGB(FADE_MILLIS, R, -1, B); - }).should.throwError('g must be between 0 and 255'); + blink1.fadeToRGB({ + delay : FADE_MILLIS, + color : new Color('rgb('+R+','+-1+','+B+')') + }).catch(error => { + error.should.eql("g must be between 0 and 255"); + }); + }); }); - it('should throw an error when g is greater than 255', function() { + it('should reject (catch) promise when g is greater than 255', () => { (function(){ - blink1.fadeToRGB(FADE_MILLIS, R, 256, B); - }).should.throwError('g must be between 0 and 255'); + blink1.fadeToRGB({ + delay : FADE_MILLIS, + color : new Color('rgb('+R+','+256+','+B+')') + }).catch(error => { + error.should.eql("g must be between 0 and 255"); + }); + }); }); - it('should throw an error when b is not a number', function() { + it('should reject (catch) promise when b is not a number', () => { (function(){ - blink1.fadeToRGB(FADE_MILLIS, R, G, 'Bad b'); - }).should.throwError('b must be a number'); + blink1.fadeToRGB({ + delay : FADE_MILLIS, + color : new Color('rgb('+R+','+G+',Bad b)') + }).catch(error => { + error.should.eql("b must be a number"); + }); + }); }); - it('should throw an error when b is less than 0', function() { + it('should reject (catch) promise when b is less than 0', () => { (function(){ - blink1.fadeToRGB(FADE_MILLIS, R, G, -1); - }).should.throwError('b must be between 0 and 255'); + blink1.fadeToRGB({ + delay : FADE_MILLIS, + color : new Color('rgb('+R+','+G+','+-1+')') + }).catch(error => { + error.should.eql("b must be between 0 and 255"); + }); + }); }); - it('should throw an error when b is greater than 255', function() { + it('should reject (catch) promise when b is greater than 255', () => { (function(){ - blink1.fadeToRGB(FADE_MILLIS, R, G, 256); - }).should.throwError('b must be between 0 and 255'); + blink1.fadeToRGB({ + delay : FADE_MILLIS, + color : new Color('rgb('+R+','+G+','+256+')') + }).catch(error => { + error.should.eql("b must be between 0 and 255"); + }); + }); }); - it('should send fadetorgb feature report', function() { - blink1.fadeToRGB(FADE_MILLIS, R, G, B); + it('should send fadetorgb feature report', () => { + blink1.fadeToRGB({ + delay : FADE_MILLIS, + color : new Color('rgb('+R+','+G+','+B+')') + }); sentFeatureReport.should.eql([FEATURE_REPORT_ID, 0x63, blink1.degamma(R), blink1.degamma(G), blink1.degamma(B), (FADE_MILLIS / 10) >> 8, (FADE_MILLIS / 10) % 0xff, 0, 0]); }); - it('should call back', function(done) { - blink1.fadeToRGB(FADE_MILLIS, blink1.degamma(R), blink1.degamma(G), blink1.degamma(B), done); + it('should resolve promise', (done) => { + blink1.fadeToRGB({ + delay : FADE_MILLIS, + color : new Color('rgb('+R+','+G+','+B+')') + }).then(() => { + done(); + }); }); - it('should throw an error when index is less than 0', function() { + it('should reject (catch) promise when index is less than 0', () => { (function(){ - blink1.fadeToRGB(FADE_MILLIS, R, G, B, -1); - }).should.throwError('index must be between 0 and 2'); + blink1.fadeToRGB({ + delay : FADE_MILLIS, + color : new Color('rgb('+R+','+G+','+B+')'), + index : -1 + }).catch(error => { + error.should.eql("index must be between 0 and 2"); + }); + }); }); - it('should throw an error when index is greater than 2', function() { + it('should reject (catch) promise when index is greater than 2', () => { (function(){ - blink1.fadeToRGB(FADE_MILLIS, R, G, B, 3); - }).should.throwError('index must be between 0 and 2'); + blink1.fadeToRGB({ + delay : FADE_MILLIS, + color : new Color('rgb('+R+','+G+','+B+')'), + index : 3 + }).catch(error => { + error.should.eql("index must be between 0 and 2"); + }); + }); }); - it('should send fadetorgb index feature report', function() { - blink1.fadeToRGB(FADE_MILLIS, R, G, B, INDEX); + it('should send fadetorgb index feature report', () => { + blink1.fadeToRGB({ + delay : FADE_MILLIS, + color : new Color('rgb('+R+','+G+','+B+')'), + index : INDEX + }); sentFeatureReport.should.eql([FEATURE_REPORT_ID, 0x63, blink1.degamma(R), blink1.degamma(G), blink1.degamma(B), (FADE_MILLIS / 10) >> 8, (FADE_MILLIS / 10) % 0xff, INDEX, 0]); }); - it('should call back (index)', function(done) { - blink1.fadeToRGB(FADE_MILLIS, blink1.degamma(R), blink1.degamma(G), blink1.degamma(B), INDEX, done); + it('should resolve promise (index)', (done) => { + blink1.fadeToRGB({ + delay : FADE_MILLIS, + color : new Color('rgb('+R+','+G+','+B+')'), + index : INDEX + }).then(() => { + done(); + }); }); }); - describe('#Blink1.setRGB', function() { + describe('#Blink1.setRGB', () => { var R = 10; var G = 20; var B = 40; @@ -417,88 +528,110 @@ describe('blink(1)', function() { beforeEach(setupBlink1); afterEach(teardownBlink1); - it('should throw an error when r is not a number', function() { + it('should reject (catch) promise when r is not a number', () => { (function(){ - blink1.setRGB('Bad r', G, B); - }).should.throwError('r must be a number'); + blink1.setRGB(new Color('rgb(bad r,'+G+','+B+')')).catch(error => { + error.should.eql("r must be a number"); + }); + }); }); - it('should throw an error when r is less than 0', function() { + it('should reject (catch) promise when r is less than 0', () => { (function(){ - blink1.setRGB(-1, G, B); - }).should.throwError('r must be between 0 and 255'); + blink1.setRGB(new Color('rgb('+-1+','+G+','+B+')')).catch(error => { + error.should.eql("r must be between 0 and 255"); + }); + }); }); - it('should throw an error when r is greater than 255', function() { + it('should reject (catch) promise when r is greater than 255', () => { (function(){ - blink1.setRGB(256, G, B); - }).should.throwError('r must be between 0 and 255'); + blink1.setRGB(new Color('rgb('+256+','+G+','+B+')')).catch(error => { + error.should.eql("r must be between 0 and 255"); + }); + }); }); - it('should throw an error when g is not a number', function() { + it('should reject (catch) promise when g is not a number', () => { (function(){ - blink1.setRGB(R, 'Bad g', B); - }).should.throwError('g must be a number'); + blink1.setRGB(new Color('rgb('+R+',Bad g,'+B+')')).catch(error => { + error.should.eql("g must be a number"); + }); + }); }); - it('should throw an error when g is less than 0', function() { + it('should reject (catch) promise when g is less than 0', () => { (function(){ - blink1.setRGB(R, -1, B); - }).should.throwError('g must be between 0 and 255'); + blink1.setRGB(new Color('rgb('+R+','+-1+','+B+')')).catch(error => { + error.should.eql("g must be between 0 and 255"); + }); + }); }); - it('should throw an error when g is greater than 255', function() { + it('should reject (catch) promise when g is greater than 255', () => { (function(){ - blink1.setRGB(R, 256, B); - }).should.throwError('g must be between 0 and 255'); + blink1.setRGB(new Color('rgb('+R+','+256+','+B+')')).catch(error => { + error.should.eql("g must be between 0 and 255"); + }); + }); }); - it('should throw an error when b is not a number', function() { + it('should reject (catch) promise when b is not a number', () => { (function(){ - blink1.setRGB(R, G, 'Bad b'); - }).should.throwError('b must be a number'); + blink1.setRGB(new Color('rgb('+R+','+G+',Bad b)')).catch(error => { + error.should.eql("b must be a number"); + }); + }); }); - it('should throw an error when b is less than 0', function() { + it('should reject (catch) promise when b is less than 0', () => { (function(){ - blink1.setRGB(R, G, -1); - }).should.throwError('b must be between 0 and 255'); + blink1.setRGB(new Color('rgb('+R+','+G+','+-1+')')).catch(error => { + error.should.eql("b must be between 0 and 255"); + }); + }); }); - it('should throw an error when b is greater than 255', function() { + it('should reject (catch) promise when b is greater than 255', () => { (function(){ - blink1.setRGB(R, G, 256); - }).should.throwError('b must be between 0 and 255'); + blink1.setRGB(new Color('rgb('+R+','+G+','+256+')')).catch(error => { + error.should.eql("b must be between 0 and 255"); + }); + }); }); - it('should send setrgb feature report', function() { - blink1.setRGB(R, G, B); + it('should send setrgb feature report', () => { + blink1.setRGB(new Color('rgb('+R+','+G+','+B+')')); sentFeatureReport.should.eql([FEATURE_REPORT_ID, 0x6e, blink1.degamma(R), blink1.degamma(G), blink1.degamma(B), 0, 0, 0, 0]); }); - it('should call back', function(done) { - blink1.setRGB(R, G, B, done); + it('should resolve promise', (done) => { + blink1.setRGB(new Color('rgb('+R+','+G+','+B+')')).then(() => { + done(); + }); }); }); - describe('#Blink1.off', function() { + describe('#Blink1.off', () => { beforeEach(setupBlink1); afterEach(teardownBlink1); - it('should send setrgb 0, 0, 0 feature report', function() { + it('should send setrgb 0, 0, 0 feature report', () => { blink1.off(); sentFeatureReport.should.eql([FEATURE_REPORT_ID, 0x6e, 0, 0, 0, 0, 0, 0, 0]); }); - it('should call back', function(done) { - blink1.off(done); + it('should resolve promise', (done) => { + blink1.off().then(() => { + done(); + }); }); }); - describe('#Blink1.rgb', function() { + describe('#Blink1.getRGB', () => { var INDEX = 1; var R = 1; var G = 2; @@ -511,156 +644,180 @@ describe('blink(1)', function() { }); afterEach(teardownBlink1); - it('should send rgb feature report', function() { - blink1.rgb(); + it('should send rgb feature report', () => { + blink1.getRGB(); sentFeatureReport.should.eql([FEATURE_REPORT_ID, 0x72, 0, 0, 0, 0, 0, 0, 0]); }); - it('should call back with r, g, b', function(done) { - blink1.rgb(function(r, g, b) { + it('should resolve promise with r, g, b', (done) => { + blink1.getRGB().then(({r, g, b}) => { done(); }); }); - it('should call back with correct r, g, b', function(done) { - blink1.rgb(function(r, g, b) { - r.should.eql(R); - g.should.eql(G); - b.should.eql(B); + it('should resolve promise with correct r, g, b', (done) => { + blink1.getRGB().then(({r, g, b}) => { + r.should.eql(R); + g.should.eql(G); + b.should.eql(B); done(); }); }); - it('should send rgb index feature report', function() { - blink1.rgb(INDEX); + it('should send rgb index feature report', () => { + blink1.getRGB(INDEX); sentFeatureReport.should.eql([FEATURE_REPORT_ID, 0x72, INDEX, 0, 0, 0, 0, INDEX, 0]); }); - it('should call back with r, g, b (index)', function(done) { - blink1.rgb(INDEX, function(r, g, b) { + it('should resolve promise with r, g, b (index)', (done) => { + blink1.getRGB(INDEX).then(({r, g, b}) => { done(); }); }); - it('should call back with correct r, g, b (index)', function(done) { - blink1.rgb(INDEX, function(r, g, b) { - r.should.eql(R); - g.should.eql(G); - b.should.eql(B); + it('should resolve promise with correct r, g, b (index)', (done) => { + blink1.getRGB(INDEX).then(({r, g, b}) => { + r.should.eql(R); + g.should.eql(G); + b.should.eql(B); done(); }); }); }); - describe('#Blink1.enableServerDown', function() { + describe('#Blink1.enableServerDown', () => { var MILLIS = 10; beforeEach(setupBlink1); afterEach(teardownBlink1); - it('should throw an error when millis is not a number', function() { + it('should reject (catch) promise when millis is not a number', () => { (function(){ - blink1.enableServerDown('Bad millis'); - }).should.throwError('millis must be a number'); + blink1.enableServerDown('Bad millis').catch(error => { + error.should.eql("millis must be a number"); + }); + }); }); - it('should throw an error when millis is less than 0', function() { + it('should reject (catch) promise when millis is less than 0', () => { (function(){ - blink1.enableServerDown(-1); - }).should.throwError('millis must be between 0 and 655350'); + blink1.enableServerDown(-1).catch(error => { + error.should.eql("millis must be between 0 and 655350"); + }); + }); }); - it('should throw an error when millis is greater than 655350', function() { + it('should reject (catch) promise when millis is greater than 655350', () => { (function(){ - blink1.enableServerDown(655351); - }).should.throwError('millis must be between 0 and 655350'); + blink1.enableServerDown(655351).catch(error => { + error.should.eql("millis must be between 0 and 655350"); + }); + }); }); - it('should send serverdown on feature report', function() { + it('should send serverdown on feature report', () => { blink1.enableServerDown(MILLIS); sentFeatureReport.should.eql([FEATURE_REPORT_ID, 0x44, 1, (MILLIS / 10) >> 8, (MILLIS / 10) % 0xff, 0, 0, 0, 0]); }); - it('should call back', function(done) { - blink1.enableServerDown(0, done); + it('should resolve promise', (done) => { + blink1.enableServerDown(0).then(() => { + done(); + }); }); }); - describe('#Blink1.disableServerDown', function() { + describe('#Blink1.disableServerDown', () => { var MILLIS = 10; beforeEach(setupBlink1); afterEach(teardownBlink1); - it('should throw an error when millis is not a number', function() { + it('should reject (catch) promise when millis is not a number', () => { (function(){ - blink1.disableServerDown('Bad millis'); - }).should.throwError('millis must be a number'); + blink1.disableServerDown('Bad millis').catch(error => { + error.should.eql("millis must be a number"); + }); + }); }); - it('should throw an error when millis is less than 0', function() { + it('should reject (catch) promise when millis is less than 0', () => { (function(){ - blink1.disableServerDown(-1); - }).should.throwError('millis must be between 0 and 655350'); + blink1.disableServerDown(-1).catch(error => { + error.should.eql("millis must be between 0 and 655350"); + }); + }); }); - it('should throw an error when millis is greater than 655350', function() { + it('should reject (catch) promise when millis is greater than 655350', () => { (function(){ - blink1.disableServerDown(655351); - }).should.throwError('millis must be between 0 and 655350'); + blink1.disableServerDown(-1).catch(error => { + error.should.eql("millis must be between 0 and 655350"); + }); + }); }); - it('should send serverdown off feature report', function() { + it('should send serverdown off feature report', () => { blink1.disableServerDown(0); sentFeatureReport.should.eql([FEATURE_REPORT_ID, 0x44, 0, 0, 0, 0, 0, 0, 0]); }); - it('should call back', function(done) { - blink1.disableServerDown(0, done); + it('should resolve promise', (done) => { + blink1.disableServerDown(0).then(() => { + done(); + }); }); }); - describe('#Blink1.play', function() { + describe('#Blink1.play', () => { var POSITION = 5; beforeEach(setupBlink1); afterEach(teardownBlink1); - it('should throw an error when position is not a number', function() { + it('should reject (catch) promise when position is not a number', () => { (function(){ - blink1.play('Bad position'); - }).should.throwError('position must be a number'); + blink1.play('Bad position').catch(error => { + error.should.eql('position must be a number'); + }); + }); }); - it('should throw an error when position is less than 0', function() { + it('should reject (catch) promise when position is less than 0', () => { (function(){ - blink1.play(-1); - }).should.throwError('position must be between 0 and 11'); + blink1.play(-1).catch(error => { + error.should.eql('position must be between 0 and 11'); + }); + }); }); - it('should throw an error when position is greater than 11', function() { + it('should reject (catch) promise when position is greater than 11', () => { (function(){ - blink1.play(12); - }).should.throwError('position must be between 0 and 11'); + blink1.play(12).catch(error => { + error.should.eql('position must be between 0 and 11'); + }); + }); }); - it('should send play on feature report', function() { + it('should send play on feature report', () => { blink1.play(POSITION); sentFeatureReport.should.eql([FEATURE_REPORT_ID, 0x70, 1, POSITION, 0, 0, 0, 0, 0]); }); - it('should call back', function(done) { - blink1.play(0, done); + it('should resolve promise', (done) => { + blink1.play(0).then(() => { + done(); + }); }); }); - describe('#Blink1.playLoop', function() { + describe('#Blink1.playLoop', () => { var STARTPOSITION = 5; var ENDPOSITION = 8; var COUNT = 1; @@ -669,81 +826,143 @@ describe('blink(1)', function() { afterEach(teardownBlink1); - it('should throw an error when start position is not a number', function() { + it('should reject (catch) promise when start position is not a number', () => { (function(){ - blink1.playLoop('Bad position', 2, 2); - }).should.throwError('position must be a number'); + blink1.playLoop({ + start : 'Bad position', + end : 2, + count : 2 + }).catch(error => { + error.should.eql('position must be a number'); + }); + }); }); - it('should throw an error when end position is not a number', function() { + it('should reject (catch) promise when end position is not a number', () => { (function(){ - blink1.playLoop(1, 'Bad position', 2); - }).should.throwError('position must be a number'); + blink1.playLoop({ + start : 1, + end : 'Bad position', + count : 2 + }).catch(error => { + error.should.eql('position must be a number'); + }); + }); }); - it('should throw an error when count is not a number', function() { + it('should reject (catch) promise when count is not a number', () => { (function(){ - blink1.playLoop(1, 2, 'Bad count'); - }).should.throwError('count must be a number'); + blink1.playLoop({ + start : 1, + end : 2, + count : 'Bad count' + }).catch(error => { + error.should.eql('count must be a number'); + }); + }); }); - it('should throw an error when start position is less than 0', function() { + it('should reject (catch) promise when start position is less than 0', () => { (function(){ - blink1.playLoop(-1, 2, 2); - }).should.throwError('position must be between 0 and 11'); + blink1.playLoop({ + start : -1, + end : 2, + count : 2 + }).catch(error => { + error.should.eql('position must be between 0 and 11'); + }); + }); }); - it('should throw an error when end position is less than 0', function() { + it('should reject (catch) promise when end position is less than 0', () => { (function(){ - blink1.playLoop(1, -1, 2); - }).should.throwError('position must be between 0 and 11'); + blink1.playLoop({ + start : 1, + end : -1, + count : 2 + }).catch(error => { + error.should.eql('position must be between 0 and 11'); + }); + }); }); - it('should throw an error when count is less than 0', function() { + it('should reject (catch) promise when count is less than 0', () => { (function(){ - blink1.playLoop(1, 1, -1); - }).should.throwError('count must be between 0 and 255'); + blink1.playLoop({ + start : 1, + end : 1, + count : -1 + }).catch(error => { + error.should.eql('count must be between 0 and 255'); + }); + }); }); - it('should throw an error when start position is greater than 11', function() { + it('should reject (catch) promise when start position is greater than 11', () => { (function(){ - blink1.playLoop(12, 2, 2); - }).should.throwError('position must be between 0 and 11'); + blink1.playLoop({ + start : 12, + end : 2, + count : 2 + }).catch(error => { + error.should.eql('position must be between 0 and 11'); + }); + }); }); - it('should throw an error when end position is greater than 11', function() { + it('should reject (catch) promise when end position is greater than 11', () => { (function(){ - blink1.playLoop(2, 12, 2); - }).should.throwError('position must be between 0 and 11'); + blink1.playLoop({ + start : 2, + end : 12, + count : 2 + }).catch(error => { + error.should.eql('position must be between 0 and 11'); + }); + }); }); - it('should send play on feature report', function() { - blink1.playLoop(STARTPOSITION, ENDPOSITION, COUNT ); + it('should send play on feature report', () => { + (function(){ + blink1.playLoop({ + start : STARTPOSITION, + end : ENDPOSITION, + count : COUNT + }); - sentFeatureReport.should.eql([FEATURE_REPORT_ID, 0x70, 1, STARTPOSITION, ENDPOSITION, COUNT, 0, 0, 0]); + sentFeatureReport.should.eql([FEATURE_REPORT_ID, 0x70, 1, STARTPOSITION, ENDPOSITION, COUNT, 0, 0, 0]); + }); }); - it('should call back', function(done) { - blink1.playLoop(0, 1, 1, done); + it('should resolve promise', (done) => { + blink1.playLoop({ + start : 0, + end : 1, + count : 1 + }).then(() => { + done(); + }); }); }); - describe('#Blink1.pause', function() { + describe('#Blink1.pause', () => { beforeEach(setupBlink1); afterEach(teardownBlink1); - it('should send play off feature report', function() { + it('should send play off feature report', () => { blink1.pause(); sentFeatureReport.should.eql([FEATURE_REPORT_ID, 0x70, 0, 0, 0, 0, 0, 0, 0]); }); - it('should call back', function(done) { - blink1.pause(done); + it('should resolve promise', (done) => { + blink1.pause().then(() => { + done(); + }); }); }); - describe('#Blink1.writePatternLine', function() { + describe('#Blink1.writePatternLine', () => { var FADE_MILLIS = 10; var R = 10; var G = 20; @@ -753,108 +972,208 @@ describe('blink(1)', function() { beforeEach(setupBlink1); afterEach(teardownBlink1); - it('should throw an error when fadeMillis is not a number', function() { + it('should reject (catch) promise when fadeMillis is not a number', () => { (function(){ - blink1.writePatternLine('Bad fadeMillis', R, G, B, POSITION); - }).should.throwError('fadeMillis must be a number'); + blink1.writePatternLine({ + delay : 'Bad fadeMillis', + color : new Color('rgb('+R+','+G+','+B+')'), + position : POSITION + }).catch(error => { + error.should.eql('fadeMillis must be a number'); + }); + }); }); - it('should throw an error when fadeMillis is less than 0', function() { + it('should reject (catch) promise when fadeMillis is less than 0', () => { (function(){ - blink1.writePatternLine(-1, R, G, B, POSITION); - }).should.throwError('fadeMillis must be between 0 and 655350'); + blink1.writePatternLine({ + delay : -1, + color : new Color('rgb('+R+','+G+','+B+')'), + position : POSITION + }).catch(error => { + error.should.eql('fadeMillis must be between 0 and 655350'); + }); + }); }); - it('should throw an error when fadeMillis is greater than 655350', function() { + it('should reject (catch) promise when fadeMillis is greater than 655350', () => { (function(){ - blink1.writePatternLine(655351, R, G, B, POSITION); - }).should.throwError('fadeMillis must be between 0 and 655350'); + blink1.writePatternLine({ + delay : 655351, + color : new Color('rgb('+R+','+G+','+B+')'), + position : POSITION + }).catch(error => { + error.should.eql('fadeMillis must be between 0 and 655350'); + }); + }); }); - it('should throw an error when r is not a number', function() { + it('should reject (catch) promise when r is not a number', () => { (function(){ - blink1.writePatternLine(FADE_MILLIS, 'Bad r', G, B, POSITION); - }).should.throwError('r must be a number'); + blink1.writePatternLine({ + delay : FADE_MILLIS, + color : new Color('rgb(Bad r,'+G+','+B+')'), + position : POSITION + }).catch(error => { + error.should.eql('r must be a number'); + }); + }); }); - it('should throw an error when r is less than 0', function() { + it('should reject (catch) promise when r is less than 0', () => { (function(){ - blink1.writePatternLine(FADE_MILLIS, -1, G, B, POSITION); - }).should.throwError('r must be between 0 and 255'); + blink1.writePatternLine({ + delay : FADE_MILLIS, + color : new Color('rgb('+-1+','+G+','+B+')'), + position : POSITION + }).catch(error => { + error.should.eql('r must be between 0 and 255'); + }); + }); }); - it('should throw an error when r is greater than 255', function() { + it('should reject (catch) promise when r is greater than 255', () => { (function(){ - blink1.writePatternLine(FADE_MILLIS, 256, G, B, POSITION); - }).should.throwError('r must be between 0 and 255'); + blink1.writePatternLine({ + delay : FADE_MILLIS, + color : new Color('rgb('+256+','+G+','+B+')'), + position : POSITION + }).catch(error => { + error.should.eql('r must be between 0 and 255'); + }); + }); }); - it('should throw an error when g is not a number', function() { + it('should reject (catch) promise when g is not a number', () => { (function(){ - blink1.writePatternLine(FADE_MILLIS, R, 'Bad g', B, POSITION); - }).should.throwError('g must be a number'); + blink1.writePatternLine({ + delay : FADE_MILLIS, + color : new Color('rgb('+R+',Bad g,'+B+')'), + position : POSITION + }).catch(error => { + error.should.eql('g must be a number'); + }); + }); }); - it('should throw an error when g is less than 0', function() { + it('should reject (catch) promise when g is less than 0', () => { (function(){ - blink1.writePatternLine(FADE_MILLIS, R, -1, B, POSITION); - }).should.throwError('g must be between 0 and 255'); + blink1.writePatternLine({ + delay : FADE_MILLIS, + color : new Color('rgb('+R+','+-1+','+B+')'), + position : POSITION + }).catch(error => { + error.should.eql('g must be between 0 and 255'); + }); + }); }); - it('should throw an error when g is greater than 255', function() { + it('should reject (catch) promise when g is greater than 255', () => { (function(){ - blink1.writePatternLine(FADE_MILLIS, R, 256, B, POSITION); - }).should.throwError('g must be between 0 and 255'); + blink1.writePatternLine({ + delay : FADE_MILLIS, + color : new Color('rgb('+R+','+256+','+B+')'), + position : POSITION + }).catch(error => { + error.should.eql('g must be between 0 and 255'); + }); + }); }); - it('should throw an error when b is not a number', function() { + it('should reject (catch) promise when b is not a number', () => { (function(){ - blink1.writePatternLine(FADE_MILLIS, R, G, 'Bad b', POSITION); - }).should.throwError('b must be a number'); + blink1.writePatternLine({ + delay : FADE_MILLIS, + color : new Color('rgb('+R+','+G+',Bad b)'), + position : POSITION + }).catch(error => { + error.should.eql('b must be a number'); + }); + }); }); - it('should throw an error when b is less than 0', function() { + it('should reject (catch) promise when b is less than 0', () => { (function(){ - blink1.writePatternLine(FADE_MILLIS, R, G, -1, POSITION); - }).should.throwError('b must be between 0 and 255'); + blink1.writePatternLine({ + delay : FADE_MILLIS, + color : new Color('rgb('+R+','+G+','+-1+')'), + position : POSITION + }).catch(error => { + error.should.eql('b must be between 0 and 255'); + }); + }); }); - it('should throw an error when b is greater than 255', function() { + it('should reject (catch) promise when b is greater than 255', () => { (function(){ - blink1.writePatternLine(FADE_MILLIS, R, G, 256, POSITION); - }).should.throwError('b must be between 0 and 255'); + blink1.writePatternLine({ + delay : FADE_MILLIS, + color : new Color('rgb('+R+','+G+','+256+')'), + position : POSITION + }).catch(error => { + error.should.eql('b must be between 0 and 255'); + }); + }); }); - it('should throw an error when position is not a number', function() { + it('should reject (catch) promise when position is not a number', () => { (function(){ - blink1.writePatternLine(FADE_MILLIS, R, G, B, 'Bad position'); - }).should.throwError('position must be a number'); + blink1.writePatternLine({ + delay : FADE_MILLIS, + color : new Color('rgb('+R+','+G+','+B+')'), + position : 'Bad position' + }).catch(error => { + error.should.eql('position must be a number'); + }); + }); }); - it('should throw an error when position is less than 0', function() { + it('should reject (catch) promise when position is less than 0', () => { (function(){ - blink1.writePatternLine(FADE_MILLIS, R, G, B, -1); - }).should.throwError('position must be between 0 and 11'); + blink1.writePatternLine({ + delay : FADE_MILLIS, + color : new Color('rgb('+R+','+G+','+B+')'), + position : -1 + }).catch(error => { + error.should.eql('position must be between 0 and 11'); + }); + }); }); - it('should throw an error when position is greater than 11', function() { + it('should reject (catch) promise when position is greater than 11', () => { (function(){ - blink1.writePatternLine(FADE_MILLIS, R, G, B, 12); - }).should.throwError('position must be between 0 and 11'); + blink1.writePatternLine({ + delay : FADE_MILLIS, + color : new Color('rgb('+R+','+G+','+B+')'), + position : 12 + }).catch(error => { + error.should.eql('position must be between 0 and 11'); + }); + }); }); - it('should send writepatternline feature report', function() { - blink1.writePatternLine(FADE_MILLIS, R, G, B, POSITION); + it('should send writepatternline feature report', () => { + blink1.writePatternLine({ + delay : FADE_MILLIS, + color : new Color('rgb('+R+','+G+','+B+')'), + position : POSITION + }); sentFeatureReport.should.eql([FEATURE_REPORT_ID, 0x50, blink1.degamma(R), blink1.degamma(G), blink1.degamma(B), (FADE_MILLIS / 10) >> 8, (FADE_MILLIS / 10) % 0xff, POSITION, 0]); }); - it('should call back', function(done) { - blink1.writePatternLine(FADE_MILLIS, R, G, B, POSITION, done); + it('should resolve promise', (done) => { + blink1.writePatternLine({ + delay : FADE_MILLIS, + color : new Color('rgb('+R+','+G+','+B+')'), + position : POSITION + }).then(() => { + done(); + }); }); }); - describe('#Blink1.readPatternLine', function() { + describe('#Blink1.readPatternLine', () => { var POSITION = 5; var FADE_MILLIS = 1000; @@ -869,61 +1188,75 @@ describe('blink(1)', function() { }); afterEach(teardownBlink1); - it('should throw an error when position is not a number', function() { + it('should reject (catch) promise when position is not a number', () => { (function(){ - blink1.readPatternLine('Bad position'); - }).should.throwError('position must be a number'); + blink1.readPatternLine('Bad position').catch(error => { + error.should.eql('position must be a number'); + }); + }); }); - it('should throw an error when position is less than 0', function() { + it('should reject (catch) promise when position is less than 0', () => { (function(){ - blink1.readPatternLine(-1); - }).should.throwError('position must be between 0 and 11'); + blink1.readPatternLine(-1).catch(error => { + error.should.eql('position must be between 0 and 11'); + }); + }); }); - it('should throw an error when position is greater than 11', function() { + it('should reject (catch) promise when position is greater than 11', () => { (function(){ - blink1.readPatternLine(12); - }).should.throwError('position must be between 0 and 11'); + blink1.readPatternLine(12).catch(error => { + error.should.eql('position must be between 0 and 11'); + }); + }); }); - it('should send readpatternline feature report', function() { + it('should send readpatternline feature report', () => { blink1.readPatternLine(POSITION); sentFeatureReport.should.eql([FEATURE_REPORT_ID, 0x52, 0, 0, 0, 0, 0, POSITION, 0]); }); - it('should call back with value', function(done) { - blink1.readPatternLine(POSITION, function(value) { - done(); + it('should resolve promise with value', (done) => { + blink1.readPatternLine(POSITION).then(({ + color, + delay + }) => { + done(); }); }); - it('should call back with correct value', function(done) { + it('should resolve promise with correct value', (done) => { - blink1.readPatternLine(POSITION, function(value) { - value.r.should.eql(R); - value.g.should.eql(G); - value.b.should.eql(B); - value.fadeMillis.should.eql(FADE_MILLIS); + blink1.readPatternLine(POSITION).then(({ + color, + delay + }) => { + color.r.should.eql(R); + color.g.should.eql(G); + color.b.should.eql(B); + delay.should.eql(FADE_MILLIS); - done(); + done(); }); }); }); - describe('#Blink1.close', function() { + describe('#Blink1.close', () => { beforeEach(setupBlink1); afterEach(teardownBlink1); - it('should close HID device', function(done) { - blink1.close(done); + it('should close HID device', (done) => { + blink1.close().then(() => { + done(); + }); closed.should.eql(true); }); - it('should callback', function(done) { - blink1.close(function() { + it('should resolve promise', (done) => { + blink1.close().then(() => { closed.should.eql(true); done(); diff --git a/validators.js b/validators.js new file mode 100644 index 0000000..9d94811 --- /dev/null +++ b/validators.js @@ -0,0 +1,67 @@ +const Blink1_Helpers = require('./helpers'); +const Color = require('rgbcolor'); + +class Blink1_Validators extends Blink1_Helpers { + constructor(serialNumber) { + super(serialNumber); + } + + // Validators + + _isValidCallback(callback) { + return (typeof callback === 'function'); + } + + _validateNumber(number, name, min, max) { + if (typeof number !== 'number') { + throw new Error(name + ' must be a number'); + } + + if (number < min || number > max) { + throw new Error(name + ' must be between ' + min + ' and ' + max); + } + } + + _validateAddress(address) { + this._validateNumber(address, 'address', 0, 0xffff); // Decimal 0 - 65535 + } + + _validateValue(value) { + this._validateNumber(value, 'value', 0, 0xff); // Decimal 0 - 255 + } + + _validateCount(value) { + this._validateNumber(value, 'count', 0, 0xff); // Decimal 0 - 255 + } + + _validateFadeMillis(fadeMillis) { + this._validateNumber(fadeMillis, 'fadeMillis', 0, 0x9FFF6); // Decimal 0 - 655350 + } + + _validateColor(color) { + if (color instanceof Color && !color.ok) { + throw new Error('color ('+color+')is invalid'); + } + } + + _validateRGB(color) { + this._validateColor(color); + this._validateNumber(color.r, 'r', 0, 0xff); // Decimal 0 - 255 + this._validateNumber(color.g, 'g', 0, 0xff); // Decimal 0 - 255 + this._validateNumber(color.b, 'b', 0, 0xff); // Decimal 0 - 255 + } + + _validateMillis(millis) { + this._validateNumber(millis, 'millis', 0, 0x9FFF6); // Decimal 0 - 655350 + } + + _validatePosition(position) { + this._validateNumber(position, 'position', 0, 11); + } + + _validateIndex(index) { + this._validateNumber(index, 'index', 0, 2); + } +} + +module.exports = Blink1_Validators; diff --git a/yarn.lock b/yarn.lock new file mode 100644 index 0000000..2dc849c --- /dev/null +++ b/yarn.lock @@ -0,0 +1,580 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +ansi-regex@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" + +aproba@^1.0.3: + version "1.2.0" + resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" + +are-we-there-yet@~1.1.2: + version "1.1.4" + resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.4.tgz#bb5dca382bb94f05e15194373d16fd3ba1ca110d" + dependencies: + delegates "^1.0.0" + readable-stream "^2.0.6" + +async@^2.6.0: + version "2.6.0" + resolved "https://registry.yarnpkg.com/async/-/async-2.6.0.tgz#61a29abb6fcc026fea77e56d1c6ec53a795951f4" + dependencies: + lodash "^4.14.0" + +balanced-match@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" + +bindings@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.3.0.tgz#b346f6ecf6a95f5a815c5839fc7cdb22502f1ed7" + +bl@^1.0.0: + version "1.2.1" + resolved "https://registry.yarnpkg.com/bl/-/bl-1.2.1.tgz#cac328f7bee45730d404b692203fcb590e172d5e" + dependencies: + readable-stream "^2.0.5" + +brace-expansion@^1.1.7: + version "1.1.8" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.8.tgz#c07b211c7c952ec1f8efd51a77ef0d1d3990a292" + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +browser-stdout@1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.0.tgz#f351d32969d32fa5d7a5567154263d928ae3bd1f" + +chownr@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.0.1.tgz#e2a75042a9551908bebd25b8523d5f9769d79181" + +cli@~1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/cli/-/cli-1.0.1.tgz#22817534f24bfa4950c34d532d48ecbc621b8c14" + dependencies: + exit "0.1.2" + glob "^7.1.1" + +code-point-at@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" + +commander@2.11.0: + version "2.11.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.11.0.tgz#157152fd1e7a6c8d98a5b715cf376df928004563" + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + +console-browserify@1.1.x: + version "1.1.0" + resolved "https://registry.yarnpkg.com/console-browserify/-/console-browserify-1.1.0.tgz#f0241c45730a9fc6323b206dbf38edc741d0bb10" + dependencies: + date-now "^0.1.4" + +console-control-strings@^1.0.0, console-control-strings@~1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" + +core-util-is@~1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" + +date-now@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/date-now/-/date-now-0.1.4.tgz#eaf439fd4d4848ad74e5cc7dbef200672b9e345b" + +debug@3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" + dependencies: + ms "2.0.0" + +deep-extend@~0.4.0: + version "0.4.2" + resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.4.2.tgz#48b699c27e334bf89f10892be432f6e4c7d34a7f" + +delegates@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" + +diff@3.3.1: + version "3.3.1" + resolved "https://registry.yarnpkg.com/diff/-/diff-3.3.1.tgz#aa8567a6eed03c531fc89d3f711cd0e5259dec75" + +dom-serializer@0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-0.1.0.tgz#073c697546ce0780ce23be4a28e293e40bc30c82" + dependencies: + domelementtype "~1.1.1" + entities "~1.1.1" + +domelementtype@1: + version "1.3.0" + resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-1.3.0.tgz#b17aed82e8ab59e52dd9c19b1756e0fc187204c2" + +domelementtype@~1.1.1: + version "1.1.3" + resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-1.1.3.tgz#bd28773e2642881aec51544924299c5cd822185b" + +domhandler@2.3: + version "2.3.0" + resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-2.3.0.tgz#2de59a0822d5027fabff6f032c2b25a2a8abe738" + dependencies: + domelementtype "1" + +domutils@1.5: + version "1.5.1" + resolved "https://registry.yarnpkg.com/domutils/-/domutils-1.5.1.tgz#dcd8488a26f563d61079e48c9f7b7e32373682cf" + dependencies: + dom-serializer "0" + domelementtype "1" + +end-of-stream@^1.0.0, end-of-stream@^1.1.0: + version "1.4.1" + resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.1.tgz#ed29634d19baba463b6ce6b80a37213eab71ec43" + dependencies: + once "^1.4.0" + +entities@1.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/entities/-/entities-1.0.0.tgz#b2987aa3821347fcde642b24fdfc9e4fb712bf26" + +entities@~1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/entities/-/entities-1.1.1.tgz#6e5c2d0a5621b5dadaecef80b90edfb5cd7772f0" + +escape-string-regexp@1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + +exit@0.1.2, exit@0.1.x: + version "0.1.2" + resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" + +expand-template@^1.0.2: + version "1.1.0" + resolved "https://registry.yarnpkg.com/expand-template/-/expand-template-1.1.0.tgz#e09efba977bf98f9ee0ed25abd0c692e02aec3fc" + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + +gauge@~2.7.3: + version "2.7.4" + resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7" + dependencies: + aproba "^1.0.3" + console-control-strings "^1.0.0" + has-unicode "^2.0.0" + object-assign "^4.1.0" + signal-exit "^3.0.0" + string-width "^1.0.1" + strip-ansi "^3.0.1" + wide-align "^1.1.0" + +github-from-package@0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/github-from-package/-/github-from-package-0.0.0.tgz#97fb5d96bfde8973313f20e8288ef9a167fa64ce" + +glob@7.1.2, glob@^7.1.1: + version "7.1.2" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15" + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" + +growl@1.10.3: + version "1.10.3" + resolved "https://registry.yarnpkg.com/growl/-/growl-1.10.3.tgz#1926ba90cf3edfe2adb4927f5880bc22c66c790f" + +has-flag@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-2.0.0.tgz#e8207af1cc7b30d446cc70b734b5e8be18f88d51" + +has-unicode@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" + +he@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/he/-/he-1.1.1.tgz#93410fd21b009735151f8868c2f271f3427e23fd" + +htmlparser2@3.8.x: + version "3.8.3" + resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-3.8.3.tgz#996c28b191516a8be86501a7d79757e5c70c1068" + dependencies: + domelementtype "1" + domhandler "2.3" + domutils "1.5" + entities "1.0" + readable-stream "1.1" + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2, inherits@~2.0.1, inherits@~2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" + +ini@~1.3.0: + version "1.3.5" + resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927" + +is-fullwidth-code-point@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" + dependencies: + number-is-nan "^1.0.0" + +isarray@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" + +isarray@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" + +jshint@^2.9.5: + version "2.9.5" + resolved "https://registry.yarnpkg.com/jshint/-/jshint-2.9.5.tgz#1e7252915ce681b40827ee14248c46d34e9aa62c" + dependencies: + cli "~1.0.0" + console-browserify "1.1.x" + exit "0.1.x" + htmlparser2 "3.8.x" + lodash "3.7.x" + minimatch "~3.0.2" + shelljs "0.3.x" + strip-json-comments "1.0.x" + +lodash@3.7.x: + version "3.7.0" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-3.7.0.tgz#3678bd8ab995057c07ade836ed2ef087da811d45" + +lodash@^4.14.0, lodash@^4.17.4: + version "4.17.4" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae" + +minimatch@^3.0.4, minimatch@~3.0.2: + version "3.0.4" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" + dependencies: + brace-expansion "^1.1.7" + +minimist@0.0.8: + version "0.0.8" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" + +minimist@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" + +mkdirp@0.5.1, mkdirp@^0.5.1: + version "0.5.1" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" + dependencies: + minimist "0.0.8" + +mocha@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/mocha/-/mocha-5.0.0.tgz#cccac988b0bc5477119cba0e43de7af6d6ad8f4e" + dependencies: + browser-stdout "1.3.0" + commander "2.11.0" + debug "3.1.0" + diff "3.3.1" + escape-string-regexp "1.0.5" + glob "7.1.2" + growl "1.10.3" + he "1.1.1" + mkdirp "0.5.1" + supports-color "4.4.0" + +mockery@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/mockery/-/mockery-2.1.0.tgz#5b0aef1ff564f0f8139445e165536c7909713470" + +ms@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" + +nan@^2.6.2: + version "2.8.0" + resolved "https://registry.yarnpkg.com/nan/-/nan-2.8.0.tgz#ed715f3fe9de02b57a5e6252d90a96675e1f085a" + +node-abi@^2.1.1: + version "2.1.2" + resolved "https://registry.yarnpkg.com/node-abi/-/node-abi-2.1.2.tgz#4da6caceb6685fcd31e7dd1994ef6bb7d0a9c0b2" + dependencies: + semver "^5.4.1" + +node-hid@^0.7.2: + version "0.7.2" + resolved "https://registry.yarnpkg.com/node-hid/-/node-hid-0.7.2.tgz#15025cdea2e9756aca2de7266529996d40e52c56" + dependencies: + bindings "^1.3.0" + nan "^2.6.2" + prebuild-install "^2.2.2" + +noop-logger@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/noop-logger/-/noop-logger-0.1.1.tgz#94a2b1633c4f1317553007d8966fd0e841b6a4c2" + +npmlog@^4.0.1: + version "4.1.2" + resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b" + dependencies: + are-we-there-yet "~1.1.2" + console-control-strings "~1.1.0" + gauge "~2.7.3" + set-blocking "~2.0.0" + +number-is-nan@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" + +object-assign@^4.1.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" + +once@^1.3.0, once@^1.3.1, once@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + dependencies: + wrappy "1" + +os-homedir@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" + +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + +prebuild-install@^2.2.2: + version "2.4.1" + resolved "https://registry.yarnpkg.com/prebuild-install/-/prebuild-install-2.4.1.tgz#c28ba1d1eedc17fbd6b3229a657ffc0fba479b49" + dependencies: + expand-template "^1.0.2" + github-from-package "0.0.0" + minimist "^1.2.0" + mkdirp "^0.5.1" + node-abi "^2.1.1" + noop-logger "^0.1.1" + npmlog "^4.0.1" + os-homedir "^1.0.1" + pump "^1.0.1" + rc "^1.1.6" + simple-get "^1.4.2" + tar-fs "^1.13.0" + tunnel-agent "^0.6.0" + xtend "4.0.1" + +process-nextick-args@~1.0.6: + version "1.0.7" + resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-1.0.7.tgz#150e20b756590ad3f91093f25a4f2ad8bff30ba3" + +pump@^1.0.0, pump@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/pump/-/pump-1.0.3.tgz#5dfe8311c33bbf6fc18261f9f34702c47c08a954" + dependencies: + end-of-stream "^1.1.0" + once "^1.3.1" + +rc@^1.1.6: + version "1.2.4" + resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.4.tgz#a0f606caae2a3b862bbd0ef85482c0125b315fa3" + dependencies: + deep-extend "~0.4.0" + ini "~1.3.0" + minimist "^1.2.0" + strip-json-comments "~2.0.1" + +readable-stream@1.1: + version "1.1.13" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.1.13.tgz#f6eef764f514c89e2b9e23146a75ba106756d23e" + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.1" + isarray "0.0.1" + string_decoder "~0.10.x" + +readable-stream@^2.0.0, readable-stream@^2.0.5, readable-stream@^2.0.6: + version "2.3.3" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.3.tgz#368f2512d79f9d46fdfc71349ae7878bbc1eb95c" + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.3" + isarray "~1.0.0" + process-nextick-args "~1.0.6" + safe-buffer "~5.1.1" + string_decoder "~1.0.3" + util-deprecate "~1.0.1" + +rgbcolor@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/rgbcolor/-/rgbcolor-1.0.1.tgz#d6505ecdb304a6595da26fa4b43307306775945d" + +safe-buffer@^5.0.1, safe-buffer@~5.1.0, safe-buffer@~5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.1.tgz#893312af69b2123def71f57889001671eeb2c853" + +semver@^5.4.1: + version "5.5.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.5.0.tgz#dc4bbc7a6ca9d916dee5d43516f0092b58f7b8ab" + +set-blocking@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" + +shelljs@0.3.x: + version "0.3.0" + resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.3.0.tgz#3596e6307a781544f591f37da618360f31db57b1" + +should-equal@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/should-equal/-/should-equal-2.0.0.tgz#6072cf83047360867e68e98b09d71143d04ee0c3" + dependencies: + should-type "^1.4.0" + +should-format@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/should-format/-/should-format-3.0.3.tgz#9bfc8f74fa39205c53d38c34d717303e277124f1" + dependencies: + should-type "^1.3.0" + should-type-adaptors "^1.0.1" + +should-type-adaptors@^1.0.1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/should-type-adaptors/-/should-type-adaptors-1.1.0.tgz#401e7f33b5533033944d5cd8bf2b65027792e27a" + dependencies: + should-type "^1.3.0" + should-util "^1.0.0" + +should-type@^1.3.0, should-type@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/should-type/-/should-type-1.4.0.tgz#0756d8ce846dfd09843a6947719dfa0d4cff5cf3" + +should-util@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/should-util/-/should-util-1.0.0.tgz#c98cda374aa6b190df8ba87c9889c2b4db620063" + +should@^13.2.1: + version "13.2.1" + resolved "https://registry.yarnpkg.com/should/-/should-13.2.1.tgz#84e6ebfbb145c79e0ae42307b25b3f62dcaf574e" + dependencies: + should-equal "^2.0.0" + should-format "^3.0.3" + should-type "^1.4.0" + should-type-adaptors "^1.0.1" + should-util "^1.0.0" + +signal-exit@^3.0.0: + version "3.0.2" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" + +simple-get@^1.4.2: + version "1.4.3" + resolved "https://registry.yarnpkg.com/simple-get/-/simple-get-1.4.3.tgz#e9755eda407e96da40c5e5158c9ea37b33becbeb" + dependencies: + once "^1.3.1" + unzip-response "^1.0.0" + xtend "^4.0.0" + +string-width@^1.0.1, string-width@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" + dependencies: + code-point-at "^1.0.0" + is-fullwidth-code-point "^1.0.0" + strip-ansi "^3.0.0" + +string_decoder@~0.10.x: + version "0.10.31" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" + +string_decoder@~1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.0.3.tgz#0fc67d7c141825de94282dd536bec6b9bce860ab" + dependencies: + safe-buffer "~5.1.0" + +strip-ansi@^3.0.0, strip-ansi@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" + dependencies: + ansi-regex "^2.0.0" + +strip-json-comments@1.0.x: + version "1.0.4" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-1.0.4.tgz#1e15fbcac97d3ee99bf2d73b4c656b082bbafb91" + +strip-json-comments@~2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" + +supports-color@4.4.0: + version "4.4.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-4.4.0.tgz#883f7ddabc165142b2a61427f3352ded195d1a3e" + dependencies: + has-flag "^2.0.0" + +tar-fs@^1.13.0: + version "1.16.0" + resolved "https://registry.yarnpkg.com/tar-fs/-/tar-fs-1.16.0.tgz#e877a25acbcc51d8c790da1c57c9cf439817b896" + dependencies: + chownr "^1.0.1" + mkdirp "^0.5.1" + pump "^1.0.0" + tar-stream "^1.1.2" + +tar-stream@^1.1.2: + version "1.5.5" + resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-1.5.5.tgz#5cad84779f45c83b1f2508d96b09d88c7218af55" + dependencies: + bl "^1.0.0" + end-of-stream "^1.0.0" + readable-stream "^2.0.0" + xtend "^4.0.0" + +tunnel-agent@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" + dependencies: + safe-buffer "^5.0.1" + +unzip-response@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/unzip-response/-/unzip-response-1.0.2.tgz#b984f0877fc0a89c2c773cc1ef7b5b232b5b06fe" + +util-deprecate@~1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + +wide-align@^1.1.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.2.tgz#571e0f1b0604636ebc0dfc21b0339bbe31341710" + dependencies: + string-width "^1.0.2" + +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + +xtend@4.0.1, xtend@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af"