diff --git a/.jscsrc b/.jscsrc index 2d41de15..28abb3b7 100644 --- a/.jscsrc +++ b/.jscsrc @@ -2,15 +2,23 @@ "fileExtensions": [ ".js", "jscs" ], "excludeFiles": [ "node_modules/**" ], "validateIndentation": 4, - "requireCurlyBraces": true, + "disallowKeywordsOnNewLine": [], "disallowMixedSpacesAndTabs": true, "disallowMultipleSpaces": {"allowEOLComments": true}, - "disallowKeywordsOnNewLine": [], - "requireSpaceBeforeBlockStatements": 1, - //"requireSpaceBeforeObjectValues": false, + "disallowNewlineBeforeBlockStatements": true, + "disallowTabs": true, + "disallowTrailingWhitespace": true, + "requireCurlyBraces": true, + //"requireKeywordsOnNewLine": ["else", "catch"], //"requireSemicolons": true, + //"requireSpaceAfterBinaryOperators": true, + //"requireSpaceAfterComma": {"allExcept": ["trailing"]}, + "requireSpaceAfterKeywords": ["do","for","if","else","switch","case","try","while"], + "requireSpaceBeforeBlockStatements": 1, + "requireSpaceBeforeObjectValues": false, + "requireSpacesInForStatement": true, + "requireSpacesInFunction": { "beforeOpeningCurlyBrace": true }, //"validateParameterSeparator": ", ", //"validateQuoteMarks": false, - "requireSpaceAfterKeywords": ["do","for","if","else","switch","case","try","while"], - "maximumLineLength": 255 + "maximumLineLength": 280 } diff --git a/.jshintrc b/.jshintrc index db63befe..81998b32 100644 --- a/.jshintrc +++ b/.jshintrc @@ -2,6 +2,9 @@ "asi": true, // allow missing semicolons "curly": true, // require braces "eqnull": true, // ignore ==null + //"eqeqeq": true, // enforce === + "freeze": true, // don't allow override + "indent": 4, // default indent of 4 "forin": true, // require property filtering in "for in" loops "immed": true, // require immediate functions to be wrapped in ( ) "nonbsp": true, // warn on unexpected whitespace breaking chars @@ -9,6 +12,8 @@ //"unused": true, // Check for unused functions and variables "loopfunc": true, // allow functions to be defined in loops //"expr": true, // allow ternery operator syntax... + "shadow": true, // allow variable shadowing (re-use of names...) "sub": true, // don't warn that foo['bar'] should be written as foo.bar - "proto": true // allow setting of __proto__ in node < v0.12 + "proto": true, // allow setting of __proto__ in node < v0.12 + "esversion": 6 // allow es6 } diff --git a/.travis.yml b/.travis.yml index 4b22e120..41485f0f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,14 +11,12 @@ addons: - gcc-4.8 matrix: allow_failures: - - node_js: "5" -before_install: - - npm install -g npm@latest-2 + - node_js: "7" node_js: - - "5" + - "8" + - "7" + - "6" - "4" - - "0.12" - - "0.10" before_script: - npm install -g istanbul grunt-cli - npm install coveralls diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index cec0e825..006f956a 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -40,26 +40,18 @@ the [mailing list](https://groups.google.com/forum/#!forum/node-red) first. ### Contributor License Agreement -In order for us to accept pull-requests, the contributor must first complete -a Contributor License Agreement (CLA). This clarifies the intellectual -property license granted with any contribution. It is for your protection as a -Contributor as well as the protection of IBM and its customers; it does not -change your rights to use your own Contributions for any other purpose. +All contributors need to sign the JS Foundation's Contributor License Agreement. +It is an online process and quick to do. You can read the details of the agreement +here: https://cla.js.foundation/node-red/node-red. -You can download the CLAs here: - - - [individual](http://nodered.org/cla/node-red-cla-individual.pdf) - - [corporate](http://nodered.org/cla/node-red-cla-corporate.pdf) - -If you are an IBMer, please contact us directly as the contribution process is -slightly different. +If you raise a pull-request without having signed the CLA, you will be prompted +to do so automatically. ### Coding standards Please ensure you follow the coding standards used through-out the existing code base. Some basic rules include: - - all files must have the Apache license in the header. - indent with 4-spaces, no tabs. No arguments. - opening brace on same line as `if`/`for`/`function` and so on, closing brace on its own line. diff --git a/Gruntfile.js b/Gruntfile.js index fc388087..c67e8bf8 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -1,7 +1,10 @@ // Configuration for Node-RED-nodes project module.exports = function(grunt) { + + // Project configuration. grunt.initConfig({ + pkg: grunt.file.readJSON('package.json'), simplemocha: { options: { globals: ['expect'], @@ -10,27 +13,24 @@ module.exports = function(grunt) { ui: 'bdd', reporter: 'spec' }, - all: { src: ['test/*/*/*_spec.js'] }, + all: { src: ['test/*/*/*_spec.js'] } }, jshint: { options: { - jshintrc:".jshintrc", // Use external file - configured as below... + jshintrc:true // Use external jshinrc file configured as below // http://www.jshint.com/docs/options/ - //"asi": true, // allow missing semicolons - //"curly": true, // require braces - //"eqnull": true, // ignore ==null - //"forin": true, // require property filtering in "for in" loops - //"immed": true, // require immediate functions to be wrapped in ( ) - //"nonbsp": true, // warn on unexpected whitespace breaking chars - ////"strict": true, // commented out for now as it causes 100s of warnings, but want to get there eventually - //"loopfunc": true, // allow functions to be defined in loops - //"sub": true, // don't warn that foo['bar'] should be written as foo.bar - ////"unused": true, // Check for unused functions - ////"forin":false, // turn off check for "for (x in y...)" - //"reporter": require('jshint-stylish') + //"asi": true, // allow missing semicolons + //"curly": true, // require braces + //"eqnull": true, // ignore ==null + //"forin": true, // require property filtering in "for in" loops + //"immed": true, // require immediate functions to be wrapped in ( ) + //"nonbsp": true, // warn on unexpected whitespace breaking chars + ////"strict": true, // commented out for now as it causes 100s of warnings, but want to get there eventually + //"loopfunc": true, // allow functions to be defined in loops + //"sub": true // don't warn that foo['bar'] should be written as foo.bar }, all: { - src: ['*/*.js','*/*/*.js'], + src: ['*/*/*.js'], filter: function(filepath) { // on some developer machines the test coverage HTML report utilities cause further failures if ((filepath.indexOf("coverage/") !== -1) || (filepath.indexOf("node_modules") !== -1)) { console.log( "\033[30m filtered out \033[32m:\033[37m " + filepath + "\033[0m"); @@ -42,7 +42,7 @@ module.exports = function(grunt) { }, }, inlinelint: { - html: ['*/*/*.html'], + html: ['*/*/*.html', '!node_modules/*/*.html', '!*/node_modules/*.html'], options: { jshintrc: ".jshintrc" //,reporter: require('jshint-stylish') @@ -53,6 +53,7 @@ module.exports = function(grunt) { options: { config: ".jscsrc", reporter: "inline" + //,fix: true } } }); @@ -62,6 +63,6 @@ module.exports = function(grunt) { grunt.loadNpmTasks('grunt-lint-inline'); grunt.loadNpmTasks('grunt-jscs'); - grunt.registerTask('default', ['jshint:all', 'inlinelint', 'simplemocha:all']); + grunt.registerTask('default', ['jshint:all', 'inlinelint:html', 'simplemocha:all']); grunt.registerTask('style', ['jscs']); }; diff --git a/README.md b/README.md index e78ad545..74444fef 100644 --- a/README.md +++ b/README.md @@ -71,6 +71,8 @@ Copyright 2013, 2016 IBM Corp. under [the Apache 2.0 license](LICENSE). **node-red-node-intel-galileo** - *[mraa-spio](hardware/intel)* - A collection of analogue & digital input & output nodes for the Intel Galileo and Edison. +**node-red-node-pi-gpiod** - *[pigpiod](hardware/pigpiod)* - An alternative to the default PI GPIO nodes that allows remote access - so a host machine can access a remote Pi (via network) and is better for driving multiple servos. + **node-red-node-pi-mcp3008** - *[pimcp3008](hardware/mcp3008)* - Allows A Raspberry Pi to node to read from an MCP3008 Analogue to Digital Converter chip via the SPI bus. **node-red-node-pi-neopixel** - *[neopixel](hardware/neopixel)* - Allows A Raspberry Pi to drive a strip of NeoPixels directly. @@ -109,7 +111,7 @@ Copyright 2013, 2016 IBM Corp. under [the Apache 2.0 license](LICENSE). **node-red-node-ping** - *[88-ping](io/ping)* - Pings a machine and returns the trip time in mS. Returns false if no response received within 3 seconds, or if the host is unresolveable. Default ping is every 20 seconds but can be configured. -**node-red-node-mdns** - *[mdns](io/mdns)* - discovers other Avahi/Bonjour services on the network. +**node-red-node-discovery** - *[mdns](io/mdns)* - discovers other Avahi/Bonjour services on the network. **node-red-node-mqlight** - *[mqlight](io/mqlight)* - Adds nodes to send and receive using MQlight. diff --git a/function/datagenerator/datagenerator.html b/function/datagenerator/datagenerator.html index 9f747e18..edfabacc 100644 --- a/function/datagenerator/datagenerator.html +++ b/function/datagenerator/datagenerator.html @@ -79,13 +79,18 @@ this.editor.focus(); }, oneditsave: function() { - $("#node-input-template").val(this.editor.getValue()) + $("#node-input-template").val(this.editor.getValue()); + this.editor.destroy(); + delete this.editor; + }, + oneditcancel: function() { + this.editor.destroy(); delete this.editor; }, oneditresize: function(size) { var rows = $("#dialog-form>div:not(.node-text-editor-row)"); var height = $("#dialog-form").height(); - for (var i=0;idiv.node-text-editor-row"); diff --git a/function/datagenerator/datagenerator.js b/function/datagenerator/datagenerator.js index 0979f80e..15366a37 100644 --- a/function/datagenerator/datagenerator.js +++ b/function/datagenerator/datagenerator.js @@ -20,14 +20,17 @@ module.exports = function(RED) { } if (node.fieldType === 'msg') { RED.util.setMessageProperty(msg,node.field,value); - } else if (node.fieldType === 'flow') { + } + else if (node.fieldType === 'flow') { node.context().flow.set(node.field,value); - } else if (node.fieldType === 'global') { + } + else if (node.fieldType === 'global') { node.context().global.set(node.field,value); } node.send(msg); - } catch(err) { - node.error(err.message); + } + catch(e) { + node.error(e.message); } }); } diff --git a/function/datagenerator/package.json b/function/datagenerator/package.json index fe6b353b..5aae89e2 100644 --- a/function/datagenerator/package.json +++ b/function/datagenerator/package.json @@ -1,6 +1,6 @@ { "name" : "node-red-node-data-generator", - "version" : "0.0.3", + "version" : "0.0.4", "description" : "A Node-RED node to create a string of dummy data values from a template. Useful for test-cases.", "dependencies" : { "dummy-json": "1.0.*" diff --git a/function/random/package.json b/function/random/package.json index f2815dc3..f6e48cac 100644 --- a/function/random/package.json +++ b/function/random/package.json @@ -1,6 +1,6 @@ { "name" : "node-red-node-random", - "version" : "0.0.7", + "version" : "0.0.8", "description" : "A Node-RED node that when triggered generates a random number between two values.", "dependencies" : { }, diff --git a/function/random/random.html b/function/random/random.html index eaf292f8..1a9cb7c7 100644 --- a/function/random/random.html +++ b/function/random/random.html @@ -35,7 +35,7 @@ defaults: { name: {value:""}, low: {value:"1"}, - high: {value:"6"}, + high: {value:"10"}, inte: {value:"true"} }, inputs:1, diff --git a/function/random/random.js b/function/random/random.js index c5a3eaa3..69da1d65 100644 --- a/function/random/random.js +++ b/function/random/random.js @@ -10,7 +10,8 @@ module.exports = function(RED) { this.on("input", function(msg) { if (node.inte == "true" || node.inte === true) { msg.payload = Math.round(Number(Math.random()) * (node.high - node.low + 1) + node.low - 0.5); - } else { + } + else { msg.payload = Number(Math.random()) * (node.high - node.low) + node.low; } node.send(msg); diff --git a/function/rbe/locales/en-US/rbe.json b/function/rbe/locales/en-US/rbe.json index 2dc6535b..d0d967bb 100644 --- a/function/rbe/locales/en-US/rbe.json +++ b/function/rbe/locales/en-US/rbe.json @@ -2,6 +2,7 @@ "rbe": { "label": { "func": "Mode", + "init": "Send initial value", "start": "Start value", "name": "Name" }, @@ -11,8 +12,11 @@ }, "opts": { "rbe": "block unless value changes", - "deadband": "block unless value changes by more than", - "narrowband": "block if value changes by more than", + "rbei": "block unless value changes (ignore initial value)", + "deadband": "block unless value change is greater than", + "deadbandEq": "block unless value change is greater or equal to", + "narrowband": "block if value change is greater than", + "narrowbandEq": "block if value change is greater or equal to", "in": "compared to last input value", "out": "compared to last valid output value" }, diff --git a/function/rbe/locales/ja/rbe.json b/function/rbe/locales/ja/rbe.json new file mode 100644 index 00000000..fd913794 --- /dev/null +++ b/function/rbe/locales/ja/rbe.json @@ -0,0 +1,27 @@ +{ + "rbe": { + "label": { + "func": "動作", + "init": "初期値を送付", + "start": "初期値", + "name": "名前" + }, + "placeholder": { + "bandgap": "例:10、5%", + "start": "最初に受け取った値を用いる場合は空欄" + }, + "opts": { + "rbe": "値が変化した時のみメッセージを中継", + "rbei": "値が変化した時のみメッセージを中継(初期値を無視)", + "deadband": "値が比較値を超える時のみメッセージを中継", + "deadbandEq": "値が比較値以上の時のみメッセージを中継", + "narrowband": "初期値、値が比較値を超える時のみメッセージを中継", + "narrowbandEq": "初期値、値が比較値以上の時のみメッセージを中継", + "in": "を最後の入力値と比較", + "out": "を最後の出力値と比較" + }, + "warn": { + "nonumber": "ペイロードに数値が含まれていません" + } + } +} diff --git a/function/rbe/package.json b/function/rbe/package.json index 05f16e2e..57d0abfb 100644 --- a/function/rbe/package.json +++ b/function/rbe/package.json @@ -1,6 +1,6 @@ { "name" : "node-red-node-rbe", - "version" : "0.1.6", + "version" : "0.1.13", "description" : "A Node-RED node that provides report-by-exception (RBE) and deadband capability.", "dependencies" : { }, diff --git a/function/rbe/rbe.html b/function/rbe/rbe.html index 5717e508..6839c83f 100644 --- a/function/rbe/rbe.html +++ b/function/rbe/rbe.html @@ -4,14 +4,17 @@
- - + @@ -27,21 +30,38 @@ @@ -44,7 +55,8 @@ name: {value:""}, action: {value:"mean"}, count: {value:"10",required:true,validate:RED.validators.number()}, - round: {value:""} + round: {value:""}, + mult: {value:"single"} }, inputs: 1, outputs: 1, diff --git a/function/smooth/17-smooth.js b/function/smooth/17-smooth.js index cd954d96..c7fa914a 100644 --- a/function/smooth/17-smooth.js +++ b/function/smooth/17-smooth.js @@ -8,41 +8,50 @@ module.exports = function(RED) { this.round = n.round || false; if (this.round == "true") { this.round = 0; } this.count = Number(n.count); + this.mult = n.mult || "single"; var node = this; - var a = []; - var tot = 0; - var tot2 = 0; - var pop = 0; - var old = null; + var v = {}; this.on('input', function (msg) { + var top = msg.topic || "_my_default_topic"; + if (this.mult === "single") { top = "a"; } + + if ((v.hasOwnProperty(top) !== true) || msg.hasOwnProperty("reset")) { + v[top] = {}; + v[top].a = []; + v[top].tot = 0; + v[top].tot2 = 0; + v[top].pop = 0; + v[top].old = null; + v[top].count = this.count; + } if (msg.hasOwnProperty("payload")) { var n = Number(msg.payload); if (!isNaN(n)) { if ((node.action === "low") || (node.action === "high")) { - if (old == null) { old = n; } - old = old + (n - old) / node.count; - if (node.action === "low") { msg.payload = old; } - else { msg.payload = n - old; } + if (v[top].old == null) { v[top].old = n; } + v[top].old = v[top].old + (n - v[top].old) / v[top].count; + if (node.action === "low") { msg.payload = v[top].old; } + else { msg.payload = n - v[top].old; } } else { - a.push(n); - if (a.length > node.count) { pop = a.shift(); } + v[top].a.push(n); + if (v[top].a.length > v[top].count) { v[top].pop = v[top].a.shift(); } if (node.action === "max") { - msg.payload = Math.max.apply(Math, a); + msg.payload = Math.max.apply(Math, v[top].a); } if (node.action === "min") { - msg.payload = Math.min.apply(Math, a); + msg.payload = Math.min.apply(Math, v[top].a); } if (node.action === "mean") { - tot = tot + n - pop; - msg.payload = tot / a.length; + v[top].tot = v[top].tot + n - v[top].pop; + msg.payload = v[top].tot / v[top].a.length; } if (node.action === "sd") { - tot = tot + n - pop; - tot2 = tot2 + (n*n) - (pop * pop); - if (a.length > 1) { - msg.payload = Math.sqrt((a.length * tot2 - tot * tot)/(a.length * (a.length - 1))); + v[top].tot = v[top].tot + n - v[top].pop; + v[top].tot2 = v[top].tot2 + (n*n) - (v[top].pop * v[top].pop); + if (v[top].a.length > 1) { + msg.payload = Math.sqrt((v[top].a.length * v[top].tot2 - v[top].tot * v[top].tot)/(v[top].a.length * (v[top].a.length - 1))); } else { msg.payload = 0; } } diff --git a/function/smooth/README.md b/function/smooth/README.md index 9beb68e5..5cb2f7dd 100644 --- a/function/smooth/README.md +++ b/function/smooth/README.md @@ -33,5 +33,7 @@ the more the smoothing. E.g. a value of 10 is similar to an α of 0.1. It is analogous to an RC time constant - but there is no time component to this as the code is based on events arriving. +If `msg.reset` is received (with any value), all the counters and intermediate values are reset to an initial state. + **Note:** This node only operates on **numbers**. Anything else will try to be made into a number and rejected if that fails. diff --git a/function/smooth/package.json b/function/smooth/package.json index c2f857c4..349362fe 100644 --- a/function/smooth/package.json +++ b/function/smooth/package.json @@ -1,6 +1,6 @@ { "name" : "node-red-node-smooth", - "version" : "0.0.9", + "version" : "0.0.11", "description" : "A Node-RED node that provides several simple smoothing algorithms for incoming data values.", "dependencies" : { }, diff --git a/hardware/Arduino/35-arduino.js b/hardware/Arduino/35-arduino.js index 5a475d51..ca0a1d5c 100644 --- a/hardware/Arduino/35-arduino.js +++ b/hardware/Arduino/35-arduino.js @@ -3,7 +3,7 @@ module.exports = function(RED) { "use strict"; var Board = require('firmata'); - var SP = require('firmata/node_modules/serialport'); + var SP = require('serialport'); // The Board Definition - this opens (and closes) the connection function ArduinoNode(n) { @@ -36,8 +36,10 @@ module.exports = function(RED) { done(); if (RED.settings.verbose) { node.log(RED._("arduino.status.portclosed")); } }); - } catch(e) { done(); } - } else { done(); } + } + catch(e) { done(); } + } + else { done(); } }); } RED.nodes.registerType("arduino-board",ArduinoNode); diff --git a/hardware/Arduino/README.md b/hardware/Arduino/README.md index 2438d138..9bce8882 100644 --- a/hardware/Arduino/README.md +++ b/hardware/Arduino/README.md @@ -9,7 +9,7 @@ Install Run the following command in your Node-RED user directory - typically `~/.node-red` - npm i node-red-node-arduino + npm i --unsafe-perm node-red-node-arduino Usage ----- diff --git a/hardware/Arduino/package.json b/hardware/Arduino/package.json index 89cf432b..53aa3d7d 100644 --- a/hardware/Arduino/package.json +++ b/hardware/Arduino/package.json @@ -1,9 +1,9 @@ { "name" : "node-red-node-arduino", - "version" : "0.0.11", + "version" : "0.0.14", "description" : "A Node-RED node to talk to an Arduino running firmata", "dependencies" : { - "firmata" : "~0.14.1" + "firmata" : "~0.17.0" }, "repository" : { "type":"git", diff --git a/hardware/BBB/145-BBB-hardware.js b/hardware/BBB/145-BBB-hardware.js index 1d9a8d9e..696fd75e 100644 --- a/hardware/BBB/145-BBB-hardware.js +++ b/hardware/BBB/145-BBB-hardware.js @@ -14,9 +14,11 @@ module.exports = function (RED) { adjustName = function (pin) { if (pin === "P8_7") { pin = "P8_07"; - } else if (pin === "P8_8") { + } + else if (pin === "P8_8") { pin = "P8_08"; - } else if (pin === "P8_9") { + } + else if (pin === "P8_9") { pin = "P8_09"; } return pin; @@ -38,7 +40,8 @@ module.exports = function (RED) { this.averaging = n.averaging; if (this.averaging) { this.averages = 10; - } else { + } + else { this.averages = 1; } @@ -54,7 +57,8 @@ module.exports = function (RED) { count = count - 1; if (count > 0) { bonescript.analogRead(node._pin, analogReadCallback); - } else { + } + else { var msg = {}; msg.topic = node.topic; sum = sum/node.averages; @@ -76,7 +80,8 @@ module.exports = function (RED) { count = node.averages; bonescript.analogRead(node._pin, analogReadCallback); }); - } else { + } + else { node.error("Unconfigured input pin"); } } @@ -92,18 +97,22 @@ module.exports = function (RED) { this._pin = adjustName(this.pin); // Adjusted for Octal if necessary if (n.activeLow) { // Set the 'active' state 0 or 1 as appropriate this.activeState = 0; - } else { + } + else { this.activeState = 1; } this.updateInterval = n.updateInterval*1000; // How often to send totalActiveTime messages this.debounce = n.debounce || null; // Enable switch contact debouncing algorithm if (n.outputOn === "rising") { this.activeEdges = [false, true]; - } else if (n.outputOn === "falling") { + } + else if (n.outputOn === "falling") { this.activeEdges = [true, false]; - } else if (n.outputOn === "both") { + } + else if (n.outputOn === "both") { this.activeEdges = [true, true]; - } else { + } + else { node.error("Invalid edge type: " + n.outputOn); } @@ -130,10 +139,12 @@ module.exports = function (RED) { node.interruptAttached = true; node.on("input", inputCallback); node.intervalId = setInterval(timerCallback, node.updateInterval); - } else { + } + else { node.error("Failed to attach interrupt"); } - } else if (node.currentState !== Number(x)) { + } + else if (node.currentState !== Number(x)) { if (node.debounce) { if (node.debouncing === false) { node.debouncing = true; @@ -141,7 +152,8 @@ module.exports = function (RED) { bonescript.digitalRead(node._pin, debounceCallback); }, Number(node.debounce)); } - } else { + } + else { sendStateMessage(x); } } @@ -166,7 +178,8 @@ module.exports = function (RED) { var now = Date.now(); if (node.currentState === node.activeState) { node.lastActiveTime = now; - } else if (!isNaN(node.lastActiveTime)) { + } + else if (!isNaN(node.lastActiveTime)) { node.totalActiveTime += now - node.lastActiveTime; } if (node.activeEdges[node.currentState]) { @@ -203,7 +216,8 @@ module.exports = function (RED) { var inputCallback = function (ipMsg) { if (String(ipMsg.topic).search(/load/i) < 0 || isFinite(ipMsg.payload) === false) { node.totalActiveTime = 0; - } else { + } + else { node.totalActiveTime = Number(ipMsg.payload); } if (node.currentState === node.activeState) { @@ -217,7 +231,8 @@ module.exports = function (RED) { if (node.activeEdges[0] && node.activeEdges[1]) { msg = [{topic: node.topic}, {topic: node.topic}]; msg[0].payload = node.currentState; - } else { + } + else { msg = [null, {topic: node.topic}]; } msg[1].payload = node.totalActiveTime; @@ -246,12 +261,14 @@ module.exports = function (RED) { node.emit("input", {}); }, 50); }); - } else { + } + else { node.error("Unable to set " + pin + " as input: " + response); } }); }); - } else { + } + else { node.error("Unconfigured input pin"); } } @@ -286,10 +303,12 @@ module.exports = function (RED) { node.interruptAttached = true; node.on("input", inputCallback); node.intervalId = setInterval(timerCallback, node.updateInterval); - } else { + } + else { node.error("Failed to attach interrupt"); } - } else { + } + else { node.pulseTime = [node.pulseTime[1], process.hrtime()]; node.pulseCount = node.pulseCount + 1; } @@ -301,7 +320,8 @@ module.exports = function (RED) { var inputCallback = function (msg) { if (String(msg.topic).search(/load/i) < 0 || isFinite(msg.payload) === false) { node.pulseCount = 0; - } else { + } + else { node.pulseCount = Number(msg.payload); } }; @@ -337,19 +357,22 @@ module.exports = function (RED) { if (node.countType === "pulse") { // interruptType = bonescript.FALLING; <- doesn't work in v0.2.4 interruptType = bonescript.RISING; - } else { + } + else { interruptType = bonescript.CHANGE; } // Attempt to attach the required interrupt handler to the pin. If we succeed, // the input event and interval handlers will be installed by interruptCallback bonescript.attachInterrupt(node._pin, interruptType, interruptCallback) }); - } else { + } + else { node.error("Unable to set " + pin + " as input: " + response); } }); }); - } else { + } + else { node.error("Unconfigured input pin"); } } @@ -376,12 +399,15 @@ module.exports = function (RED) { var newState; if (node.toggle) { newState = node.currentState === 0 ? 1 : 0; - } else { + } + else { if (isFinite(Number(msg.payload))) { newState = Number(msg.payload) > 0.5; - } else if (msg.payload) { + } + else if (msg.payload) { newState = true; - } else { + } + else { newState = false; } if (node.inverting) { @@ -402,7 +428,8 @@ module.exports = function (RED) { setPinMode(node._pin, bonescript.OUTPUT, function (response, pin) { if (response) { node.error("Unable to set " + pin + " as output: " + response.err); - } else { + } + else { node.on("input", inputCallback); setTimeout(function () { bonescript.digitalWrite(node._pin, node.defaultState, function() {}); @@ -410,7 +437,8 @@ module.exports = function (RED) { } }); }); - } else { + } + else { node.error("Unconfigured output pin"); } } @@ -453,10 +481,12 @@ module.exports = function (RED) { node.send({topic: node.topic, payload: node.pulseState}); }); } - } else { + } + else { if (node.pulseTimer !== null) { clearTimeout(node.pulseTimer); - } else { + } + else { bonescript.digitalWrite(node._pin, node.pulseState, function() { node.send({topic: node.topic, payload: node.pulseState}); }); @@ -484,12 +514,14 @@ module.exports = function (RED) { node.on("input", inputCallback); // Set the pin to the default state once the dust settles setTimeout(endPulseCallback, 50); - } else { + } + else { node.error("Unable to set " + pin + " as output: " + response.err); } }); }); - } else { + } + else { node.error("Unconfigured output pin"); } } diff --git a/hardware/BBB/package.json b/hardware/BBB/package.json index 98143bbd..c4c1acc9 100644 --- a/hardware/BBB/package.json +++ b/hardware/BBB/package.json @@ -1,9 +1,9 @@ { "name" : "node-red-node-beaglebone", - "version" : "0.1.8", + "version" : "0.1.9", "description" : "A set of Node-RED nodes to interface to the GPIO pins of a Beaglebone Black board", "dependencies" : { - "octalbonescript":"^1.2.*" + "octalbonescript":"^1.2.2" }, "repository" : { "type":"git", diff --git a/hardware/LEDborg/78-ledborg.html b/hardware/LEDborg/78-ledborg.html index 47835be9..ed1d23fa 100644 --- a/hardware/LEDborg/78-ledborg.html +++ b/hardware/LEDborg/78-ledborg.html @@ -4,7 +4,7 @@
-
Uses pins 11, 13 aand 15.
+
Uses pins 11, 13 and 15.
See info panel for the various input options and limitations.
diff --git a/hardware/LEDborg/78-ledborg.js b/hardware/LEDborg/78-ledborg.js index d5af9e20..dea2ebe9 100644 --- a/hardware/LEDborg/78-ledborg.js +++ b/hardware/LEDborg/78-ledborg.js @@ -12,7 +12,8 @@ module.exports = function(RED) { try { var cpuinfo = fs.readFileSync("/proc/cpuinfo").toString(); if (cpuinfo.indexOf(": BCM") === -1) { throw "Info : "+RED._("rpi-gpio.errors.ignorenode"); } - } catch(err) { + } + catch(err) { throw "Info : "+RED._("rpi-gpio.errors.ignorenode"); } diff --git a/hardware/LEDborg/package.json b/hardware/LEDborg/package.json index 3a28ce51..787b388a 100644 --- a/hardware/LEDborg/package.json +++ b/hardware/LEDborg/package.json @@ -1,6 +1,6 @@ { "name" : "node-red-node-ledborg", - "version" : "0.0.17", + "version" : "0.0.18", "description" : "A Node-RED node to control a PiBorg LedBorg board for a Raspberry Pi.", "dependencies" : { }, diff --git a/hardware/PiLiter/39-rpi-piliter.js b/hardware/PiLiter/39-rpi-piliter.js index 10f24058..ac6b1ec9 100644 --- a/hardware/PiLiter/39-rpi-piliter.js +++ b/hardware/PiLiter/39-rpi-piliter.js @@ -69,9 +69,8 @@ module.exports = function(RED) { var l = Number(msg.payload.state); if ((out >= 1) && (out <= 8)) { out = (Math.pow(2, (out-1))); - if (l === 0) { out = ~ out; } - byte = byte & out & 255; - console.log("NOW",byte); + if (l === 0) { byte = (byte & (~out) & 255); } + else { byte = (byte | out) & 255; } if (node.child !== null) { node.child.stdin.write(byte+"\n"); } else { node.warn("Command not running"); } } diff --git a/hardware/PiLiter/package.json b/hardware/PiLiter/package.json index 8b2f3228..ea7a7143 100644 --- a/hardware/PiLiter/package.json +++ b/hardware/PiLiter/package.json @@ -1,6 +1,6 @@ { "name" : "node-red-node-piliter", - "version" : "0.0.10", + "version" : "0.0.11", "description" : "A Node-RED node to drive a Raspberry Pi Pi-LITEr 8 LED board.", "dependencies" : { }, diff --git a/hardware/PiSrf/README.md b/hardware/PiSrf/README.md index d9735f52..46c8c6f8 100644 --- a/hardware/PiSrf/README.md +++ b/hardware/PiSrf/README.md @@ -23,8 +23,10 @@ These can be any spare valid Pi GPIO pins. e.g. 7,11 +You can also set the repeat frequency of measurements - default 0.5 seconds. + Outputs a `msg.payload` with a number representing the range in cm. -Produces one measure every 0.5s - but only if the distance is different from the previous reading. +Produces one measure every 0.5s (by default) - but only if the distance is different from the previous reading. **Note:** we are using the actual physical pin numbers on connector P1 as they are easier to locate. diff --git a/hardware/PiSrf/nrsrf.py b/hardware/PiSrf/nrsrf.py index 7cffa5c0..d21e9f56 100755 --- a/hardware/PiSrf/nrsrf.py +++ b/hardware/PiSrf/nrsrf.py @@ -15,46 +15,62 @@ GPIO.setwarnings(False) ECHO = 0 TRIGGER = 0 OLD = 0 +SLEEP = 0.5 def Measure(): start = 0 - realstart = 0 - realstart = time.time() GPIO.output(TRIGGER, True) time.sleep(0.00001) GPIO.output(TRIGGER, False) + + channel = GPIO.wait_for_edge(ECHO, GPIO.BOTH, timeout=200) + if channel is None: + print("Ultrasonic sensor timed out (pre-echo).") + GPIO.remove_event_detect(ECHO) + restart() + # else: + # print("Echo start detected") start = time.time() - while GPIO.input(ECHO)==0: - start = time.time() - Dif = time.time() - realstart - if Dif > 0.2: - print("Ultrasonic Sensor Timed out, Restarting.") - time.sleep(0.4) - Main() - while GPIO.input(ECHO)==1: - stop = time.time() + + GPIO.wait_for_edge(ECHO, GPIO.BOTH, timeout=400) + if channel is None: + print("Ultrasonic sensor timed out (post-echo).") + GPIO.remove_event_detect(ECHO) + restart() + # else: + # print("Echo finish detected") + stop = time.time() + elapsed = stop-start - distance = (elapsed * 36000)/2 + distance = (elapsed * 34300)/2 # Using speed of sound at 20C (68F) return distance +def restart(): + # print("Restarting...") + GPIO.setmode(GPIO.BOARD) # Use GPIO BOARD numbers + GPIO.setup(TRIGGER, GPIO.OUT) # Trigger + GPIO.output(TRIGGER, False) # Set low + GPIO.setup(ECHO, GPIO.OUT) # Echo + GPIO.output(ECHO, False) + time.sleep(0.1) + GPIO.setup(ECHO,GPIO.IN) + GPIO.add_event_detect(ECHO, GPIO.BOTH) + time.sleep(2.0) # Main program loop if len(sys.argv) > 1: pins = sys.argv[1].lower().split(',') - if len(pins) != 2: - print "Bad number of pins supplied" + if len(pins) != 3: + print "Bad parameters supplied" print pins sys.exit(0) TRIGGER = int(pins[0]) ECHO = int(pins[1]) + SLEEP = float(pins[2]) - GPIO.setmode(GPIO.BOARD) # Use GPIO BOARD numbers - GPIO.setup(TRIGGER, GPIO.OUT) # Trigger - GPIO.setup(ECHO, GPIO.OUT) # Echo - GPIO.output(ECHO, False) - GPIO.setup(ECHO,GPIO.IN) + restart() # Flush stdin so we start clean while len(select.select([sys.stdin.fileno()], [], [], 0.0)[0])>0: @@ -63,17 +79,18 @@ if len(sys.argv) > 1: while True: try: distance = int( Measure() + 0.5 ) - if distance != OLD: + if distance != OLD and distance > 2 and distance < 400: print(distance) OLD = distance - time.sleep(0.5) - except: # try to clean up on exit - print("0.0"); + time.sleep(SLEEP) + except Exception as e: # try to clean up on exit + print(e) # Print error message on exception + GPIO.remove_event_detect(ECHO) GPIO.cleanup(TRIGGER) GPIO.cleanup(ECHO) sys.exit(0) else: print "Bad params" - print " sudo nrsrf.py trigger_pin,echo_pin" + print " sudo nrsrf.py trigger_pin,echo_pin,rate_in_seconds" sys.exit(0) diff --git a/hardware/PiSrf/package.json b/hardware/PiSrf/package.json index 0bafe01c..0efbd041 100644 --- a/hardware/PiSrf/package.json +++ b/hardware/PiSrf/package.json @@ -1,6 +1,6 @@ { "name" : "node-red-node-pisrf", - "version" : "0.0.3", + "version" : "0.1.0", "description" : "A Node-RED node for a Raspberry Pi to use a SRF04 or SRF05 range finder", "dependencies" : { }, diff --git a/hardware/PiSrf/pisrf.html b/hardware/PiSrf/pisrf.html index df614961..5dfe2f6b 100644 --- a/hardware/PiSrf/pisrf.html +++ b/hardware/PiSrf/pisrf.html @@ -4,7 +4,14 @@
-
+
+ + +
+
+ + +
@@ -16,7 +23,7 @@ @@ -26,6 +33,8 @@ color:"#c6dbef", defaults: { name: { value:"" }, + topic: { value:"SRF" }, + pulse: {value:"0.5" }, pins: { value:"", required:true, validate:RED.validators.regex(/^\d+,\d+$/) } }, inputs:0, diff --git a/hardware/PiSrf/pisrf.js b/hardware/PiSrf/pisrf.js index 3f92fc68..10a8a9d9 100644 --- a/hardware/PiSrf/pisrf.js +++ b/hardware/PiSrf/pisrf.js @@ -24,19 +24,21 @@ module.exports = function(RED) { function PiSrfNode(n) { RED.nodes.createNode(this, n); + this.topic = n.topic; this.pins = n.pins; + this.pins += ","+(n.pulse || 0.5); var node = this; if (node.pins !== undefined) { node.child = spawn(gpioCommand, [node.pins]); node.running = true; - if (RED.settings.verbose) { node.log("pin: " + node.pins + " :"); } + if (RED.settings.verbose) { node.log("parameters: " + node.pins + " :"); } node.child.stdout.on('data', function(data) { if (RED.settings.verbose) { node.log("out: " + data + " :"); } data = data.toString().trim(); if (data.length > 0) { - node.send({topic:"SRF",payload:data}); + node.send({topic:node.topic, payload:data}); } }); @@ -58,7 +60,7 @@ module.exports = function(RED) { } else { - node.error("Invalid GPIO pins: " + node.pin); + node.error("Invalid Parameters: " + node.pins); } var wfi = function(done) { diff --git a/hardware/Pibrella/38-rpi-pibrella.js b/hardware/Pibrella/38-rpi-pibrella.js index ffe719b2..be8b49f8 100644 --- a/hardware/Pibrella/38-rpi-pibrella.js +++ b/hardware/Pibrella/38-rpi-pibrella.js @@ -164,10 +164,12 @@ module.exports = function(RED) { if (node.pin !== undefined) { if (node.pin === "12") { node.child = spawn(gpioCommand, ["buzz",node.pin]); - } else { + } + else { if (node.set && (node.out === "out")) { node.child = spawn(gpioCommand, [node.out,node.pin,node.level]); - } else { + } + else { node.child = spawn(gpioCommand, [node.out,node.pin]); } } diff --git a/hardware/blinkstick/76-blinkstick.js b/hardware/blinkstick/76-blinkstick.js index d403e11a..bb78719c 100644 --- a/hardware/blinkstick/76-blinkstick.js +++ b/hardware/blinkstick/76-blinkstick.js @@ -32,7 +32,7 @@ module.exports = function(RED) { return typeof (value) === "undefined" || value === null ? value = defaultValue : value; } - function validateArray(value, defaultValue){ + function validateArray(value, defaultValue) { return typeof (value) === "undefined" || Array.isArray(value) ? value : defaultValue; } @@ -66,7 +66,7 @@ module.exports = function(RED) { this.name = n.name; this.serial = n.serial; - this.mode = n.mode || "normal"; + this.mode = n.mode || "normal"; this.task = n.task || "set_color"; this.delay = n.delay || 500; this.repeats = n.repeats || 1; @@ -95,25 +95,28 @@ module.exports = function(RED) { if (Object.size(node.led) === 0) { node.status({fill:"red",shape:"ring",text:"not found"}); node.error("BlinkStick with serial number " + node.serial + " not found"); - } else { + } + else { node.status({fill:"green",shape:"dot",text:"connected"}); - if(node.mode == "normal"){node.led.setMode(0);} - else if(node.mode == "inverted"){node.led.setMode(1);} - else if(node.mode == "neopixel"){node.led.setMode(2);} + if (node.mode == "normal") {node.led.setMode(0);} + else if (node.mode == "inverted") {node.led.setMode(1);} + else if (node.mode == "neopixel") {node.led.setMode(2);} if (callback) { callback(); } } }); - } else { + } + else { node.led = blinkstick.findFirst(); if (Object.size(node.led) === 0) { node.status({fill:"red",shape:"ring",text:"not found"}); node.error("No BlinkStick found"); - } else { + } + else { node.status({fill:"green",shape:"dot",text:"connected"}); - if(node.mode == "normal"){node.led.setMode(0);} - else if(node.mode == "inverted"){node.led.setMode(1);} - else if(node.mode == "neopixel"){node.led.setMode(2);} + if (node.mode == "normal") {node.led.setMode(0);} + else if (node.mode == "inverted") {node.led.setMode(1);} + else if (node.mode == "neopixel") {node.led.setMode(2);} if (callback) { callback(); } } } @@ -159,12 +162,15 @@ module.exports = function(RED) { //Select animation to perform if (node.task == "pulse") { node.led.pulse(node.color, {'duration': node.duration, 'steps': node.steps, 'channel': node.channel, 'index': node.index }, blinkstickAnimationComplete); - } else if (node.task == "morph") { + } + else if (node.task == "morph") { node.led.morph(node.color, {'duration': node.duration, 'steps': node.steps, 'channel': node.channel, 'index': node.index }, blinkstickAnimationComplete); - } else if (node.task == "blink") { + } + else if (node.task == "blink") { node.led.blink(node.color,{'repeats': node.repeats, 'delay': node.delay, 'channel': node.channel, 'index': node.index }, blinkstickAnimationComplete); - } else { - if(node.row.length > 0){ + } + else { + if (node.row.length > 0) { var dat = []; for (var i = 0; i < node.row.length; i++) { if (typeof node.row[i] === "string") { // if string then assume must be colour names @@ -187,14 +193,15 @@ module.exports = function(RED) { node.led.setColors(node.channel, dat, blinkstickAnimationComplete); } else { - node.warn("Colour array length not / 3"); + node.warn("Colour array length not / 3"); } } else { node.led.setColor(node.color, {'channel': node.channel, 'index': node.index}, blinkstickAnimationComplete); } } - } catch (err) { + } + catch (err) { if (err.toString().indexOf("setColor") !== -1) { node.led.setColour(node.color, blinkstickAnimationComplete); node.warn("Old version - please upgrade Blinkstick npm"); @@ -269,19 +276,22 @@ module.exports = function(RED) { node.channel = typeof(data.channel) !== 'undefined' ? data.channel : node.channel; node.index = data.index ? data.index : node.index; node.row = data.row ? data.row : node.row; - } else { + } + else { node.error(data); return; } } - } else if (p1.test(msg.payload)) { + } + else if (p1.test(msg.payload)) { //Color value is represented as "red,green,blue" string of bytes var rgb = msg.payload.split(","); //Convert color value back to HEX string for easier implementation node.color = "#" + decimalToHex(parseInt(rgb[0])&255) + decimalToHex(parseInt(rgb[1])&255) + decimalToHex(parseInt(rgb[2])&255); - } else { + } + else { //Sanitize color value node.color = msg.payload.toLowerCase().replace(/\s+/g,''); if (node.color === "amber") { node.color = "#FFBF00"; } @@ -293,7 +303,8 @@ module.exports = function(RED) { if (animationComplete) { applyColor(); } - } else { + } + else { //Attempt to find BlinkStick and start animation if it's found findBlinkStick(function() { if (animationComplete) { diff --git a/hardware/digiRGB/78-digiRGB.js b/hardware/digiRGB/78-digiRGB.js index 128cb476..eac688e8 100644 --- a/hardware/digiRGB/78-digiRGB.js +++ b/hardware/digiRGB/78-digiRGB.js @@ -16,7 +16,8 @@ module.exports = function(RED) { try { device = new HID.HID(devices[i].path); break; - } catch (e) { + } + catch (e) { node.log(e) } } @@ -32,16 +33,19 @@ module.exports = function(RED) { var g = parseInt(msg.payload.slice(3,5),16); var b = parseInt(msg.payload.slice(5),16); device.sendFeatureReport([115,r,g,b]); - } else if (p2.test(msg.payload)) { + } + else if (p2.test(msg.payload)) { var args = msg.payload.split(','); if (args.length == 3) { device.sendFeatureReport([115,parseInt(args[0]),parseInt(args[1]),parseInt(args[2])]); } - } else { + } + else { node.warn("incompatable input - " + msg.payload); } }); - } else { + } + else { node.warn("no digispark RGB found"); } diff --git a/hardware/heatmiser/100-heatmiser.js b/hardware/heatmiser/100-heatmiser.js index 10ed72b7..e9f311fe 100644 --- a/hardware/heatmiser/100-heatmiser.js +++ b/hardware/heatmiser/100-heatmiser.js @@ -13,7 +13,7 @@ module.exports = function(RED) { this.pollIntervalRef = undefined; var hmoutnode = this; - this.hm = new Heatmiser(this.ip, this.pin); + this.hm = new Heatmiser.Wifi(this.ip, this.pin); this.hm.on('success', function(data) { if (DEBUG) { @@ -84,7 +84,7 @@ module.exports = function(RED) { var hminnode = this; this.pollIntervalRef = undefined; - this.hm = new Heatmiser(this.ip, this.pin); + this.hm = new Heatmiser.Wifi(this.ip, this.pin); this.hm.on('success', function(data) { if (DEBUG) { diff --git a/hardware/heatmiser/package.json b/hardware/heatmiser/package.json index b4d03f8f..c4b0830d 100644 --- a/hardware/heatmiser/package.json +++ b/hardware/heatmiser/package.json @@ -1,9 +1,9 @@ { "name" : "node-red-contrib-heatmiser", - "version" : "0.0.4", + "version" : "0.0.5", "description" : "A Node-RED node to control and poll a HeatMiser thermostat.", "dependencies" : { - "heatmiser" : "2.0.0" + "heatmiser" : "~2.0.0" }, "repository" : { "type":"git", diff --git a/hardware/intel/mraa-gpio-din.js b/hardware/intel/mraa-gpio-din.js index 56605d72..5966e448 100644 --- a/hardware/intel/mraa-gpio-din.js +++ b/hardware/intel/mraa-gpio-din.js @@ -16,31 +16,37 @@ module.exports = function(RED) { var g = node.x.read(); var msg = { payload:g, topic:node.board+"/D"+node.pin }; switch (g) { - case 0: + case 0: { node.status({fill:"green",shape:"ring",text:"low"}); if (node.interrupt=== "f" || node.interrupt === "b") { node.send(msg); } break; - case 1: + } + case 1: { node.status({fill:"green",shape:"dot",text:"high"}); if (node.interrupt=== "r" || node.interrupt === "b") { node.send(msg); } break; - default: + } + default: { node.status({fill:"grey",shape:"ring",text:"unknown"}); + } } }); switch (node.x.read()) { - case 0: + case 0: { node.status({fill:"green",shape:"ring",text:"low"}); break; - case 1: + } + case 1: { node.status({fill:"green",shape:"dot",text:"high"}); break; - default: + } + default: { node.status({}); + } } this.on('close', function() { node.x.isr(m.EDGE_BOTH, null); diff --git a/hardware/intel/mraa-gpio-dout.js b/hardware/intel/mraa-gpio-dout.js index 75ce9456..020db558 100644 --- a/hardware/intel/mraa-gpio-dout.js +++ b/hardware/intel/mraa-gpio-dout.js @@ -10,7 +10,8 @@ module.exports = function(RED) { var node = this; if (node.pin === 14) { node.p = new m.Gpio(3,false,true); // special for onboard LED v1 - } else { + } + else { node.p = new m.Gpio(node.pin); } node.p.mode(m.PIN_GPIO); @@ -21,7 +22,8 @@ module.exports = function(RED) { node.on("input", function(msg) { if (msg.payload == "1") { node.p.write(1); - } else { + } + else { node.p.write(0); } }); diff --git a/hardware/makey/42-makey.js b/hardware/makey/42-makey.js index ad6d185b..837f5621 100644 --- a/hardware/makey/42-makey.js +++ b/hardware/makey/42-makey.js @@ -56,7 +56,8 @@ module.exports = function(RED) { } else { console.log(key); } }); - } catch(err) { node.warn("can't open MakeyMakey: Do you need root access ?"); } + } + catch(err) { node.warn("can't open MakeyMakey: Do you need root access ?"); } } else { findmakey(); diff --git a/hardware/mcp3008/README.md b/hardware/mcp3008/README.md index 64e05eac..4267a8a9 100644 --- a/hardware/mcp3008/README.md +++ b/hardware/mcp3008/README.md @@ -14,8 +14,8 @@ It will appear in the menu as ` A/D Converter `. You must ensure that SPI is enabled. For recent (2016) versions of Raspbian you can do this - Run `sudo raspi-config` - - Select `9 - Advanced Options` - - Select `A5 - SPI` + - Select `5 - Interfacing Options` + - Select `P4 - SPI` - Select `yes` to enable SPI - Select `OK` to confirm - Select the `Finish` button diff --git a/hardware/mcp3008/package.json b/hardware/mcp3008/package.json index 71a529b5..bc86b108 100644 --- a/hardware/mcp3008/package.json +++ b/hardware/mcp3008/package.json @@ -1,6 +1,6 @@ { "name" : "node-red-node-pi-mcp3008", - "version" : "0.0.7", + "version" : "0.0.8", "description" : "A Node-RED node to read from the MCP3008 Analogue to Digital Converter", "dependencies" : { "mcp-spi-adc": "^0.3.1" diff --git a/hardware/mcp3008/pimcp3008.js b/hardware/mcp3008/pimcp3008.js index 439bcdfb..5cc6d1ff 100644 --- a/hardware/mcp3008/pimcp3008.js +++ b/hardware/mcp3008/pimcp3008.js @@ -6,7 +6,8 @@ module.exports = function(RED) { try { var cpuinfo = fs.readFileSync("/proc/cpuinfo").toString(); if (cpuinfo.indexOf(": BCM") === -1) { throw "Info : "+RED._("rpi-gpio.errors.ignorenode"); } - } catch(err) { + } + catch(err) { throw "Info : "+RED._("rpi-gpio.errors.ignorenode"); } diff --git a/hardware/neopixel/neopix.py b/hardware/neopixel/neopix.py index f80e4bd8..7f92fefb 100755 --- a/hardware/neopixel/neopix.py +++ b/hardware/neopixel/neopix.py @@ -3,7 +3,11 @@ # Import library functions we need import sys import time -from neopixel import * +try: + from rpi_ws281x import __version__, PixelStrip, Adafruit_NeoPixel, Color +except ImportError: + from neopixel import Adafruit_NeoPixel as PixelStrip, Color + __version__ = "legacy" # LED strip configuration: LED_COUNT = 8 # Number of LED pixels. @@ -12,10 +16,25 @@ LED_FREQ_HZ = 800000 # LED signal frequency in hertz (usually 800khz) LED_DMA = 5 # DMA channel to use for generating signal (try 5) LED_BRIGHTNESS = 255 # Set to 0 for darkest and 255 for brightest LED_INVERT = False # True to invert the signal (when using NPN transistor level shift) +LED_CHANNEL = 0 # PWM channel +LED_GAMMA = [ +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, +2, 2, 2, 3, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, +6, 6, 6, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10, 10, 11, 11, +11, 12, 12, 13, 13, 13, 14, 14, 15, 15, 16, 16, 17, 17, 18, 18, +19, 19, 20, 21, 21, 22, 22, 23, 23, 24, 25, 25, 26, 27, 27, 28, +29, 29, 30, 31, 31, 32, 33, 34, 34, 35, 36, 37, 37, 38, 39, 40, +40, 41, 42, 43, 44, 45, 46, 46, 47, 48, 49, 50, 51, 52, 53, 54, +55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, +71, 72, 73, 74, 76, 77, 78, 79, 80, 81, 83, 84, 85, 86, 88, 89, +90, 91, 93, 94, 95, 96, 98, 99,100,102,103,104,106,107,109,110, +111,113,114,116,117,119,120,121,123,124,126,128,129,131,132,134, +135,137,138,140,142,143,145,146,148,150,151,153,155,157,158,160, +162,163,165,167,169,170,172,174,176,178,179,181,183,185,187,189, +191,193,194,196,198,200,202,204,206,208,210,212,214,216,218,220, +222,224,227,229,231,233,235,237,239,241,244,246,248,250,252,255] -if sys.version_info >= (3,0): - print("Sorry - currently only configured to work with python 2.x") - sys.exit(1) LED_COUNT = int(sys.argv[1]) WAIT_MS = int(sys.argv[2]) @@ -103,8 +122,12 @@ def rainbowCycle(strip, wait_ms=20, iterations=2): # Main loop: if __name__ == '__main__': # Create NeoPixel object with appropriate configuration. - strip = Adafruit_NeoPixel(LED_COUNT, LED_PIN, LED_FREQ_HZ, LED_DMA, LED_INVERT, LED_BRIGHTNESS) - # Intialize the library (must be called once before other functions). + #strip = Adafruit_NeoPixel(LED_COUNT, LED_PIN, LED_FREQ_HZ, LED_DMA, LED_INVERT, LED_BRIGHTNESS) + if __version__ == "legacy": + strip = PixelStrip(LED_COUNT, LED_PIN, LED_FREQ_HZ, LED_DMA, LED_INVERT, LED_BRIGHTNESS, LED_CHANNEL) + else: + strip = PixelStrip(LED_COUNT, LED_PIN, LED_FREQ_HZ, LED_DMA, LED_INVERT, LED_BRIGHTNESS, LED_CHANNEL, LED_GAMMA)# Intialize the library (must be called once before other functions). + strip.begin() ## Color wipe animations. diff --git a/hardware/neopixel/neopixel.js b/hardware/neopixel/neopixel.js index 2ebcbea8..85980bb2 100644 --- a/hardware/neopixel/neopixel.js +++ b/hardware/neopixel/neopixel.js @@ -2,21 +2,22 @@ module.exports = function(RED) { "use strict"; var spawn = require('child_process').spawn; + var execSync = require('child_process').execSync; var fs = require('fs'); var colors = require('./colours.js'); - var piCommand = __dirname+'/neopix'; try { var cpuinfo = fs.readFileSync("/proc/cpuinfo").toString(); if (cpuinfo.indexOf(": BCM") === -1) { throw "Info : "+RED._("rpi-gpio.errors.ignorenode"); } - } catch(err) { + } + catch(err) { throw "Info : "+RED._("rpi-gpio.errors.ignorenode"); } - if (!fs.existsSync('/usr/local/lib/python2.7/dist-packages/neopixel.py')) { - RED.log.warn("Can't find neopixel.py python library"); - throw "Warning : Can't find neopixel.py python library"; + if (execSync('python -c "import neopixel"').toString() !== "") { + RED.log.warn("Can't find neopixel python library"); + throw "Warning : Can't find neopixel python library"; } if ( !(1 & parseInt ((fs.statSync(piCommand).mode & parseInt ("777", 8)).toString (8)[0]) )) { @@ -57,7 +58,8 @@ module.exports = function(RED) { if (node.mode.indexOf("need") >= 0) { needle = colors.getRGB(parts[0],node.rgb); pay = "0,"+(l-1)+","+node.fgnd+"\n"+l+","+needle+"\n"+(l+1)+","+(node.pixels-1)+","+node.bgnd; - } else { + } + else { node.fgnd = colors.getRGB(parts[0],node.rgb); pay = "0,"+l+","+node.fgnd+"\n"+(l+1)+","+(node.pixels-1)+","+node.bgnd; } @@ -78,7 +80,8 @@ module.exports = function(RED) { ll = ll - 1; if (node.mode.indexOf("need") >= 0) { pay = "0,"+(ll-1)+","+node.fgnd+"\n"+ll+","+needle+"\n"+(ll+1)+","+(node.pixels-1)+","+node.bgnd; - } else { + } + else { pay = "0,"+ll+","+node.fgnd+"\n"+(ll+1)+","+(node.pixels-1)+","+node.bgnd; } } diff --git a/hardware/neopixel/package.json b/hardware/neopixel/package.json index 0a09c765..2f8e5e20 100644 --- a/hardware/neopixel/package.json +++ b/hardware/neopixel/package.json @@ -1,6 +1,6 @@ { "name" : "node-red-node-pi-neopixel", - "version" : "0.0.14", + "version" : "0.0.16", "description" : "A Node-RED node to output to a neopixel (ws2812) string of LEDS from a Raspberry Pi.", "dependencies" : { }, diff --git a/hardware/neopixel/scripts/checklib.js b/hardware/neopixel/scripts/checklib.js index bdd3bf0f..0ebb8a95 100755 --- a/hardware/neopixel/scripts/checklib.js +++ b/hardware/neopixel/scripts/checklib.js @@ -1,13 +1,13 @@ #!/usr/bin/env node var fs = require('fs'); -if (!fs.existsSync('/usr/local/lib/python2.7/dist-packages/neopixel.py')) { - console.warn("WARNING : Can't find neopixel.py python library"); +if (!fs.existsSync('/usr/local/lib/python2.7/dist-packages/unicornhat.py')) { + console.warn("WARNING : Can't find required python library"); console.warn("WARNING : Please install using the following command"); console.warn("WARNING : Note: this uses root..."); console.warn("WARNING : curl -sS get.pimoroni.com/unicornhat | bash\n"); //process.exit(1); } else { - console.log("Neopixel Python library found OK.\n") + console.log("Python library found OK.\n") } diff --git a/hardware/physical-web/physical-web.js b/hardware/physical-web/physical-web.js index af185d30..3631b598 100644 --- a/hardware/physical-web/physical-web.js +++ b/hardware/physical-web/physical-web.js @@ -7,42 +7,49 @@ module.exports = function(RED) { var checkLength = function(text) { var l = text.length; - switch(true) { - case /^http:\/\/www./.test(text): - l -= 10; - break; - case /^https:\/\/www./.test(text): - l -= 11; - break; - case /^http:\/\//.test(text): - l -= 6; - break; - case /^https:\/\//.test(text): - l -= 7; - break; + switch (true) { + case /^http:\/\/www./.test(text): { + l -= 10; + break; + } + case /^https:\/\/www./.test(text): { + l -= 11; + break; + } + case /^http:\/\//.test(text): { + l -= 6; + break; + } + case /^https:\/\//.test(text): { + l -= 7; + break; + } } - switch(true) { - case /.*\.info\/.*/.test(text): - l -= 5; - break; + switch (true) { + case /.*\.info\/.*/.test(text): { + l -= 5; + break; + } case /.*\.com\/.*/.test(text): case /.*\.net\/.*/.test(text): case /.*\.org\/.*/.test(text): case /.*\.edu\/.*/.test(text): case /.*\.biz\/.*/.test(text): case /.*\.gov\/.*/.test(text): - case /.*\.info.*/.test(text): - l -= 4; - break; + case /.*\.info.*/.test(text): { + l -= 4; + break; + } case /.*\.com.*/.test(text): case /.*\.net.*/.test(text): case /.*\.org.*/.test(text): case /.*\.edu.*/.test(text): case /.*\.biz.*/.test(text): - case /.*\.gov.*/.test(text): - l -= 3; - break; + case /.*\.gov.*/.test(text): { + l -= 3; + break; + } } return l; } @@ -70,7 +77,8 @@ module.exports = function(RED) { try { eddystoneBeacon.advertiseUrl(node.url, node.options); node.status({fill:"green",shape:"dot",text:node.url}); - } catch(e) { + } + catch(e) { node.error('Error setting beacon URL', e); } } @@ -83,7 +91,8 @@ module.exports = function(RED) { try { eddystoneBeacon.advertiseUid(node.namespace, node.instance, node.options); node.status({fill:"green",shape:"dot",text:node.namespace}); - } catch(e) { + } + catch(e) { node.error('Error setting beacon information', e); } } @@ -96,7 +105,8 @@ module.exports = function(RED) { try { eddystoneBeacon.stop(); node.status({fill:"red",shape:"dot",text:"Stopped"}); - } catch(e) { + } + catch(e) { node.error('error shutting down beacon', e); } return; @@ -107,7 +117,8 @@ module.exports = function(RED) { try { eddystoneBeacon.advertiseUrl(node.url, node.options); node.status({fill:"green",shape:"dot",text:node.url}); - } catch(e) { + } + catch(e) { node.error('Error setting beacon URL', e); } return; @@ -116,7 +127,8 @@ module.exports = function(RED) { try { eddystoneBeacon.advertiseUid(node.namespace, node.instance, node.options); node.status({fill:"green",shape:"dot",text:node.namespace}); - } catch(e) { + } + catch(e) { node.error('Error setting beacon information', e); } return; @@ -124,30 +136,33 @@ module.exports = function(RED) { } // url mode if (node.mode === "url") { - if (checkLength(msg.payload) <= 18) { - try { - node.url = msg.payload; - eddystoneBeacon.advertiseUrl(node.url, node.options); - node.status({fill:"green",shape:"dot",text:node.url}); - } catch(e) { - node.status({fill:"red",shape:"dot",text:"Error setting URL"}); - node.error('error updating beacon URL', e); - } - } else { - node.status({fill:"red",shape:"dot",text:"URL too long"}); - } + if (checkLength(msg.payload) <= 18) { + try { + node.url = msg.payload; + eddystoneBeacon.advertiseUrl(node.url, node.options); + node.status({fill:"green",shape:"dot",text:node.url}); + } + catch(e) { + node.status({fill:"red",shape:"dot",text:"Error setting URL"}); + node.error('error updating beacon URL', e); + } + } + else { + node.status({fill:"red",shape:"dot",text:"URL too long"}); + } } // uid mode else { - try { - node.namespace = msg.payload; - node.instance = msg.topic; - eddystoneBeacon.advertiseUid(node.namespace, node.instance, node.options); - node.status({fill:"green",shape:"dot",text:msg.payload}); - } catch(e) { - node.status({fill:"red",shape:"dot",text:"Error setting beacon information"}); - node.error('Error setting beacon information', e); - } + try { + node.namespace = msg.payload; + node.instance = msg.topic; + eddystoneBeacon.advertiseUid(node.namespace, node.instance, node.options); + node.status({fill:"green",shape:"dot",text:msg.payload}); + } + catch(e) { + node.status({fill:"red",shape:"dot",text:"Error setting beacon information"}); + node.error('Error setting beacon information', e); + } } }); @@ -157,7 +172,8 @@ module.exports = function(RED) { node.status({}); eddystoneBeacon.stop(); done(); - } catch(e) { + } + catch(e) { node.error('error shutting down beacon', e); } }); diff --git a/hardware/pigpiod/LICENSE b/hardware/pigpiod/LICENSE new file mode 100644 index 00000000..f433b1a5 --- /dev/null +++ b/hardware/pigpiod/LICENSE @@ -0,0 +1,177 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS diff --git a/hardware/pigpiod/README.md b/hardware/pigpiod/README.md new file mode 100644 index 00000000..d6bdadeb --- /dev/null +++ b/hardware/pigpiod/README.md @@ -0,0 +1,65 @@ +node-red-node-pi-gpiod +====================== + +An alternative pair of Node-RED nodes to interact with Pi GPIO using +the PiGPIOd daemon that is now part of Raspbian. + +The advantage is that it also talk to GPIO on a Pi that is remote as long as it is running the daemon, and also sharing pins works more cleanly as contention is handled by the multiple connections. + +The disadvantage is that you must setup and run the PiGPIO daemon first. + +## Requirements + +PiGPIOd must be running on the pi. The easiest way to ensure this is to add the following line to your Pi `/etc/rc.local` file. + + /usr/bin/pigpiod + +**Note**: By default this will expose the daemon on TCP port 8888, which is obviously a **security vulnerability**. If you don't want or need remote access then you can start it in local mode only, (`-l` option), or restrict permissions to certain ip addresses, (`-n {ipaddr}` option). For example: + + /usr/bin/pigpiod -l + /usr/bin/pigpiod -n 192.168.1.10 + +See the instructions for more details. + +## Install + +Run the following command in your Node-RED user directory - typically `~/.node-red` + + npm install node-red-node-pi-gpiod + +## Usage + +**Note:** the pin numbers refer the physical pin numbers on connector P1 as they are easier to locate.

+ +### Input node + +Generates a `msg.payload` with either a 0 or 1 depending on the state of the input pin. + +##### Outputs + + - `msg.payload` - *number* - the level of the pin (0 or 1) + - `msg.topic` - *string* - pi/{the pin number} + +You may also enable the input pullup resistor ↑ or the pulldown resistor ↓. + +### Output node + +Can be used in Digital, PWM or Servo modes. + +##### Input + + - `msg.payload` - *number | string* + - Digital - 0, 1 - set pin low or high + - PWM - 0 to 100 - level from 0 to 100% + - Servo - 0 to 100, 50 is centred. + +*Hint*: The `range` node can be used to scale inputs to the correct values. + +Digital mode expects a `msg.payload` with either a 0 or 1 (or true or false), +and will set the selected physical pin high or low depending on the value passed in. + +The initial value of the pin at deploy time can also be set to 0 or 1. + +When using PWM and Servo modes, the input value should be a number 0 - 100, and can be floating point. + +In servo mode you can also preset the minimum and maximum pulse times as required by your servo in order to reach its full range. Minimum of 5mS, maximum of 25 mS - defaults to 10 and 20 mS respectively. diff --git a/hardware/pigpiod/locales/en-US/pi-gpiod.json b/hardware/pigpiod/locales/en-US/pi-gpiod.json new file mode 100644 index 00000000..69199beb --- /dev/null +++ b/hardware/pigpiod/locales/en-US/pi-gpiod.json @@ -0,0 +1,57 @@ +{ + "pi-gpiod": { + "label": { + "gpiopin": "GPIO", + "selectpin": "select pin", + "host": "Host", + "resistor": "Resistor?", + "readinitial": "Read initial state of pin on deploy/restart?", + "type": "Type", + "initpin": "Initialise pin state?", + "debounce": "Debounce", + "limits": "Limits", + "min": "min", + "max": "max" + }, + "place": { + "host": "local or remote ip", + "port": "port" + }, + "resistor": { + "none": "none", + "pullup": "pullup", + "pulldown": "pulldown" + }, + "digout": "Digital output", + "pwmout": "PWM output", + "servo": "Servo output", + "initpin0": "initial level of pin - low (0)", + "initpin1": "initial level of pin - high (1)", + "pinname": "Pin", + "tip": { + "pin": "Pins in Use: ", + "in": "Tip: Only Digital Input is supported - input must be 0 or 1.", + "dig": "Tip: For digital output - input must be 0 or 1.", + "pwm": "Tip: For PWM output - input must be between 0 to 100.", + "ser": "Tip: For Servo output - input must be between 0 to 100. 50 is centre.
Min must be 500uS or more, Max must be 2500uS or less." + }, + "types": { + "digout": "digital output", + "input": "input", + "pullup": "input with pull up", + "pulldown": "input with pull down", + "pwmout": "PWM output", + "servo": "Servo output" + }, + "status": { + "stopped": "stopped", + "closed": "closed", + "not-running": "not running" + }, + "errors": { + "invalidpin": "Invalid GPIO pin", + "invalidinput": "Invalid input", + "error": "error: __error__" + } + } +} diff --git a/hardware/pigpiod/package.json b/hardware/pigpiod/package.json new file mode 100644 index 00000000..c188c5c4 --- /dev/null +++ b/hardware/pigpiod/package.json @@ -0,0 +1,29 @@ +{ + "name": "node-red-node-pi-gpiod", + "version": "0.0.7", + "description": "A node-red node for PiGPIOd", + "dependencies" : { + "js-pigpio": "*" + }, + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "repository": { + "type": "git", + "url": "https://github.com/node-red/node-red-nodes/tree/master/hardware/pigpiod" + }, + "keywords": [ + "node-red", "Pi", "GPIO", "PiGPIOd" + ], + "author": { + "name": "Dave Conway-Jones", + "email": "ceejay@vnet.ibm.com", + "url": "http://nodered.org" + }, + "license": "Apache-2.0", + "node-red" : { + "nodes": { + "pi-gpiod": "pi-gpiod.js" + } + } +} diff --git a/hardware/pigpiod/pi-gpiod.html b/hardware/pigpiod/pi-gpiod.html new file mode 100644 index 00000000..507e63f6 --- /dev/null +++ b/hardware/pigpiod/pi-gpiod.html @@ -0,0 +1,527 @@ + + + + + + + + + + + + diff --git a/hardware/pigpiod/pi-gpiod.js b/hardware/pigpiod/pi-gpiod.js new file mode 100644 index 00000000..ca16dd1f --- /dev/null +++ b/hardware/pigpiod/pi-gpiod.js @@ -0,0 +1,167 @@ + +module.exports = function(RED) { + "use strict"; + var Pigpio = require('js-pigpio'); + + var bcm2pin = { + "2":"3", "3":"5", "4":"7", "14":"8", "15":"10", "17":"11", "18":"12", "27":"13", "22":"15", + "23":"16", "24":"18", "10":"19", "9":"21", "25":"22", "11":"23", "8":"24", "7":"26", + "5":"29", "6":"31", "12":"32", "13":"33", "19":"35", "16":"36", "26":"37", "20":"38", "21":"40" + }; + var pinTypes = { + "PUD_OFF":RED._("pi-gpiod:types.input"), + "PUD_UP":RED._("pi-gpiod:types.pullup"), + "PUD_DOWN":RED._("pi-gpiod:types.pulldown"), + "out":RED._("pi-gpiod:types.digout"), + "pwm":RED._("pi-gpiod:types.pwmout"), + "ser":RED._("pi-gpiod:types.servo") + }; + + function GPioInNode(n) { + RED.nodes.createNode(this,n); + this.host = n.host || "127.0.0.1"; + this.port = n.port || 8888; + this.pin = n.pin; + this.pio = bcm2pin[n.pin]; + this.intype = n.intype; + this.read = n.read || false; + this.debounce = Number(n.debounce || 25); + var node = this; + var PiGPIO; + + if (node.pin !== undefined) { + PiGPIO = new Pigpio(); + var inerror = false; + var doit = function() { + PiGPIO.pi(node.host, node.port, function(err) { + if (err) { + node.status({fill:"red",shape:"ring",text:err.code+" "+node.host+":"+node.port}); + if (!inerror) { node.error(err); inerror = true; } + node.retry = setTimeout(function() { doit(); }, 5000); + } + else { + inerror = false; + PiGPIO.set_mode(node.pin,PiGPIO.INPUT); + PiGPIO.set_pull_up_down(node.pin,PiGPIO[node.intype]); + PiGPIO.set_glitch_filter(node.pin,node.debounce); + node.status({fill:"green",shape:"dot",text:"node-red:common.status.ok"}); + node.cb = PiGPIO.callback(node.pin, PiGPIO.EITHER_EDGE, function(gpio, level, tick) { + node.send({ topic:"pi/"+node.pio, payload:Number(level) }); + node.status({fill:"green",shape:"dot",text:level}); + }); + if (node.read) { + setTimeout(function() { + PiGPIO.read(node.pin, function(err, level) { + node.send({ topic:"pi/"+node.pio, payload:Number(level) }); + node.status({fill:"green",shape:"dot",text:level}); + }); + }, 20); + } + } + }); + } + doit(); + } + else { + node.warn(RED._("pi-gpiod:errors.invalidpin")+": "+node.pio); + } + + node.on("close", function(done) { + if (node.retry) { clearTimeout(node.retry); } + node.status({fill:"grey",shape:"ring",text:"pi-gpiod.status.closed"}); + node.cb.cancel(); + PiGPIO.close(); + done(); + }); + } + RED.nodes.registerType("pi-gpiod in",GPioInNode); + + + function GPioOutNode(n) { + RED.nodes.createNode(this,n); + this.host = n.host || "127.0.0.1"; + this.port = n.port || 8888; + this.pin = n.pin; + this.pio = bcm2pin[n.pin]; + this.set = n.set || false; + this.level = parseInt(n.level || 0); + this.out = n.out || "out"; + this.sermin = Number(n.sermin)/100; + this.sermax = Number(n.sermax)/100; + if (this.sermin > this.sermax) { + var tmp = this.sermin; + this.sermin = this.sermax; + this.sermax = tmp; + } + if (this.sermin < 5) { this.sermin = 5; } + if (this.sermax > 25) { this.sermax = 25; } + var node = this; + var PiGPIO; + + function inputlistener(msg) { + if (!inerror) { + if (msg.payload === "true") { msg.payload = true; } + if (msg.payload === "false") { msg.payload = false; } + var out = Number(msg.payload); + var limit = 1; + if (node.out !== "out") { limit = 100; } + if ((out >= 0) && (out <= limit)) { + if (RED.settings.verbose) { node.log("out: "+msg.payload); } + if (node.out === "out") { + PiGPIO.write(node.pin, msg.payload); + } + if (node.out === "pwm") { + PiGPIO.set_PWM_dutycycle(node.pin, parseInt(msg.payload * 2.55)); + } + if (node.out === "ser") { + var r = (node.sermax - node.sermin) * 100; + PiGPIO.setServoPulsewidth(node.pin, parseInt(1500 - (r/2) + (msg.payload * r / 100))); + } + node.status({fill:"green",shape:"dot",text:msg.payload.toString()}); + } + else { node.warn(RED._("pi-gpiod:errors.invalidinput")+": "+out); } + } + } + + if (node.pin !== undefined) { + PiGPIO = new Pigpio(); + var inerror = false; + var doit = function() { + PiGPIO.pi(node.host, node.port, function(err) { + if (err) { + node.status({fill:"red",shape:"ring",text:err.code+" "+node.host+":"+node.port}); + if (!inerror) { node.error(err,err); inerror = true; } + node.retry = setTimeout(function() { doit(); }, 5000); + } + else { + inerror = false; + PiGPIO.set_mode(node.pin,PiGPIO.OUTPUT); + if (node.set) { + setTimeout(function() { PiGPIO.write(node.pin,node.level); }, 25 ); + node.status({fill:"green",shape:"dot",text:node.level}); + } else { + node.status({fill:"green",shape:"dot",text:"node-red:common.status.ok"}); + } + // if (node.out === "pwm") { + // PiGPIO.set_PWM_frequency(1000); + // PiGPIO.set_PWM_range(1000); + // } + } + }); + } + doit(); + node.on("input", inputlistener); + } + else { + node.warn(RED._("pi-gpiod:errors.invalidpin")+": "+node.pio); + } + + node.on("close", function(done) { + if (node.retry) { clearTimeout(node.retry); } + node.status({fill:"grey",shape:"ring",text:"pi-gpiod.status.closed"}); + PiGPIO.close(); + done(); + }); + } + RED.nodes.registerType("pi-gpiod out",GPioOutNode); +} diff --git a/hardware/sensehat/package.json b/hardware/sensehat/package.json index c43d641e..4c9eb5a4 100644 --- a/hardware/sensehat/package.json +++ b/hardware/sensehat/package.json @@ -1,6 +1,6 @@ { "name" : "node-red-node-pi-sense-hat", - "version" : "0.0.13", + "version" : "0.0.15", "description" : "A Node-RED node to interact with a Raspberry Pi Sense HAT", "repository" : { "type":"git", diff --git a/hardware/sensehat/sensehat.html b/hardware/sensehat/sensehat.html index 0d1abb53..a7ec2d1e 100644 --- a/hardware/sensehat/sensehat.html +++ b/hardware/sensehat/sensehat.html @@ -102,7 +102,7 @@ be sent in a single message by separating them with newline (\n) characters.

angle must be 0, 90, 180 or 270.

Flip the screen

-

Format: R<axis>

+

Format: F<axis>

axis must be either H or V to flip on the horizontal or vertical axis respectively.

diff --git a/hardware/sensehat/sensehat.js b/hardware/sensehat/sensehat.js index f2dfec03..67179233 100644 --- a/hardware/sensehat/sensehat.js +++ b/hardware/sensehat/sensehat.js @@ -52,7 +52,7 @@ module.exports = function(RED) { } buffer = lines.pop(); var m,msg; - for (var i=0;i 0) { var pixels = {}; var rules = []; - for (i=expanded.length-1;i>=0;i--) { + for (i=expanded.length-1; i>=0; i--) { var rule = expanded[i]; if (!pixels[rule[0]+","+rule[1]]) { rules.unshift(rule.join(",")); diff --git a/hardware/sensehat/sensehat.py b/hardware/sensehat/sensehat.py index deea43f8..76c7e05e 100644 --- a/hardware/sensehat/sensehat.py +++ b/hardware/sensehat/sensehat.py @@ -151,7 +151,7 @@ def process_command(data): speed = 0.1 s = data.split(':',1) if len(s) == 2: - data = s[1] + data = s[1][0:-1] if len(s[0]) > 0: c = s[0].split(",") if len(c) == 1: diff --git a/hardware/sensehatsim/sensehatsim.js b/hardware/sensehatsim/sensehatsim.js index c667964a..bcdb8cd6 100644 --- a/hardware/sensehatsim/sensehatsim.js +++ b/hardware/sensehatsim/sensehatsim.js @@ -42,9 +42,9 @@ module.exports = function(RED) { currentFlipV = false; currentRotation = "R0"; currentDisplay = []; - for (var y=0;y<8;y++) { + for (var y=0; y<8; y++) { currentDisplay.push([]); - for (var x=0;x<8;x++) { + for (var x=0; x<8; x++) { currentDisplay[y].push('0,0,0'); } } @@ -80,8 +80,8 @@ module.exports = function(RED) { socket.send("FH"); } var cmd = ""; - for (var y=0;y<8;y++) { - for (var x=0;x<8;x++) { + for (var y=0; y<8; y++) { + for (var x=0; x<8; x++) { cmd += ","+x+","+y+","+currentDisplay[y][x]; } } @@ -110,7 +110,7 @@ module.exports = function(RED) { topic: "joystick", payload: {key: KEY_MAP[m[1]], state: Number(m[2])} } - for (var j=0;j 0) { var pixels = {}; var rules = []; - for (i=expanded.length-1;i>=0;i--) { + for (i=expanded.length-1; i>=0; i--) { var rule = expanded[i]; if (!pixels[rule[0]+","+rule[1]]) { rules.unshift(rule.join(",")); diff --git a/hardware/sensorTag/79-sensorTag.js b/hardware/sensorTag/79-sensorTag.js index 1fa53241..bc3a8c89 100644 --- a/hardware/sensorTag/79-sensorTag.js +++ b/hardware/sensorTag/79-sensorTag.js @@ -100,7 +100,8 @@ module.exports = function(RED) { },node.uuid); } },15000); - } else { + } + else { console.log("reconfig",node.uuid); enable(node); } @@ -114,46 +115,54 @@ module.exports = function(RED) { var enable = function(node) { if (node.temperature) { node.stag.notifyIrTemperature(function() {}); - } else { + } + else { node.stag.unnotifyIrTemperature(function() {}); } if (node.pressure) { node.stag.notifyBarometricPressure(function() {}); - } else { + } + else { node.stag.unnotifyBarometricPressure(function() {}); } if (node.humidity) { node.stag.notifyHumidity(function() {}); - } else { + } + else { node.stag.unnotifyHumidity(function() {}); } if (node.accelerometer) { node.stag.notifyAccelerometer(function() {}); - } else { + } + else { node.stag.unnotifyAccelerometer(function() {}); } if (node.magnetometer) { node.stag.notifyMagnetometer(function() {}); - } else { + } + else { node.stag.unnotifyMagnetometer(function() {}); } if (node.gyroscope) { node.stag.notifyGyroscope(function() {}); - } else { + } + else { node.stag.unnotifyGyroscope(function() {}); } if (node.stag.type === "cc2650") { if (node.luxometer) { node.stag.enableLuxometer(function() {}); node.stag.notifyLuxometer(function() {}); - } else { + } + else { node.stag.unnotifyLuxometer(function() {}); node.stag.disableLuxometer(function() {}); } } if (node.keys) { node.stag.notifySimpleKey(function() {}); - } else { + } + else { node.stag.unnotifySimpleKey(function() {}); } } diff --git a/hardware/sensorTag/package.json b/hardware/sensorTag/package.json index 356cf909..cee98612 100644 --- a/hardware/sensorTag/package.json +++ b/hardware/sensorTag/package.json @@ -1,7 +1,7 @@ { "name": "node-red-node-sensortag", "description": "A Node-RED node to read data from a TI SensorTag", - "version": "0.0.18", + "version": "0.0.19", "keywords": [ "node-red", "sensortag", @@ -9,7 +9,7 @@ "Ti CC2541" ], "dependencies": { - "sensortag": "~1.2.0" + "sensortag": "~1.3.0" }, "scripts" : { "postinstall" : "node scripts/checkplatform.js pibt.sh" diff --git a/hardware/sensorTag/scripts/checkplatform.js b/hardware/sensorTag/scripts/checkplatform.js index 59b8cf1e..abd58cb3 100644 --- a/hardware/sensorTag/scripts/checkplatform.js +++ b/hardware/sensorTag/scripts/checkplatform.js @@ -1,17 +1,18 @@ var spawn = require('child_process').spawn; if (process.argv.length === 3) { - var command = process.argv[2]; + var command = process.argv[2]; - if (process.platform === 'linux') { - var dir = __dirname; - var script = spawn(dir + "/" + command); - script.on('close',function(code){ - process.exit(code); - }); - } else { - process.exit(0); - } + if (process.platform === 'linux') { + var dir = __dirname; + var script = spawn(dir + "/" + command); + script.on('close',function(code) { + process.exit(code); + }); + } + else { + process.exit(0); + } } else { - process.exit(0); -} \ No newline at end of file + process.exit(0); +} diff --git a/hardware/sensorTag/scripts/pibt.sh b/hardware/sensorTag/scripts/pibt.sh index d4acebbc..9564459d 100755 --- a/hardware/sensorTag/scripts/pibt.sh +++ b/hardware/sensorTag/scripts/pibt.sh @@ -1,4 +1,3 @@ #!/bin/bash #sudo apt-get install libbluetooth-dev libudev-dev pi-bluetooth - sudo setcap cap_net_raw+eip $(eval readlink -f `which node`) - +sudo setcap cap_net_raw+eip $(eval readlink -f `which node`) diff --git a/hardware/unicorn/package.json b/hardware/unicorn/package.json index cd1f4241..31b8bffb 100644 --- a/hardware/unicorn/package.json +++ b/hardware/unicorn/package.json @@ -1,6 +1,6 @@ { "name" : "node-red-node-pi-unicorn-hat", - "version" : "0.0.14", + "version" : "0.0.16", "description" : "A Node-RED node to output to a Raspberry Pi Unicorn HAT from Pimorini.", "dependencies" : { "pngjs": "2.2.*" diff --git a/hardware/unicorn/scripts/checklib.js b/hardware/unicorn/scripts/checklib.js index bd19f8c0..0ebb8a95 100755 --- a/hardware/unicorn/scripts/checklib.js +++ b/hardware/unicorn/scripts/checklib.js @@ -2,12 +2,12 @@ var fs = require('fs'); if (!fs.existsSync('/usr/local/lib/python2.7/dist-packages/unicornhat.py')) { - console.warn("WARNING : Can't find unicorn.py python library"); + console.warn("WARNING : Can't find required python library"); console.warn("WARNING : Please install using the following command"); console.warn("WARNING : Note: this uses root..."); console.warn("WARNING : curl -sS get.pimoroni.com/unicornhat | bash\n"); //process.exit(1); } else { - console.log("Unicorn Hat Python library found OK.\n") + console.log("Python library found OK.\n") } diff --git a/hardware/unicorn/unicorn.js b/hardware/unicorn/unicorn.js index 139ddf1d..c1f11ac8 100644 --- a/hardware/unicorn/unicorn.js +++ b/hardware/unicorn/unicorn.js @@ -4,6 +4,7 @@ module.exports = function(RED) { var fs = require('fs'); var PNG = require('pngjs').PNG; var spawn = require('child_process').spawn; + var execSync = require('child_process').execSync; var hatCommand = __dirname+'/unihat'; @@ -12,9 +13,9 @@ module.exports = function(RED) { throw "Info : "+RED._("rpi-gpio.errors.ignorenode"); } - if (!fs.existsSync('/usr/local/lib/python2.7/dist-packages/unicornhat.py')) { - RED.log.warn("Can't find Unicorn HAT python libraries"); - throw "Warning : Can't find Unicorn HAT python libraries"; + if (execSync('python -c "import neopixel"').toString() !== "") { + RED.log.warn("Can't find neopixel python library"); + throw "Warning : Can't find neopixel python library"; } if ( !(1 & parseInt ((fs.statSync(hatCommand).mode & parseInt ("777", 8)).toString (8)[0]) )) { diff --git a/hardware/wemo/README.md b/hardware/wemo/README.md index 3f5fe7f1..dd49ff71 100644 --- a/hardware/wemo/README.md +++ b/hardware/wemo/README.md @@ -24,7 +24,7 @@ The node accecpts the following inputs * Strings on/off * integers 1/0 * boolean true/false - * an Object like this (lights only, coming soon) + * an Object like this (lights only & color control is still work in the progress) ``` { state: 1, diff --git a/hardware/wemo/WeMoNG.html b/hardware/wemo/WeMoNG.html index f0e8e11d..b9cec3ab 100644 --- a/hardware/wemo/WeMoNG.html +++ b/hardware/wemo/WeMoNG.html @@ -29,8 +29,9 @@
  • Light Groups
  • Motion Detector
  • -

    Sockets will generate msg.payload with values of 0/1 for off or on, all other - types will return an object like this:

    +

    Sockets will generate msg.payload with values of 0/1/8 for off or on + (8 is on but at standby load for insight sockets), lightswill return an + object like this:

       {
         name: 'Bedroom light',
    @@ -44,6 +45,8 @@
       
    • 10006 - on/off
    • 10008 - brightness
    • +
    • 10300 - color
    • +
    • 30301 - color temperature
    @@ -53,7 +56,8 @@ defaults: { // defines the editable properties of the node name: {value:""}, // along with default values. topic: {value:"wemo", required: true}, - device: {value:"", type: "wemo-dev"} + device: {value:"", type: "wemo-dev"}, + label: {value:""} }, color: "LawnGreen", inputs:0, // set the number of inputs - only 0 or 1 @@ -61,10 +65,17 @@ // set the icon (held in icons dir below where you save the node) icon: "belkin.png", // saved in icons/myicon.png label: function() { // sets the default label contents - return this.name||"wemo"; + if (this.name){ + return this.name; + } else { + return this.label||"wemo"; + } }, labelStyle: function() { // sets the class to apply to the label return this.name?"node_label_italic":""; + }, + oneditsave: function(){ + this.label = $('#node-input-device option:selected').text(); } }); @@ -106,6 +117,7 @@ temperature: 25000 }
    +

    color control is still a work in progress, but the rest should work

    + + + + + + diff --git a/hardware/wemo/WeMoNG.js b/hardware/wemo/WeMoNG.js index c43e08b6..1676fb94 100644 --- a/hardware/wemo/WeMoNG.js +++ b/hardware/wemo/WeMoNG.js @@ -45,10 +45,11 @@ module.exports = function(RED) { console.log('problem with resubscription %s - %s', res.statusCode, res.statusMessage); console.log('opts - %s', util.inspect(reSubOptions)); console.log('dev - %s', util.inspect(dev)); - delete subscriptions[dev]; + delete subscriptions[subs[s]]; delete sub2dev[sub.sid]; subscribe({dev: subs[s]}); - } else { + } + else { // console.log("resubscription good %s", res.statusCode); // console.log("dev - %s", util.inspect(dev)); } @@ -57,7 +58,7 @@ module.exports = function(RED) { resub_request.on('error', function() { //console.log("failed to resubscribe to %s", dev.name ); //need to find a way to resubsribe - delete subscriptions[dev]; + delete subscriptions[subs[s]]; delete sub2dev[sub.sid]; subscribe({dev: subs[s]}); }); @@ -69,7 +70,7 @@ module.exports = function(RED) { }; - setInterval(resubscribe, 200000); + setInterval(resubscribe, 100000); var subscribe = function(node) { var dev = node.dev; @@ -78,7 +79,8 @@ module.exports = function(RED) { if (subscriptions[dev]) { //exists subscriptions[dev].count++; - } else { + } + else { //new var ipAddr; @@ -97,7 +99,8 @@ module.exports = function(RED) { break; } } - } else { + } + else { //node 0.10 not great but best we can do if (!addrs[add].internal && addrs[add].family == 'IPv4') { ipAddr = addrs[add].address; @@ -143,7 +146,8 @@ module.exports = function(RED) { if (res.statusCode == 200) { subscriptions[dev] = {'count': 1, 'sid': res.headers.sid}; sub2dev[res.headers.sid] = dev; - } else { + } + else { console.log('failed to subsrcibe'); } }); @@ -181,10 +185,12 @@ module.exports = function(RED) { unSubreq.end(); - } else { + } + else { subscriptions[dev].count--; } - } else { + } + else { //shouldn't ever get here } } @@ -210,7 +216,8 @@ module.exports = function(RED) { node.status({fill: 'green',shape: 'dot',text: 'found'}); } }); - } else { + } + else { node.status({fill: 'green',shape: 'dot',text: 'found'}); } @@ -224,10 +231,12 @@ module.exports = function(RED) { } var on = 0; + var capability = '10006'; if (typeof msg.payload === 'string') { if (msg.payload == 'on' || msg.payload == '1' || msg.payload == 'true') { on = 1; - } else if (msg.payload === 'toggle') { + } + else if (msg.payload === 'toggle') { on = 2; } } else if (typeof msg.payload === 'number') { @@ -236,14 +245,30 @@ module.exports = function(RED) { } } else if (typeof msg.payload === 'object') { //object need to get complicated here - if (msg.payload.state && typeof msg.payload.state === 'number') { + if (msg.payload.hasOwnProperty('state') && typeof msg.payload.state === 'number') { if (dev.type === 'socket') { - if (msg.payload >= 0 && msg.payload < 2) { + if (msg.payload.state >= 0 && msg.payload.state < 2) { on = msg.payload.state; } - } else if (dev.type === 'light' || dev.type === 'group') { - if (msg.payload >= 0 && msg.payload < 3) { - on = msg.payload.state; + } + else if (dev.type === 'light' || dev.type === 'group') { + // if (msg.payload.state >= 0 && msg.payload.state < 3) { + // on = msg.payload.state; + // } + var keys = Object.keys(msg.payload); + var caps = []; + var states = []; + for (var i=0; i 0) { + capability = caps.join(','); + on = states.join(','); } } } @@ -253,15 +278,14 @@ module.exports = function(RED) { } } - if (dev.type === 'socket') { + if (dev.type == 'socket') { //console.log("socket"); wemo.toggleSocket(dev, on); - } else if (dev.type === 'light`') { - //console.log("light"); - wemo.setStatus(dev,'10006', on); + } else if (dev.type === 'light') { + wemo.setStatus(dev,capability, on); } else { - console.log('group'); - wemo.setStatus(dev, '10006', on); + //console.log('group'); + wemo.setStatus(dev, capability, on); } }); }; @@ -295,17 +319,18 @@ module.exports = function(RED) { switch (notification.type){ case 'light': - case 'group': + case 'group': { if (dd.id === notification.id) { node.send(msg); } break; - case 'socket': + } + case 'socket': { node.send(msg); break; - default: + } + default: {} } - } }; @@ -316,7 +341,8 @@ module.exports = function(RED) { if (wemo.get(node.dev)) { node.status({fill: 'green',shape: 'dot',text: 'found'}); subscribe(node); - } else { + } + else { wemo.on('discovered', function(d) { if (node.dev === d) { node.status({fill: 'green',shape: 'dot',text: 'found'}); @@ -324,7 +350,8 @@ module.exports = function(RED) { } }); } - } else if (node.ipaddr) { + } + else if (node.ipaddr) { //legacy var devices = Object.keys(wemo.devices); for (var d in devices) { @@ -349,6 +376,76 @@ module.exports = function(RED) { }; RED.nodes.registerType('wemo in', wemoNGEvent); + var wemoNGLookup = function(n) { + RED.nodes.createNode(this,n); + var node = this; + node.device = n.device; + node.name = n.name; + node.dev = RED.nodes.getNode(node.device).device; + node.status({fill: 'red',shape: 'dot',text: 'searching'}); + + if (!wemo.get(node.dev)) { + wemo.on('discovered', function(d) { + if (node.dev === d) { + node.status({fill: 'green',shape: 'dot',text: 'found'}); + } + }); + } + else { + node.status({fill: 'green',shape: 'dot',text: 'found'}); + } + + node.on('input', function(msg) { + var dev = wemo.get(node.dev); + + if (!dev) { + //need to show that dev not currently found + console.log('no device found'); + return; + } + + //console.log(dev.type); + if (dev.type === 'light' || dev.type === 'group') { + //console.log("light"); + wemo.getLightStatus(dev) + .then(function(status) { + // if (status.available) { + var caps = status.capabilities.split(','); + var vals = status.state.split(','); + for (var i=0; i', '', ''].join('\n'); - var postbodyfooter = ['', '' ].join('\n'); - var getenddevs = {}; getenddevs.path = '/upnp/control/bridge1'; getenddevs.action = '"urn:Belkin:service:bridge:1#GetEndDevices"'; @@ -45,6 +44,58 @@ getcapabilities.body = [ postbodyfooter ].join('\n'); +var getDevStatus = { + method: 'POST', + path: '/upnp/control/bridge1', + action: '"urn:Belkin:service:bridge:1#GetDeviceStatus"', + body: [ + postbodyheader, + '', + '%s', + '', + postbodyfooter + ].join('\n') +}; + +var getSocketState = { + method: 'POST', + path: '/upnp/control/basicevent1', + action: '"urn:Belkin:service:basicevent:1#GetBinaryState"', + body: [ + postbodyheader, + '', + '', + postbodyfooter + ].join('\n') +} + + +var setdevstatus = {}; +setdevstatus.path = '/upnp/control/bridge1'; +setdevstatus.action = '"urn:Belkin:service:bridge:1#SetDeviceStatus"'; +setdevstatus.body = [ + postbodyheader, + '', + '', + '<?xml version="1.0" encoding="UTF-8"?><DeviceStatus><IsGroupAction>%s</IsGroupAction><DeviceID available="YES">%s</DeviceID><CapabilityID>%s</CapabilityID><CapabilityValue>%s</CapabilityValue></DeviceStatus>', + '', + '', + postbodyfooter +].join('\n'); + +var capabilityMap = { + '10006': 'state', + '10008': 'dim', + '10300': 'color', + '30301': 'temperature' + }; + +var reverseCapabilityMap = { + 'state': '10006', + 'dim': '10008', + 'color': '10300', + 'temperature': '30301' + }; var WeMoNG = function () { this.devices = {}; @@ -52,6 +103,10 @@ var WeMoNG = function () { this._interval; events.EventEmitter.call(this); + this.capabilityMap = capabilityMap; + + this.reverseCapabilityMap = reverseCapabilityMap; + } util.inherits(WeMoNG, events.EventEmitter); @@ -68,7 +123,7 @@ WeMoNG.prototype.start = function start() { request.get(location.href, function(err, res, xml) { if (!err) { xml2js.parseString(xml, function(err, json) { - if (!err) { + if (!err && json && json.root) { var device = { ip: location.hostname, port: location.port }; for (var key in json.root.device[0]) { device[key] = json.root.device[0][key][0]; @@ -248,20 +303,114 @@ WeMoNG.prototype.toggleSocket = function toggleSocket(socket, on) { post_request.end(); } -WeMoNG.prototype.setStatus = function setStatus(light, capability, value) { - var setdevstatus = {}; - setdevstatus.path = '/upnp/control/bridge1'; - setdevstatus.action = '"urn:Belkin:service:bridge:1#SetDeviceStatus"'; - setdevstatus.body = [ - postbodyheader, - '', - '', - '<?xml version="1.0" encoding="UTF-8"?><DeviceStatus><IsGroupAction>NO</IsGroupAction><DeviceID available="YES">%s</DeviceID><CapabilityID>%s</CapabilityID><CapabilityValue>%s</CapabilityValue></DeviceStatus>', - '', - '', - postbodyfooter - ].join('\n'); +WeMoNG.prototype.getSocketStatus = function getSocketStatus(socket) { + var postoptions = { + host: socket.ip, + port: socket.port, + path: getSocketState.path, + method: getSocketState.method, + headers: { + 'SOAPACTION': getSocketState.action, + 'Content-Type': 'text/xml; charset="utf-8"', + 'Accept': '' + } + } + var def = Q.defer(); + + var post_request = http.request(postoptions, function(res){ + var data = ""; + res.setEncoding('utf8'); + res.on('data', function(chunk){ + data += chunk; + }); + + res.on('end', function(){ + xml2js.parseString(data, function(err, result){ + if (!err) { + var status = result["s:Envelope"]["s:Body"][0]["u:GetBinaryStateResponse"][0]["BinaryState"][0]; + status = parseInt(status); + def.resolve(status); + } + }); + }); + }); + + post_request.on('error', function (e) { + console.log(e); + console.log("%j", postoptions); + def.reject(); + }); + + post_request.write(getSocketState.body); + post_request.end(); + + return def.promise; +}; + +WeMoNG.prototype.getLightStatus = function getLightStatus(light) { + var postoptions = { + host: light.ip, + port: light.port, + path: getDevStatus.path, + method: getDevStatus.method, + headers: { + 'SOAPACTION': getDevStatus.action, + 'Content-Type': 'text/xml; charset="utf-8"', + 'Accept': '' + } + }; + + var def = Q.defer(); + + var post_request = http.request(postoptions, function(res){ + var data = ""; + res.setEncoding('utf8'); + res.on('data', function(chunk) { + data += chunk; + }); + + res.on('end', function() { + xml2js.parseString(data, function(err, result){ + if(!err) { + if (result["s:Envelope"]) { + var status = result["s:Envelope"]["s:Body"][0]["u:GetDeviceStatusResponse"][0].DeviceStatusList[0]; + xml2js.parseString(status, function(err,result2){ + if (!err) { + var available = result2['DeviceStatusList']['DeviceStatus'][0]['DeviceID'][0]['$'].available === 'YES'; + var state = result2['DeviceStatusList']['DeviceStatus'][0]['CapabilityValue'][0]; + var capabilities = result2['DeviceStatusList']['DeviceStatus'][0]['CapabilityID'][0]; + var obj = { + available: available, + state: state, + capabilities: capabilities + }; + def.resolve(obj); + } else { + console.log("err"); + } + }); + } + } else { + console.log("err"); + } + }); + }); + }); + + post_request.on('error', function (e) { + console.log(e); + console.log("%j", postoptions); + def.reject(); + }); + + post_request.write(util.format(getDevStatus.body, light.id)); + post_request.end(); + + return def.promise; +} + +WeMoNG.prototype.setStatus = function setStatus(light, capability, value) { var postoptions = { host: light.ip, port: light.port, @@ -269,7 +418,7 @@ WeMoNG.prototype.setStatus = function setStatus(light, capability, value) { method: 'POST', headers: { 'SOAPACTION': setdevstatus.action, - 'Content-Type': 'text/xml; charset="utf-8"', + 'Content-Type': 'text/xml; charset="utf-8"', 'Accept': '' } }; @@ -293,7 +442,7 @@ WeMoNG.prototype.setStatus = function setStatus(light, capability, value) { //console.log(util.format(setdevstatus.body, light.id, capability, value)); - post_request.write(util.format(setdevstatus.body, light.id, capability, value)); + post_request.write(util.format(setdevstatus.body, light.type === 'light'?'NO':'YES',light.id, capability, value)); post_request.end(); } @@ -312,6 +461,7 @@ WeMoNG.prototype.parseEvent = function parseEvent(evt) { if (!err && res != null) { msg.id = res['StateEvent']['DeviceID'][0]['_']; msg.capability = res['StateEvent']['CapabilityId'][0]; + msg.capabilityName = capabilityMap[msg.capability]; msg.value = res['StateEvent']['Value'][0]; def.resolve(msg); } @@ -364,4 +514,27 @@ WeMoNG.prototype.rgb2xy = function rgb2xy(red, green, blue) { ]; }; +//http://stackoverflow.com/questions/22894498/philips-hue-convert-xy-from-api-to-hex-or-rgb +WeMoNG.prototype.xy2rgb = function xy2rgb(x,y,bri) { + z = 1.0 - x - y; + Y = bri / 255.0; // Brightness of lamp + X = (Y / y) * x; + Z = (Y / y) * z; + r = X * 1.612 - Y * 0.203 - Z * 0.302; + g = -X * 0.509 + Y * 1.412 + Z * 0.066; + b = X * 0.026 - Y * 0.072 + Z * 0.962; + r = r <= 0.0031308 ? 12.92 * r : (1.0 + 0.055) * Math.pow(r, (1.0 / 2.4)) - 0.055; + g = g <= 0.0031308 ? 12.92 * g : (1.0 + 0.055) * Math.pow(g, (1.0 / 2.4)) - 0.055; + b = b <= 0.0031308 ? 12.92 * b : (1.0 + 0.055) * Math.pow(b, (1.0 / 2.4)) - 0.055; + maxValue = Math.max(r,g,b); + r /= maxValue; + g /= maxValue; + b /= maxValue; + r = r * 255; if (r < 0) { r = 255 }; + g = g * 255; if (g < 0) { g = 255 }; + b = b * 255; if (b < 0) { b = 255 }; + + return [r,g,b]; +}; + module.exports = WeMoNG; diff --git a/hardware/wemo/package.json b/hardware/wemo/package.json index 53fb50c5..1b5b5758 100644 --- a/hardware/wemo/package.json +++ b/hardware/wemo/package.json @@ -1,6 +1,6 @@ { "name": "node-red-node-wemo", - "version": "0.1.9", + "version": "0.1.13", "description": "Input and Output nodes for Belkin WeMo devices", "repository": "https://github.com/node-red/node-red-nodes/tree/master/hardware", "main": "WeMoNG.js", @@ -9,7 +9,8 @@ }, "keywords": [ "node-red", - "wemo" + "wemo", + "belkin" ], "author": { "email": "hardillb@gmail.com", @@ -18,7 +19,7 @@ }, "license": "APACHE-2.0", "dependencies": { - "node-ssdp": "~2.6.3", + "node-ssdp": "~2.9.1", "request": "~2.74.0", "xml2js": "~0.4.13", "util": "~0.10.3", diff --git a/io/emoncms/88-emoncms.html b/io/emoncms/88-emoncms.html index 9aa22c88..21fe4a9a 100644 --- a/io/emoncms/88-emoncms.html +++ b/io/emoncms/88-emoncms.html @@ -31,7 +31,7 @@ defaults: { name: {value:"Emoncms"}, emonServer: {type:"emoncms-server", required:true}, - nodegroup: {value:"", validate:function(v) {return ((v === undefined)||(/^\d+$/).test(v)); }} + nodegroup: {value:"", validate:function(v) {return ((v === "")||(/^[\d\w\s.-]*$/).test(v));} } }, inputs:1, outputs:0, diff --git a/io/emoncms/88-emoncms.js b/io/emoncms/88-emoncms.js index 8fb8e0c1..aadc7281 100644 --- a/io/emoncms/88-emoncms.js +++ b/io/emoncms/88-emoncms.js @@ -34,8 +34,9 @@ module.exports = function(RED) { else { if (msg.payload.indexOf(':') > -1) { this.url += 'json={' + msg.payload + '}'; - } else { - this.url += 'csv='+msg.payload; + } + else { + this.url += 'csv=' + msg.payload; } } this.url += '&apikey='+this.apikey; @@ -96,7 +97,8 @@ module.exports = function(RED) { if (msg.rc === 200) { try { msg.payload = JSON.parse(msg.payload); - } catch(err) { + } + catch(err) { // Failed to parse, pass it on } node.send(msg); diff --git a/io/emoncms/package.json b/io/emoncms/package.json index cc74809f..80355120 100644 --- a/io/emoncms/package.json +++ b/io/emoncms/package.json @@ -1,6 +1,6 @@ { "name" : "node-red-node-emoncms", - "version" : "0.0.11", + "version" : "0.0.15", "description" : "A Node-RED node to fetch/post data to/from emoncms", "dependencies" : { }, diff --git a/io/mdns/README.md b/io/mdns/README.md index 2c97055b..e494b886 100644 --- a/io/mdns/README.md +++ b/io/mdns/README.md @@ -1,5 +1,5 @@ -node-red-node-discover -====================== +node-red-node-discovery +======================= A Node-RED node that uses Bonjour / Avahi to discover local network services such as iTunes libraries, printers, etc. diff --git a/io/mdns/mdns.js b/io/mdns/mdns.js index b202018d..74296edf 100644 --- a/io/mdns/mdns.js +++ b/io/mdns/mdns.js @@ -10,13 +10,18 @@ module.exports = function(RED) { RED.nodes.createNode(this, n); this.topic = n.topic || ""; this.service = n.service; + var node = this; // var sequence = [ // mdns.rst.DNSServiceResolve(), // mdns.rst.getaddrinfo({families: [4] }) // ]; // var browser = mdns.createBrowser(this.service,{resolverSequence: sequence}); - var browser = mdns.createBrowser(this.service); - var node = this; + var sequence = [ + mdns.rst.DNSServiceResolve(), + 'DNSServiceGetAddrInfo' in mdns.dns_sd ? mdns.rst.DNSServiceGetAddrInfo() : mdns.rst.getaddrinfo({families:[4]}), + mdns.rst.makeAddressesUnique() + ]; + var browser = mdns.createBrowser((this.service), {resolverSequence:sequence}); browser.on('serviceUp', function(service) { if (RED.settings.verbose) { node.log("here : " + service.name); } @@ -30,6 +35,9 @@ module.exports = function(RED) { var msg = {topic:node.topic, payload:service}; node.send(msg); }); + browser.on('error', function(exception) { + node.error(exception.toString()); + }); browser.start(); node.on("close", function() { diff --git a/io/mdns/package.json b/io/mdns/package.json index beb14f9b..968a3dee 100644 --- a/io/mdns/package.json +++ b/io/mdns/package.json @@ -1,16 +1,16 @@ { "name" : "node-red-node-discovery", - "version" : "0.0.13", + "version" : "0.0.18", "description" : "A Node-RED node that uses Bonjour / Avahi to discover nearby services.", "dependencies" : { - "mdns" : "2.2.*" + "mdns" : "~2.3.3" }, "repository" : { "type":"git", "url":"https://github.com/node-red/node-red-nodes/tree/master/io/mdns" }, "license": "Apache-2.0", - "keywords": [ "node-red", "mdns", "avahi", "bonjour" ], + "keywords": [ "node-red", "mdns", "avahi", "bonjour", "discovery" ], "node-red" : { "nodes" : { "discovery": "mdns.js" diff --git a/io/mqlight/mqlight.js b/io/mqlight/mqlight.js index d917723e..471b8a9e 100644 --- a/io/mqlight/mqlight.js +++ b/io/mqlight/mqlight.js @@ -22,7 +22,8 @@ module.exports = function(RED) { this.client = mqlight.createClient(opts, function(err) { if (err) { util.log('[mqlight] ['+id+'] not connected to service '+n.service); - } else { + } + else { util.log('[mqlight] ['+id+'] connected to service '+n.service); } }); @@ -47,11 +48,10 @@ module.exports = function(RED) { if (node.serviceConfig) { if (node.serviceConfig.client) { - var recvClient; + var recvClient = node.serviceConfig.client; recvClient.on("error", function(err) { if (err) { node.error(err.toString()); } }); - recvClient = node.serviceConfig.client; recvClient.on("started", function() { recvClient.on("message", function(data, delivery) { if (node.topic === delivery.destination.topicPattern) { @@ -72,13 +72,15 @@ module.exports = function(RED) { var subscribeCallback = function(err) { if (err) { node.error("Failed to subscribe: " + err); - } else { + } + else { node.log("Subscribed to "+node.topic+(node.share?" ["+node.share+"]":"")); } }; if (node.share) { recvClient.subscribe(node.topic, node.share, subscribeCallback); - } else { + } + else { recvClient.subscribe(node.topic, subscribeCallback); } }); @@ -102,18 +104,18 @@ module.exports = function(RED) { if (node.serviceConfig) { if (node.serviceConfig.client) { - var sendClient; + var sendClient = node.serviceConfig.client; sendClient.on("error", function(err) { if (err) { node.error(err.toString()); } }); - sendClient = node.serviceConfig.client; sendClient.on("started", function () { node.on("input", function(msg) { var topic = node.topic; if (topic === "") { if (msg.topic) { topic = msg.topic; - } else { + } + else { node.warn("No topic set in MQ Light out node"); return; } diff --git a/io/mqlight/package.json b/io/mqlight/package.json index 02f89477..1cc79129 100644 --- a/io/mqlight/package.json +++ b/io/mqlight/package.json @@ -1,6 +1,6 @@ { "name" : "node-red-node-mqlight", - "version" : "0.0.10", + "version" : "0.0.11", "description" : "A Node-RED node to send and receive message from IBM MQ Light", "dependencies" : { "mqlight" : "1.0.x" diff --git a/io/ping/88-ping.html b/io/ping/88-ping.html index e4f2af00..32959eeb 100644 --- a/io/ping/88-ping.html +++ b/io/ping/88-ping.html @@ -1,16 +1,16 @@ diff --git a/io/ping/88-ping.js b/io/ping/88-ping.js index a8999a73..84fb577e 100644 --- a/io/ping/88-ping.js +++ b/io/ping/88-ping.js @@ -14,7 +14,7 @@ module.exports = function(RED) { var ex; if (plat == "linux") { ex = spawn('ping', ['-n', '-w', '5', '-c', '1', node.host]); } else if (plat.match(/^win/)) { ex = spawn('ping', ['-n', '1', '-w', '5000', node.host]); } - else if (plat == "darwin") { ex = spawn('ping', ['-n', '-t', '5', '-c', '1', node.host]); } + else if (plat == "darwin" || plat == "freebsd") { ex = spawn('ping', ['-n', '-t', '5', '-c', '1', node.host]); } else { node.error("Sorry - your platform - "+plat+" - is not recognised."); } var res = false; var line = ""; diff --git a/io/ping/locales/en-US/88-ping.json b/io/ping/locales/en-US/88-ping.json new file mode 100644 index 00000000..209e9da4 --- /dev/null +++ b/io/ping/locales/en-US/88-ping.json @@ -0,0 +1,8 @@ +{ + "ping": { + "label": { + "target": "Target", + "ping": "Ping (S)" + } + } +} diff --git a/io/ping/locales/ja/88-ping.json b/io/ping/locales/ja/88-ping.json new file mode 100644 index 00000000..46478887 --- /dev/null +++ b/io/ping/locales/ja/88-ping.json @@ -0,0 +1,8 @@ +{ + "ping": { + "label": { + "target": "対象", + "ping": "Ping (秒)" + } + } +} diff --git a/io/ping/package.json b/io/ping/package.json index c5a7c17f..6d4ccf1f 100644 --- a/io/ping/package.json +++ b/io/ping/package.json @@ -1,6 +1,6 @@ { "name" : "node-red-node-ping", - "version" : "0.0.13", + "version" : "0.0.14", "description" : "A Node-RED node to ping a remote server, for use as a keep-alive check.", "dependencies" : { }, diff --git a/io/serialport/25-serial.html b/io/serialport/25-serial.html index b1cde5b2..287515bb 100644 --- a/io/serialport/25-serial.html +++ b/io/serialport/25-serial.html @@ -12,7 +12,7 @@ + + + + + + + + + \ No newline at end of file diff --git a/io/snmp/snmp.js b/io/snmp/snmp.js index 47bd9725..008d5995 100644 --- a/io/snmp/snmp.js +++ b/io/snmp/snmp.js @@ -1,27 +1,39 @@ -module.exports = function(RED) { +module.exports = function (RED) { "use strict"; var snmp = require("net-snmp"); + var sessions = {}; + + function getSession(host, community, version) { + var sessionKey = host + ":" + community + ":" + version; + if (!(sessionKey in sessions)) { + sessions[sessionKey] = snmp.createSession(host, community, { version: version }); + } + return sessions[sessionKey]; + } + function SnmpNode(n) { - RED.nodes.createNode(this,n); - this.community = n.community || "public"; - this.host = n.host || "127.0.0.1"; + RED.nodes.createNode(this, n); + this.community = n.community; + this.host = n.host; this.version = (n.version === "2c") ? snmp.Version2c : snmp.Version1; - this.oids = n.oids.replace(/\s/g,""); - this.session = snmp.createSession(this.host, this.community, {version: this.version}); + this.oids = n.oids.replace(/\s/g, ""); var node = this; - this.on("input",function(msg) { + this.on("input", function (msg) { + var host = node.host || msg.host; + var community = node.community || msg.community; var oids = node.oids || msg.oid; if (oids) { - node.session.get(oids.split(","), function(error, varbinds) { + getSession(host, community, node.version).get(oids.split(","), function (error, varbinds) { if (error) { - node.error(error.toString(),msg); - } else { + node.error(error.toString(), msg); + } + else { for (var i = 0; i < varbinds.length; i++) { if (snmp.isVarbindError(varbinds[i])) { - node.error(snmp.varbindError(varbinds[i]),msg); + node.error(snmp.varbindError(varbinds[i]), msg); } else { if (varbinds[i].type == 4) { varbinds[i].value = varbinds[i].value.toString(); } @@ -40,17 +52,56 @@ module.exports = function(RED) { } }); } - RED.nodes.registerType("snmp",SnmpNode); + RED.nodes.registerType("snmp", SnmpNode); + + + function SnmpSNode(n) { + RED.nodes.createNode(this, n); + this.community = n.community; + this.host = n.host; + this.version = (n.version === "2c") ? snmp.Version2c : snmp.Version1; + this.varbinds = n.varbinds; + var node = this; + this.on("input", function (msg) { + var host = node.host || msg.host; + var community = node.community || msg.community; + var varbinds = (node.varbinds) ? JSON.parse(node.varbinds) : msg.varbinds; + if (varbinds) { + for (var i = 0; i < varbinds.length; i++) { + varbinds[i].type = snmp.ObjectType[varbinds[i].type]; + } + getSession(host, community, node.version).set(varbinds, function (error, varbinds) { + if (error) { + node.error(error.toString(), msg); + } + else { + for (var i = 0; i < varbinds.length; i++) { + // for version 2c we must check each OID for an error condition + if (snmp.isVarbindError(varbinds[i])) { + node.error(snmp.varbindError(varbinds[i]), msg); + } + } + } + }); + } + else { + node.warn("No varbinds to set"); + } + }); + + } + RED.nodes.registerType("snmp set", SnmpSNode); + + + function SnmpTNode(n) { - RED.nodes.createNode(this,n); - this.community = n.community || "public"; - this.host = n.host || "127.0.0.1"; + RED.nodes.createNode(this, n); + this.community = n.community; + this.host = n.host; this.version = (n.version === "2c") ? snmp.Version2c : snmp.Version1; - this.oids = n.oids.replace(/\s/g,""); - this.session = snmp.createSession(this.host, this.community, {version: this.version}); + this.oids = n.oids.replace(/\s/g, ""); var node = this; - var msg; var maxRepetitions = 20; function sortInt(a, b) { @@ -59,143 +110,141 @@ module.exports = function(RED) { else { return 0; } } - function responseCb(error, table) { - if (error) { - le.error(error.toString()); - } else { - var indexes = []; - for (var index in table) { - if (table.hasOwnProperty(index)) { - indexes.push(parseInt(index)); - } - } - indexes.sort(sortInt); - for (var i = 0; i < indexes.length; i++) { - var columns = []; - for (var column in table[indexes[i]]) { - if (table[indexes[i]].hasOwnProperty(column)) { - columns.push(parseInt(column)); - } - } - columns.sort(sortInt); - // console.log("row index = " + indexes[i]); - // for (var j = 0; j < columns.length; j++) { - // console.log(" column " + columns[j] + " = " + table[indexes[i]][columns[j]]); - // } - } - msg.payload = table; - node.send(msg); - } - } - - this.on("input",function(m) { - msg = m; + this.on("input", function (msg) { + var host = node.host || msg.host; + var community = node.community || msg.community; var oids = node.oids || msg.oid; if (oids) { msg.oid = oids; - node.session.table(oids, maxRepetitions, responseCb); + getSession(host, community, node.version).table(oids, maxRepetitions, function (error, table) { + if (error) { + node.error(error.toString(), msg); + } + else { + var indexes = []; + for (var index in table) { + if (table.hasOwnProperty(index)) { + indexes.push(parseInt(index)); + } + } + indexes.sort(sortInt); + for (var i = 0; i < indexes.length; i++) { + var columns = []; + for (var column in table[indexes[i]]) { + if (table[indexes[i]].hasOwnProperty(column)) { + columns.push(parseInt(column)); + } + } + columns.sort(sortInt); + // console.log("row index = " + indexes[i]); + // for (var j = 0; j < columns.length; j++) { + // console.log(" column " + columns[j] + " = " + table[indexes[i]][columns[j]]); + // } + } + msg.payload = table; + node.send(msg); + } + }); } else { node.warn("No oid to search for"); } }); } - RED.nodes.registerType("snmp table",SnmpTNode); + RED.nodes.registerType("snmp table", SnmpTNode); function SnmpSubtreeNode(n) { - RED.nodes.createNode(this,n); - this.community = n.community || "public"; - this.host = n.host || "127.0.0.1"; + RED.nodes.createNode(this, n); + this.community = n.community; + this.host = n.host; this.version = (n.version === "2c") ? snmp.Version2c : snmp.Version1; - this.oids = n.oids.replace(/\s/g,""); - this.session = snmp.createSession(this.host, this.community, {version: this.version}); + this.oids = n.oids.replace(/\s/g, ""); var node = this; var maxRepetitions = 20; var response = []; - function doneCb(error) { - if (error) { - console.error(error.toString()); - } - else { - var msg = {}; - msg.payload = response; - node.send(msg); - response.clear(); - } - } - function feedCb(varbinds) { for (var i = 0; i < varbinds.length; i++) { if (snmp.isVarbindError(varbinds[i])) { - node.error(snmp.varbindError(varbinds[i])); + node.error(snmp.varbindError(varbinds[i]), msg); } else { //console.log(varbinds[i].oid + "|" + varbinds[i].value); - response.add({oid: varbinds[i].oid, value: varbinds[i].value}); + response.push({ oid: varbinds[i].oid, value: varbinds[i].value }); } } } - this.on("input",function(msg) { + this.on("input", function (msg) { + var host = node.host || msg.host; + var community = node.community || msg.community; var oids = node.oids || msg.oid; if (oids) { msg.oid = oids; - node.session.subtree(msg.oid, maxRepetitions, feedCb, doneCb); - //node.session.subtree(oids, maxRepetitions, responseCb); + getSession(host, community, node.version).subtree(msg.oid, maxRepetitions, feedCb, function (error) { + if (error) { + node.error(error.toString(), msg); + } + else { + msg.payload = response; + node.send(msg); + //Clears response + response.length = 0; + } + }); } else { node.warn("No oid to search for"); } }); } - RED.nodes.registerType("snmp subtree",SnmpSubtreeNode); + RED.nodes.registerType("snmp subtree", SnmpSubtreeNode); function SnmpWalkerNode(n) { - RED.nodes.createNode(this,n); - this.community = n.community || "public"; - this.host = n.host || "127.0.0.1"; + RED.nodes.createNode(this, n); + this.community = n.community; + this.host = n.host; this.version = (n.version === "2c") ? snmp.Version2c : snmp.Version1; - this.oids = n.oids.replace(/\s/g,""); - this.session = snmp.createSession(this.host, this.community, {version: this.version}); + this.oids = n.oids.replace(/\s/g, ""); var node = this; var maxRepetitions = 20; var response = []; - function doneCb(error) { - if (error) { - node.error(error.toString()); - } - else { - var msg = {}; - msg.payload = response; - node.send(msg); - response.clear(); - } - } - function feedCb(varbinds) { for (var i = 0; i < varbinds.length; i++) { if (snmp.isVarbindError(varbinds[i])) { - node.error(snmp.varbindError(varbinds[i])); + node.error(snmp.varbindError(varbinds[i]), msg); } else { //console.log(varbinds[i].oid + "|" + varbinds[i].value); - response.add({oid: varbinds[i].oid, value: varbinds[i].value}); + response.push({ oid: varbinds[i].oid, value: varbinds[i].value }); } } } - this.on("input",function(msg) { + this.on("input", function (msg) { + node.msg = msg; var oids = node.oids || msg.oid; + var host = node.host || msg.host; + var community = node.community || msg.community; if (oids) { msg.oid = oids; - node.session.walk(msg.oid, maxRepetitions, feedCb, doneCb); + getSession(host, community, node.version).walk(msg.oid, maxRepetitions, feedCb, function (error) { + if (error) { + node.error(error.toString(), msg); + } + else { + msg.payload = response; + node.send(msg); + //Clears response + response.length = 0; + } + }); } else { node.warn("No oid to search for"); } }); } - RED.nodes.registerType("snmp walker",SnmpWalkerNode); + RED.nodes.registerType("snmp walker", SnmpWalkerNode); }; diff --git a/io/stomp/18-stomp.js b/io/stomp/18-stomp.js index 1ac3d58f..62fa5044 100644 --- a/io/stomp/18-stomp.js +++ b/io/stomp/18-stomp.js @@ -41,7 +41,7 @@ module.exports = function(RED) { } }; if (this.serverConfig.vhost) { - this.stompClientOpts.vhost = this.serverConfig.vhost; + this.stompClientOpts.vhost = this.serverConfig.vhost; } var node = this; @@ -49,7 +49,7 @@ module.exports = function(RED) { node.client = new StompClient(node.stompClientOpts); node.client.on("connect", function() { - node.status({fill:"green",shape:"dot",text:"connected"}); + node.status({fill:"green",shape:"dot",text:"connected"}); }); node.client.on("reconnecting", function() { @@ -110,14 +110,14 @@ module.exports = function(RED) { } }; if (this.serverConfig.vhost) { - this.stompClientOpts.vhost = this.serverConfig.vhost; + this.stompClientOpts.vhost = this.serverConfig.vhost; } var node = this; node.client = new StompClient(node.stompClientOpts); node.client.on("connect", function() { - node.status({fill:"green",shape:"dot",text:"connected"}); + node.status({fill:"green",shape:"dot",text:"connected"}); }); node.client.on("reconnecting", function() { diff --git a/io/wol/39-wol.js b/io/wol/39-wol.js index aee413be..0bd45d01 100644 --- a/io/wol/39-wol.js +++ b/io/wol/39-wol.js @@ -22,7 +22,8 @@ module.exports = function(RED) { node.log("sent WOL magic packet"); } }); - } catch(e) { + } + catch(e) { if (RED.settings.verbose) { node.log("WOL: socket error"); } } } diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 00000000..07622672 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,2729 @@ +{ + "name": "node-red-nodes", + "version": "0.0.10", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "JSV": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/JSV/-/JSV-4.0.2.tgz", + "integrity": "sha1-0Hf2glVx+CEy+d/67Vh7QCn+/1c=", + "dev": true + }, + "abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", + "dev": true + }, + "addressparser": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/addressparser/-/addressparser-1.0.1.tgz", + "integrity": "sha1-R6++GiqSYhkdtoOOT9HTm0CCF0Y=", + "dev": true + }, + "ajv": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.3.0.tgz", + "integrity": "sha1-RBT/dKUIecII7l/cgm4ywwNUnto=", + "dev": true, + "requires": { + "co": "4.6.0", + "fast-deep-equal": "1.0.0", + "fast-json-stable-stringify": "2.0.0", + "json-schema-traverse": "0.3.1" + } + }, + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true + }, + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true + }, + "argparse": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.9.tgz", + "integrity": "sha1-c9g7wmP4bpf4zE9rrhsOkKfSLIY=", + "dev": true, + "requires": { + "sprintf-js": "1.0.3" + } + }, + "array-find-index": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz", + "integrity": "sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E=", + "dev": true + }, + "asn1": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz", + "integrity": "sha1-2sh4dxPJlmhJ/IGAd36+nB3fO4Y=", + "dev": true + }, + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "dev": true + }, + "async": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", + "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=", + "dev": true + }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", + "dev": true + }, + "aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=", + "dev": true + }, + "aws4": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.6.0.tgz", + "integrity": "sha1-g+9cqGCysy5KDe7e6MdxudtXRx4=", + "dev": true + }, + "babel-runtime": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", + "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", + "dev": true, + "requires": { + "core-js": "2.5.1", + "regenerator-runtime": "0.11.0" + } + }, + "babylon": { + "version": "6.18.0", + "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz", + "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==", + "dev": true + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "dev": true + }, + "bcrypt-pbkdf": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz", + "integrity": "sha1-Y7xdy2EzG5K8Bf1SiVPDNGKgb40=", + "dev": true, + "optional": true, + "requires": { + "tweetnacl": "0.14.5" + } + }, + "boom": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/boom/-/boom-4.3.1.tgz", + "integrity": "sha1-T4owBctKfjiJ90kDD9JbluAdLjE=", + "dev": true, + "requires": { + "hoek": "4.2.0" + } + }, + "brace-expansion": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.8.tgz", + "integrity": "sha1-wHshHHyVLsH479Uad+8NHTmQopI=", + "dev": true, + "requires": { + "balanced-match": "1.0.0", + "concat-map": "0.0.1" + } + }, + "browser-stdout": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.0.tgz", + "integrity": "sha1-81HTKWnTL6XXpVZxVCY9korjvR8=", + "dev": true + }, + "buildmail": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/buildmail/-/buildmail-2.0.0.tgz", + "integrity": "sha1-8LewpZ6aShtQZrv6BR0kjzgy7s4=", + "dev": true, + "requires": { + "addressparser": "0.3.2", + "libbase64": "0.1.0", + "libmime": "1.2.0", + "libqp": "1.1.0", + "needle": "0.10.0" + }, + "dependencies": { + "addressparser": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/addressparser/-/addressparser-0.3.2.tgz", + "integrity": "sha1-WYc/Nej89sc2HBAjkmHXbhU0i7I=", + "dev": true + }, + "needle": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/needle/-/needle-0.10.0.tgz", + "integrity": "sha1-FqJNY/KmEVLrdMzh0Sr4XFB1d9Q=", + "dev": true, + "requires": { + "debug": "2.6.9", + "iconv-lite": "0.4.19" + } + } + } + }, + "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 + }, + "camelcase": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz", + "integrity": "sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8=", + "dev": true + }, + "camelcase-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz", + "integrity": "sha1-MIvur/3ygRkFHvodkyITyRuPkuc=", + "dev": true, + "requires": { + "camelcase": "2.1.1", + "map-obj": "1.0.1" + } + }, + "caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", + "dev": true + }, + "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" + } + }, + "cli": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cli/-/cli-1.0.1.tgz", + "integrity": "sha1-IoF1NPJL+klQw01TLUjsvGIbjBQ=", + "dev": true, + "requires": { + "exit": "0.1.2", + "glob": "7.1.2" + }, + "dependencies": { + "glob": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", + "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", + "dev": true, + "requires": { + "fs.realpath": "1.0.0", + "inflight": "1.0.6", + "inherits": "2.0.3", + "minimatch": "3.0.4", + "once": "1.4.0", + "path-is-absolute": "1.0.1" + } + } + } + }, + "cli-table": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/cli-table/-/cli-table-0.3.1.tgz", + "integrity": "sha1-9TsFJmqLGguTSz0IIebi3FkUriM=", + "dev": true, + "requires": { + "colors": "1.0.3" + }, + "dependencies": { + "colors": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.0.3.tgz", + "integrity": "sha1-BDP0TYCWgP3rYO0mDxsMJi6CpAs=", + "dev": true + } + } + }, + "clone": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.2.tgz", + "integrity": "sha1-Jgt6meux7f4kdTgXX3gyQ8sZ0Uk=", + "dev": true + }, + "co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", + "dev": true + }, + "coffee-script": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/coffee-script/-/coffee-script-1.10.0.tgz", + "integrity": "sha1-EpOLz5vhlI+gBvkuDEyegXBRCMA=", + "dev": true + }, + "colors": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.1.2.tgz", + "integrity": "sha1-FopHAXVran9RoSzgyXv6KMCE7WM=", + "dev": true + }, + "combined-stream": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.5.tgz", + "integrity": "sha1-k4NwpXtKUd6ix3wV1cX9+JUWQAk=", + "dev": true, + "requires": { + "delayed-stream": "1.0.0" + } + }, + "commander": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.9.0.tgz", + "integrity": "sha1-nJkJQXbhIkDLItbFFGCYQA/g99Q=", + "dev": true, + "requires": { + "graceful-readlink": "1.0.1" + } + }, + "comment-parser": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/comment-parser/-/comment-parser-0.3.2.tgz", + "integrity": "sha1-PAPwd2uGo239mgosl8YwfzMggv4=", + "dev": true, + "requires": { + "readable-stream": "2.3.3" + }, + "dependencies": { + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "readable-stream": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz", + "integrity": "sha512-m+qzzcn7KUxEmd1gMbchF+Y2eIUbieUaxkWtptyHywrX0rE8QEYqPC07Vuy4Wm32/xE16NcdBctb8S0Xe/5IeQ==", + "dev": true, + "requires": { + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "1.0.0", + "process-nextick-args": "1.0.7", + "safe-buffer": "5.1.1", + "string_decoder": "1.0.3", + "util-deprecate": "1.0.2" + } + }, + "string_decoder": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", + "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==", + "dev": true, + "requires": { + "safe-buffer": "5.1.1" + } + } + } + }, + "component-emitter": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", + "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=", + "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=", + "dev": true + }, + "console-browserify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.1.0.tgz", + "integrity": "sha1-8CQcRXMKn8YyOyBtvzjtx0HQuxA=", + "dev": true, + "requires": { + "date-now": "0.1.4" + } + }, + "cookiejar": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/cookiejar/-/cookiejar-2.1.1.tgz", + "integrity": "sha1-Qa1XsbVVlR7BcUEqgZQrHoIA00o=", + "dev": true + }, + "core-js": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.5.1.tgz", + "integrity": "sha1-rmh03GaTd4m4B1T/VCjfZoGcpQs=", + "dev": true + }, + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", + "dev": true + }, + "cryptiles": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-3.1.2.tgz", + "integrity": "sha1-qJ+7Ig9c4l7FboxKqKT9e1sNKf4=", + "dev": true, + "requires": { + "boom": "5.2.0" + }, + "dependencies": { + "boom": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/boom/-/boom-5.2.0.tgz", + "integrity": "sha512-Z5BTk6ZRe4tXXQlkqftmsAUANpXmuwlsF5Oov8ThoMbQRzdGTA1ngYRW160GexgOgjsFOKJz0LYhoNi+2AMBUw==", + "dev": true, + "requires": { + "hoek": "4.2.0" + } + } + } + }, + "cst": { + "version": "0.4.10", + "resolved": "https://registry.npmjs.org/cst/-/cst-0.4.10.tgz", + "integrity": "sha512-U5ETe1IOjq2h56ZcBE3oe9rT7XryCH6IKgPMv0L7sSk6w29yR3p5egCK0T3BDNHHV95OoUBgXsqiVG+3a900Ag==", + "dev": true, + "requires": { + "babel-runtime": "6.26.0", + "babylon": "6.18.0", + "source-map-support": "0.4.18" + } + }, + "currently-unhandled": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz", + "integrity": "sha1-mI3zP+qxke95mmE2nddsF635V+o=", + "dev": true, + "requires": { + "array-find-index": "1.0.2" + } + }, + "cycle": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/cycle/-/cycle-1.0.3.tgz", + "integrity": "sha1-IegLK+hYD5i0aPN5QwZisEbDStI=", + "dev": true + }, + "dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", + "dev": true, + "requires": { + "assert-plus": "1.0.0" + } + }, + "date-now": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/date-now/-/date-now-0.1.4.tgz", + "integrity": "sha1-6vQ5/U1ISK105cx9vvIAZyueNFs=", + "dev": true + }, + "dateformat": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-1.0.12.tgz", + "integrity": "sha1-nxJLZ1lMk3/3BpMuSmQsyo27/uk=", + "dev": true, + "requires": { + "get-stdin": "4.0.1", + "meow": "3.7.0" + } + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", + "dev": true + }, + "deep-equal": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.0.1.tgz", + "integrity": "sha1-9dJgKStmDghO/0zbyfCK0yR0SLU=", + "dev": true + }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", + "dev": true + }, + "diff": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-3.2.0.tgz", + "integrity": "sha1-yc45Okt8vQsFinJck98pkCeGj/k=", + "dev": true + }, + "dom-serializer": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.1.0.tgz", + "integrity": "sha1-BzxpdUbOB4DOI75KKOKT5AvDDII=", + "dev": true, + "requires": { + "domelementtype": "1.1.3", + "entities": "1.1.1" + }, + "dependencies": { + "domelementtype": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.1.3.tgz", + "integrity": "sha1-vSh3PiZCiBrsUVRJJCmcXNgiGFs=", + "dev": true + }, + "entities": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.1.tgz", + "integrity": "sha1-blwtClYhtdra7O+AuQ7ftc13cvA=", + "dev": true + } + } + }, + "domelementtype": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.0.tgz", + "integrity": "sha1-sXrtguirWeUt2cGbF1bg/BhyBMI=", + "dev": true + }, + "domhandler": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.3.0.tgz", + "integrity": "sha1-LeWaCCLVAn+r/28DLCsloqir5zg=", + "dev": true, + "requires": { + "domelementtype": "1.3.0" + } + }, + "domutils": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.5.1.tgz", + "integrity": "sha1-3NhIiib1Y9YQeeSMn3t+Mjc2gs8=", + "dev": true, + "requires": { + "dom-serializer": "0.1.0", + "domelementtype": "1.3.0" + } + }, + "ecc-jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz", + "integrity": "sha1-D8c6ntXw1Tw4GTOYUj735UN3dQU=", + "dev": true, + "optional": true, + "requires": { + "jsbn": "0.1.1" + } + }, + "encoding": { + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.12.tgz", + "integrity": "sha1-U4tm8+5izRq1HsMjgp0flIDHS+s=", + "dev": true, + "requires": { + "iconv-lite": "0.4.19" + } + }, + "entities": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-1.0.0.tgz", + "integrity": "sha1-sph6o4ITR/zeZCsk/fyeT7cSvyY=", + "dev": true + }, + "error-ex": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.1.tgz", + "integrity": "sha1-+FWobOYa3E6GIcPNoh56dhLDqNw=", + "dev": true, + "requires": { + "is-arrayish": "0.2.1" + } + }, + "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": "2.7.3", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-2.7.3.tgz", + "integrity": "sha1-luO3DVd59q1JzQMmc9HDEnZ7pYE=", + "dev": true + }, + "estraverse": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz", + "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=", + "dev": true + }, + "event-lite": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/event-lite/-/event-lite-0.1.1.tgz", + "integrity": "sha1-R88IqNN9C2lM23s7F7UfqsZXYIY=", + "dev": true + }, + "eventemitter2": { + "version": "0.4.14", + "resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-0.4.14.tgz", + "integrity": "sha1-j2G3XN4BKy6esoTUVFWDtWQ7Yas=", + "dev": true + }, + "exif": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/exif/-/exif-0.6.0.tgz", + "integrity": "sha1-YKYmaAdlQst+T1cZnUrG830sX0o=", + "dev": true, + "requires": { + "debug": "2.6.9" + } + }, + "exit": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", + "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=", + "dev": true + }, + "extend": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.1.tgz", + "integrity": "sha1-p1Xqe8Gt/MWjHOfnYtuq3F5jZEQ=", + "dev": true + }, + "extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", + "dev": true + }, + "eyes": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/eyes/-/eyes-0.1.8.tgz", + "integrity": "sha1-Ys8SAjTGg3hdkCNIqADvPgzCC8A=", + "dev": true + }, + "fast-deep-equal": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.0.0.tgz", + "integrity": "sha1-liVqO8l1WV6zbYLpkp0GDYk0Of8=", + "dev": true + }, + "fast-json-stable-stringify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", + "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=", + "dev": true + }, + "fill-keys": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/fill-keys/-/fill-keys-1.0.2.tgz", + "integrity": "sha1-mo+jb06K1jTjv2tPPIiCVRRS6yA=", + "dev": true, + "requires": { + "is-object": "1.0.1", + "merge-descriptors": "1.0.1" + } + }, + "find-up": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", + "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", + "dev": true, + "requires": { + "path-exists": "2.1.0", + "pinkie-promise": "2.0.1" + } + }, + "findup-sync": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-0.3.0.tgz", + "integrity": "sha1-N5MKpdgWt3fANEXhlmzGeQpMCxY=", + "dev": true, + "requires": { + "glob": "5.0.15" + }, + "dependencies": { + "glob": { + "version": "5.0.15", + "resolved": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz", + "integrity": "sha1-G8k2ueAvSmA/zCIuz3Yz0wuLk7E=", + "dev": true, + "requires": { + "inflight": "1.0.6", + "inherits": "2.0.3", + "minimatch": "3.0.4", + "once": "1.4.0", + "path-is-absolute": "1.0.1" + } + } + } + }, + "forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", + "dev": true + }, + "form-data": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.1.tgz", + "integrity": "sha1-b7lPvXGIUwbXPRXMSX/kzE7NRL8=", + "dev": true, + "requires": { + "asynckit": "0.4.0", + "combined-stream": "1.0.5", + "mime-types": "2.1.17" + } + }, + "formatio": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/formatio/-/formatio-1.1.1.tgz", + "integrity": "sha1-XtPM1jZVEJc4NGXZlhmRAOhhYek=", + "dev": true, + "requires": { + "samsam": "1.1.2" + } + }, + "formidable": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/formidable/-/formidable-1.1.1.tgz", + "integrity": "sha1-lriIb3w8NQi5Mta9cMTTqI818ak=", + "dev": true + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "get-stdin": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz", + "integrity": "sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4=", + "dev": true + }, + "getobject": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/getobject/-/getobject-0.1.0.tgz", + "integrity": "sha1-BHpEl4n6Fg0Bj1SG7ZEyC27HiFw=", + "dev": true + }, + "getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", + "dev": true, + "requires": { + "assert-plus": "1.0.0" + } + }, + "glob": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.0.6.tgz", + "integrity": "sha1-IRuvr0nlJbjNkyYNFKsTYVKz9Xo=", + "dev": true, + "requires": { + "fs.realpath": "1.0.0", + "inflight": "1.0.6", + "inherits": "2.0.3", + "minimatch": "3.0.4", + "once": "1.4.0", + "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 + }, + "graceful-readlink": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz", + "integrity": "sha1-TK+tdrxi8C+gObL5Tpo906ORpyU=", + "dev": true + }, + "growl": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/growl/-/growl-1.9.2.tgz", + "integrity": "sha1-Dqd0NxXbjY3ixe3hd14bRayFwC8=", + "dev": true + }, + "grunt": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/grunt/-/grunt-1.0.1.tgz", + "integrity": "sha1-6HeHZOlEsY8yuw8QuQeEdcnftWs=", + "dev": true, + "requires": { + "coffee-script": "1.10.0", + "dateformat": "1.0.12", + "eventemitter2": "0.4.14", + "exit": "0.1.2", + "findup-sync": "0.3.0", + "glob": "7.0.6", + "grunt-cli": "1.2.0", + "grunt-known-options": "1.1.0", + "grunt-legacy-log": "1.0.0", + "grunt-legacy-util": "1.0.0", + "iconv-lite": "0.4.19", + "js-yaml": "3.5.5", + "minimatch": "3.0.4", + "nopt": "3.0.6", + "path-is-absolute": "1.0.1", + "rimraf": "2.2.8" + }, + "dependencies": { + "grunt-cli": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/grunt-cli/-/grunt-cli-1.2.0.tgz", + "integrity": "sha1-VisRnrsGndtGSs4oRVAb6Xs1tqg=", + "dev": true, + "requires": { + "findup-sync": "0.3.0", + "grunt-known-options": "1.1.0", + "nopt": "3.0.6", + "resolve": "1.1.7" + } + } + } + }, + "grunt-contrib-jshint": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/grunt-contrib-jshint/-/grunt-contrib-jshint-1.1.0.tgz", + "integrity": "sha1-Np2QmyWTxA6L55lAshNAhQx5Oaw=", + "dev": true, + "requires": { + "chalk": "1.1.3", + "hooker": "0.2.3", + "jshint": "2.9.5" + } + }, + "grunt-jscs": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/grunt-jscs/-/grunt-jscs-3.0.1.tgz", + "integrity": "sha1-H65Q4+lV3546nZQlrsIqzK4AgJI=", + "dev": true, + "requires": { + "hooker": "0.2.3", + "jscs": "3.0.7", + "lodash": "4.6.1", + "vow": "0.4.17" + }, + "dependencies": { + "lodash": { + "version": "4.6.1", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.6.1.tgz", + "integrity": "sha1-3wDBFkrSNrGDz8OIel6NOMxjy7w=", + "dev": true + } + } + }, + "grunt-known-options": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/grunt-known-options/-/grunt-known-options-1.1.0.tgz", + "integrity": "sha1-pCdO6zL6dl2lp6OxcSYXzjsUQUk=", + "dev": true + }, + "grunt-legacy-log": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/grunt-legacy-log/-/grunt-legacy-log-1.0.0.tgz", + "integrity": "sha1-+4bxgJhHvAfcR4Q/ns1srLYt8tU=", + "dev": true, + "requires": { + "colors": "1.1.2", + "grunt-legacy-log-utils": "1.0.0", + "hooker": "0.2.3", + "lodash": "3.10.1", + "underscore.string": "3.2.3" + } + }, + "grunt-legacy-log-utils": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/grunt-legacy-log-utils/-/grunt-legacy-log-utils-1.0.0.tgz", + "integrity": "sha1-p7ji0Ps1taUPSvmG/BEnSevJbz0=", + "dev": true, + "requires": { + "chalk": "1.1.3", + "lodash": "4.3.0" + }, + "dependencies": { + "lodash": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.3.0.tgz", + "integrity": "sha1-79nEpuxT87BUEkKZFcPkgk5NJaQ=", + "dev": true + } + } + }, + "grunt-legacy-util": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/grunt-legacy-util/-/grunt-legacy-util-1.0.0.tgz", + "integrity": "sha1-OGqnjcbtUJhsKxiVcmWxtIq7m4Y=", + "dev": true, + "requires": { + "async": "1.5.2", + "exit": "0.1.2", + "getobject": "0.1.0", + "hooker": "0.2.3", + "lodash": "4.3.0", + "underscore.string": "3.2.3", + "which": "1.2.14" + }, + "dependencies": { + "lodash": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.3.0.tgz", + "integrity": "sha1-79nEpuxT87BUEkKZFcPkgk5NJaQ=", + "dev": true + } + } + }, + "grunt-lint-inline": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/grunt-lint-inline/-/grunt-lint-inline-1.0.0.tgz", + "integrity": "sha1-8ZXnEuNJSij2lqSE0SFrZ2sQ4bA=", + "dev": true, + "requires": { + "grunt-contrib-jshint": "1.0.0", + "temporary": "0.0.8" + }, + "dependencies": { + "grunt-contrib-jshint": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/grunt-contrib-jshint/-/grunt-contrib-jshint-1.0.0.tgz", + "integrity": "sha1-MPQFpR3mVr+m6wKbmkZLn+AqQCo=", + "dev": true, + "requires": { + "chalk": "1.1.3", + "hooker": "0.2.3", + "jshint": "2.9.5" + } + } + } + }, + "grunt-simple-mocha": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/grunt-simple-mocha/-/grunt-simple-mocha-0.4.1.tgz", + "integrity": "sha1-V5RJJJ6vCoGHj6cvPtq1FF1F/Xc=", + "dev": true, + "requires": { + "mocha": "3.5.3" + } + }, + "har-schema": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=", + "dev": true + }, + "har-validator": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.0.3.tgz", + "integrity": "sha1-ukAsJmGU8VlW7xXg/PJCmT9qff0=", + "dev": true, + "requires": { + "ajv": "5.3.0", + "har-schema": "2.0.0" + } + }, + "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-color": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/has-color/-/has-color-0.1.7.tgz", + "integrity": "sha1-ZxRKUmDDT8PMpnfQQdr1L+e3iy8=", + "dev": true + }, + "has-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", + "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=", + "dev": true + }, + "hawk": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/hawk/-/hawk-6.0.2.tgz", + "integrity": "sha512-miowhl2+U7Qle4vdLqDdPt9m09K6yZhkLDTWGoUiUzrQCn+mHHSmfJgAyGaLRZbPmTqfFFjRV1QWCW0VWUJBbQ==", + "dev": true, + "requires": { + "boom": "4.3.1", + "cryptiles": "3.1.2", + "hoek": "4.2.0", + "sntp": "2.1.0" + } + }, + "he": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/he/-/he-1.1.1.tgz", + "integrity": "sha1-k0EP0hsAlzUVH4howvJx80J+I/0=", + "dev": true + }, + "hoek": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/hoek/-/hoek-4.2.0.tgz", + "integrity": "sha512-v0XCLxICi9nPfYrS9RL8HbYnXi9obYAeLbSP00BmnZwCK9+Ih9WOjoZ8YoHCoav2csqn4FOz4Orldsy2dmDwmQ==", + "dev": true + }, + "hooker": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/hooker/-/hooker-0.2.3.tgz", + "integrity": "sha1-uDT3I8xKJCqmWWNFnfbZhMXT2Vk=", + "dev": true + }, + "hosted-git-info": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.5.0.tgz", + "integrity": "sha512-pNgbURSuab90KbTqvRPsseaTxOJCZBD0a7t+haSN33piP9cCM4l0CqdzAif2hUqm716UovKB2ROmiabGAKVXyg==", + "dev": true + }, + "htmlparser2": { + "version": "3.8.3", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.8.3.tgz", + "integrity": "sha1-mWwosZFRaovoZQGn15dX5ccMEGg=", + "dev": true, + "requires": { + "domelementtype": "1.3.0", + "domhandler": "2.3.0", + "domutils": "1.5.1", + "entities": "1.0.0", + "readable-stream": "1.1.14" + } + }, + "http-signature": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", + "dev": true, + "requires": { + "assert-plus": "1.0.0", + "jsprim": "1.4.1", + "sshpk": "1.13.1" + } + }, + "i": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/i/-/i-0.3.6.tgz", + "integrity": "sha1-2WyScyB28HJxG2sQ/X1PZa2O4j0=", + "dev": true + }, + "iconv-lite": { + "version": "0.4.19", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.19.tgz", + "integrity": "sha512-oTZqweIP51xaGPI4uPa56/Pri/480R+mo7SeU+YETByQNhDG55ycFyNLIgta9vXhILrxXDmF7ZGhqZIcuN0gJQ==", + "dev": true + }, + "ieee754": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.8.tgz", + "integrity": "sha1-vjPUCsEO8ZJnAfbwii2G+/0a0+Q=", + "dev": true + }, + "imap": { + "version": "0.8.19", + "resolved": "https://registry.npmjs.org/imap/-/imap-0.8.19.tgz", + "integrity": "sha1-NniHOTSrCc6mukh0HyhNoq9Z2NU=", + "dev": true, + "requires": { + "readable-stream": "1.1.14", + "utf7": "1.0.2" + } + }, + "indent-string": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-2.1.0.tgz", + "integrity": "sha1-ji1INIdCEhtKghi3oTfppSBJ3IA=", + "dev": true, + "requires": { + "repeating": "2.0.1" + } + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "requires": { + "once": "1.4.0", + "wrappy": "1.0.2" + } + }, + "inherit": { + "version": "2.2.6", + "resolved": "https://registry.npmjs.org/inherit/-/inherit-2.2.6.tgz", + "integrity": "sha1-8WFLBshUToEo5CKchjR9tzrZeI0=", + "dev": true + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "dev": true + }, + "int64-buffer": { + "version": "0.1.9", + "resolved": "https://registry.npmjs.org/int64-buffer/-/int64-buffer-0.1.9.tgz", + "integrity": "sha1-ngOdoEOyT3ixlrKD4EZT716ZD2E=", + "dev": true + }, + "is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", + "dev": true + }, + "is-builtin-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz", + "integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=", + "dev": true, + "requires": { + "builtin-modules": "1.1.1" + } + }, + "is-finite": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.0.2.tgz", + "integrity": "sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko=", + "dev": true, + "requires": { + "number-is-nan": "1.0.1" + } + }, + "is-object": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-object/-/is-object-1.0.1.tgz", + "integrity": "sha1-iVJojF7C/9awPsyF52ngKQMINHA=", + "dev": true + }, + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", + "dev": true + }, + "is-utf8": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", + "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=", + "dev": true + }, + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", + "dev": true + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", + "dev": true + }, + "js-yaml": { + "version": "3.5.5", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.5.5.tgz", + "integrity": "sha1-A3fDgBfKvHMisNH7zSWkkWQfL74=", + "dev": true, + "requires": { + "argparse": "1.0.9", + "esprima": "2.7.3" + } + }, + "jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", + "dev": true, + "optional": true + }, + "jscs": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/jscs/-/jscs-3.0.7.tgz", + "integrity": "sha1-cUG03/W4bjLQ6Z12S4NnZ8MNIBo=", + "dev": true, + "requires": { + "chalk": "1.1.3", + "cli-table": "0.3.1", + "commander": "2.9.0", + "cst": "0.4.10", + "estraverse": "4.2.0", + "exit": "0.1.2", + "glob": "5.0.15", + "htmlparser2": "3.8.3", + "js-yaml": "3.4.6", + "jscs-jsdoc": "2.0.0", + "jscs-preset-wikimedia": "1.0.0", + "jsonlint": "1.6.2", + "lodash": "3.10.1", + "minimatch": "3.0.4", + "natural-compare": "1.2.2", + "pathval": "0.1.1", + "prompt": "0.2.14", + "reserved-words": "0.1.2", + "resolve": "1.1.7", + "strip-bom": "2.0.0", + "strip-json-comments": "1.0.4", + "to-double-quotes": "2.0.0", + "to-single-quotes": "2.0.1", + "vow": "0.4.17", + "vow-fs": "0.3.6", + "xmlbuilder": "3.1.0" + }, + "dependencies": { + "glob": { + "version": "5.0.15", + "resolved": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz", + "integrity": "sha1-G8k2ueAvSmA/zCIuz3Yz0wuLk7E=", + "dev": true, + "requires": { + "inflight": "1.0.6", + "inherits": "2.0.3", + "minimatch": "3.0.4", + "once": "1.4.0", + "path-is-absolute": "1.0.1" + } + }, + "js-yaml": { + "version": "3.4.6", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.4.6.tgz", + "integrity": "sha1-a+GyP2JJ9T0pM3D9TRqqY84bTrA=", + "dev": true, + "requires": { + "argparse": "1.0.9", + "esprima": "2.7.3", + "inherit": "2.2.6" + } + } + } + }, + "jscs-jsdoc": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/jscs-jsdoc/-/jscs-jsdoc-2.0.0.tgz", + "integrity": "sha1-9T684CmqMSW9iCkLpQ1k1FEKSHE=", + "dev": true, + "requires": { + "comment-parser": "0.3.2", + "jsdoctypeparser": "1.2.0" + } + }, + "jscs-preset-wikimedia": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/jscs-preset-wikimedia/-/jscs-preset-wikimedia-1.0.0.tgz", + "integrity": "sha1-//VjNCA4/C6IJre7cwnDrjQG/H4=", + "dev": true + }, + "jsdoctypeparser": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/jsdoctypeparser/-/jsdoctypeparser-1.2.0.tgz", + "integrity": "sha1-597cFToRhJ/8UUEUSuhqfvDCU5I=", + "dev": true, + "requires": { + "lodash": "3.10.1" + } + }, + "jshint": { + "version": "2.9.5", + "resolved": "https://registry.npmjs.org/jshint/-/jshint-2.9.5.tgz", + "integrity": "sha1-HnJSkVzmgbQIJ+4UJIxG006apiw=", + "dev": true, + "requires": { + "cli": "1.0.1", + "console-browserify": "1.1.0", + "exit": "0.1.2", + "htmlparser2": "3.8.3", + "lodash": "3.7.0", + "minimatch": "3.0.4", + "shelljs": "0.3.0", + "strip-json-comments": "1.0.4" + }, + "dependencies": { + "lodash": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-3.7.0.tgz", + "integrity": "sha1-Nni9irmVBXwHreg27S7wh9qBHUU=", + "dev": true + } + } + }, + "json-schema": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", + "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=", + "dev": true + }, + "json-schema-traverse": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz", + "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=", + "dev": true + }, + "json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", + "dev": true + }, + "json3": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/json3/-/json3-3.3.2.tgz", + "integrity": "sha1-PAQ0dD35Pi9cQq7nsZvLSDV19OE=", + "dev": true + }, + "jsonlint": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/jsonlint/-/jsonlint-1.6.2.tgz", + "integrity": "sha1-VzcEUIX1XrRVxosf9OvAG9UOiDA=", + "dev": true, + "requires": { + "JSV": "4.0.2", + "nomnom": "1.8.1" + } + }, + "jsprim": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", + "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", + "dev": true, + "requires": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.2.3", + "verror": "1.10.0" + } + }, + "libbase64": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/libbase64/-/libbase64-0.1.0.tgz", + "integrity": "sha1-YjUag5VjrF/1vSbxL2Dpgwu3UeY=", + "dev": true + }, + "libmime": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/libmime/-/libmime-1.2.0.tgz", + "integrity": "sha1-jYS087Ils3BEECNu9JSQZDa6dCs=", + "dev": true, + "requires": { + "iconv-lite": "0.4.19", + "libbase64": "0.1.0", + "libqp": "1.1.0" + } + }, + "libqp": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/libqp/-/libqp-1.1.0.tgz", + "integrity": "sha1-9ebgatdLeU+1tbZpiL9yjvHe2+g=", + "dev": true + }, + "load-json-file": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", + "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", + "dev": true, + "requires": { + "graceful-fs": "4.1.11", + "parse-json": "2.2.0", + "pify": "2.3.0", + "pinkie-promise": "2.0.1", + "strip-bom": "2.0.0" + } + }, + "lodash": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz", + "integrity": "sha1-W/Rejkm6QYnhfUgnid/RW9FAt7Y=", + "dev": true + }, + "lodash._baseassign": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/lodash._baseassign/-/lodash._baseassign-3.2.0.tgz", + "integrity": "sha1-jDigmVAPIVrQnlnxci/QxSv+Ck4=", + "dev": true, + "requires": { + "lodash._basecopy": "3.0.1", + "lodash.keys": "3.1.2" + } + }, + "lodash._basecopy": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz", + "integrity": "sha1-jaDmqHbPNEwK2KVIghEd08XHyjY=", + "dev": true + }, + "lodash._basecreate": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash._basecreate/-/lodash._basecreate-3.0.3.tgz", + "integrity": "sha1-G8ZhYU2qf8MRt9A78WgGoCE8+CE=", + "dev": true + }, + "lodash._getnative": { + "version": "3.9.1", + "resolved": "https://registry.npmjs.org/lodash._getnative/-/lodash._getnative-3.9.1.tgz", + "integrity": "sha1-VwvH3t5G1hzc3mh9ZdPuy6o6r/U=", + "dev": true + }, + "lodash._isiterateecall": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz", + "integrity": "sha1-UgOte6Ql+uhCRg5pbbnPPmqsBXw=", + "dev": true + }, + "lodash.create": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/lodash.create/-/lodash.create-3.1.1.tgz", + "integrity": "sha1-1/KEnw29p+BGgruM1yqwIkYd6+c=", + "dev": true, + "requires": { + "lodash._baseassign": "3.2.0", + "lodash._basecreate": "3.0.3", + "lodash._isiterateecall": "3.0.9" + } + }, + "lodash.isarguments": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz", + "integrity": "sha1-L1c9hcaiQon/AGY7SRwdM4/zRYo=", + "dev": true + }, + "lodash.isarray": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-3.0.4.tgz", + "integrity": "sha1-eeTriMNqgSKvhvhEqpvNhRtfu1U=", + "dev": true + }, + "lodash.keys": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-3.1.2.tgz", + "integrity": "sha1-TbwEcrFWvlCgsoaFXRvQsMZWCYo=", + "dev": true, + "requires": { + "lodash._getnative": "3.9.1", + "lodash.isarguments": "3.1.0", + "lodash.isarray": "3.0.4" + } + }, + "lolex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/lolex/-/lolex-1.3.2.tgz", + "integrity": "sha1-fD2mL/yzDw9agKJWbKJORdigHzE=", + "dev": true + }, + "loud-rejection": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.6.0.tgz", + "integrity": "sha1-W0b4AUft7leIcPCG0Eghz5mOVR8=", + "dev": true, + "requires": { + "currently-unhandled": "0.4.1", + "signal-exit": "3.0.2" + } + }, + "mailcomposer": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mailcomposer/-/mailcomposer-2.1.0.tgz", + "integrity": "sha1-plMYIomWFP7omckiJtgeK5y7GD0=", + "dev": true, + "requires": { + "buildmail": "2.0.0", + "libmime": "1.2.0" + } + }, + "mailparser": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/mailparser/-/mailparser-0.6.2.tgz", + "integrity": "sha1-A8SGA5vfTfbNO2rcqqxBB9/bwGg=", + "dev": true, + "requires": { + "encoding": "0.1.12", + "mime": "1.4.1", + "mimelib": "0.3.1", + "uue": "3.1.0" + } + }, + "map-obj": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", + "integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=", + "dev": true + }, + "meow": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz", + "integrity": "sha1-cstmi0JSKCkKu/qFaJJYcwioAfs=", + "dev": true, + "requires": { + "camelcase-keys": "2.1.0", + "decamelize": "1.2.0", + "loud-rejection": "1.6.0", + "map-obj": "1.0.1", + "minimist": "1.2.0", + "normalize-package-data": "2.4.0", + "object-assign": "4.1.1", + "read-pkg-up": "1.0.1", + "redent": "1.0.0", + "trim-newlines": "1.0.0" + } + }, + "merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=", + "dev": true + }, + "methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=", + "dev": true + }, + "mime": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz", + "integrity": "sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ==", + "dev": true + }, + "mime-db": { + "version": "1.30.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.30.0.tgz", + "integrity": "sha1-dMZD2i3Z1qRTmZY0ZbJtXKfXHwE=", + "dev": true + }, + "mime-types": { + "version": "2.1.17", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.17.tgz", + "integrity": "sha1-Cdejk/A+mVp5+K+Fe3Cp4KsWVXo=", + "dev": true, + "requires": { + "mime-db": "1.30.0" + } + }, + "mimelib": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/mimelib/-/mimelib-0.3.1.tgz", + "integrity": "sha1-eHrdJBXYJ6yzr27EvKHqlZZBiFM=", + "dev": true, + "requires": { + "addressparser": "1.0.1", + "encoding": "0.1.12" + } + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "requires": { + "brace-expansion": "1.1.8" + } + }, + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true + }, + "mkdirp": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "dev": true, + "requires": { + "minimist": "0.0.8" + }, + "dependencies": { + "minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", + "dev": true + } + } + }, + "mocha": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-3.5.3.tgz", + "integrity": "sha512-/6na001MJWEtYxHOV1WLfsmR4YIynkUEhBwzsb+fk2qmQ3iqsi258l/Q2MWHJMImAcNpZ8DEdYAK72NHoIQ9Eg==", + "dev": true, + "requires": { + "browser-stdout": "1.3.0", + "commander": "2.9.0", + "debug": "2.6.8", + "diff": "3.2.0", + "escape-string-regexp": "1.0.5", + "glob": "7.1.1", + "growl": "1.9.2", + "he": "1.1.1", + "json3": "3.3.2", + "lodash.create": "3.1.1", + "mkdirp": "0.5.1", + "supports-color": "3.1.2" + }, + "dependencies": { + "debug": { + "version": "2.6.8", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.8.tgz", + "integrity": "sha1-5zFTHKLt4n0YgiJCfaF4IdaP9Pw=", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "glob": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.1.tgz", + "integrity": "sha1-gFIR3wT6rxxjo2ADBs31reULLsg=", + "dev": true, + "requires": { + "fs.realpath": "1.0.0", + "inflight": "1.0.6", + "inherits": "2.0.3", + "minimatch": "3.0.4", + "once": "1.4.0", + "path-is-absolute": "1.0.1" + } + }, + "supports-color": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.1.2.tgz", + "integrity": "sha1-cqJiiU2dQIuVbKBf83su2KbiotU=", + "dev": true, + "requires": { + "has-flag": "1.0.0" + } + } + } + }, + "module-not-found-error": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/module-not-found-error/-/module-not-found-error-1.0.1.tgz", + "integrity": "sha1-z4tP9PKWQGdNbN0CsOO8UjwrvcA=", + "dev": true + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "msgpack-lite": { + "version": "0.1.26", + "resolved": "https://registry.npmjs.org/msgpack-lite/-/msgpack-lite-0.1.26.tgz", + "integrity": "sha1-3TxQsm8FnyXn7e42REGDWOKprYk=", + "dev": true, + "requires": { + "event-lite": "0.1.1", + "ieee754": "1.1.8", + "int64-buffer": "0.1.9", + "isarray": "1.0.0" + }, + "dependencies": { + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + } + } + }, + "mute-stream": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz", + "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=", + "dev": true + }, + "nan": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.7.0.tgz", + "integrity": "sha1-2Vv3IeyHfgjbJ27T/G63j5CDrUY=", + "dev": true + }, + "natural-compare": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.2.2.tgz", + "integrity": "sha1-H5bWDjFBysG20FZTzg2urHY69qo=", + "dev": true + }, + "ncp": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/ncp/-/ncp-0.4.2.tgz", + "integrity": "sha1-q8xsvT7C7Spyn/bnwfqPAXhKhXQ=", + "dev": true + }, + "needle": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/needle/-/needle-0.11.0.tgz", + "integrity": "sha1-AqcbAI6vfVWuifuf12hbe4jXvCk=", + "dev": true, + "requires": { + "debug": "2.6.9", + "iconv-lite": "0.4.19" + } + }, + "ngeohash": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/ngeohash/-/ngeohash-0.6.0.tgz", + "integrity": "sha1-MpcT6ec9HxpG2SqrC5StuUUz9oc=", + "dev": true + }, + "node-forge": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.7.1.tgz", + "integrity": "sha1-naYR6giYL0uUIGs760zJZl8gwwA=", + "dev": true + }, + "nodemailer": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-1.11.0.tgz", + "integrity": "sha1-TmnLObAwFbHR7wx4qBVBK56Xb3k=", + "dev": true, + "requires": { + "libmime": "1.2.0", + "mailcomposer": "2.1.0", + "needle": "0.11.0", + "nodemailer-direct-transport": "1.1.0", + "nodemailer-smtp-transport": "1.1.0" + } + }, + "nodemailer-direct-transport": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/nodemailer-direct-transport/-/nodemailer-direct-transport-1.1.0.tgz", + "integrity": "sha1-oveHCO5vFuoFc/yClJ0Tj/Fy9iQ=", + "dev": true, + "requires": { + "smtp-connection": "1.3.8" + } + }, + "nodemailer-smtp-transport": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/nodemailer-smtp-transport/-/nodemailer-smtp-transport-1.1.0.tgz", + "integrity": "sha1-5sN/MYhaswgOfe089SjErX5pE5g=", + "dev": true, + "requires": { + "clone": "1.0.2", + "nodemailer-wellknown": "0.1.10", + "smtp-connection": "1.3.8" + } + }, + "nodemailer-wellknown": { + "version": "0.1.10", + "resolved": "https://registry.npmjs.org/nodemailer-wellknown/-/nodemailer-wellknown-0.1.10.tgz", + "integrity": "sha1-WG24EB2zDLRDjrVGc3pBqtDPE9U=", + "dev": true + }, + "nomnom": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/nomnom/-/nomnom-1.8.1.tgz", + "integrity": "sha1-IVH3Ikcrp55Qp2/BJbuMjy5Nwqc=", + "dev": true, + "requires": { + "chalk": "0.4.0", + "underscore": "1.6.0" + }, + "dependencies": { + "ansi-styles": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-1.0.0.tgz", + "integrity": "sha1-yxAt8cVvUSPquLZ817mAJ6AnkXg=", + "dev": true + }, + "chalk": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-0.4.0.tgz", + "integrity": "sha1-UZmj3c0MHv4jvAjBsCewYXbgxk8=", + "dev": true, + "requires": { + "ansi-styles": "1.0.0", + "has-color": "0.1.7", + "strip-ansi": "0.1.1" + } + }, + "strip-ansi": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-0.1.1.tgz", + "integrity": "sha1-OeipjQRNFQZgq+SmgIrPcLt7yZE=", + "dev": true + } + } + }, + "nopt": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", + "integrity": "sha1-xkZdvwirzU2zWTF/eaxopkayj/k=", + "dev": true, + "requires": { + "abbrev": "1.1.1" + } + }, + "normalize-package-data": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.0.tgz", + "integrity": "sha512-9jjUFbTPfEy3R/ad/2oNbKtW9Hgovl5O1FvFWKkKblNXoN/Oou6+9+KKohPK13Yc3/TyunyWhJp6gvRNR/PPAw==", + "dev": true, + "requires": { + "hosted-git-info": "2.5.0", + "is-builtin-module": "1.0.0", + "semver": "5.4.1", + "validate-npm-package-license": "3.0.1" + } + }, + "number-is-nan": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", + "dev": true + }, + "oauth-sign": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz", + "integrity": "sha1-Rqarfwrq2N6unsBWV4C31O/rnUM=", + "dev": true + }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", + "dev": true + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "requires": { + "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.10", + "wordwrap": "0.0.3" + }, + "dependencies": { + "minimist": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz", + "integrity": "sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8=", + "dev": true + } + } + }, + "package": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/package/-/package-1.0.1.tgz", + "integrity": "sha1-0lofmeJQbcsn1nBLg9yooxLk7cw=", + "dev": true + }, + "parse-json": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", + "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", + "dev": true, + "requires": { + "error-ex": "1.3.1" + } + }, + "path-exists": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", + "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", + "dev": true, + "requires": { + "pinkie-promise": "2.0.1" + } + }, + "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=", + "dev": true + }, + "path-type": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", + "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=", + "dev": true, + "requires": { + "graceful-fs": "4.1.11", + "pify": "2.3.0", + "pinkie-promise": "2.0.1" + } + }, + "pathval": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-0.1.1.tgz", + "integrity": "sha1-CPkRzcqczllCiA2ngXvAtyO2bYI=", + "dev": true + }, + "performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", + "dev": true + }, + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true + }, + "pinkie": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", + "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", + "dev": true + }, + "pinkie-promise": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", + "dev": true, + "requires": { + "pinkie": "2.0.4" + } + }, + "pkginfo": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/pkginfo/-/pkginfo-0.4.1.tgz", + "integrity": "sha1-tUGO8EOd5UJfxJlQQtztFPsqhP8=", + "dev": true + }, + "poplib": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/poplib/-/poplib-0.1.7.tgz", + "integrity": "sha1-L0tYtVkpcjUM2X9IKrpo+OBVdLw=", + "dev": true, + "requires": { + "optimist": "0.6.1" + } + }, + "process-nextick-args": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", + "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=", + "dev": true + }, + "prompt": { + "version": "0.2.14", + "resolved": "https://registry.npmjs.org/prompt/-/prompt-0.2.14.tgz", + "integrity": "sha1-V3VPZPVD/XsIRXB8gY7OYY8F/9w=", + "dev": true, + "requires": { + "pkginfo": "0.4.1", + "read": "1.0.7", + "revalidator": "0.1.8", + "utile": "0.2.1", + "winston": "0.8.3" + } + }, + "proxyquire": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/proxyquire/-/proxyquire-1.8.0.tgz", + "integrity": "sha1-AtUUpb7ZhvBMuyCTrxZ0FTX3ntw=", + "dev": true, + "requires": { + "fill-keys": "1.0.2", + "module-not-found-error": "1.0.1", + "resolve": "1.1.7" + } + }, + "punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", + "dev": true + }, + "pushbullet": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/pushbullet/-/pushbullet-2.1.0.tgz", + "integrity": "sha512-kRuNGNIVVgZCNCL+27C7PDT/AYOluykgIr2azwDHY4Ne7EM1za/bM2tPOecNQPRCDr0Ix/1+F75HyijSV3aEQA==", + "dev": true, + "requires": { + "clone": "2.1.1", + "mime": "1.4.1", + "node-forge": "0.7.1", + "request": "2.83.0", + "websocket": "1.0.25" + }, + "dependencies": { + "clone": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.1.tgz", + "integrity": "sha1-0hfR6WERjjrJpLi7oyhVU79kfNs=", + "dev": true + } + } + }, + "qs": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.1.tgz", + "integrity": "sha512-eRzhrN1WSINYCDCbrz796z37LOe3m5tmW7RQf6oBntukAG1nmovJvhnwHHRMAfeoItc1m2Hk02WER2aQ/iqs+A==", + "dev": true + }, + "read": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/read/-/read-1.0.7.tgz", + "integrity": "sha1-s9oZvQUkMal2cdRKQmNK33ELQMQ=", + "dev": true, + "requires": { + "mute-stream": "0.0.7" + } + }, + "read-pkg": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", + "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=", + "dev": true, + "requires": { + "load-json-file": "1.1.0", + "normalize-package-data": "2.4.0", + "path-type": "1.1.0" + } + }, + "read-pkg-up": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", + "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=", + "dev": true, + "requires": { + "find-up": "1.1.2", + "read-pkg": "1.1.0" + } + }, + "readable-stream": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", + "dev": true, + "requires": { + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "0.0.1", + "string_decoder": "0.10.31" + } + }, + "redent": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/redent/-/redent-1.0.0.tgz", + "integrity": "sha1-z5Fqsf1fHxbfsggi3W7H9zDCr94=", + "dev": true, + "requires": { + "indent-string": "2.1.0", + "strip-indent": "1.0.1" + } + }, + "regenerator-runtime": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.0.tgz", + "integrity": "sha512-/aA0kLeRb5N9K0d4fw7ooEbI+xDe+DKD499EQqygGqeS8N3xto15p09uY2xj7ixP81sNPXvRLnAQIqdVStgb1A==", + "dev": true + }, + "repeating": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz", + "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=", + "dev": true, + "requires": { + "is-finite": "1.0.2" + } + }, + "request": { + "version": "2.83.0", + "resolved": "https://registry.npmjs.org/request/-/request-2.83.0.tgz", + "integrity": "sha512-lR3gD69osqm6EYLk9wB/G1W/laGWjzH90t1vEa2xuxHD5KUrSzp9pUSfTm+YC5Nxt2T8nMPEvKlhbQayU7bgFw==", + "dev": true, + "requires": { + "aws-sign2": "0.7.0", + "aws4": "1.6.0", + "caseless": "0.12.0", + "combined-stream": "1.0.5", + "extend": "3.0.1", + "forever-agent": "0.6.1", + "form-data": "2.3.1", + "har-validator": "5.0.3", + "hawk": "6.0.2", + "http-signature": "1.2.0", + "is-typedarray": "1.0.0", + "isstream": "0.1.2", + "json-stringify-safe": "5.0.1", + "mime-types": "2.1.17", + "oauth-sign": "0.8.2", + "performance-now": "2.1.0", + "qs": "6.5.1", + "safe-buffer": "5.1.1", + "stringstream": "0.0.5", + "tough-cookie": "2.3.3", + "tunnel-agent": "0.6.0", + "uuid": "3.1.0" + }, + "dependencies": { + "uuid": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.1.0.tgz", + "integrity": "sha512-DIWtzUkw04M4k3bf1IcpS2tngXEL26YUD2M0tMDUpnUrz2hgzUBlD55a4FjdLGPvfHxS6uluGWvaVEqgBcVa+g==", + "dev": true + } + } + }, + "reserved-words": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/reserved-words/-/reserved-words-0.1.2.tgz", + "integrity": "sha1-AKCUD5jNUBrqqsMWQR2a3FKzGrE=", + "dev": true + }, + "resolve": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", + "integrity": "sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs=", + "dev": true + }, + "revalidator": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/revalidator/-/revalidator-0.1.8.tgz", + "integrity": "sha1-/s5hv6DBtSoga9axgZgYS91SOjs=", + "dev": true + }, + "rimraf": { + "version": "2.2.8", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.2.8.tgz", + "integrity": "sha1-5Dm+Kq7jJzIZUnMPmaiSnk/FBYI=", + "dev": true + }, + "safe-buffer": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", + "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==", + "dev": true + }, + "samsam": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/samsam/-/samsam-1.1.2.tgz", + "integrity": "sha1-vsEf3IOp/aBjQBIQ5AF2wwJNFWc=", + "dev": true + }, + "semver": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.4.1.tgz", + "integrity": "sha512-WfG/X9+oATh81XtllIo/I8gOiY9EXRdv1cQdyykeXK17YcUW3EXUAi2To4pcH6nZtJPr7ZOpM5OMyWJZm+8Rsg==", + "dev": true + }, + "shelljs": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.3.0.tgz", + "integrity": "sha1-NZbmMHp4FUT1kfN9phg2DzHbV7E=", + "dev": true + }, + "should": { + "version": "11.2.1", + "resolved": "https://registry.npmjs.org/should/-/should-11.2.1.tgz", + "integrity": "sha1-kPVRRVUtAc/CAGZuToGKHJZw7aI=", + "dev": true, + "requires": { + "should-equal": "1.0.1", + "should-format": "3.0.3", + "should-type": "1.4.0", + "should-type-adaptors": "1.0.1", + "should-util": "1.0.0" + } + }, + "should-equal": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/should-equal/-/should-equal-1.0.1.tgz", + "integrity": "sha1-C26VFvJgGp+wuy3MNpr6HH4gCvc=", + "dev": true, + "requires": { + "should-type": "1.4.0" + } + }, + "should-format": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/should-format/-/should-format-3.0.3.tgz", + "integrity": "sha1-m/yPdPo5IFxT04w01xcwPidxJPE=", + "dev": true, + "requires": { + "should-type": "1.4.0", + "should-type-adaptors": "1.0.1" + } + }, + "should-type": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/should-type/-/should-type-1.4.0.tgz", + "integrity": "sha1-B1bYzoRt/QmEOmlHcZ36DUz/XPM=", + "dev": true + }, + "should-type-adaptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/should-type-adaptors/-/should-type-adaptors-1.0.1.tgz", + "integrity": "sha1-7+VVPN9oz/ZuXF9RtxLcNRx3vqo=", + "dev": true, + "requires": { + "should-type": "1.4.0", + "should-util": "1.0.0" + } + }, + "should-util": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/should-util/-/should-util-1.0.0.tgz", + "integrity": "sha1-yYzaN0qmsZDfi6h8mInCtNtiAGM=", + "dev": true + }, + "signal-exit": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", + "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", + "dev": true + }, + "sinon": { + "version": "1.17.7", + "resolved": "https://registry.npmjs.org/sinon/-/sinon-1.17.7.tgz", + "integrity": "sha1-RUKk9JugxFwF6y6d2dID4rjv4L8=", + "dev": true, + "requires": { + "formatio": "1.1.1", + "lolex": "1.3.2", + "samsam": "1.1.2", + "util": "0.10.3" + } + }, + "smtp-connection": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/smtp-connection/-/smtp-connection-1.3.8.tgz", + "integrity": "sha1-VYMsIWDPswhuHc2H/RwZ+mG39TY=", + "dev": true + }, + "sntp": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/sntp/-/sntp-2.1.0.tgz", + "integrity": "sha512-FL1b58BDrqS3A11lJ0zEdnJ3UOKqVxawAkF3k7F0CVN7VQ34aZrV+G8BZ1WC9ZL7NyrwsW0oviwsWDgRuVYtJg==", + "dev": true, + "requires": { + "hoek": "4.2.0" + } + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + }, + "source-map-support": { + "version": "0.4.18", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.18.tgz", + "integrity": "sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA==", + "dev": true, + "requires": { + "source-map": "0.5.7" + } + }, + "spdx-correct": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-1.0.2.tgz", + "integrity": "sha1-SzBz2TP/UfORLwOsVRlJikFQ20A=", + "dev": true, + "requires": { + "spdx-license-ids": "1.2.2" + } + }, + "spdx-expression-parse": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-1.0.4.tgz", + "integrity": "sha1-m98vIOH0DtRH++JzJmGR/O1RYmw=", + "dev": true + }, + "spdx-license-ids": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-1.2.2.tgz", + "integrity": "sha1-yd96NCRZSt5r0RkA1ZZpbcBrrFc=", + "dev": true + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + }, + "sshpk": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.13.1.tgz", + "integrity": "sha1-US322mKHFEMW3EwY/hzx2UBzm+M=", + "dev": true, + "requires": { + "asn1": "0.2.3", + "assert-plus": "1.0.0", + "bcrypt-pbkdf": "1.0.1", + "dashdash": "1.14.1", + "ecc-jsbn": "0.1.1", + "getpass": "0.1.7", + "jsbn": "0.1.1", + "tweetnacl": "0.14.5" + } + }, + "stack-trace": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", + "integrity": "sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA=", + "dev": true + }, + "string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", + "dev": true + }, + "stringstream": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz", + "integrity": "sha1-TkhM1N5aC7vuGORjB3EKioFiGHg=", + "dev": true + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dev": true, + "requires": { + "ansi-regex": "2.1.1" + } + }, + "strip-bom": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", + "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", + "dev": true, + "requires": { + "is-utf8": "0.2.1" + } + }, + "strip-indent": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-1.0.1.tgz", + "integrity": "sha1-DHlipq3vp7vUrDZkYKY4VSrhoKI=", + "dev": true, + "requires": { + "get-stdin": "4.0.1" + } + }, + "strip-json-comments": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-1.0.4.tgz", + "integrity": "sha1-HhX7ysl9Pumb8tc7TGVrCCu6+5E=", + "dev": true + }, + "superagent": { + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/superagent/-/superagent-3.8.0.tgz", + "integrity": "sha512-71XGWgtn70TNwgmgYa69dPOYg55aU9FCahjUNY03rOrKvaTCaU3b9MeZmqonmf9Od96SCxr3vGfEAnhM7dtxCw==", + "dev": true, + "requires": { + "component-emitter": "1.2.1", + "cookiejar": "2.1.1", + "debug": "3.1.0", + "extend": "3.0.1", + "form-data": "2.3.1", + "formidable": "1.1.1", + "methods": "1.1.2", + "mime": "1.4.1", + "qs": "6.5.1", + "readable-stream": "2.3.3" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "readable-stream": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz", + "integrity": "sha512-m+qzzcn7KUxEmd1gMbchF+Y2eIUbieUaxkWtptyHywrX0rE8QEYqPC07Vuy4Wm32/xE16NcdBctb8S0Xe/5IeQ==", + "dev": true, + "requires": { + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "1.0.0", + "process-nextick-args": "1.0.7", + "safe-buffer": "5.1.1", + "string_decoder": "1.0.3", + "util-deprecate": "1.0.2" + } + }, + "string_decoder": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", + "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==", + "dev": true, + "requires": { + "safe-buffer": "5.1.1" + } + } + } + }, + "supertest": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/supertest/-/supertest-3.0.0.tgz", + "integrity": "sha1-jUu2j9GDDuBwM7HFpamkAhyWUpY=", + "dev": true, + "requires": { + "methods": "1.1.2", + "superagent": "3.8.0" + } + }, + "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 + }, + "temporary": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/temporary/-/temporary-0.0.8.tgz", + "integrity": "sha1-oYqYHSi6jKNgJ/s8MFOMPst0CsA=", + "dev": true, + "requires": { + "package": "1.0.1" + } + }, + "to-double-quotes": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-double-quotes/-/to-double-quotes-2.0.0.tgz", + "integrity": "sha1-qvIx1vqUiUn4GTAburRITYWI5Kc=", + "dev": true + }, + "to-single-quotes": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/to-single-quotes/-/to-single-quotes-2.0.1.tgz", + "integrity": "sha1-fMKRUfD18sQZRvEZ9ZMv5VQXASU=", + "dev": true + }, + "tough-cookie": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.3.tgz", + "integrity": "sha1-C2GKVWW23qkL80JdBNVe3EdadWE=", + "dev": true, + "requires": { + "punycode": "1.4.1" + } + }, + "trim-newlines": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-1.0.0.tgz", + "integrity": "sha1-WIeWa7WCpFA6QetST301ARgVphM=", + "dev": true + }, + "tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "dev": true, + "requires": { + "safe-buffer": "5.1.1" + } + }, + "tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", + "dev": true, + "optional": true + }, + "typedarray-to-buffer": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.2.tgz", + "integrity": "sha1-EBezLZhP9VbroQD1AViauhrOLgQ=", + "dev": true, + "requires": { + "is-typedarray": "1.0.0" + } + }, + "underscore": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.6.0.tgz", + "integrity": "sha1-izixDKze9jM3uLJOT/htRa6lKag=", + "dev": true + }, + "underscore.string": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/underscore.string/-/underscore.string-3.2.3.tgz", + "integrity": "sha1-gGmSYzZl1eX8tNsfs6hi62jp5to=", + "dev": true + }, + "utf7": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/utf7/-/utf7-1.0.2.tgz", + "integrity": "sha1-lV9JCq5lO6IguUVqCod2wZk2CZE=", + "dev": true, + "requires": { + "semver": "5.3.0" + }, + "dependencies": { + "semver": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz", + "integrity": "sha1-myzl094C0XxgEq0yaqa00M9U+U8=", + "dev": true + } + } + }, + "util": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz", + "integrity": "sha1-evsa/lCAUkZInj23/g7TeTNqwPk=", + "dev": true, + "requires": { + "inherits": "2.0.1" + }, + "dependencies": { + "inherits": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz", + "integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE=", + "dev": true + } + } + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", + "dev": true + }, + "utile": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/utile/-/utile-0.2.1.tgz", + "integrity": "sha1-kwyI6ZCY1iIINMNWy9mncFItkNc=", + "dev": true, + "requires": { + "async": "0.2.10", + "deep-equal": "1.0.1", + "i": "0.3.6", + "mkdirp": "0.5.1", + "ncp": "0.4.2", + "rimraf": "2.2.8" + }, + "dependencies": { + "async": { + "version": "0.2.10", + "resolved": "https://registry.npmjs.org/async/-/async-0.2.10.tgz", + "integrity": "sha1-trvgsGdLnXGXCMo43owjfLUmw9E=", + "dev": true + } + } + }, + "uue": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/uue/-/uue-3.1.0.tgz", + "integrity": "sha1-XWfTcDDmbv67tLiqxG2vm1W++/Y=", + "dev": true, + "requires": { + "extend": "3.0.1" + } + }, + "uuid": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-2.0.3.tgz", + "integrity": "sha1-Z+LoY3lyFVMN/zGOW/nc6/1Hsho=", + "dev": true + }, + "validate-npm-package-license": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.1.tgz", + "integrity": "sha1-KAS6vnEq0zeUWaz74kdGqywwP7w=", + "dev": true, + "requires": { + "spdx-correct": "1.0.2", + "spdx-expression-parse": "1.0.4" + } + }, + "verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", + "dev": true, + "requires": { + "assert-plus": "1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "1.3.0" + } + }, + "vow": { + "version": "0.4.17", + "resolved": "https://registry.npmjs.org/vow/-/vow-0.4.17.tgz", + "integrity": "sha512-A3/9bWFqf6gT0jLR4/+bT+IPTe1mQf+tdsW6+WI5geP9smAp8Kbbu4R6QQCDKZN/8TSCqTlXVQm12QliB4rHfg==", + "dev": true + }, + "vow-fs": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/vow-fs/-/vow-fs-0.3.6.tgz", + "integrity": "sha1-LUxZviLivyYY3fWXq0uqkjvnIA0=", + "dev": true, + "requires": { + "glob": "7.0.6", + "uuid": "2.0.3", + "vow": "0.4.17", + "vow-queue": "0.4.3" + } + }, + "vow-queue": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/vow-queue/-/vow-queue-0.4.3.tgz", + "integrity": "sha512-/poAKDTFL3zYbeQg7cl4BGcfP4sGgXKrHnRFSKj97dteUFu8oyXMwIcdwu8NSx/RmPGIuYx1Bik/y5vU4H/VKw==", + "dev": true, + "requires": { + "vow": "0.4.17" + } + }, + "websocket": { + "version": "1.0.25", + "resolved": "https://registry.npmjs.org/websocket/-/websocket-1.0.25.tgz", + "integrity": "sha512-M58njvi6ZxVb5k7kpnHh2BvNKuBWiwIYvsToErBzWhvBZYwlEiLcyLrG41T1jRcrY9ettqPYEqduLI7ul54CVQ==", + "dev": true, + "requires": { + "debug": "2.6.9", + "nan": "2.7.0", + "typedarray-to-buffer": "3.1.2", + "yaeti": "0.0.6" + } + }, + "when": { + "version": "3.7.8", + "resolved": "https://registry.npmjs.org/when/-/when-3.7.8.tgz", + "integrity": "sha1-xxMLan6gRpPoQs3J56Hyqjmjn4I=", + "dev": true + }, + "which": { + "version": "1.2.14", + "resolved": "https://registry.npmjs.org/which/-/which-1.2.14.tgz", + "integrity": "sha1-mofEN48D6CfOyvGs31bHNsAcFOU=", + "dev": true, + "requires": { + "isexe": "2.0.0" + } + }, + "winston": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/winston/-/winston-0.8.3.tgz", + "integrity": "sha1-ZLar9M0Brcrv1QCTk7HY6L7BnbA=", + "dev": true, + "requires": { + "async": "0.2.10", + "colors": "0.6.2", + "cycle": "1.0.3", + "eyes": "0.1.8", + "isstream": "0.1.2", + "pkginfo": "0.3.1", + "stack-trace": "0.0.10" + }, + "dependencies": { + "async": { + "version": "0.2.10", + "resolved": "https://registry.npmjs.org/async/-/async-0.2.10.tgz", + "integrity": "sha1-trvgsGdLnXGXCMo43owjfLUmw9E=", + "dev": true + }, + "colors": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/colors/-/colors-0.6.2.tgz", + "integrity": "sha1-JCP+ZnisDF2uiFLl0OW+CMmXq8w=", + "dev": true + }, + "pkginfo": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/pkginfo/-/pkginfo-0.3.1.tgz", + "integrity": "sha1-Wyn2qB9wcXFC4J52W76rl7T4HiE=", + "dev": true + } + } + }, + "wordwrap": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", + "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=", + "dev": true + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "xmlbuilder": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-3.1.0.tgz", + "integrity": "sha1-LIaIjy1OrehQ+jjKf3Ij9yCVFuE=", + "dev": true, + "requires": { + "lodash": "3.10.1" + } + }, + "yaeti": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/yaeti/-/yaeti-0.0.6.tgz", + "integrity": "sha1-8m9ITXJoTPQr7ft2lwqhYI+/lXc=", + "dev": true + } + } +} diff --git a/package.json b/package.json index a6cbec9e..8ccf535b 100644 --- a/package.json +++ b/package.json @@ -1,43 +1,50 @@ { - "name" : "node-red-nodes", - "version" : "0.0.8", - "description" : "Node-RED-nodes package to hold the test framework ONLY - use npm to install individual nodes", - "homepage" : "http://nodered.org", - "license" : "Apache-2.0", - "repository" : { - "type":"git", - "url":"https://github.com/node-red/node-red-nodes.git" + "name": "node-red-nodes", + "version": "0.0.10", + "description": "Node-RED-nodes package to hold the test framework ONLY - use npm to install individual nodes", + "homepage": "http://nodered.org", + "license": "Apache-2.0", + "repository": { + "type": "git", + "url": "https://github.com/node-red/node-red-nodes.git" }, "contributors": [ - {"name": "Dave Conway-Jones"}, - {"name": "Nick O'Leary"}, - {"name": "Ben Hardill"} + { + "name": "Dave Conway-Jones" + }, + { + "name": "Nick O'Leary" + }, + { + "name": "Ben Hardill" + } ], "keywords": [ - "Node-RED", "nodes", "iot", "ibm", "flow" + "node-red", + "nodes", + "iot", + "ibm", + "flow" ], "devDependencies": { - "grunt": "^0.4.5", - "grunt-simple-mocha": "^0.4.1", - "grunt-contrib-jshint": "^1.0.0", - "grunt-lint-inline": "^0.4.4", - "grunt-jscs": "^2.8.0", - "mocha": "^2.4.5", - "should": "^8.3.1", - "sinon": "^1.17.3", - "supertest": "^1.2.0", - "proxyquire": "^1.7.10", - "pushbullet": "^1.4.3", - "when": "^3.7.7", "exif": "^0.6.0", + "grunt": "^1.0.1", + "grunt-contrib-jshint": "^1.1.0", + "grunt-jscs": "^3.0.1", + "grunt-lint-inline": "^1.0.0", + "grunt-simple-mocha": "^0.4.1", + "imap": "^0.8.19", + "mailparser": "^0.6.1", + "mocha": "~3.5.3", + "msgpack-lite": "^0.1.26", "ngeohash": "^0.6.0", - "nodemailer" : "^1.11.0", - "poplib" : "^0.1.7", - "mailparser" : "^0.6.1", - "imap" : "^0.8.18", - "msgpack-js": "^0.3.0" - }, - "engines": { - "node": ">=0.10" + "nodemailer": "^1.11.0", + "poplib": "^0.1.7", + "proxyquire": "^1.7.11", + "pushbullet": "~2.1.0", + "should": "^11.2.1", + "sinon": "^1.17.7", + "supertest": "^3.0.0", + "when": "^3.7.8" } } diff --git a/parsers/base64/70-base64.html b/parsers/base64/70-base64.html index c612cb64..e2d3a128 100644 --- a/parsers/base64/70-base64.html +++ b/parsers/base64/70-base64.html @@ -1,8 +1,8 @@ diff --git a/parsers/base64/70-base64.js b/parsers/base64/70-base64.js index 5dc05140..741fa5dc 100644 --- a/parsers/base64/70-base64.js +++ b/parsers/base64/70-base64.js @@ -14,9 +14,10 @@ module.exports = function(RED) { } else if (typeof msg.payload === "string") { // Take base64 string and make into binary buffer - var regexp = new RegExp('^[A-Za-z0-9+\/=]*$'); - if ( regexp.test(msg.payload) && (msg.payload.length % 4 === 0) ) { - msg.payload = new Buffer(msg.payload,'base64'); + var load = msg.payload.replace(/\s+/g,''); // remove any whitespace + var regexp = new RegExp('^[A-Za-z0-9+\/=]*$'); // check it only contains valid characters + if ( regexp.test(load) && (load.length % 4 === 0) ) { + msg.payload = new Buffer(load,'base64'); node.send(msg); } else { @@ -28,7 +29,8 @@ module.exports = function(RED) { else { node.warn("This node only handles strings or buffers."); } - } else { node.warn("No payload found to process"); } + } + else { node.warn("No payload found to process"); } }); } RED.nodes.registerType("base64",Base64Node); diff --git a/parsers/base64/README.md b/parsers/base64/README.md index 66a175cc..ae5bc154 100644 --- a/parsers/base64/README.md +++ b/parsers/base64/README.md @@ -23,5 +23,5 @@ If the input is a Base64 string it converts it back to a binary buffer. Sample Flow ----------- -
    [{"id":"d2ccae00.2d335","type":"inject","name":"","topic":"","payload":"","payloadType":"none","repeat":"","crontab":"","once":false,"x":136,"y":99,"z":"385bdf8b.c7a42","wires":[["e03cae10.1fc35"]]},{"id":"b778ef09.48871","type":"base64","name":"","x":411.5,"y":160,"z":"385bdf8b.c7a42","wires":[["6295d1b1.9d6a3","46b597ba.b94a68"]]},{"id":"6295d1b1.9d6a3","type":"debug","name":"","active":true,"console":"false","complete":"false","x":610,"y":160,"z":"385bdf8b.c7a42","wires":[]},{"id":"ead9e7c9.152618","type":"debug","name":"","active":true,"console":"false","complete":"false","x":610,"y":240,"z":"385bdf8b.c7a42","wires":[]},{"id":"46b597ba.b94a68","type":"base64","name":"","x":411.5,"y":240,"z":"385bdf8b.c7a42","wires":[["ead9e7c9.152618"]]},{"id":"1c9124e9.e36edb","type":"inject","name":"","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"x":1775,"y":113,"z":"385bdf8b.c7a42","wires":[[]]},{"id":"48a892ea.b7576c","type":"debug","name":"","active":true,"console":"false","complete":"false","x":2171,"y":210,"z":"385bdf8b.c7a42","wires":[]},{"id":"e03cae10.1fc35","type":"function","name":"","func":"msg.payload = new Buffer(\"12345\");\nreturn msg;","outputs":1,"x":250,"y":160,"z":"385bdf8b.c7a42","wires":[["b778ef09.48871"]]}]
    +
    [{"id":"d2ccae00.2d335","type":"inject","name":"","topic":"","payload":"","payloadType":"none","repeat":"","crontab":"","once":false,"x":136,"y":99,"z":"385bdf8b.c7a42","wires":[["e03cae10.1fc35"]]},{"id":"b778ef09.48871","type":"base64","name":"","x":411.5,"y":160,"z":"385bdf8b.c7a42","wires":[["6295d1b1.9d6a3","46b597ba.b94a68"]]},{"id":"6295d1b1.9d6a3","type":"debug","name":"","active":true,"console":"false","complete":"false","x":610,"y":160,"z":"385bdf8b.c7a42","wires":[]},{"id":"ead9e7c9.152618","type":"debug","name":"","active":true,"console":"false","complete":"false","x":610,"y":240,"z":"385bdf8b.c7a42","wires":[]},{"id":"46b597ba.b94a68","type":"base64","name":"","x":411.5,"y":240,"z":"385bdf8b.c7a42","wires":[["ead9e7c9.152618"]]},{"id":"1c9124e9.e36edb","type":"inject","name":"","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"x":1775,"y":113,"z":"385bdf8b.c7a42","wires":[[]]},{"id":"48a892ea.b7576c","type":"debug","name":"","active":true,"console":"false","complete":"false","x":2171,"y":210,"z":"385bdf8b.c7a42","wires":[]},{"id":"e03cae10.1fc35","type":"function","name":"","func":"msg.payload = new Buffer.from(\"12345\");\nreturn msg;","outputs":1,"x":250,"y":160,"z":"385bdf8b.c7a42","wires":[["b778ef09.48871"]]}]
     
    diff --git a/parsers/base64/package.json b/parsers/base64/package.json index db55a242..99197caf 100644 --- a/parsers/base64/package.json +++ b/parsers/base64/package.json @@ -1,6 +1,6 @@ { "name" : "node-red-node-base64", - "version" : "0.0.4", + "version" : "0.0.8", "description" : "A Node-RED node to pack and unpack objects to base64 format", "dependencies" : { }, diff --git a/parsers/geohash/70-geohash.js b/parsers/geohash/70-geohash.js index ecc644e5..f0bebd11 100644 --- a/parsers/geohash/70-geohash.js +++ b/parsers/geohash/70-geohash.js @@ -29,7 +29,8 @@ module.exports = function(RED) { if (lt && ln) { msg.location.geohash = geohash.encode(lt, ln, le); node.send(msg); - } else { + } + else { node.warn("lat or lon missing from msg.location"); } } @@ -62,7 +63,8 @@ module.exports = function(RED) { if (!isNaN(la) && !isNaN(lo)) { msg.payload = geohash.encode(la, lo, li); node.send(msg); - } else { + } + else { node.warn("Incorrect string format - should be lat,lon"); } } @@ -79,7 +81,8 @@ module.exports = function(RED) { if (lat && lon) { msg.payload.geohash = geohash.encode(lat, lon, len); node.send(msg); - } else { + } + else { node.warn("lat or lon missing from msg.payload"); } } diff --git a/parsers/msgpack/70-msgpack.html b/parsers/msgpack/70-msgpack.html index c3fc2094..64361fbe 100644 --- a/parsers/msgpack/70-msgpack.html +++ b/parsers/msgpack/70-msgpack.html @@ -1,15 +1,18 @@ diff --git a/parsers/what3words/what3words.js b/parsers/what3words/what3words.js index cbc20c9f..4d8a2fa3 100644 --- a/parsers/what3words/what3words.js +++ b/parsers/what3words/what3words.js @@ -6,17 +6,14 @@ module.exports = function(RED) { var what3wordsNode = function(n) { RED.nodes.createNode(this, n); this.lang = n.lang || "en"; - var credentials = RED.nodes.getCredentials(n.id); - if ((credentials) && (credentials.hasOwnProperty("pushkey"))) { this.pushkey = credentials.pushkey; } else { this.error("No what3words API key set"); } - this.w3w = new What3Words(this.pushkey); var node = this; + //if ( !node.credentials.apikey ) { this.error("No what3words API key set"); } + this.w3w = new What3Words(node.credentials.apikey); var w1 = /^\*\w{6,31}$/; var w3 = /^\w+\.\w+\.\w+$/; this.on("input", function(msg) { - if (msg.hasOwnProperty("location")) { - var lat = msg.location.lat; - var lon = msg.location.lon; - node.w3w.positionToWords({ position:lat + "," + lon, lang:node.lang }) + if (msg.hasOwnProperty("location") && msg.location.hasOwnProperty("lat") && msg.location.hasOwnProperty("lon")) { + node.w3w.positionToWords({ position:msg.location.lat + "," + msg.location.lon, lang:node.lang }) .then(function(response) { msg.payload = response; // prom.cape.pump if (!msg.hasOwnProperty("topic") || (msg.topic === "")) { msg.topic = "what3words"; } @@ -25,7 +22,19 @@ module.exports = function(RED) { .catch(function(err) { node.warn(err) }); - } else if (typeof (msg.payload) === "string") { + } + else if (msg.hasOwnProperty("payload") && msg.payload.hasOwnProperty("lat") && msg.payload.hasOwnProperty("lon")) { + node.w3w.positionToWords({ position:msg.payload.lat + "," + msg.payload.lon, lang:node.lang }) + .then(function(response) { + msg.payload = response; // prom.cape.pump + if (!msg.hasOwnProperty("topic") || (msg.topic === "")) { msg.topic = "what3words"; } + node.send(msg); + }) + .catch(function(err) { + node.warn(err) + }); + } + else if (typeof (msg.payload) === "string") { if (msg.payload.split(",").length === 2) { // see if it's 2 comma separated words node.w3w.positionToWords({ position:msg.payload, lang:node.lang }) .then(function(response) { @@ -36,7 +45,8 @@ module.exports = function(RED) { .catch(function(err) { node.warn(err); }); - } else if (msg.payload.match(w3)) { // see if it's 3 dot separated words + } + else if (msg.payload.match(w3)) { // see if it's 3 dot separated words node.w3w.wordsToPosition({ words:msg.payload }) .then(function(response) { if (!msg.hasOwnProperty("location")) { msg.location = {}; } @@ -47,7 +57,8 @@ module.exports = function(RED) { .catch(function(err) { node.warn(err) }); - } else if (msg.payload.match(w1)) { // see if it's a *Oneword + } + else if (msg.payload.match(w1)) { // see if it's a *Oneword node.w3w.wordsToPosition({ words:msg.payload }) .then(function(response) { if (!msg.hasOwnProperty("location")) { msg.location = {}; } @@ -59,43 +70,13 @@ module.exports = function(RED) { .catch(function(err) { node.warn(err); }); - } else { node.warn("No useable data found. See info."); } - } else { node.warn("No useable data found. See info."); } + } + else { node.warn("No useable data found. See info."); } + } + else { node.warn("No useable data found. See info."); } }); } - RED.nodes.registerType("what3words", what3wordsNode); - - var querystring = require('querystring'); - - RED.httpAdmin.get('/what3words/:id', RED.auth.needsPermission('what3words.read'), function(req, res) { - var credentials = RED.nodes.getCredentials(req.params.id); - if (credentials) { - res.send(JSON.stringify({hasPassword:(credentials.pushkey && credentials.pushkey !== "")})); - } else { - res.send(JSON.stringify({})); - } - }); - - RED.httpAdmin.delete('/what3words/:id', RED.auth.needsPermission('what3words.write'), function(req, res) { - RED.nodes.deleteCredentials(req.params.id); - res.send(200); - }); - - RED.httpAdmin.post('/what3words/:id', RED.auth.needsPermission('what3words.write'), function(req, res) { - var body = ""; - req.on('data', function(chunk) { - body += chunk; - }); - req.on('end', function() { - var newCreds = querystring.parse(body); - var credentials = RED.nodes.getCredentials(req.params.id) || {}; - if (newCreds.pushkey === "") { - delete credentials.pushkey; - } else { - credentials.pushkey = newCreds.pushkey || credentials.pushkey; - } - RED.nodes.addCredentials(req.params.id, credentials); - res.send(200); - }); + RED.nodes.registerType("what3words", what3wordsNode, { + credentials: { apikey: {type: "password"} } }); } diff --git a/social/dweetio/55-dweetio.html b/social/dweetio/55-dweetio.html index 5870bcf9..235da627 100644 --- a/social/dweetio/55-dweetio.html +++ b/social/dweetio/55-dweetio.html @@ -15,7 +15,7 @@

    Sends the msg.payload to Dweet.io

    Optionally uses msg.thing to set the thing id, if not already set in the properties.

    You need to make the thing id unique - you are recommended to use a GUID.

    -

    For further info see the Dweet.io website.

    +

    For further info see the Dweet.io website.

    - diff --git a/social/pushover/package.json b/social/pushover/package.json index 41a551d5..abd8c230 100644 --- a/social/pushover/package.json +++ b/social/pushover/package.json @@ -1,6 +1,6 @@ { "name" : "node-red-node-pushover", - "version" : "0.0.10", + "version" : "0.0.11", "description" : "A Node-RED node to send alerts via Pushover", "dependencies" : { "pushover-notifications" : "~0.2.3" diff --git a/social/twilio/56-twilio.html b/social/twilio/56-twilio.html index 5db02535..46bee5bc 100644 --- a/social/twilio/56-twilio.html +++ b/social/twilio/56-twilio.html @@ -18,7 +18,6 @@
    -