diff --git a/.gitignore b/.gitignore index c2658d7..08dc7b0 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,3 @@ node_modules/ +dist/ + diff --git a/boosthub.js b/boosthub.ts similarity index 57% rename from boosthub.js rename to boosthub.ts index 3daff12..4f60e89 100644 --- a/boosthub.js +++ b/boosthub.ts @@ -1,18 +1,33 @@ -const debug = require("debug")("lpf2"), - EventEmitter = require("events").EventEmitter; +import { Peripheral } from "noble"; -const Hub = require("./hub.js"), - Port = require("./port.js"), - Consts = require("./consts.js"); +import { Hub } from "./hub.js"; +import { Port } from "./port.js"; + +import Debug = require("debug"); +const debug = Debug("lpf2"); +import { Consts } from "./consts.js"; -class BoostHub extends Hub { +/** + * @class BoostHub + * @extends Hub + */ +export class BoostHub extends Hub { - constructor (peripheral, autoSubscribe) { + public static IsBoostHub (peripheral: Peripheral) { + return (peripheral.advertisement.localName === Consts.BLE.Name.BOOST_MOVE_HUB_NAME && peripheral.advertisement.serviceUuids.indexOf(Consts.BLE.Services.BOOST_MOVE_HUB) >= 0); + } + + + private _lastTiltX: number = 0; + private _lastTiltY: number = 0; + + + constructor (peripheral: Peripheral, autoSubscribe: boolean = true) { super(peripheral, autoSubscribe); this.type = Consts.Hubs.BOOST_MOVE_HUB; - this.ports = { + this._ports = { "A": new Port("A", 55), "B": new Port("B", 56), "AB": new Port("AB", 57), @@ -20,18 +35,11 @@ class BoostHub extends Hub { "C": new Port("C", 1), "D": new Port("D", 2) }; - this._lastTiltX = 0; - this._lastTiltY = 0; debug("Discovered Boost Move Hub"); } - static isBoostHub (peripheral) { - return (peripheral.advertisement.localName === Consts.BLE.Name.BOOST_MOVE_HUB_NAME && peripheral.advertisement.serviceUuids.indexOf(Consts.BLE.Services.BOOST_MOVE_HUB) >= 0); - } - - - connect (callback) { + public connect (callback: () => void) { debug("Connecting to Boost Move Hub"); super.connect(() => { const characteristic = this._characteristics[Consts.BLE.Characteristics.Boost.ALL]; @@ -41,11 +49,16 @@ class BoostHub extends Hub { if (callback) { callback(); } - }) + }); } - setLEDColor (color) { + /** + * Set the color of the LED on the Hub via a color value. + * @method BoostHub#setLEDColor + * @param {number} color - A number representing one of the LED color consts. + */ + public setLEDColor (color: number | boolean) { const characteristic = this._characteristics[Consts.BLE.Characteristics.Boost.ALL]; if (characteristic) { let data = Buffer.from([0x05, 0x00, 0x01, 0x02, 0x02]); @@ -70,25 +83,39 @@ class BoostHub extends Hub { // } - setMotorSpeed (port, speed, time) { + /** + * Set the motor speed on a given port. + * @method BoostHub#setMotorSpeed + * @param {string} port + * @param {number} speed - For forward, a value between 1 - 100 should be set. For reverse, a value between -1 to -100. Stop is 0. + * @param {number} [time] - How long to activate the motor for (in milliseconds). Leave empty to turn the motor on indefinitely. + */ + public setMotorSpeed (port: string, speed: number, time: number) { const characteristic = this._characteristics[Consts.BLE.Characteristics.Boost.ALL]; if (characteristic) { if (time) { - const data = Buffer.from([0x0c, 0x00, 0x81, this.ports[port].value, 0x11, 0x09, 0x00, 0x00, speed, 0x64, 0x7f, 0x03]); + const data = Buffer.from([0x0c, 0x00, 0x81, this._ports[port].value, 0x11, 0x09, 0x00, 0x00, speed, 0x64, 0x7f, 0x03]); data.writeUInt16LE(time > 65535 ? 65535 : time, 6); characteristic.write(data); } else { - const data = Buffer.from([0x0a, 0x00, 0x81, this.ports[port].value, 0x11, 0x01, speed, 0x64, 0x7f, 0x03]); + const data = Buffer.from([0x0a, 0x00, 0x81, this._ports[port].value, 0x11, 0x01, speed, 0x64, 0x7f, 0x03]); characteristic.write(data); } } } - setMotorAngle (port, angle, speed = 100) { + /** + * Rotate a motor by a given angle. + * @method BoostHub#setMotorAngle + * @param {string} port + * @param {number} angle - How much the motor should be rotated (in degrees). + * @param {number} [speed=100] - How fast the motor should be rotated. + */ + public setMotorAngle (port: string, angle: number, speed: number = 100) { const characteristic = this._characteristics[Consts.BLE.Characteristics.Boost.ALL]; if (characteristic) { - const data = Buffer.from([0x0e, 0x00, 0x81, this.ports[port].value, 0x11, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x7f, 0x03]);; + const data = Buffer.from([0x0e, 0x00, 0x81, this._ports[port].value, 0x11, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x7f, 0x03]); data.writeUInt32LE(angle, 6); data.writeInt8(speed, 10); characteristic.write(data); @@ -96,22 +123,38 @@ class BoostHub extends Hub { } - _getPortForPortNumber (num) { + protected _activatePortDevice (port: number, type: number, mode: number, format: number, callback: () => void) { + const characteristic = this._characteristics[Consts.BLE.Characteristics.Boost.ALL]; + if (characteristic) { + characteristic.write(Buffer.from([0x0a, 0x00, 0x41, port, mode, 0x01, 0x00, 0x00, 0x00, 0x01]), callback); + } + } + + + protected _deactivatePortDevice (port: number, type: number, mode: number, format: number, callback: () => void) { + const characteristic = this._characteristics[Consts.BLE.Characteristics.Boost.ALL]; + if (characteristic) { + characteristic.write(Buffer.from([0x0a, 0x00, 0x41, port, mode, 0x01, 0x00, 0x00, 0x00, 0x00]), callback); + } + } + + + private _getPortForPortNumber (num: number) { let port = null; if (num === 1) { - port = this.ports["C"]; + port = this._ports["C"]; } else if (num === 2) { - port = this.ports["D"]; + port = this._ports["D"]; } else if (num === 55) { - port = this.ports["A"]; + port = this._ports["A"]; } else if (num === 56) { - port = this.ports["B"]; + port = this._ports["B"]; } else if (num === 57) { - port = this.ports["AB"]; + port = this._ports["AB"]; } else if (num === 58) { - port = this.ports["TILT"]; + port = this._ports["TILT"]; } else { return false; } @@ -121,7 +164,7 @@ class BoostHub extends Hub { } - _parseMessage (data) { + private _parseMessage (data: Buffer) { switch (data[2]) { case 0x01: @@ -147,10 +190,15 @@ class BoostHub extends Hub { } - _parseDeviceInfo (data) { - + private _parseDeviceInfo (data: Buffer) { + if (data[3] === 2) { if (data[5] === 1) { + /** + * Emits when a button is pressed. + * @event BoostHub#button + * @param {number} state - A number representing one of the button state consts. + */ this.emit("button", Consts.Button.PRESSED); return; } else if (data[5] === 0) { @@ -162,9 +210,9 @@ class BoostHub extends Hub { } - _parsePortMessage (data) { + private _parsePortMessage (data: Buffer) { - let port = this._getPortForPortNumber(data[3]); + const port = this._getPortForPortNumber(data[3]); if (!port) { return; @@ -172,13 +220,13 @@ class BoostHub extends Hub { port.connected = (data[4] === 1 || data[4] === 2) ? true : false; this._registerDeviceAttachment(port, data[5]); - + } - _parsePortAction (data) { + private _parsePortAction (data: Buffer) { - let port = this._getPortForPortNumber(data[3]); + const port = this._getPortForPortNumber(data[3]); if (!port) { return; @@ -189,25 +237,9 @@ class BoostHub extends Hub { } - _activatePortDevice (port, type, mode, format, callback) { - const characteristic = this._characteristics[Consts.BLE.Characteristics.Boost.ALL]; - if (characteristic) { - characteristic.write(Buffer.from([0x0a, 0x00, 0x41, port, mode, 0x01, 0x00, 0x00, 0x00, 0x01]), callback); - } - } + private _parseSensorMessage (data: Buffer) { - - _deactivatePortDevice (port, type, mode, format, callback) { - const characteristic = this._characteristics[Consts.BLE.Characteristics.Boost.ALL]; - if (characteristic) { - characteristic.write(Buffer.from([0x0a, 0x00, 0x41, port, mode, 0x01, 0x00, 0x00, 0x00, 0x00]), callback); - } - } - - - _parseSensorMessage (data) { - - let port = this._getPortForPortNumber(data[3]); + const port = this._getPortForPortNumber(data[3]); if (!port) { return; @@ -221,43 +253,68 @@ class BoostHub extends Hub { if (data[5] === 1) { distance = data[4] + 255; } + /** + * Emits when a distance sensor is activated. + * @event BoostHub#distance + * @param {string} port + * @param {number} distance - Distance, in millimeters. + */ this.emit("distance", port.id, distance * 10); break; } case Consts.Devices.BOOST_DISTANCE: { + /** + * Emits when a color sensor is activated. + * @event BoostHub#color + * @param {string} port + * @param {number} color - A number representing one of the LED color consts. + */ this.emit("color", port.id, data[4]); - let distance = data[5], - partial = data[7]; + let distance = data[5]; + const partial = data[7]; if (partial > 0) { distance += 1 / partial; } - + this.emit("distance", port.id, Math.floor(distance * 25.4) - 20); break; } case Consts.Devices.WEDO2_TILT: { - let tiltX = data[4] > 160 ? data[4] - 255 : data[4] - (data[4] * 2); - let tiltY = data[5] > 160 ? 255 - data[5] : data[5] - (data[5] * 2); + const tiltX = data[4] > 160 ? data[4] - 255 : data[4] - (data[4] * 2); + const tiltY = data[5] > 160 ? 255 - data[5] : data[5] - (data[5] * 2); this._lastTiltX = tiltX; this._lastTiltY = tiltY; + /** + * Emits when a tilt sensor is activated. + * @event BoostHub#tilt + * @param {string} port + * @param {number} x + * @param {number} y + */ this.emit("tilt", port.id, this._lastTiltX, this._lastTiltY); break; } case Consts.Devices.BOOST_INTERACTIVE_MOTOR: { const rotation = data.readInt32LE(2); + /** + * Emits when a rotation sensor is activated. + * @event BoostHub#rotate + * @param {string} port + * @param {number} rotation + */ this.emit("rotate", port.id, rotation); break; } case Consts.Devices.BOOST_TILT: { - let tiltX = data[4] > 160 ? data[4] - 255 : data[4]; - let tiltY = data[5] > 160 ? 255 - data[5] : data[5] - (data[5] * 2); + const tiltX = data[4] > 160 ? data[4] - 255 : data[4]; + const tiltY = data[5] > 160 ? 255 - data[5] : data[5] - (data[5] * 2); this.emit("tilt", port.id, tiltX, tiltY); break; } @@ -268,6 +325,3 @@ class BoostHub extends Hub { } - - -module.exports = BoostHub; \ No newline at end of file diff --git a/consts.js b/consts.ts similarity index 97% rename from consts.js rename to consts.ts index 2c8ac45..a89d3bd 100644 --- a/consts.js +++ b/consts.ts @@ -1,4 +1,6 @@ -const Consts = { +/* tslint:disable */ + +export const Consts = { Hubs: { UNKNOWN: 0, WEDO2_SMART_HUB: 1, @@ -63,6 +65,4 @@ const Consts = { } } } -} - -module.exports = Consts; +} \ No newline at end of file diff --git a/hub.js b/hub.js deleted file mode 100644 index 42251d9..0000000 --- a/hub.js +++ /dev/null @@ -1,152 +0,0 @@ -const debug = require("debug")("lpf2"), - EventEmitter = require("events").EventEmitter; - -const Port = require("./port.js"), - Consts = require("./consts.js"); - - -class Hub extends EventEmitter { - - - constructor (peripheral, autoSubscribe) { - super(); - this.autoSubscribe = !!autoSubscribe; - this._peripheral = peripheral; - this._characteristics = {}; - this._batteryLevel = 100; - this._rssi = -100; // Initialize as -100 - no signal - this._ports = {}; - this.type = Consts.Hubs.UNKNOWN; - this.uuid = peripheral.uuid; - } - - - connect (callback) { - - const self = this; - - this._peripheral.connect((err) => { - - this._rssi = this._peripheral.rssi; - - let rssiUpdateInterval = setInterval(() => { - this._peripheral.updateRssi((err, rssi) => { - if (!err) { - if (this._rssi != rssi) { - this._rssi = rssi; - debug(`RSSI change ${rssi}`) - self.emit("rssiChange", rssi); - } - } - }); - }, 2000); - - self._peripheral.on("disconnect", () => { - clearInterval(rssiUpdateInterval); - }); - - self._peripheral.discoverServices([], (err, services) => { - - if (err) { - this.emit("error", err); - return; - } - - debug("Service/characteristic discovery started"); - - const servicePromises = []; - - services.forEach((service) => { - - servicePromises.push(new Promise((resolve, reject) => { - - service.discoverCharacteristics([], (err, characteristics) => { - characteristics.forEach((characteristic) => { - this._characteristics[characteristic.uuid] = characteristic; - }); - return resolve(); - }); - - })); - - }); - - Promise.all(servicePromises).then(() => { - debug("Service/characteristic discovery finished"); - if (callback) { - callback(); - } - }) - - }); - - }); - - } - - - subscribe (port, mode = false) { - if (!mode) { - mode = this._getModeForDeviceType(this.ports[port].type); - } - this._activatePortDevice(this.ports[port].value, this.ports[port].type, mode, 0x00); - } - - - unsubscribe (port, mode = false) { - if (!mode) { - mode = this._getModeForDeviceType(this.ports[port].type); - } - this._deactivatePortDevice(this.ports[port].value, this.ports[port].type, mode, 0x00); - } - - - _getModeForDeviceType (type) { - switch (type) { - case Consts.Devices.BASIC_MOTOR: - return 0x02; - case Consts.Devices.BOOST_INTERACTIVE_MOTOR: - return 0x02; - case Consts.Devices.BOOST_MOVE_HUB_MOTOR: - return 0x02; - case Consts.Devices.BOOST_DISTANCE: - return (this.type == Consts.Hubs.WEDO2_SMART_HUB ? 0x00 : 0x08); - case Consts.Devices.BOOST_TILT: - return 0x04; - default: - return 0x00; - } - } - - - _subscribeToCharacteristic (characteristic, callback) { - characteristic.on("data", (data, isNotification) => { - return callback(data); - }); - characteristic.subscribe((err) => { - if (err) { - this.emit("error", err); - } - }); - } - - - _registerDeviceAttachment (port, type) { - - if (port.connected) { - port.type = type; - if (this.autoSubscribe) { - this._activatePortDevice(port.value, type, this._getModeForDeviceType(type), 0x00); - } - } else { - port.type = null; - debug(`Port ${port.id} disconnected`); - } - - } - - -} - - -module.exports = Hub; \ No newline at end of file diff --git a/hub.ts b/hub.ts new file mode 100644 index 0000000..176c059 --- /dev/null +++ b/hub.ts @@ -0,0 +1,192 @@ +import { EventEmitter } from "events"; + +import { Characteristic, Peripheral, Service } from "noble"; +import { Port } from "./port"; + +import Debug = require("debug"); +const debug = Debug("lpf2"); +import { Consts } from "./consts.js"; + + +/** + * @class Hub + * @extends EventEmitter + */ +export class Hub extends EventEmitter { + + + public autoSubscribe: boolean; + public type: number = Consts.Hubs.UNKNOWN; + public uuid: string; + + protected _ports: any = {}; + protected _characteristics: any = {}; + + private _peripheral: Peripheral; + private _rssi: number = -100; + private _batteryLevel: number = 100; + + constructor (peripheral: Peripheral, autoSubscribe: boolean = true) { + super(); + this.autoSubscribe = !!autoSubscribe; + this._peripheral = peripheral; + this.uuid = peripheral.uuid; + } + + + /** + * Connect to the Hub. + * @method Hub#connect + * @param {function} [callback] + */ + public connect (callback: () => void) { + + const self = this; + + this._peripheral.connect((err: string) => { + + this._rssi = this._peripheral.rssi; + + const rssiUpdateInterval = setInterval(() => { + this._peripheral.updateRssi((err: string, rssi: number) => { + if (!err) { + if (this._rssi !== rssi) { + this._rssi = rssi; + debug(`RSSI change ${rssi}`); + self.emit("rssiChange", rssi); + } + } + }); + }, 2000); + + self._peripheral.on("disconnect", () => { + clearInterval(rssiUpdateInterval); + this.emit("disconnect"); + }); + + self._peripheral.discoverServices([], (err: string, services: Service[]) => { + + if (err) { + this.emit("error", err); + return; + } + + debug("Service/characteristic discovery started"); + + const servicePromises: Array> = []; + + services.forEach((service) => { + + servicePromises.push(new Promise((resolve, reject) => { + + service.discoverCharacteristics([], (err, characteristics) => { + characteristics.forEach((characteristic) => { + this._characteristics[characteristic.uuid] = characteristic; + }); + return resolve(); + }); + + })); + + }); + + Promise.all(servicePromises).then(() => { + debug("Service/characteristic discovery finished"); + this.emit("connect"); + if (callback) { + callback(); + } + }); + + }); + + }); + + } + + + /** + * Subscribe to sensor notifications on a given port. + * @method Hub#subscribe + * @param {string} port + * @param {number|boolean} [mode=false] - The sensor mode to activate. If no mode is provided, the default for that sensor will be chosen. + */ + public subscribe (port: string, mode: number | boolean = false, callback?: () => void) { + let newMode = 0x00; + if (!mode) { + newMode = this._getModeForDeviceType(this._ports[port].type); + } + this._activatePortDevice(this._ports[port].value, this._ports[port].type, newMode, 0x00, callback); + } + + /** + * Unsubscribe to sensor notifications on a given port. + * @method Hub#unsubscribe + * @param {string} port + */ + public unsubscribe (port: string, callback?: () => void) { + const mode = this._getModeForDeviceType(this._ports[port].type); + this._deactivatePortDevice(this._ports[port].value, this._ports[port].type, mode, 0x00, callback); + } + + + protected _subscribeToCharacteristic (characteristic: Characteristic, callback: (data: Buffer) => void) { + characteristic.on("data", (data: Buffer) => { + return callback(data); + }); + characteristic.subscribe((err) => { + if (err) { + this.emit("error", err); + } + }); + } + + + protected _activatePortDevice (port: number, type: number, mode: number, format: number, callback?: () => void) { + if (callback) { + callback(); + } + } + + + protected _deactivatePortDevice (port: number, type: number, mode: number, format: number, callback?: () => void) { + if (callback) { + callback(); + } + } + + + protected _registerDeviceAttachment (port: Port, type: number) { + + if (port.connected) { + port.type = type; + if (this.autoSubscribe) { + this._activatePortDevice(port.value, type, this._getModeForDeviceType(type), 0x00); + } + } else { + port.type = null; + debug(`Port ${port.id} disconnected`); + } + + } + + + private _getModeForDeviceType (type: number) { + switch (type) { + case Consts.Devices.BASIC_MOTOR: + return 0x02; + case Consts.Devices.BOOST_INTERACTIVE_MOTOR: + return 0x02; + case Consts.Devices.BOOST_MOVE_HUB_MOTOR: + return 0x02; + case Consts.Devices.BOOST_DISTANCE: + return (this.type === Consts.Hubs.WEDO2_SMART_HUB ? 0x00 : 0x08); + case Consts.Devices.BOOST_TILT: + return 0x04; + default: + return 0x00; + } + } + + +} diff --git a/lpf2.js b/lpf2.ts similarity index 53% rename from lpf2.js rename to lpf2.ts index 933bf48..1f6c79a 100644 --- a/lpf2.js +++ b/lpf2.ts @@ -1,15 +1,19 @@ -const noble = require("noble"), - debug = require("debug")("lpf2"), - EventEmitter = require("events").EventEmitter; +import { Peripheral } from "noble"; -const WeDo2Hub = require("./wedo2hub.js"), - BoostHub = require("./boosthub.js"), - Consts = require("./consts.js"); +import { BoostHub } from "./boosthub"; +import { Hub } from "./hub"; +import { WeDo2Hub } from "./wedo2hub"; -let ready = false, - wantScan = false; +import { EventEmitter} from "events"; -noble.on("stateChange", (state) => { +import Debug = require("debug"); +const debug = Debug("lpf2"); +import noble = require("noble"); + +let ready = false; +let wantScan = false; + +noble.on("stateChange", (state: string) => { ready = (state === "poweredOn"); if (ready) { if (wantScan) { @@ -21,26 +25,38 @@ noble.on("stateChange", (state) => { } }); -class LPF2 extends EventEmitter { +/** + * @class LPF2 + * @extends EventEmitter + */ +export class LPF2 extends EventEmitter { + + + public autoSubscribe: boolean = true; + + + private _connectedDevices: any = {}; constructor () { super(); - this.autoSubscribe = true; - this._connectedDevices = {}; } - scan () { + /** + * Begin scanning for LPF2 Hub devices. + * @method LPF2#scan + */ + public scan () { wantScan = true; - noble.on("discover", (peripheral) => { + noble.on("discover", (peripheral: Peripheral) => { - let hub = null; + let hub: Hub; - if (WeDo2Hub.isWeDo2Hub(peripheral)) { + if (WeDo2Hub.IsWeDo2Hub(peripheral)) { hub = new WeDo2Hub(peripheral, this.autoSubscribe); - } else if (BoostHub.isBoostHub(peripheral)) { + } else if (BoostHub.IsBoostHub(peripheral)) { hub = new BoostHub(peripheral, this.autoSubscribe); } else { return; @@ -50,12 +66,12 @@ class LPF2 extends EventEmitter { noble.stopScanning(); noble.startScanning(); - hub._peripheral.on("connect", () => { + hub.on("connect", () => { debug(`Hub ${hub.uuid} connected`); this._connectedDevices[hub.uuid] = hub; }); - hub._peripheral.on("disconnect", () => { + hub.on("disconnect", () => { debug(`Hub ${hub.uuid} disconnected`); delete this._connectedDevices[hub.uuid]; @@ -67,6 +83,11 @@ class LPF2 extends EventEmitter { }); debug(`Hub ${hub.uuid} discovered`); + /** + * Emits when a LPF2 Hub device is found. + * @event LPF2#discover + * @param {Hub} hub + */ this.emit("discover", hub); }); @@ -79,6 +100,3 @@ class LPF2 extends EventEmitter { } - - -module.exports = LPF2; \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 6c26ab4..29f640d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4,17 +4,73 @@ "lockfileVersion": 1, "requires": true, "dependencies": { + "@types/debug": { + "version": "0.0.30", + "resolved": "https://registry.npmjs.org/@types/debug/-/debug-0.0.30.tgz", + "integrity": "sha512-orGL5LXERPYsLov6CWs3Fh6203+dXzJkR7OnddIr2514Hsecwc8xRpzCapshBbKFImCsvS/mk6+FWiN5LyZJAQ==" + }, + "@types/events": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@types/events/-/events-1.2.0.tgz", + "integrity": "sha512-KEIlhXnIutzKwRbQkGWb/I4HFqBuUykAdHgDED6xqwXJfONCjF5VoE0cXEiurh3XauygxzeDzgtXUqvLkxFzzA==" + }, + "@types/noble": { + "version": "0.0.37", + "resolved": "https://registry.npmjs.org/@types/noble/-/noble-0.0.37.tgz", + "integrity": "sha512-1g/UifUgJXLaVv/7Q4YE1ppXYpkpafdTtgaZ9NubL6zzMXXaFrD+KAliyDnLh0Vur6f/JkxhB7i3kx4yD5hWKA==", + "requires": { + "@types/events": "1.2.0", + "@types/node": "10.3.4" + } + }, + "@types/node": { + "version": "10.3.4", + "resolved": "https://registry.npmjs.org/@types/node/-/node-10.3.4.tgz", + "integrity": "sha512-YMLlzdeNnAyLrQew39IFRkMacAR5BqKGIEei9ZjdHsIZtv+ZWKYTu1i7QJhetxQ9ReXx8w5f+cixdHZG3zgMQA==" + }, "abbrev": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", "optional": true }, + "align-text": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz", + "integrity": "sha1-DNkKVhCT810KmSVsIrcGlDP60Rc=", + "dev": true, + "requires": { + "kind-of": "3.2.2", + "longest": "1.0.1", + "repeat-string": "1.6.1" + } + }, + "amdefine": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", + "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=", + "dev": true + }, + "ansi-escape-sequences": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/ansi-escape-sequences/-/ansi-escape-sequences-4.0.0.tgz", + "integrity": "sha512-v+0wW9Wezwsyb0uF4aBVCjmSqit3Ru7PZFziGF0o2KwTvN2zWfTi3BRLq9EkJFdg3eBbyERXGTntVpBxH1J68Q==", + "dev": true, + "requires": { + "array-back": "2.0.0" + } + }, "ansi-regex": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" }, + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true + }, "aproba": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", @@ -31,11 +87,83 @@ "readable-stream": "2.3.6" } }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "requires": { + "sprintf-js": "1.0.3" + } + }, + "argv-tools": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/argv-tools/-/argv-tools-0.1.1.tgz", + "integrity": "sha512-Cc0dBvx4dvrjjKpyDA6w8RlNAw8Su30NvZbWl/Tv9ZALEVlLVkWQiHMi84Q0xNfpVuSaiQbYkdmWK8g1PLGhKw==", + "dev": true, + "requires": { + "array-back": "2.0.0", + "find-replace": "2.0.1" + } + }, + "array-back": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/array-back/-/array-back-2.0.0.tgz", + "integrity": "sha512-eJv4pLLufP3g5kcZry0j6WXpIbzYw9GUB4mVJZno9wfwiBxbizTnHCw3VJb07cBihbFX48Y7oSrW9y+gt4glyw==", + "dev": true, + "requires": { + "typical": "2.6.1" + } + }, + "async": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", + "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=", + "dev": true + }, + "babel-code-frame": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", + "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", + "dev": true, + "requires": { + "chalk": "1.1.3", + "esutils": "2.0.2", + "js-tokens": "3.0.2" + }, + "dependencies": { + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, + "requires": { + "ansi-styles": "2.2.1", + "escape-string-regexp": "1.0.5", + "has-ansi": "2.0.0", + "strip-ansi": "3.0.1", + "supports-color": "2.0.0" + } + } + } + }, + "babylon": { + "version": "7.0.0-beta.19", + "resolved": "https://registry.npmjs.org/babylon/-/babylon-7.0.0-beta.19.tgz", + "integrity": "sha512-Vg0C9s/REX6/WIXN37UKpv5ZhRi6A4pjHlpkE34+8/a6c2W1Q692n3hmc+SZG5lKRnaExLUbxtJ1SVT+KaCQ/A==", + "dev": true + }, "balanced-match": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" }, + "bluebird": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.1.tgz", + "integrity": "sha512-MKiLiV+I1AA596t9w1sQJ8jkiSr5+ZKi0WKrYGUn6d1Fx+Ij4tIj+m2WMQSGczs5jZVxV339chE8iwk6F64wjA==", + "dev": true + }, "bluetooth-hci-socket": { "version": "0.5.1", "resolved": "https://registry.npmjs.org/bluetooth-hci-socket/-/bluetooth-hci-socket-0.5.1.tgz", @@ -62,22 +190,210 @@ "concat-map": "0.0.1" } }, + "builtin-modules": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", + "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", + "dev": true + }, + "cache-point": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/cache-point/-/cache-point-0.4.1.tgz", + "integrity": "sha512-4TgWfe9SF+bUy5cCql8gWHqKNrviufNwSYxLjf2utB0pY4+bdcuFwMmY1hDB+67Gz/L1vmhFNhePAjJTFBtV+Q==", + "dev": true, + "requires": { + "array-back": "2.0.0", + "fs-then-native": "2.0.0", + "mkdirp2": "1.0.4" + } + }, + "camelcase": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz", + "integrity": "sha1-m7UwTS4LVmmLLHWLCKPqqdqlijk=", + "dev": true, + "optional": true + }, + "catharsis": { + "version": "0.8.9", + "resolved": "https://registry.npmjs.org/catharsis/-/catharsis-0.8.9.tgz", + "integrity": "sha1-mMyJDKZS3S7w5ws3klMQ/56Q/Is=", + "dev": true, + "requires": { + "underscore-contrib": "0.3.0" + } + }, + "center-align": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz", + "integrity": "sha1-qg0yYptu6XIgBBHL1EYckHvCt60=", + "dev": true, + "optional": true, + "requires": { + "align-text": "0.1.4", + "lazy-cache": "1.0.4" + } + }, + "chalk": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz", + "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==", + "dev": true, + "requires": { + "ansi-styles": "3.2.1", + "escape-string-regexp": "1.0.5", + "supports-color": "5.4.0" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "1.9.2" + } + }, + "supports-color": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz", + "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==", + "dev": true, + "requires": { + "has-flag": "3.0.0" + } + } + } + }, "chownr": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.0.1.tgz", "integrity": "sha1-4qdQQqlVGQi+vSW4Uj1fl2nXkYE=", "optional": true }, + "cliui": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz", + "integrity": "sha1-S0dXYP+AJkx2LDoXGQMukcf+oNE=", + "dev": true, + "optional": true, + "requires": { + "center-align": "0.1.3", + "right-align": "0.1.3", + "wordwrap": "0.0.2" + }, + "dependencies": { + "wordwrap": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz", + "integrity": "sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8=", + "dev": true, + "optional": true + } + } + }, "code-point-at": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=" }, + "collect-all": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/collect-all/-/collect-all-1.0.3.tgz", + "integrity": "sha512-0y0rBgoX8IzIjBAUnO73SEtSb4Mhk3IoceWJq5zZSxb9mWORhWH8xLYo4EDSOE1jRBk1LhmfjqWFFt10h/+MEA==", + "dev": true, + "requires": { + "stream-connect": "1.0.2", + "stream-via": "1.0.4" + } + }, + "color-convert": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.2.tgz", + "integrity": "sha512-3NUJZdhMhcdPn8vJ9v2UQJoH0qqoGUkYTgFEPZaPjEtwmmKUfNV46zZmgB2M5M4DCEQHMaCfWHCxiBflLm04Tg==", + "dev": true, + "requires": { + "color-name": "1.1.1" + } + }, + "color-name": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.1.tgz", + "integrity": "sha1-SxQVMEz1ACjqgWQ2Q72C6gWANok=", + "dev": true + }, + "command-line-args": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/command-line-args/-/command-line-args-5.0.2.tgz", + "integrity": "sha512-/qPcbL8zpqg53x4rAaqMFlRV4opN3pbla7I7k9x8kyOBMQoGT6WltjN6sXZuxOXw6DgdK7Ad+ijYS5gjcr7vlA==", + "dev": true, + "requires": { + "argv-tools": "0.1.1", + "array-back": "2.0.0", + "find-replace": "2.0.1", + "lodash.camelcase": "4.3.0", + "typical": "2.6.1" + } + }, + "command-line-tool": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/command-line-tool/-/command-line-tool-0.8.0.tgz", + "integrity": "sha512-Xw18HVx/QzQV3Sc5k1vy3kgtOeGmsKIqwtFFoyjI4bbcpSgnw2CWVULvtakyw4s6fhyAdI6soQQhXc2OzJy62g==", + "dev": true, + "requires": { + "ansi-escape-sequences": "4.0.0", + "array-back": "2.0.0", + "command-line-args": "5.0.2", + "command-line-usage": "4.1.0", + "typical": "2.6.1" + } + }, + "command-line-usage": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/command-line-usage/-/command-line-usage-4.1.0.tgz", + "integrity": "sha512-MxS8Ad995KpdAC0Jopo/ovGIroV/m0KHwzKfXxKag6FHOkGsH8/lv5yjgablcRxCJJC0oJeUMuO/gmaq+Wq46g==", + "dev": true, + "requires": { + "ansi-escape-sequences": "4.0.0", + "array-back": "2.0.0", + "table-layout": "0.4.4", + "typical": "2.6.1" + } + }, + "commander": { + "version": "2.15.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.15.1.tgz", + "integrity": "sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag==", + "dev": true + }, + "common-sequence": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/common-sequence/-/common-sequence-1.0.2.tgz", + "integrity": "sha1-MOB/P49vf5s97oVPILLTnu4Ibeg=", + "dev": true + }, "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" }, + "config-master": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/config-master/-/config-master-3.1.0.tgz", + "integrity": "sha1-ZnZjWQUFooO/JqSE1oSJ10xUhdo=", + "dev": true, + "requires": { + "walk-back": "2.0.1" + }, + "dependencies": { + "walk-back": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/walk-back/-/walk-back-2.0.1.tgz", + "integrity": "sha1-VU4qnYdPrEeoywBr9EwvDEmYoKQ=", + "dev": true + } + } + }, "console-control-strings": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", @@ -97,11 +413,17 @@ "ms": "0.7.1" } }, + "decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", + "dev": true, + "optional": true + }, "deep-extend": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", - "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", - "optional": true + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==" }, "delegates": { "version": "1.0.0", @@ -115,6 +437,70 @@ "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=", "optional": true }, + "diff": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", + "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", + "dev": true + }, + "dmd": { + "version": "3.0.12", + "resolved": "https://registry.npmjs.org/dmd/-/dmd-3.0.12.tgz", + "integrity": "sha512-79w644JdsB2TthYpVl2bDurX7i9Abaegg2E7X46Ajc135aASTMXxrHzJ9mOa5X5nbmnXwlBYiF68K+1baX+BzQ==", + "dev": true, + "requires": { + "array-back": "2.0.0", + "cache-point": "0.4.1", + "common-sequence": "1.0.2", + "file-set": "2.0.0", + "handlebars": "4.0.11", + "marked": "0.3.19", + "object-get": "2.1.0", + "reduce-flatten": "1.0.1", + "reduce-unique": "1.0.0", + "reduce-without": "1.0.1", + "test-value": "3.0.0", + "walk-back": "3.0.0" + } + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true + }, + "esprima": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.0.tgz", + "integrity": "sha512-oftTcaMu/EGrEIu904mWteKIv8vMuOgGYo7EhVJJN00R/EED9DCua/xxHRdYnKtcECzVg7xOWhflvJMnqcFZjw==", + "dev": true + }, + "esutils": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", + "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", + "dev": true + }, + "file-set": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/file-set/-/file-set-2.0.0.tgz", + "integrity": "sha512-cCWXfw+nrYoIoUVmEF7Xsw91lGWuObtSnTEZ7AmdvZou1A/6Xx237HfxdQyC/ayKRvQSMbNOBwg62OjN5JxbXw==", + "dev": true, + "requires": { + "array-back": "2.0.0", + "glob": "7.1.2" + } + }, + "find-replace": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/find-replace/-/find-replace-2.0.1.tgz", + "integrity": "sha512-LzDo3Fpa30FLIBsh6DCDnMN1KW2g4QKkqKmejlImgWY67dDFPX/x9Kh/op/GK522DchQXEvDi/wD48HKW49XOQ==", + "dev": true, + "requires": { + "array-back": "2.0.0", + "test-value": "3.0.0" + } + }, "fs-minipass": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.5.tgz", @@ -124,11 +510,16 @@ "minipass": "2.3.3" } }, + "fs-then-native": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fs-then-native/-/fs-then-native-2.0.0.tgz", + "integrity": "sha1-GaEk2U2QwiyOBF8ujdbr6jbUjGc=", + "dev": true + }, "fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", - "optional": true + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" }, "gauge": { "version": "2.7.4", @@ -150,7 +541,6 @@ "version": "7.1.2", "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", - "optional": true, "requires": { "fs.realpath": "1.0.0", "inflight": "1.0.6", @@ -160,6 +550,39 @@ "path-is-absolute": "1.0.1" } }, + "graceful-fs": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", + "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=", + "dev": true + }, + "handlebars": { + "version": "4.0.11", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.0.11.tgz", + "integrity": "sha1-Ywo13+ApS8KB7a5v/F0yn8eYLcw=", + "dev": true, + "requires": { + "async": "1.5.2", + "optimist": "0.6.1", + "source-map": "0.4.4", + "uglify-js": "2.8.29" + } + }, + "has-ansi": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", + "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", + "dev": true, + "requires": { + "ansi-regex": "2.1.1" + } + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, "has-unicode": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", @@ -188,7 +611,6 @@ "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "optional": true, "requires": { "once": "1.4.0", "wrappy": "1.0.2" @@ -205,6 +627,12 @@ "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==", "optional": true }, + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true + }, "is-fullwidth-code-point": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", @@ -219,6 +647,158 @@ "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", "optional": true }, + "js-tokens": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", + "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=", + "dev": true + }, + "js-yaml": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.12.0.tgz", + "integrity": "sha512-PIt2cnwmPfL4hKNwqeiuz4bKfnzHTBv6HyVgjahA6mPLwPDzjDWrplJBMjHUFxku/N3FlmrbyPclad+I+4mJ3A==", + "dev": true, + "requires": { + "argparse": "1.0.10", + "esprima": "4.0.0" + } + }, + "js2xmlparser": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/js2xmlparser/-/js2xmlparser-3.0.0.tgz", + "integrity": "sha1-P7YOqgicVED5MZ9RdgzNB+JJlzM=", + "dev": true, + "requires": { + "xmlcreate": "1.0.2" + } + }, + "jsdoc": { + "version": "3.5.5", + "resolved": "https://registry.npmjs.org/jsdoc/-/jsdoc-3.5.5.tgz", + "integrity": "sha512-6PxB65TAU4WO0Wzyr/4/YhlGovXl0EVYfpKbpSroSj0qBxT4/xod/l40Opkm38dRHRdQgdeY836M0uVnJQG7kg==", + "dev": true, + "requires": { + "babylon": "7.0.0-beta.19", + "bluebird": "3.5.1", + "catharsis": "0.8.9", + "escape-string-regexp": "1.0.5", + "js2xmlparser": "3.0.0", + "klaw": "2.0.0", + "marked": "0.3.19", + "mkdirp": "0.5.1", + "requizzle": "0.2.1", + "strip-json-comments": "2.0.1", + "taffydb": "2.6.2", + "underscore": "1.8.3" + } + }, + "jsdoc-api": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/jsdoc-api/-/jsdoc-api-4.0.3.tgz", + "integrity": "sha512-dfYq9JgB+XahY0XfSEw93PmXmocjwYcvJ5aMuQUJ/OdDRGWamf2SSOk3W06Bsj8qdjp/UdefzqpP/mpwsvHuvA==", + "dev": true, + "requires": { + "array-back": "2.0.0", + "cache-point": "0.4.1", + "collect-all": "1.0.3", + "file-set": "2.0.0", + "fs-then-native": "2.0.0", + "jsdoc": "3.5.5", + "object-to-spawn-args": "1.1.1", + "temp-path": "1.0.0", + "walk-back": "3.0.0" + } + }, + "jsdoc-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/jsdoc-parse/-/jsdoc-parse-3.0.1.tgz", + "integrity": "sha512-btZLp4wYl90vcAfgk4hoGQbO17iBVrhh3LJRMKZNtZgniO3F8H2CjxXld0owBIB1XxN+j3bAcWZnZKMnSj3iMA==", + "dev": true, + "requires": { + "array-back": "2.0.0", + "lodash.omit": "4.5.0", + "lodash.pick": "4.4.0", + "reduce-extract": "1.0.0", + "sort-array": "2.0.0", + "test-value": "3.0.0" + } + }, + "jsdoc-to-markdown": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/jsdoc-to-markdown/-/jsdoc-to-markdown-4.0.1.tgz", + "integrity": "sha512-LHJRoLoLyDdxNcColgkLoB/rFG5iRP+PNJjMILI0x+95IdEAtyjSt0wJ6ZlKxRpkhBYtQXTQQ119hMqPIUZzTQ==", + "dev": true, + "requires": { + "array-back": "2.0.0", + "command-line-tool": "0.8.0", + "config-master": "3.1.0", + "dmd": "3.0.12", + "jsdoc-api": "4.0.3", + "jsdoc-parse": "3.0.1", + "walk-back": "3.0.0" + } + }, + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "1.1.6" + } + }, + "klaw": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/klaw/-/klaw-2.0.0.tgz", + "integrity": "sha1-WcEo4Nxc5BAgEVEZTuucv4WGUPY=", + "dev": true, + "requires": { + "graceful-fs": "4.1.11" + } + }, + "lazy-cache": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz", + "integrity": "sha1-odePw6UEdMuAhF07O24dpJpEbo4=", + "dev": true, + "optional": true + }, + "lodash.camelcase": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", + "integrity": "sha1-soqmKIorn8ZRA1x3EfZathkDMaY=", + "dev": true + }, + "lodash.omit": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.omit/-/lodash.omit-4.5.0.tgz", + "integrity": "sha1-brGa5aHuHdnfC5aeZs4Lf6MLXmA=", + "dev": true + }, + "lodash.padend": { + "version": "4.6.1", + "resolved": "https://registry.npmjs.org/lodash.padend/-/lodash.padend-4.6.1.tgz", + "integrity": "sha1-U8y6BH0G4VjTEfRdpiX05J5vFm4=", + "dev": true + }, + "lodash.pick": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.pick/-/lodash.pick-4.4.0.tgz", + "integrity": "sha1-UvBWEP/53tQiYRRB7R/BI6AwAbM=", + "dev": true + }, + "longest": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz", + "integrity": "sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc=", + "dev": true + }, + "marked": { + "version": "0.3.19", + "resolved": "https://registry.npmjs.org/marked/-/marked-0.3.19.tgz", + "integrity": "sha512-ea2eGWOqNxPcXv8dyERdSr/6FmzvWwzjMxpfGB/sbMccXoct+xY+YukPD+QTUZwyvK7BZwcr4m21WBOW41pAkg==", + "dev": true + }, "minimatch": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", @@ -258,6 +838,12 @@ "minimist": "0.0.8" } }, + "mkdirp2": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp2/-/mkdirp2-1.0.4.tgz", + "integrity": "sha512-Q2PKB4ZR4UPtjLl76JfzlgSCUZhSV1AXQgAZa1qt5RiaALFjP/CDrGvFBrOz7Ck6McPcwMAxTsJvWOUjOU8XMw==", + "dev": true + }, "ms": { "version": "0.7.1", "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz", @@ -358,6 +944,18 @@ "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", "optional": true }, + "object-get": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/object-get/-/object-get-2.1.0.tgz", + "integrity": "sha1-ciu9tgA576R8rTxtws5RqFwCxa4=", + "dev": true + }, + "object-to-spawn-args": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-to-spawn-args/-/object-to-spawn-args-1.1.1.tgz", + "integrity": "sha1-d9qIJ/Bz0BHJ4bFz+JV4FHAkZ4U=", + "dev": true + }, "once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -366,6 +964,16 @@ "wrappy": "1.0.2" } }, + "optimist": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz", + "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=", + "dev": true, + "requires": { + "minimist": "0.0.8", + "wordwrap": "0.0.3" + } + }, "os-homedir": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", @@ -391,8 +999,13 @@ "path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", - "optional": true + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" + }, + "path-parse": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.5.tgz", + "integrity": "sha1-PBrfhx6pzWyUMbbqK9dKD/BVxME=", + "dev": true }, "process-nextick-args": { "version": "2.0.0", @@ -435,6 +1048,120 @@ "util-deprecate": "1.0.2" } }, + "reduce-extract": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/reduce-extract/-/reduce-extract-1.0.0.tgz", + "integrity": "sha1-Z/I4W+2mUGG19fQxJmLosIDKFSU=", + "dev": true, + "requires": { + "test-value": "1.1.0" + }, + "dependencies": { + "array-back": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/array-back/-/array-back-1.0.4.tgz", + "integrity": "sha1-ZEun8JX3/898Q7Xw3DnTwfA8Bjs=", + "dev": true, + "requires": { + "typical": "2.6.1" + } + }, + "test-value": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/test-value/-/test-value-1.1.0.tgz", + "integrity": "sha1-oJE29y7AQ9J8iTcHwrFZv6196T8=", + "dev": true, + "requires": { + "array-back": "1.0.4", + "typical": "2.6.1" + } + } + } + }, + "reduce-flatten": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/reduce-flatten/-/reduce-flatten-1.0.1.tgz", + "integrity": "sha1-JYx479FT3fk8tWEjf2EYTzaW4yc=", + "dev": true + }, + "reduce-unique": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/reduce-unique/-/reduce-unique-1.0.0.tgz", + "integrity": "sha1-flhrz4ek4ytter2Cd/rWzeyfSAM=", + "dev": true + }, + "reduce-without": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/reduce-without/-/reduce-without-1.0.1.tgz", + "integrity": "sha1-aK0OrRGFXJo31OglbBW7+Hly/Iw=", + "dev": true, + "requires": { + "test-value": "2.1.0" + }, + "dependencies": { + "array-back": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/array-back/-/array-back-1.0.4.tgz", + "integrity": "sha1-ZEun8JX3/898Q7Xw3DnTwfA8Bjs=", + "dev": true, + "requires": { + "typical": "2.6.1" + } + }, + "test-value": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/test-value/-/test-value-2.1.0.tgz", + "integrity": "sha1-Edpv9nDzRxpztiXKTz/c97t0gpE=", + "dev": true, + "requires": { + "array-back": "1.0.4", + "typical": "2.6.1" + } + } + } + }, + "repeat-string": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", + "dev": true + }, + "requizzle": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/requizzle/-/requizzle-0.2.1.tgz", + "integrity": "sha1-aUPDUwxNmn5G8c3dUcFY/GcM294=", + "dev": true, + "requires": { + "underscore": "1.6.0" + }, + "dependencies": { + "underscore": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.6.0.tgz", + "integrity": "sha1-izixDKze9jM3uLJOT/htRa6lKag=", + "dev": true + } + } + }, + "resolve": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.8.1.tgz", + "integrity": "sha512-AicPrAC7Qu1JxPCZ9ZgCZlY35QgFnNqc+0LtbRNxnVw4TXvjQ72wnuL9JQcEBgXkI9JM8MsT9kaQoHcpCRJOYA==", + "dev": true, + "requires": { + "path-parse": "1.0.5" + } + }, + "right-align": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz", + "integrity": "sha1-YTObci/mo1FWiSENJOFMlhSGE+8=", + "dev": true, + "optional": true, + "requires": { + "align-text": "0.1.4" + } + }, "rimraf": { "version": "2.6.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz", @@ -464,8 +1191,7 @@ "semver": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz", - "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==", - "optional": true + "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==" }, "set-blocking": { "version": "2.0.0", @@ -479,6 +1205,69 @@ "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", "optional": true }, + "sort-array": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/sort-array/-/sort-array-2.0.0.tgz", + "integrity": "sha1-OKnG2if9fRR7QuYFVPKBGHtN9HI=", + "dev": true, + "requires": { + "array-back": "1.0.4", + "object-get": "2.1.0", + "typical": "2.6.1" + }, + "dependencies": { + "array-back": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/array-back/-/array-back-1.0.4.tgz", + "integrity": "sha1-ZEun8JX3/898Q7Xw3DnTwfA8Bjs=", + "dev": true, + "requires": { + "typical": "2.6.1" + } + } + } + }, + "source-map": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz", + "integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=", + "dev": true, + "requires": { + "amdefine": "1.0.1" + } + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + }, + "stream-connect": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/stream-connect/-/stream-connect-1.0.2.tgz", + "integrity": "sha1-GLyB8u2zW4tdmoAJIAqYUxRCipc=", + "dev": true, + "requires": { + "array-back": "1.0.4" + }, + "dependencies": { + "array-back": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/array-back/-/array-back-1.0.4.tgz", + "integrity": "sha1-ZEun8JX3/898Q7Xw3DnTwfA8Bjs=", + "dev": true, + "requires": { + "typical": "2.6.1" + } + } + } + }, + "stream-via": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/stream-via/-/stream-via-1.0.4.tgz", + "integrity": "sha512-DBp0lSvX5G9KGRDTkR/R+a29H+Wk2xItOF+MpZLLNDWbEV9tGPnqLPxHEYjmiz8xGtJHRIqmI+hCjmNzqoA4nQ==", + "dev": true + }, "string-width": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", @@ -509,8 +1298,32 @@ "strip-json-comments": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", - "optional": true + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=" + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true + }, + "table-layout": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/table-layout/-/table-layout-0.4.4.tgz", + "integrity": "sha512-uNaR3SRMJwfdp9OUr36eyEi6LLsbcTqTO/hfTsNviKsNeyMBPICJCC7QXRF3+07bAP6FRwA8rczJPBqXDc0CkQ==", + "dev": true, + "requires": { + "array-back": "2.0.0", + "deep-extend": "0.6.0", + "lodash.padend": "4.6.1", + "typical": "2.6.1", + "wordwrapjs": "3.0.0" + } + }, + "taffydb": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/taffydb/-/taffydb-2.6.2.tgz", + "integrity": "sha1-fLy2S1oUG2ou/CxdLGe04VCyomg=", + "dev": true }, "tar": { "version": "4.4.4", @@ -527,6 +1340,119 @@ "yallist": "3.0.2" } }, + "temp-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/temp-path/-/temp-path-1.0.0.tgz", + "integrity": "sha1-JLFUOXOrRCiW2a02fdnL2/r+kYs=", + "dev": true + }, + "test-value": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/test-value/-/test-value-3.0.0.tgz", + "integrity": "sha512-sVACdAWcZkSU9x7AOmJo5TqE+GyNJknHaHsMrR6ZnhjVlVN9Yx6FjHrsKZ3BjIpPCT68zYesPWkakrNupwfOTQ==", + "dev": true, + "requires": { + "array-back": "2.0.0", + "typical": "2.6.1" + } + }, + "tslib": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.2.tgz", + "integrity": "sha512-AVP5Xol3WivEr7hnssHDsaM+lVrVXWUvd1cfXTRkTj80b//6g2wIFEH6hZG0muGZRnHGrfttpdzRk3YlBkWjKw==", + "dev": true + }, + "tslint": { + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/tslint/-/tslint-5.10.0.tgz", + "integrity": "sha1-EeJrzLiK+gLdDZlWyuPUVAtfVMM=", + "dev": true, + "requires": { + "babel-code-frame": "6.26.0", + "builtin-modules": "1.1.1", + "chalk": "2.4.1", + "commander": "2.15.1", + "diff": "3.5.0", + "glob": "7.1.2", + "js-yaml": "3.12.0", + "minimatch": "3.0.4", + "resolve": "1.8.1", + "semver": "5.5.0", + "tslib": "1.9.2", + "tsutils": "2.27.1" + } + }, + "tsutils": { + "version": "2.27.1", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.27.1.tgz", + "integrity": "sha512-AE/7uzp32MmaHvNNFES85hhUDHFdFZp6OAiZcd6y4ZKKIg6orJTm8keYWBhIhrJQH3a4LzNKat7ZPXZt5aTf6w==", + "dev": true, + "requires": { + "tslib": "1.9.2" + } + }, + "typescript": { + "version": "2.9.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-2.9.2.tgz", + "integrity": "sha512-Gr4p6nFNaoufRIY4NMdpQRNmgxVIGMs4Fcu/ujdYk3nAZqk7supzBE9idmvfZIlH/Cuj//dvi+019qEue9lV0w==" + }, + "typical": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/typical/-/typical-2.6.1.tgz", + "integrity": "sha1-XAgOXWYcu+OCWdLnCjxyU+hziB0=", + "dev": true + }, + "uglify-js": { + "version": "2.8.29", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.8.29.tgz", + "integrity": "sha1-KcVzMUgFe7Th913zW3qcty5qWd0=", + "dev": true, + "optional": true, + "requires": { + "source-map": "0.5.7", + "uglify-to-browserify": "1.0.2", + "yargs": "3.10.0" + }, + "dependencies": { + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true, + "optional": true + } + } + }, + "uglify-to-browserify": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz", + "integrity": "sha1-bgkk1r2mta/jSeOabWMoUKD4grc=", + "dev": true, + "optional": true + }, + "underscore": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.8.3.tgz", + "integrity": "sha1-Tz+1OxBuYJf8+ctBCfKl6b36UCI=", + "dev": true + }, + "underscore-contrib": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/underscore-contrib/-/underscore-contrib-0.3.0.tgz", + "integrity": "sha1-ZltmwkeD+PorGMn4y7Dix9SMJsc=", + "dev": true, + "requires": { + "underscore": "1.6.0" + }, + "dependencies": { + "underscore": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.6.0.tgz", + "integrity": "sha1-izixDKze9jM3uLJOT/htRa6lKag=", + "dev": true + } + } + }, "usb": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/usb/-/usb-1.3.2.tgz", @@ -543,6 +1469,12 @@ "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", "optional": true }, + "walk-back": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/walk-back/-/walk-back-3.0.0.tgz", + "integrity": "sha1-I1h4ejXakQMtrV6S+AsSNw2HlcU=", + "dev": true + }, "wide-align": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", @@ -552,11 +1484,40 @@ "string-width": "1.0.2" } }, + "window-size": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz", + "integrity": "sha1-VDjNLqk7IC76Ohn+iIeu58lPnJ0=", + "dev": true, + "optional": true + }, + "wordwrap": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", + "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=", + "dev": true + }, + "wordwrapjs": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/wordwrapjs/-/wordwrapjs-3.0.0.tgz", + "integrity": "sha512-mO8XtqyPvykVCsrwj5MlOVWvSnCdT+C+QVbm6blradR7JExAhbkZ7hZ9A+9NUtwzSqrlUo9a67ws0EiILrvRpw==", + "dev": true, + "requires": { + "reduce-flatten": "1.0.1", + "typical": "2.6.1" + } + }, "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" }, + "xmlcreate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/xmlcreate/-/xmlcreate-1.0.2.tgz", + "integrity": "sha1-+mv3YqYKQT+z3Y9LA8WyaSONMI8=", + "dev": true + }, "xpc-connection": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/xpc-connection/-/xpc-connection-0.1.4.tgz", @@ -570,6 +1531,19 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.2.tgz", "integrity": "sha1-hFK0u36Dx8GI2AQcGoN8dz1ti7k=" + }, + "yargs": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz", + "integrity": "sha1-9+572FfdfB0tOMDnTvvWgdFDH9E=", + "dev": true, + "optional": true, + "requires": { + "camelcase": "1.2.1", + "cliui": "2.1.0", + "decamelize": "1.2.0", + "window-size": "0.1.0" + } } } } diff --git a/package.json b/package.json index 5e70b0a..f130b1f 100644 --- a/package.json +++ b/package.json @@ -2,13 +2,22 @@ "name": "node-lpf2", "version": "1.0.0", "description": "A Node.js module to interface with Lego Power Functions 2.0 components.", - "main": "lpf2.js", + "main": "dist/lpf2.js", + "types": "dist/lpf2.d.ts", "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" + "build": "tslint -c tslint.json \"*.ts\" && tsc" }, "author": "Nathan Kunicki ", "license": "MIT", "dependencies": { - "noble": "^1.9.1" + "@types/debug": "0.0.30", + "@types/noble": "0.0.37", + "@types/node": "^10.3.4", + "noble": "^1.9.1", + "typescript": "^2.9.2" + }, + "devDependencies": { + "jsdoc-to-markdown": "^4.0.1", + "tslint": "^5.10.0" } } diff --git a/port.js b/port.js deleted file mode 100644 index dd2610b..0000000 --- a/port.js +++ /dev/null @@ -1,12 +0,0 @@ -class Port { - - constructor (id, value) { - this.id = id; - this.value = value; - this.connected = false; - this.type = null; - } - -} - -module.exports = Port; \ No newline at end of file diff --git a/port.ts b/port.ts new file mode 100644 index 0000000..f4d18f6 --- /dev/null +++ b/port.ts @@ -0,0 +1,17 @@ +export class Port { + + + public id: string; + public value: number; + public connected: boolean; + public type: number | null; + + + constructor (id: string, value: number) { + this.id = id; + this.value = value; + this.connected = false; + this.type = null; + } + +} diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..9d0d4a0 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,59 @@ +{ + "compilerOptions": { + /* Basic Options */ + "target": "es2017", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017','ES2018' or 'ESNEXT'. */ + "module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */ + // "lib": [], /* Specify library files to be included in the compilation. */ + // "allowJs": true, /* Allow javascript files to be compiled. */ + // "checkJs": true, /* Report errors in .js files. */ + // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */ + "declaration": true, /* Generates corresponding '.d.ts' file. */ + // "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */ + // "sourceMap": true, /* Generates corresponding '.map' file. */ + // "outFile": "./", /* Concatenate and emit output to single file. */ + "outDir": "./dist", /* Redirect output structure to the directory. */ + // "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */ + // "composite": true, /* Enable project compilation */ + // "removeComments": true, /* Do not emit comments to output. */ + // "noEmit": true, /* Do not emit outputs. */ + // "importHelpers": true, /* Import emit helpers from 'tslib'. */ + // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */ + // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */ + + /* Strict Type-Checking Options */ + "strict": true, /* Enable all strict type-checking options. */ + // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ + // "strictNullChecks": true, /* Enable strict null checks. */ + // "strictFunctionTypes": true, /* Enable strict checking of function types. */ + // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */ + // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ + // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ + + /* Additional Checks */ + // "noUnusedLocals": true, /* Report errors on unused locals. */ + // "noUnusedParameters": true, /* Report errors on unused parameters. */ + // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ + // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ + + /* Module Resolution Options */ + // "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */ + // "baseUrl": "./", /* Base directory to resolve non-absolute module names. */ + // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */ + // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ + // "typeRoots": [], /* List of folders to include type definitions from. */ + // "types": [], /* Type declaration files to be included in compilation. */ + // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ + "esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */ + // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ + + /* Source Map Options */ + // "sourceRoot": "./", /* Specify the location where debugger should locate TypeScript files instead of source locations. */ + // "mapRoot": "./", /* Specify the location where debugger should locate map files instead of generated locations. */ + // "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */ + // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */ + + /* Experimental Options */ + // "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */ + // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */ + } +} \ No newline at end of file diff --git a/tslint.json b/tslint.json new file mode 100644 index 0000000..f0d91cd --- /dev/null +++ b/tslint.json @@ -0,0 +1,23 @@ +{ + "defaultSeverity": "error", + "extends": [ + "tslint:recommended" + ], + "jsRules": {}, + "rules": { + "no-consecutive-blank-lines": false, + "space-before-function-paren": false, + "no-bitwise": false, + "trailing-comma": false, + "max-line-length": false, + "prefer-for-of": false, + "typedef": true, + "no-console": false, + "variable-name": [true, "ban-keywords", "check-format", "allow-leading-underscore"], + "object-literal-key-quotes": "consistent", + "object-literal-sort-keys": false, + "no-string-literal": false, + "no-shadowed-variable": [false] + }, + "rulesDirectory": [] +} \ No newline at end of file diff --git a/wedo2hub.js b/wedo2hub.ts similarity index 57% rename from wedo2hub.js rename to wedo2hub.ts index c56467d..a695025 100644 --- a/wedo2hub.js +++ b/wedo2hub.ts @@ -1,33 +1,41 @@ -const debug = require("debug")("lpf2"), - EventEmitter = require("events").EventEmitter; +import { Peripheral } from "noble"; -const Hub = require("./hub.js"), - Port = require("./port.js"), - Consts = require("./consts.js"); +import { Hub } from "./hub.js"; +import { Port } from "./port.js"; + +import Debug = require("debug"); +const debug = Debug("lpf2"); +import { Consts } from "./consts.js"; -class WeDo2Hub extends Hub { +/** + * @class WeDo2Hub + * @extends Hub + */ +export class WeDo2Hub extends Hub { - constructor (peripheral, autoSubscribe) { - super(peripheral, autoSubscribe); - this.type = Consts.Hubs.WEDO2_SMART_HUB; - this.ports = { - "A": new Port("A", 1), - "B": new Port("B", 2) - }; - this._lastTiltX = 0; - this._lastTiltY = 0; - debug("Discovered WeDo 2.0 Smart Hub"); - } - - - static isWeDo2Hub (peripheral) { + public static IsWeDo2Hub (peripheral: Peripheral) { return (peripheral.advertisement.localName === Consts.BLE.Name.WEDO2_SMART_HUB_NAME && peripheral.advertisement.serviceUuids.indexOf(Consts.BLE.Services.WEDO2_SMART_HUB) >= 0); } - connect (callback) { + private _lastTiltX: number = 0; + private _lastTiltY: number = 0; + + + constructor (peripheral: Peripheral, autoSubscribe: boolean = true) { + super(peripheral, autoSubscribe); + this.type = Consts.Hubs.WEDO2_SMART_HUB; + this._ports = { + "A": new Port("A", 1), + "B": new Port("B", 2) + }; + debug("Discovered WeDo 2.0 Smart Hub"); + } + + + public connect (callback: () => void) { debug("Connecting to WeDo 2.0 Smart Hub"); super.connect(() => { this._subscribeToCharacteristic(this._characteristics[Consts.BLE.Characteristics.WeDo2.PORT_TYPE], this._parsePortMessage.bind(this)); @@ -37,11 +45,16 @@ class WeDo2Hub extends Hub { if (callback) { callback(); } - }) + }); } - - setLEDColor (color) { + + /** + * Set the color of the LED on the Hub via a color value. + * @method WeDo2Hub#setLEDColor + * @param {number} color - A number representing one of the LED color consts. + */ + public setLEDColor (color: number | boolean) { const motorCharacteristic = this._characteristics[Consts.BLE.Characteristics.WeDo2.MOTOR_VALUE_WRITE]; const portCharacteristic = this._characteristics[Consts.BLE.Characteristics.WeDo2.PORT_TYPE_WRITE]; if (motorCharacteristic && portCharacteristic) { @@ -56,35 +69,63 @@ class WeDo2Hub extends Hub { } - setLEDRGB (red, green, blue) { + /** + * Set the color of the LED on the Hub via RGB values. + * @method WeDo2Hub#setLEDRGB + * @param {number} red + * @param {number} green + * @param {number} blue + */ + public setLEDRGB (red: number, green: number, blue: number) { const motorCharacteristic = this._characteristics[Consts.BLE.Characteristics.WeDo2.MOTOR_VALUE_WRITE]; const portCharacteristic = this._characteristics[Consts.BLE.Characteristics.WeDo2.PORT_TYPE_WRITE]; if (motorCharacteristic && portCharacteristic) { - let data1 = Buffer.from([0x01, 0x02, 0x06, 0x17, 0x01, 0x02]); + const data1 = Buffer.from([0x01, 0x02, 0x06, 0x17, 0x01, 0x02]); portCharacteristic.write(data1); - let data2 = Buffer.from([0x06, 0x04, 0x03, red, green, blue]); - console.log(data2); + const data2 = Buffer.from([0x06, 0x04, 0x03, red, green, blue]); motorCharacteristic.write(data2); } } - setMotorSpeed (port, speed) { + /** + * Set the motor speed on a given port. + * @method WeDo2Hub#setMotorSpeed + * @param {string} port + * @param {number} speed - For forward, a value between 1 - 100 should be set. For reverse, a value between -1 to -100. Stop is 0. + */ + public setMotorSpeed (port: string, speed: number) { const characteristic = this._characteristics[Consts.BLE.Characteristics.WeDo2.MOTOR_VALUE_WRITE]; if (characteristic) { - characteristic.write(Buffer.from([this.ports[port].value, 0x01, 0x02, speed])); + characteristic.write(Buffer.from([this._ports[port].value, 0x01, 0x02, speed])); } } - _getPortForPortNumber (num) { + protected _activatePortDevice (port: number, type: number, mode: number, format: number, callback: () => void) { + const characteristic = this._characteristics[Consts.BLE.Characteristics.WeDo2.PORT_TYPE_WRITE]; + if (characteristic) { + characteristic.write(Buffer.from([0x01, 0x02, port, type, mode, 0x01, 0x00, 0x00, 0x00, format, 0x01]), callback); + } + } + + + protected _deactivatePortDevice (port: number, type: number, mode: number, format: number, callback: () => void) { + const characteristic = this._characteristics[Consts.BLE.Characteristics.WeDo2.PORT_TYPE_WRITE]; + if (characteristic) { + characteristic.write(Buffer.from([0x01, 0x02, port, type, mode, 0x01, 0x00, 0x00, 0x00, format, 0x00]), callback); + } + } + + + private _getPortForPortNumber (num: number) { let port = null; if (num === 1) { - port = this.ports["A"]; + port = this._ports["A"]; } else if (num === 2) { - port = this.ports["B"]; + port = this._ports["B"]; } else { return; } @@ -94,9 +135,9 @@ class WeDo2Hub extends Hub { } - _parsePortMessage (data) { + private _parsePortMessage (data: Buffer) { - let port = this._getPortForPortNumber(data[0]); + const port = this._getPortForPortNumber(data[0]); if (!port) { return; @@ -108,34 +149,23 @@ class WeDo2Hub extends Hub { } - _activatePortDevice (port, type, mode, format, callback) { - const characteristic = this._characteristics[Consts.BLE.Characteristics.WeDo2.PORT_TYPE_WRITE]; - if (characteristic) { - characteristic.write(Buffer.from([0x01, 0x02, port, type, mode, 0x01, 0x00, 0x00, 0x00, format, 0x01]), callback); - } - } - - - _deactivatePortDevice (port, type, mode, format, callback) { - const characteristic = this._characteristics[Consts.BLE.Characteristics.WeDo2.PORT_TYPE_WRITE]; - if (characteristic) { - characteristic.write(Buffer.from([0x01, 0x02, port, type, mode, 0x01, 0x00, 0x00, 0x00, format, 0x00]), callback); - } - } - - - _parseSensorMessage (data) { + private _parseSensorMessage (data: Buffer) { if (data[0] === 1) { + /** + * Emits when a button is pressed. + * @event WeDo2Hub#button + * @param {number} state - A number representing one of the button state consts. + */ this.emit("button", Consts.Button.PRESSED); return; } else if (data[0] === 0) { this.emit("button", Consts.Button.RELEASED); return; } - - let port = this._getPortForPortNumber(data[1]); + + const port = this._getPortForPortNumber(data[1]); if (!port) { return; @@ -149,12 +179,24 @@ class WeDo2Hub extends Hub { if (data[3] === 1) { distance = data[2] + 255; } + /** + * Emits when a distance sensor is activated. + * @event WeDo2Hub#distance + * @param {string} port + * @param {number} distance - Distance, in millimeters. + */ this.emit("distance", port.id, distance * 10); break; } case Consts.Devices.BOOST_DISTANCE: { - let distance = data[2]; + const distance = data[2]; + /** + * Emits when a color sensor is activated. + * @event WeDo2Hub#color + * @param {string} port + * @param {number} color - A number representing one of the LED color consts. + */ this.emit("color", port.id, distance); break; } @@ -168,12 +210,25 @@ class WeDo2Hub extends Hub { if (this._lastTiltY > 100) { this._lastTiltY = -(255 - this._lastTiltY); } + /** + * Emits when a tilt sensor is activated. + * @event WeDo2Hub#tilt + * @param {string} port + * @param {number} x + * @param {number} y + */ this.emit("tilt", port.id, this._lastTiltX, this._lastTiltY); break; } case Consts.Devices.BOOST_INTERACTIVE_MOTOR: { const rotation = data.readInt32LE(2); + /** + * Emits when a rotation sensor is activated. + * @event WeDo2Hub#rotate + * @param {string} port + * @param {number} rotation + */ this.emit("rotate", port.id, rotation); } } @@ -183,6 +238,3 @@ class WeDo2Hub extends Hub { } - - -module.exports = WeDo2Hub; \ No newline at end of file