├── .gitignore
├── LICENSE.txt
├── README.md
├── index.js
├── lib
├── animations.js
├── commander.js
├── frames.js
├── lighting_node_pro.js
└── ll_fan.js
├── package-lock.json
└── package.json
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 |
5 | # Runtime data
6 | pids
7 | *.pid
8 | *.seed
9 |
10 | # Directory for instrumented libs generated by jscoverage/JSCover
11 | lib-cov
12 |
13 | # Coverage directory used by tools like istanbul
14 | coverage
15 |
16 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
17 | .grunt
18 |
19 | # Compiled binary addons (http://nodejs.org/api/addons.html)
20 | build/Release
21 |
22 | # Dependency directory
23 | # Deployed apps should consider commenting this line out:
24 | # see https://npmjs.org/doc/faq.html#Should-I-check-my-node_modules-folder-into-git
25 | node_modules
26 |
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | Copyright 2018 Benjamin Burkhart
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4 |
5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6 |
7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
8 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Lighting Node Pro
2 | =================
3 |
4 | I generally find LEDs distracting, but do find their use in signalling information such as various device temperatures.
5 |
6 |
7 | I reversed the protocol of the Corsair LL fan LEDs+Lighting Node Pro controller because I wanted there to be some Linux
8 | support and found there was none.
9 |
10 |
11 | I used wireshark in Windows, turned all fans off, started recording, and then set static R, G, and B values with varying
12 | fan counts to figure out how it all worked.
13 |
14 |
15 | ## How to use this as an end-user
16 |
17 | Please note this ONLY works with Lighting Node Pro controllers with Corsair LL fans. Other fans can be added but I just
18 | haven't dug too deeply as I only have these ones.
19 |
20 |
21 | 1) Make sure your udev rules allow you acces to USB devices.
22 |
23 | 2) you MUST provide fan count
24 |
25 | 3) Choose a color or animation, animations are in animations.js if you're curious how they work
26 |
27 | 4) You must leave it running (run with & at the end if you want it to go to background)
28 |
29 |
30 | #### Sets all 3 fans to be red
31 |
32 | node index.js --fan-count=3 --colors red
33 |
34 | #### Sets fans to red, white and blue
35 |
36 | node index.js --fan-count=3 --colors red,white,blue
37 |
38 |
39 | #### Tracer Animation
40 |
41 | colors are two colors to use for ring and rotating LED
42 |
43 | node index.js --fan-count=3 --animation Tracer -p "colors=blue,black"
44 |
45 |
46 | #### I want it to go faster! (-r is framerate)
47 |
48 | This uses -r for frame rate of 10 per second
49 |
50 | node index.js --fan-count=3 --animation Tracer -p "colors=red,white" -r 10
51 |
52 |
53 | ### I want different frame rates for all the different fans
54 |
55 | Ok I think that's a bit much to ask, but here it is.
56 |
57 | node index.js --fan-count=3 --animation Tracer -p "colors=red,black&fps=16,32,48"
58 |
59 |
60 | ### Silly 3 fan animation example
61 |
62 | node index.js --fan-count=3 --animation RedBlueCollision
63 |
64 |
65 |
66 | If anything ever freezes, just control+c, if it still is frozen, hitting it again will force exit, should work fine the
67 | next run. You can use the -x flag to force a USB reset.
68 |
69 |
70 | -d flag prints the bytes as they're sent down the USB bus.
71 |
72 |
73 | -s
-b allows you to specify which device if you have multiple.
74 |
75 |
76 | ## Concepts specific to this implementation
77 |
78 | The Corsair LL fans have 16 LEDs, and it just takes simple commands to set the values of those LEDs. The effects you see
79 | in Windows are all implemented in software (there's one exception and that's the default rainbow wave which it falls back to if there's no new input).
80 |
81 | If the LED configuration is the exact same each run, you can simply send {33}{ff} to "maintain" what was last displayed on the fan LEDs.
82 |
83 | So to build animations, we need to have an event stack, and a frame rate. If the frame rate is 1 (1 per second), every second,
84 | a frame will be popped off the event stack, and that's what will be sent during subsequent "set colors" requests. When the set
85 | is exhausted, it starts back over.
86 |
87 |
88 | ## Reversing information
89 |
90 |
91 | All packets are null padded to 64 bytes
92 |
93 |
94 | #### PREAMBLE/INIT
95 |
96 | Sent at start when getting into the set color mode
97 |
98 | {37}
99 |
100 | # If num fans is 0 here, it disables all LEDs, important to do if you don't want it to fall back to rainbow after exiting
101 | {35}{00}{00}{<(short)num fans>0}{00}{01}{01}
102 | {3b}{00}{01}
103 | {38}{00}{02}
104 | {34}
105 | {37}{01}
106 | {34}{01}
107 | {38}{01}{01}
108 | {33}{ff}
109 |
110 |
111 | #### Color Request
112 |
113 | 3 requests per, 1 for each color channel
114 |
115 | {32}{00}{00}{32}{00}
116 | ^ Color channel (R=0x00, G=0x01, B=0x02)
117 |
118 | 16 bytes per fan, if you had one fan, it would be
119 |
120 | {ff}{ff}{ff}{ff}{ff}{ff}{ff}{ff}{ff}{ff}{ff}{ff}{ff}{ff}{ff}{ff}
121 |
122 |
123 |
124 | This is for the first 3 fans, If there's 4 fans, only 2 bytes of the 4th fan is done on the first request, after doing
125 | all color channels, it does an extension run, that looks like:
126 |
127 | {32}{00}{32}{2e} 14 bytes remaining for 4th fan, 16 bytes for 5th fan, 16 bytes for 6th fan.
128 |
129 |
130 | Why 16 bytes? There's 16 different LEDs. 4 on the inside, and 12 on the outside. Since there's 12, I find it easiest
131 | to refer to the positions as positions on a 12-hour clock.
132 |
133 |
134 | While facing intake (with corsair sticker logo facing you)
135 |
136 | 1st - top inner
137 | 2nd - inner left
138 | 3rd - inner bottom
139 | 4th - inner right
140 |
141 | 5th - 10 O'Clock
142 | 6th - 9 O'Clock
143 | 7th - 8 O'Clock
144 | 8th - 7 O'Clock
145 | 9th - 6 O'Clock
146 |
147 | 10th - 5 O'Clock
148 | 11th - 4 O'Clock
149 | 12th - 3 O'Clock
150 | 13th - 2 O'Clock
151 | 14th - 1 O'Clock
152 |
153 | 15th - 12 O'Clock
154 | 16th - 11 O'Clock
155 |
156 |
157 |
158 |
159 |
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | const cmdlineArgs = require('command-line-args');
4 | const rgbColor = require('rgb-color');
5 |
6 | const Commander = require('./lib/commander.js');
7 | const frames = require('./lib/frames.js');
8 | const animations = require('./lib/animations.js');
9 |
10 | const options = cmdlineArgs([
11 | {
12 | name: 'fan-count', alias: 'f', type: Number,
13 | },
14 | {
15 | name: 'framerate', alias: 'r',
16 | },
17 | {
18 | name: 'animation', alias: 'a',
19 | },
20 | {
21 | name: 'bus', alias: 'b', type: Number
22 | },
23 | {
24 | name: 'address', alias: 's', type: Number
25 | },
26 | {
27 | name: 'params', alias: 'p',
28 | },
29 | {
30 | name: 'colors', alias: 'c'
31 | },
32 | {
33 | name: 'off', alias: 'o',
34 | },
35 | {
36 | name: 'debug', alias: 'd', type: Boolean
37 | },
38 | {
39 | name: 'reset', alias: 'x', type: Boolean
40 | },
41 | ]);
42 |
43 |
44 | const run = async () => {
45 | let cmd = new Commander();
46 | let controller = cmd.scanForController(options['bus'], options['address']);
47 |
48 | // Initialize with 3 fans
49 | await controller.initialize(options['fan-count'], options['debug'], options['reset']);
50 |
51 | let sigIntCnt = 0;
52 |
53 | process.on('SIGINT', () => {
54 | if (sigIntCnt > 0) {
55 | console.log("Could not exit cleanly.");
56 | process.exit(1);
57 | }
58 |
59 | console.log("SIGINT: please press kill again to force exit if it doesn't exit within a few seconds.");
60 | sigIntCnt++;
61 |
62 | controller.exitLoop = true;
63 |
64 | controller.shutdown()
65 | .then(() => {
66 | console.log(`Successfully exited`);
67 | process.exit(0);
68 | })
69 | });
70 |
71 | if (!options.colors) {
72 | controller.devices.forEach(dev => dev.eventStack = [frames.descriptiveToFrame({
73 | topInner: 'red',
74 | bottomInner: 'red',
75 | rightInner: 'red',
76 | leftInner: 'red',
77 |
78 | elevenOClock: 'blue',
79 | twelveOClock: 'red',
80 | oneOClock: 'blue',
81 | twoOClock: 'red',
82 | threeOClock: 'blue',
83 | fourOClock: 'red',
84 | fiveOClock: 'blue',
85 | sixOClock: 'red',
86 | sevenOClock: 'blue',
87 | eightOClock: 'red',
88 | nineOClock: 'blue',
89 | tenOClock: 'red',
90 |
91 | })]);
92 | }
93 | else {
94 | let colors = options.colors.split(',');
95 |
96 | if (colors.length > 1) {
97 | for (let i = 0; i < options['fan-count']; i++) {
98 | let color = rgbColor(colors[i % colors.length]);
99 | let dev = controller.devices[i].eventStack = [frames.staticColorFrame(color)];
100 | }
101 | }
102 | else {
103 | let color = rgbColor(colors[0]);
104 |
105 | controller.devices.forEach(dev => dev.eventStack = [frames.staticColorFrame(color)]);
106 | }
107 |
108 | }
109 |
110 | if (options.animation) {
111 | if (!animations[options.animation]) {
112 | console.error(`Could not find animation ${options.animation}`);
113 | return process.exit(1);
114 | }
115 |
116 | animations[options.animation](controller.devices, options['params'])
117 | }
118 |
119 | if (options.framerate) {
120 | for (let i = 0; i < options['fan-count']; i++) {
121 | controller.devices[i].setFramerate(options.framerate);
122 | }
123 | }
124 |
125 | // Enter loop
126 | controller.loop();
127 | };
128 |
129 | run();
130 |
--------------------------------------------------------------------------------
/lib/animations.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | const qs = require('querystring');
4 |
5 | const frames = require('./frames.js');
6 |
7 | module.exports.Tracer = (devices, params) => {
8 | let pp = qs.parse(params || "");
9 |
10 | let primaryColor = 'red';
11 | let secondaryColor = 'black';
12 |
13 | if (pp.colors) {
14 | let colors = pp.colors.split(',');
15 |
16 | if (colors.length > 0)
17 | primaryColor = colors[0];
18 | if (colors.length > 1)
19 | secondaryColor = colors[1];
20 | }
21 |
22 | let toReverse = [];
23 | if (pp.reverse) {
24 | toReverse = pp.reverse.split(',').map(f => ~~f);
25 | }
26 |
27 | let fpsa = [];
28 | if (pp.fps) {
29 | fpsa = pp.fps.split(',').map(f => ~~f);
30 | }
31 |
32 | // 12 frames
33 | let ev = [
34 | frames.descriptiveToFrame({
35 | topInner: primaryColor,
36 | bottomInner: primaryColor,
37 | rightInner: primaryColor,
38 | leftInner: primaryColor,
39 |
40 | elevenOClock: secondaryColor,
41 | twelveOClock: primaryColor,
42 | oneOClock: secondaryColor,
43 | twoOClock: secondaryColor,
44 | threeOClock: secondaryColor,
45 | fourOClock: secondaryColor,
46 | fiveOClock: secondaryColor,
47 | sixOClock: secondaryColor,
48 | sevenOClock: secondaryColor,
49 | eightOClock: secondaryColor,
50 | nineOClock: secondaryColor,
51 | tenOClock: secondaryColor,
52 | }),
53 | frames.descriptiveToFrame({
54 | topInner: primaryColor,
55 | bottomInner: primaryColor,
56 | rightInner: primaryColor,
57 | leftInner: primaryColor,
58 |
59 | elevenOClock: secondaryColor,
60 | twelveOClock: secondaryColor,
61 | oneOClock: primaryColor,
62 | twoOClock: secondaryColor,
63 | threeOClock: secondaryColor,
64 | fourOClock: secondaryColor,
65 | fiveOClock: secondaryColor,
66 | sixOClock: secondaryColor,
67 | sevenOClock: secondaryColor,
68 | eightOClock: secondaryColor,
69 | nineOClock: secondaryColor,
70 | tenOClock: secondaryColor,
71 | }),
72 | frames.descriptiveToFrame({
73 | topInner: primaryColor,
74 | bottomInner: primaryColor,
75 | rightInner: primaryColor,
76 | leftInner: primaryColor,
77 |
78 | elevenOClock: secondaryColor,
79 | twelveOClock: secondaryColor,
80 | oneOClock: secondaryColor,
81 | twoOClock: primaryColor,
82 | threeOClock: secondaryColor,
83 | fourOClock: secondaryColor,
84 | fiveOClock: secondaryColor,
85 | sixOClock: secondaryColor,
86 | sevenOClock: secondaryColor,
87 | eightOClock: secondaryColor,
88 | nineOClock: secondaryColor,
89 | tenOClock: secondaryColor,
90 | }),
91 | frames.descriptiveToFrame({
92 | topInner: primaryColor,
93 | bottomInner: primaryColor,
94 | rightInner: primaryColor,
95 | leftInner: primaryColor,
96 |
97 | elevenOClock: secondaryColor,
98 | twelveOClock: secondaryColor,
99 | oneOClock: secondaryColor,
100 | twoOClock: secondaryColor,
101 | threeOClock: primaryColor,
102 | fourOClock: secondaryColor,
103 | fiveOClock: secondaryColor,
104 | sixOClock: secondaryColor,
105 | sevenOClock: secondaryColor,
106 | eightOClock: secondaryColor,
107 | nineOClock: secondaryColor,
108 | tenOClock: secondaryColor,
109 | }),
110 | frames.descriptiveToFrame({
111 | topInner: primaryColor,
112 | bottomInner: primaryColor,
113 | rightInner: primaryColor,
114 | leftInner: primaryColor,
115 |
116 | elevenOClock: secondaryColor,
117 | twelveOClock: secondaryColor,
118 | oneOClock: secondaryColor,
119 | twoOClock: secondaryColor,
120 | threeOClock: secondaryColor,
121 | fourOClock: primaryColor,
122 | fiveOClock: secondaryColor,
123 | sixOClock: secondaryColor,
124 | sevenOClock: secondaryColor,
125 | eightOClock: secondaryColor,
126 | nineOClock: secondaryColor,
127 | tenOClock: secondaryColor,
128 | }),
129 | frames.descriptiveToFrame({
130 | topInner: primaryColor,
131 | bottomInner: primaryColor,
132 | rightInner: primaryColor,
133 | leftInner: primaryColor,
134 |
135 | elevenOClock: secondaryColor,
136 | twelveOClock: secondaryColor,
137 | oneOClock: secondaryColor,
138 | twoOClock: secondaryColor,
139 | threeOClock: secondaryColor,
140 | fourOClock: secondaryColor,
141 | fiveOClock: primaryColor,
142 | sixOClock: secondaryColor,
143 | sevenOClock: secondaryColor,
144 | eightOClock: secondaryColor,
145 | nineOClock: secondaryColor,
146 | tenOClock: secondaryColor,
147 | }),
148 | frames.descriptiveToFrame({
149 | topInner: primaryColor,
150 | bottomInner: primaryColor,
151 | rightInner: primaryColor,
152 | leftInner: primaryColor,
153 |
154 | elevenOClock: secondaryColor,
155 | twelveOClock: secondaryColor,
156 | oneOClock: secondaryColor,
157 | twoOClock: secondaryColor,
158 | threeOClock: secondaryColor,
159 | fourOClock: secondaryColor,
160 | fiveOClock: secondaryColor,
161 | sixOClock: primaryColor,
162 | sevenOClock: secondaryColor,
163 | eightOClock: secondaryColor,
164 | nineOClock: secondaryColor,
165 | tenOClock: secondaryColor,
166 | }),
167 | frames.descriptiveToFrame({
168 | topInner: primaryColor,
169 | bottomInner: primaryColor,
170 | rightInner: primaryColor,
171 | leftInner: primaryColor,
172 |
173 | elevenOClock: secondaryColor,
174 | twelveOClock: secondaryColor,
175 | oneOClock: secondaryColor,
176 | twoOClock: secondaryColor,
177 | threeOClock: secondaryColor,
178 | fourOClock: secondaryColor,
179 | fiveOClock: secondaryColor,
180 | sixOClock: secondaryColor,
181 | sevenOClock: primaryColor,
182 | eightOClock: secondaryColor,
183 | nineOClock: secondaryColor,
184 | tenOClock: secondaryColor,
185 | }),
186 | frames.descriptiveToFrame({
187 | topInner: primaryColor,
188 | bottomInner: primaryColor,
189 | rightInner: primaryColor,
190 | leftInner: primaryColor,
191 |
192 | elevenOClock: secondaryColor,
193 | twelveOClock: secondaryColor,
194 | oneOClock: secondaryColor,
195 | twoOClock: secondaryColor,
196 | threeOClock: secondaryColor,
197 | fourOClock: secondaryColor,
198 | fiveOClock: secondaryColor,
199 | sixOClock: secondaryColor,
200 | sevenOClock: secondaryColor,
201 | eightOClock: primaryColor,
202 | nineOClock: secondaryColor,
203 | tenOClock: secondaryColor,
204 | }),
205 | frames.descriptiveToFrame({
206 | topInner: primaryColor,
207 | bottomInner: primaryColor,
208 | rightInner: primaryColor,
209 | leftInner: primaryColor,
210 |
211 | elevenOClock: secondaryColor,
212 | twelveOClock: secondaryColor,
213 | oneOClock: secondaryColor,
214 | twoOClock: secondaryColor,
215 | threeOClock: secondaryColor,
216 | fourOClock: secondaryColor,
217 | fiveOClock: secondaryColor,
218 | sixOClock: secondaryColor,
219 | sevenOClock: secondaryColor,
220 | eightOClock: secondaryColor,
221 | nineOClock: primaryColor,
222 | tenOClock: secondaryColor,
223 | }),
224 | frames.descriptiveToFrame({
225 | topInner: primaryColor,
226 | bottomInner: primaryColor,
227 | rightInner: primaryColor,
228 | leftInner: primaryColor,
229 |
230 | elevenOClock: secondaryColor,
231 | twelveOClock: secondaryColor,
232 | oneOClock: secondaryColor,
233 | twoOClock: secondaryColor,
234 | threeOClock: secondaryColor,
235 | fourOClock: secondaryColor,
236 | fiveOClock: secondaryColor,
237 | sixOClock: secondaryColor,
238 | sevenOClock: secondaryColor,
239 | eightOClock: secondaryColor,
240 | nineOClock: secondaryColor,
241 | tenOClock: primaryColor,
242 | }),
243 | frames.descriptiveToFrame({
244 | topInner: primaryColor,
245 | bottomInner: primaryColor,
246 | rightInner: primaryColor,
247 | leftInner: primaryColor,
248 |
249 | elevenOClock: primaryColor,
250 | twelveOClock: secondaryColor,
251 | oneOClock: secondaryColor,
252 | twoOClock: secondaryColor,
253 | threeOClock: secondaryColor,
254 | fourOClock: secondaryColor,
255 | fiveOClock: secondaryColor,
256 | sixOClock: secondaryColor,
257 | sevenOClock: secondaryColor,
258 | eightOClock: secondaryColor,
259 | nineOClock: secondaryColor,
260 | tenOClock: secondaryColor,
261 | }),
262 | ];
263 |
264 | devices.forEach((dev, i) => {
265 | let stack = ev.slice(0);
266 |
267 | if (toReverse.indexOf(i) !== -1) {
268 | stack = frames.flipFrames(stack);
269 | }
270 |
271 | if (fpsa[i%fpsa.length]) {
272 | dev.setFramerate(fpsa[i%fpsa.length]);
273 | }
274 |
275 | dev.eventStack = stack;
276 | });
277 | };
278 |
279 | module.exports.ColorWheel = (devices, params) => {
280 | let pp = qs.parse(params || "");
281 |
282 | let primaryColor = 'blue';
283 | let secondaryColor = 'white';
284 |
285 | if (pp.colors) {
286 | let colors = pp.colors.split(',');
287 |
288 | if (colors.length > 0)
289 | primaryColor = colors[0];
290 | if (colors.length > 1)
291 | secondaryColor = colors[1];
292 | }
293 |
294 | let fpsa = [];
295 | if (pp.fps) {
296 | fpsa = pp.fps.split(',').map(f => ~~f);
297 | }
298 |
299 | let ev = [
300 | frames.descriptiveToFrame({
301 | topInner: primaryColor,
302 | bottomInner: primaryColor,
303 | rightInner: secondaryColor,
304 | leftInner: secondaryColor,
305 |
306 | elevenOClock: primaryColor,
307 | twelveOClock: secondaryColor,
308 | oneOClock: primaryColor,
309 | twoOClock: secondaryColor,
310 | threeOClock: primaryColor,
311 | fourOClock: secondaryColor,
312 | fiveOClock: primaryColor,
313 | sixOClock: secondaryColor,
314 | sevenOClock: primaryColor,
315 | eightOClock: secondaryColor,
316 | nineOClock: primaryColor,
317 | tenOClock: secondaryColor,
318 |
319 | }),
320 | frames.descriptiveToFrame({
321 | topInner: secondaryColor,
322 | bottomInner: secondaryColor,
323 | rightInner: primaryColor,
324 | leftInner: primaryColor,
325 |
326 | elevenOClock: secondaryColor,
327 | twelveOClock: primaryColor,
328 | oneOClock: secondaryColor,
329 | twoOClock: primaryColor,
330 | threeOClock: secondaryColor,
331 | fourOClock: primaryColor,
332 | fiveOClock: secondaryColor,
333 | sixOClock: primaryColor,
334 | sevenOClock: secondaryColor,
335 | eightOClock: primaryColor,
336 | nineOClock: secondaryColor,
337 | tenOClock: primaryColor,
338 | }),
339 | ];
340 |
341 | devices.forEach((dev, i) => {
342 | dev.eventStack = frames.flipFrames(ev.slice(0));
343 |
344 | if (fpsa[i%fpsa.length]) {
345 | dev.setFramerate(fpsa[i%fpsa.length]);
346 | }
347 |
348 | });
349 | };
350 |
351 | module.exports.StopLight = (devices) => {
352 | let ev1 = [
353 | frames.staticColorFrame({
354 | r: 0,
355 | g: 0,
356 | b: 0,
357 | }),
358 | frames.staticColorFrame({
359 | r: 0,
360 | g: 0,
361 | b: 0,
362 | }),
363 | frames.staticColorFrame({
364 | r: 0,
365 | g: 0,
366 | b: 0,
367 | }),
368 | frames.staticColorFrame({
369 | r: 0,
370 | g: 0,
371 | b: 0,
372 | }),
373 | frames.staticColorFrame({
374 | r: 0,
375 | g: 0,
376 | b: 0,
377 | }),
378 | frames.staticColorFrame({
379 | r: 255,
380 | g: 0,
381 | b: 0,
382 | }),
383 | frames.staticColorFrame({
384 | r: 255,
385 | g: 0,
386 | b: 0,
387 | }),
388 | frames.staticColorFrame({
389 | r: 255,
390 | g: 0,
391 | b: 0,
392 | }),
393 | frames.staticColorFrame({
394 | r: 255,
395 | g: 0,
396 | b: 0,
397 | }),
398 | frames.staticColorFrame({
399 | r: 255,
400 | g: 0,
401 | b: 0,
402 | }),
403 | ];
404 |
405 | let ev2 = [
406 | frames.staticColorFrame({
407 | r: 0,
408 | g: 0,
409 | b: 0,
410 | }),
411 | frames.staticColorFrame({
412 | r: 0,
413 | g: 0,
414 | b: 0,
415 | }),
416 | frames.staticColorFrame({
417 | r: 0,
418 | g: 0,
419 | b: 0,
420 | }),
421 | frames.staticColorFrame({
422 | r: 255,
423 | g: 255,
424 | b: 0,
425 | }),
426 | frames.staticColorFrame({
427 | r: 255,
428 | g: 255,
429 | b: 0,
430 | }),
431 | frames.staticColorFrame({
432 | r: 0,
433 | g: 0,
434 | b: 0,
435 | }),
436 | frames.staticColorFrame({
437 | r: 0,
438 | g: 0,
439 | b: 0,
440 | }),
441 | frames.staticColorFrame({
442 | r: 0,
443 | g: 0,
444 | b: 0,
445 | }),
446 | frames.staticColorFrame({
447 | r: 0,
448 | g: 0,
449 | b: 0,
450 | }),
451 | frames.staticColorFrame({
452 | r: 0,
453 | g: 0,
454 | b: 0,
455 | }),
456 | ];
457 |
458 | let ev3 = [
459 | frames.staticColorFrame({
460 | r: 0,
461 | g: 255,
462 | b: 0,
463 | }),
464 | frames.staticColorFrame({
465 | r: 0,
466 | g: 255,
467 | b: 0,
468 | }),
469 | frames.staticColorFrame({
470 | r: 0,
471 | g: 255,
472 | b: 0,
473 | }),
474 | frames.staticColorFrame({
475 | r: 0,
476 | g: 0,
477 | b: 0,
478 | }),
479 | frames.staticColorFrame({
480 | r: 0,
481 | g: 0,
482 | b: 0,
483 | }),
484 | frames.staticColorFrame({
485 | r: 0,
486 | g: 0,
487 | b: 0,
488 | }),
489 | frames.staticColorFrame({
490 | r: 0,
491 | g: 0,
492 | b: 0,
493 | }),
494 | frames.staticColorFrame({
495 | r: 0,
496 | g: 0,
497 | b: 0,
498 | }),
499 | frames.staticColorFrame({
500 | r: 0,
501 | g: 0,
502 | b: 0,
503 | }),
504 | frames.staticColorFrame({
505 | r: 0,
506 | g: 0,
507 | b: 0,
508 | }),
509 | ];
510 |
511 | if (devices.length >= 1)
512 | devices[0].eventStack = ev1;
513 | if (devices.length >= 2)
514 | devices[1].eventStack = ev2;
515 | if (devices.length >= 3)
516 | devices[2].eventStack = ev3;
517 | };
518 |
519 |
520 | // 3 frame animation for 3 fans where a red circle meets
521 | // a blue circle and becomes purple, really looks pink
522 | module.exports.RedBlueCollision = (devices) => {
523 | let ev1 = [
524 | frames.staticColorFrame({
525 | r: 255,
526 | g: 0,
527 | b: 0,
528 | }),
529 | frames.blankFrame(),
530 | frames.blankFrame(),
531 | ];
532 |
533 | let ev2 = [
534 | frames.blankFrame(),
535 | {
536 | r: [
537 | 0xff,
538 | 0xff,
539 | 0x00,
540 | 0xff,
541 | 0xff,
542 | 0xff,
543 | 0x00,
544 | 0x00,
545 | 0x00,
546 | 0x00,
547 | 0x00,
548 | 0xff,
549 | 0xff,
550 | 0xff,
551 | 0xff,
552 | 0xff
553 | ],
554 | g: [
555 | 0x00,
556 | 0x00,
557 | 0x00,
558 | 0x00,
559 | 0x00,
560 | 0x00,
561 | 0x00,
562 | 0x00,
563 | 0x00,
564 | 0x00,
565 | 0x00,
566 | 0x00,
567 | 0x00,
568 | 0x00,
569 | 0x00,
570 | 0x00
571 | ],
572 | b: [
573 | 0x00,
574 | 0xff,
575 | 0xff,
576 | 0xff,
577 | 0x00,
578 | 0xff,
579 | 0xff,
580 | 0xff,
581 | 0xff,
582 | 0xff,
583 | 0xff,
584 | 0xff,
585 | 0x00,
586 | 0x00,
587 | 0x00,
588 | 0x00
589 | ],
590 | },
591 | frames.staticColorFrame({
592 | r: 255,
593 | g: 0,
594 | b: 255
595 | })
596 | ];
597 |
598 | let ev3 = [
599 | frames.staticColorFrame({
600 | r: 0,
601 | g: 0,
602 | b: 255,
603 | }),
604 | frames.blankFrame(),
605 | frames.blankFrame(),
606 | ];
607 |
608 | if (devices.length >= 1)
609 | devices[0].eventStack = ev1;
610 | if (devices.length >= 2)
611 | devices[1].eventStack = ev2;
612 | if (devices.length >= 3)
613 | devices[2].eventStack = ev3;
614 | };
615 |
--------------------------------------------------------------------------------
/lib/commander.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | const usb = require('usb');
4 |
5 | const LightingNodePro = require('./lighting_node_pro.js');
6 |
7 | module.exports = class Commander {
8 | constructor() {
9 | }
10 |
11 | scanForController(bus, address) {
12 | let devices = usb.getDeviceList();
13 |
14 | let foundDevices = devices.filter(d => {
15 | return d.deviceDescriptor.idVendor === 0x1b1c && d.deviceDescriptor.idProduct === 0x0c0b;
16 | });
17 |
18 | let devStrings = foundDevices.map(d => `(Bus ${d.busNumber} Address ${d.deviceAddress})`);
19 |
20 | if (devStrings.length > 0) {
21 | console.log(`Found devices on ${devStrings.join(', ')}`);
22 | }
23 |
24 | let target = foundDevices.find(dev => ((!bus && !address) || (dev.busNumber == bus || dev.deviceAddress == address)));
25 |
26 | if (target) {
27 | console.log(`Found Lighting Node Pro (1b1c:0c0b)`);
28 | return new LightingNodePro(target);
29 | }
30 |
31 | return null;
32 | }
33 | };
34 |
--------------------------------------------------------------------------------
/lib/frames.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | let rgbColor = require('rgb-color');
4 |
5 | const flipFrame = module.exports.flipFrame = frame => {
6 | let nf = {
7 | r: Array(16),
8 | g: Array(16),
9 | b: Array(16),
10 | };
11 |
12 | ['r', 'g', 'b'].forEach(color => {
13 | for (let i = 0; i < frame[color].length; i++) {
14 | // Inner ring
15 | if (i < 4) {
16 | nf[color][i] = frame[color][(i+2)%4];
17 | }
18 | else {
19 | nf[color][i] = frame[color][(((i-4)+6)%12)+4];
20 | }
21 | }
22 | });
23 |
24 | return nf;
25 | };
26 |
27 |
28 | module.exports.flipFrames = frameArray => frameArray.map(flipFrame);
29 |
30 | module.exports.descriptiveToFrame = (obj) => {
31 | return {
32 | r: [
33 | obj.topInner && rgbColor(obj.topInner).r || 0x00, // 0 topInner
34 | obj.leftInner && rgbColor(obj.leftInner).r || 0x00, // 1 leftInner
35 | obj.bottomInner && rgbColor(obj.bottomInner).r || 0x00, // 2 bottomInner
36 | obj.rightInner && rgbColor(obj.rightInner).r || 0x00, // 3 rightInner
37 | obj.tenOClock && rgbColor(obj.tenOClock).r || 0x00, // 4 tenOClock
38 | obj.nineOClock && rgbColor(obj.nineOClock).r || 0x00, // 5 nineOClock
39 | obj.eightOClock && rgbColor(obj.eightOClock).r || 0x00, // 6 eightOClock
40 | obj.sevenOClock && rgbColor(obj.sevenOClock).r || 0x00, // 7 sevenOClock
41 | obj.sixOClock && rgbColor(obj.sixOClock).r || 0x00, // 8 sixOClock
42 | obj.fiveOClock && rgbColor(obj.fiveOClock).r || 0x00, // 9 fiveOClock
43 | obj.fourOClock && rgbColor(obj.fourOClock).r || 0x00, // 10 fourOClock
44 | obj.threeOClock && rgbColor(obj.threeOClock).r || 0x00, // 11 threeOClock
45 | obj.twoOClock && rgbColor(obj.twoOClock).r || 0x00, // 12 twoOClock
46 | obj.oneOClock && rgbColor(obj.oneOClock).r || 0x00, // 13 oneOClock
47 | obj.twelveOClock && rgbColor(obj.twelveOClock).r || 0x00, // 14 twelveOClock
48 | obj.elevenOClock && rgbColor(obj.elevenOClock).r || 0x00, // 15 elevenOClock
49 | ],
50 | g: [
51 | obj.topInner && rgbColor(obj.topInner).g || 0x00, // 0 topInner
52 | obj.leftInner && rgbColor(obj.leftInner).g || 0x00, // 1 leftInner
53 | obj.bottomInner && rgbColor(obj.bottomInner).g || 0x00, // 2 bottomInner
54 | obj.rightInner && rgbColor(obj.rightInner).g || 0x00, // 3 rightInner
55 | obj.tenOClock && rgbColor(obj.tenOClock).g || 0x00, // 4 tenOClock
56 | obj.nineOClock && rgbColor(obj.nineOClock).g || 0x00, // 5 nineOClock
57 | obj.eightOClock && rgbColor(obj.eightOClock).g || 0x00, // 6 eightOClock
58 | obj.sevenOClock && rgbColor(obj.sevenOClock).g || 0x00, // 7 sevenOClock
59 | obj.sixOClock && rgbColor(obj.sixOClock).g || 0x00, // 8 sixOClock
60 | obj.fiveOClock && rgbColor(obj.fiveOClock).g || 0x00, // 9 fiveOClock
61 | obj.fourOClock && rgbColor(obj.fourOClock).g || 0x00, // 10 fourOClock
62 | obj.threeOClock && rgbColor(obj.threeOClock).g || 0x00, // 11 threeOClock
63 | obj.twoOClock && rgbColor(obj.twoOClock).g || 0x00, // 12 twoOClock
64 | obj.oneOClock && rgbColor(obj.oneOClock).g || 0x00, // 13 oneOClock
65 | obj.twelveOClock && rgbColor(obj.twelveOClock).g || 0x00, // 14 twelveOClock
66 | obj.elevenOClock && rgbColor(obj.elevenOClock).g || 0x00, // 15 elevenOClock
67 | ],
68 | b: [
69 | obj.topInner && rgbColor(obj.topInner).b || 0x00, // 0 topInner
70 | obj.leftInner && rgbColor(obj.leftInner).b || 0x00, // 1 leftInner
71 | obj.bottomInner && rgbColor(obj.bottomInner).b || 0x00, // 2 bottomInner
72 | obj.rightInner && rgbColor(obj.rightInner).b || 0x00, // 3 rightInner
73 | obj.tenOClock && rgbColor(obj.tenOClock).b || 0x00, // 4 tenOClock
74 | obj.nineOClock && rgbColor(obj.nineOClock).b || 0x00, // 5 nineOClock
75 | obj.eightOClock && rgbColor(obj.eightOClock).b || 0x00, // 6 eightOClock
76 | obj.sevenOClock && rgbColor(obj.sevenOClock).b || 0x00, // 7 sevenOClock
77 | obj.sixOClock && rgbColor(obj.sixOClock).b || 0x00, // 8 sixOClock
78 | obj.fiveOClock && rgbColor(obj.fiveOClock).b || 0x00, // 9 fiveOClock
79 | obj.fourOClock && rgbColor(obj.fourOClock).b || 0x00, // 10 fourOClock
80 | obj.threeOClock && rgbColor(obj.threeOClock).b || 0x00, // 11 threeOClock
81 | obj.twoOClock && rgbColor(obj.twoOClock).b || 0x00, // 12 twoOClock
82 | obj.oneOClock && rgbColor(obj.oneOClock).b || 0x00, // 13 oneOClock
83 | obj.twelveOClock && rgbColor(obj.twelveOClock).b || 0x00, // 14 twelveOClock
84 | obj.elevenOClock && rgbColor(obj.elevenOClock).b || 0x00, // 15 elevenOClock
85 | ],
86 | };
87 | };
88 |
89 | module.exports.colorfulFrame = () => {
90 | return {
91 | r: [
92 | 0xff,
93 | 0x00,
94 | 0x00,
95 | 0xff,
96 | 0x00,
97 | 0x00,
98 | 0xff,
99 | 0x00,
100 | 0x00,
101 | 0xff,
102 | 0x00,
103 | 0x00,
104 | 0xff,
105 | 0x00,
106 | 0x00,
107 | 0xff
108 | ],
109 | g: [
110 | 0x00,
111 | 0xff,
112 | 0x00,
113 | 0x00,
114 | 0xff,
115 | 0x00,
116 | 0x00,
117 | 0xff,
118 | 0x00,
119 | 0x00,
120 | 0xff,
121 | 0x00,
122 | 0x00,
123 | 0xff,
124 | 0x00,
125 | 0x00
126 | ],
127 | b: [
128 | 0x00,
129 | 0x00,
130 | 0xff,
131 | 0x00,
132 | 0x00,
133 | 0xff,
134 | 0x00,
135 | 0x00,
136 | 0xff,
137 | 0x00,
138 | 0x00,
139 | 0xff,
140 | 0x00,
141 | 0x00,
142 | 0xff,
143 | 0x00
144 | ],
145 | };
146 | };
147 |
148 |
149 | module.exports.blankFrame = () => {
150 | return {
151 | r: [
152 | 0x00,
153 | 0x00,
154 | 0x00,
155 | 0x00,
156 | 0x00,
157 | 0x00,
158 | 0x00,
159 | 0x00,
160 | 0x00,
161 | 0x00,
162 | 0x00,
163 | 0x00,
164 | 0x00,
165 | 0x00,
166 | 0x00,
167 | 0x00
168 | ],
169 | g: [
170 | 0x00,
171 | 0x00,
172 | 0x00,
173 | 0x00,
174 | 0x00,
175 | 0x00,
176 | 0x00,
177 | 0x00,
178 | 0x00,
179 | 0x00,
180 | 0x00,
181 | 0x00,
182 | 0x00,
183 | 0x00,
184 | 0x00,
185 | 0x00
186 | ],
187 | b: [
188 | 0x00,
189 | 0x00,
190 | 0x00,
191 | 0x00,
192 | 0x00,
193 | 0x00,
194 | 0x00,
195 | 0x00,
196 | 0x00,
197 | 0x00,
198 | 0x00,
199 | 0x00,
200 | 0x00,
201 | 0x00,
202 | 0x00,
203 | 0x00
204 | ],
205 | };
206 | };
207 |
208 | module.exports.staticColorFrame = (rgb) => {
209 | let frame = {};
210 |
211 | frame.r = Array(16).fill(rgb.r);
212 | frame.g = Array(16).fill(rgb.g);
213 | frame.b = Array(16).fill(rgb.b);
214 |
215 | return frame;
216 | }
217 |
218 |
--------------------------------------------------------------------------------
/lib/lighting_node_pro.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | const usb = require('usb');
3 |
4 | const LLFan = require('./ll_fan.js');
5 |
6 | const animations = require('./animations.js');
7 |
8 | module.exports = class LightingNodePro {
9 | constructor(usbDevice) {
10 | this.usbDevice = usbDevice;
11 | this.iface = null;
12 | this.outEndpoint = null;
13 | this.inEndpoint = null;
14 |
15 | this.debug = false;
16 |
17 | this.kernelDriverWasAttached = false;
18 | this.devices = [];
19 |
20 | this.exitLoop = false;
21 | }
22 |
23 | resetDevice() {
24 | return new Promise((resolve, reject) => {
25 | this.usbDevice.reset(err => {
26 | console.log("Device reset");
27 | if (err)
28 | return reject(err);
29 |
30 | return resolve();
31 | });
32 | });
33 | }
34 |
35 | async initialize(numFans, debug, reset) {
36 | this.debug = debug || false;
37 |
38 | this.numDevices = numFans;
39 | this.numDevicesShort = parseInt(numFans)<<4;
40 |
41 | for (let i = 0; i < this.numDevices; i++) {
42 | let dev = new LLFan();
43 | this.devices.push(dev);
44 |
45 | dev.setFramerate(1);
46 | }
47 |
48 | console.log("Opening USB port.");
49 | this.usbDevice.open();
50 |
51 | if (reset) {
52 | console.log("Resetting device");
53 | await this.resetDevice();
54 |
55 | console.log("Waiting for 2 seconds.");
56 | await this.delay(2000);
57 |
58 | console.log("Opening USB port again.");
59 | this.usbDevice.open();
60 | }
61 |
62 | this.iface = this.usbDevice.interface(0);
63 |
64 | if (this.iface.isKernelDriverActive()) {
65 | console.log("Detaching kernel driver");
66 | this.kernelDriverWasAttached = true;
67 | this.iface.detachKernelDriver();
68 | }
69 |
70 | console.log("Claiming interface.");
71 | this.iface.claim();
72 |
73 | this.outEndpoint = this.iface.endpoint(1);
74 | }
75 |
76 |
77 | async sendPreamble() {
78 | if (this.debug)
79 | console.log("Sending preamble");
80 |
81 | await this.sendPkt([0x37]);
82 |
83 | // 0x35 - init
84 | await this.sendPkt([0x35, 0x00, 0x00, this.numDevicesShort, 0x00, 0x01, 0x01]);
85 | await this.sendPkt([0x3b, 0x00, 0x01]);
86 | await this.sendPkt([0x38, 0x00, 0x02]);
87 | await this.sendPkt([0x34]);
88 | await this.sendPkt([0x37, 0x01]);
89 | await this.sendPkt([0x34, 0x01]);
90 | await this.sendPkt([0x38, 0x01, 0x01]);
91 | await this.sendPkt([0x33, 0xff]);
92 | }
93 |
94 | delay(ms) {
95 | return new Promise(resolve => setTimeout(resolve, ms));
96 | }
97 |
98 | prettyPrint(byteArray) {
99 | let chq = byteArray; //this.make64(byteArray);
100 | console.log(`[${chq.map(bv => `'${bv.toString(16)}'`).join(', ')}]`);
101 | };
102 |
103 | setColors() {
104 | // s, t, u are R, G, B extended for fans 3-6
105 | ['r', 'g', 'b', 's', 't', 'u'].forEach(cval => {
106 | let bytes = [];
107 |
108 | if (['r','g','b'].indexOf(cval) !== -1) {
109 | bytes.push(0x32);
110 | bytes.push(0x00);
111 | bytes.push(0x00);
112 | bytes.push(0x32);
113 |
114 | if (cval == 'r')
115 | bytes.push(0x00);
116 | else if (cval == 'g')
117 | bytes.push(0x01);
118 | else if (cval == 'b')
119 | bytes.push(0x02);
120 |
121 | for (let i = 0; i < this.numDevices && i < 3; i++) {
122 | bytes = bytes.concat(this.devices[i].getFrame()[cval]);
123 | }
124 |
125 | // If we have 4 or more fans, we need to take 2 bytes from the 4th fan and put
126 | // it on this message.
127 | if (this.numDevices > 3) {
128 | bytes = bytes.concat(this.devices[3].getFrame()[cval].slice(0, 3));
129 | }
130 | } else {
131 | bytes.push(0x32);
132 | bytes.push(0x00);
133 | bytes.push(0x32);
134 | bytes.push(0x2e);
135 |
136 | let check;
137 |
138 | if (cval == 's') {
139 | bytes.push(0x00);
140 | check = 'r';
141 | }
142 | else if (cval == 't') {
143 | bytes.push(0x01);
144 | check = 'g';
145 | }
146 | else if (cval == 'u') {
147 | bytes.push(0x02);
148 | check = 'b';
149 | }
150 |
151 | if (this.numDevices > 3) {
152 | // Continuation of 4th fan from r/g/b runs
153 | bytes = bytes.concat(this.devices[3].getFrame()[check].slice(3));
154 |
155 | for (let i = 4; i < this.numDevices && i < 6; i++) {
156 | bytes = bytes.concat(this.devices[i].getFrame()[check]);
157 | }
158 | }
159 | }
160 |
161 | this.sendPkt(bytes);
162 | });
163 | }
164 |
165 |
166 | sendPkt(byteArray) {
167 | if (this.debug)
168 | this.prettyPrint(byteArray);
169 |
170 | let fullByteArray = this.make64(byteArray);
171 |
172 | return new Promise((resolve, reject) => {
173 | this.outEndpoint.transfer(Buffer.from(fullByteArray), err => {
174 | if (err) {
175 | return reject(err);
176 | }
177 |
178 | return resolve();
179 | });
180 | });
181 | }
182 |
183 | make64(byteArray) {
184 | while (byteArray.length < 64) {
185 | byteArray.push(0x00);
186 | }
187 |
188 | return byteArray;
189 | }
190 |
191 | async loop() {
192 | await this.sendPreamble();
193 |
194 | while (!this.exitLoop) {
195 | if (this.devices.some(d => d.changed)) {
196 | await this.setColors();
197 | }
198 |
199 | await this.sendPkt([0x33, 0xff]);
200 | }
201 | }
202 |
203 | async shutdown() {
204 | this.numDevices = 0;
205 | this.numDevicesShort = 0;
206 |
207 | await this.sendPreamble();
208 | // await this.setColors();
209 | //await this.sendPkt([0x33, 0xff]);
210 |
211 | // Reattach like a nice program
212 | // if we detached it.
213 | if (this.kernelDriverWasAttached) {
214 | this.iface.attachKernelDriver();
215 | }
216 |
217 | return new Promise((resolve, reject) => {
218 | this.iface.release(true, err => {
219 | if (err) {
220 | console.error(err);
221 | return reject(err);
222 | }
223 |
224 | this.usbDevice.close();
225 | return resolve();
226 | });
227 | });
228 | }
229 | }
230 |
--------------------------------------------------------------------------------
/lib/ll_fan.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | const frames = require('./frames.js');
4 |
5 | module.exports = class LLFan {
6 | constructor() {
7 | this.eventStack = [];
8 |
9 | this.framePointer = 0;
10 | this.frameRate = 1;
11 |
12 | this.changed = true;
13 | this.intervalTimer = null;
14 | }
15 |
16 | nextFrame() {
17 | if (this.eventStack.length == 1)
18 | return;
19 |
20 | if ((this.framePointer+1) == this.eventStack.length) {
21 | this.framePointer = 0;
22 |
23 | this.changed = true;
24 | }
25 | else {
26 | this.framePointer++;
27 |
28 | this.changed = true;
29 | }
30 | }
31 |
32 | setFramerate(fps) {
33 | this.frameRate = fps;
34 |
35 | if (this.intervalTimer) {
36 | clearInterval(this.intervalTimer);
37 | }
38 |
39 | this.intervalTimer = setInterval(() => {
40 | this.nextFrame();
41 | }, Math.floor((1/fps)*1000));
42 | }
43 |
44 | getFrame() {
45 | if (this.eventStack.length == 0)
46 | return frames.blankFrame();
47 |
48 | if (this.framePointer >= this.eventStack.length) {
49 | this.framePointer = 0;
50 | }
51 |
52 |
53 | if (this.changed)
54 | this.changed = false;
55 |
56 | return this.eventStack[this.framePointer];
57 | }
58 |
59 | turnOff() {
60 | this.framePointer = 0;
61 | this.eventStack = [frames.blankFrame()];
62 | }
63 |
64 | };
65 |
--------------------------------------------------------------------------------
/package-lock.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "lighting-node-pro",
3 | "version": "1.0.0",
4 | "lockfileVersion": 1,
5 | "requires": true,
6 | "dependencies": {
7 | "abbrev": {
8 | "version": "1.1.1",
9 | "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
10 | "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q=="
11 | },
12 | "ansi-regex": {
13 | "version": "2.1.1",
14 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
15 | "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8="
16 | },
17 | "aproba": {
18 | "version": "1.2.0",
19 | "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz",
20 | "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw=="
21 | },
22 | "are-we-there-yet": {
23 | "version": "1.1.5",
24 | "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz",
25 | "integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==",
26 | "requires": {
27 | "delegates": "1.0.0",
28 | "readable-stream": "2.3.6"
29 | }
30 | },
31 | "argv-tools": {
32 | "version": "0.1.1",
33 | "resolved": "https://registry.npmjs.org/argv-tools/-/argv-tools-0.1.1.tgz",
34 | "integrity": "sha512-Cc0dBvx4dvrjjKpyDA6w8RlNAw8Su30NvZbWl/Tv9ZALEVlLVkWQiHMi84Q0xNfpVuSaiQbYkdmWK8g1PLGhKw==",
35 | "requires": {
36 | "array-back": "2.0.0",
37 | "find-replace": "2.0.1"
38 | }
39 | },
40 | "array-back": {
41 | "version": "2.0.0",
42 | "resolved": "https://registry.npmjs.org/array-back/-/array-back-2.0.0.tgz",
43 | "integrity": "sha512-eJv4pLLufP3g5kcZry0j6WXpIbzYw9GUB4mVJZno9wfwiBxbizTnHCw3VJb07cBihbFX48Y7oSrW9y+gt4glyw==",
44 | "requires": {
45 | "typical": "2.6.1"
46 | }
47 | },
48 | "balanced-match": {
49 | "version": "1.0.0",
50 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
51 | "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c="
52 | },
53 | "brace-expansion": {
54 | "version": "1.1.11",
55 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
56 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
57 | "requires": {
58 | "balanced-match": "1.0.0",
59 | "concat-map": "0.0.1"
60 | }
61 | },
62 | "chownr": {
63 | "version": "1.1.1",
64 | "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.1.tgz",
65 | "integrity": "sha512-j38EvO5+LHX84jlo6h4UzmOwi0UgW61WRyPtJz4qaadK5eY3BTS5TY/S1Stc3Uk2lIM6TPevAlULiEJwie860g=="
66 | },
67 | "code-point-at": {
68 | "version": "1.1.0",
69 | "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz",
70 | "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c="
71 | },
72 | "command-line-args": {
73 | "version": "5.0.2",
74 | "resolved": "https://registry.npmjs.org/command-line-args/-/command-line-args-5.0.2.tgz",
75 | "integrity": "sha512-/qPcbL8zpqg53x4rAaqMFlRV4opN3pbla7I7k9x8kyOBMQoGT6WltjN6sXZuxOXw6DgdK7Ad+ijYS5gjcr7vlA==",
76 | "requires": {
77 | "argv-tools": "0.1.1",
78 | "array-back": "2.0.0",
79 | "find-replace": "2.0.1",
80 | "lodash.camelcase": "4.3.0",
81 | "typical": "2.6.1"
82 | }
83 | },
84 | "concat-map": {
85 | "version": "0.0.1",
86 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
87 | "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
88 | },
89 | "console-control-strings": {
90 | "version": "1.1.0",
91 | "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz",
92 | "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4="
93 | },
94 | "core-util-is": {
95 | "version": "1.0.2",
96 | "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
97 | "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac="
98 | },
99 | "debug": {
100 | "version": "2.6.9",
101 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
102 | "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
103 | "requires": {
104 | "ms": "2.0.0"
105 | }
106 | },
107 | "deep-extend": {
108 | "version": "0.6.0",
109 | "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz",
110 | "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA=="
111 | },
112 | "delegates": {
113 | "version": "1.0.0",
114 | "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz",
115 | "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o="
116 | },
117 | "detect-libc": {
118 | "version": "1.0.3",
119 | "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz",
120 | "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups="
121 | },
122 | "find-replace": {
123 | "version": "2.0.1",
124 | "resolved": "https://registry.npmjs.org/find-replace/-/find-replace-2.0.1.tgz",
125 | "integrity": "sha512-LzDo3Fpa30FLIBsh6DCDnMN1KW2g4QKkqKmejlImgWY67dDFPX/x9Kh/op/GK522DchQXEvDi/wD48HKW49XOQ==",
126 | "requires": {
127 | "array-back": "2.0.0",
128 | "test-value": "3.0.0"
129 | }
130 | },
131 | "fs-minipass": {
132 | "version": "1.2.5",
133 | "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.5.tgz",
134 | "integrity": "sha512-JhBl0skXjUPCFH7x6x61gQxrKyXsxB5gcgePLZCwfyCGGsTISMoIeObbrvVeP6Xmyaudw4TT43qV2Gz+iyd2oQ==",
135 | "requires": {
136 | "minipass": "2.3.5"
137 | }
138 | },
139 | "fs.realpath": {
140 | "version": "1.0.0",
141 | "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
142 | "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8="
143 | },
144 | "gauge": {
145 | "version": "2.7.4",
146 | "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz",
147 | "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=",
148 | "requires": {
149 | "aproba": "1.2.0",
150 | "console-control-strings": "1.1.0",
151 | "has-unicode": "2.0.1",
152 | "object-assign": "4.1.1",
153 | "signal-exit": "3.0.2",
154 | "string-width": "1.0.2",
155 | "strip-ansi": "3.0.1",
156 | "wide-align": "1.1.3"
157 | }
158 | },
159 | "glob": {
160 | "version": "7.1.3",
161 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz",
162 | "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==",
163 | "requires": {
164 | "fs.realpath": "1.0.0",
165 | "inflight": "1.0.6",
166 | "inherits": "2.0.3",
167 | "minimatch": "3.0.4",
168 | "once": "1.4.0",
169 | "path-is-absolute": "1.0.1"
170 | }
171 | },
172 | "has-unicode": {
173 | "version": "2.0.1",
174 | "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz",
175 | "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk="
176 | },
177 | "iconv-lite": {
178 | "version": "0.4.24",
179 | "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
180 | "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
181 | "requires": {
182 | "safer-buffer": "2.1.2"
183 | }
184 | },
185 | "ignore-walk": {
186 | "version": "3.0.1",
187 | "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-3.0.1.tgz",
188 | "integrity": "sha512-DTVlMx3IYPe0/JJcYP7Gxg7ttZZu3IInhuEhbchuqneY9wWe5Ojy2mXLBaQFUQmo0AW2r3qG7m1mg86js+gnlQ==",
189 | "requires": {
190 | "minimatch": "3.0.4"
191 | }
192 | },
193 | "inflight": {
194 | "version": "1.0.6",
195 | "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
196 | "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
197 | "requires": {
198 | "once": "1.4.0",
199 | "wrappy": "1.0.2"
200 | }
201 | },
202 | "inherits": {
203 | "version": "2.0.3",
204 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
205 | "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4="
206 | },
207 | "ini": {
208 | "version": "1.3.5",
209 | "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz",
210 | "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw=="
211 | },
212 | "is-fullwidth-code-point": {
213 | "version": "1.0.0",
214 | "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz",
215 | "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=",
216 | "requires": {
217 | "number-is-nan": "1.0.1"
218 | }
219 | },
220 | "isarray": {
221 | "version": "1.0.0",
222 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
223 | "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
224 | },
225 | "lodash.camelcase": {
226 | "version": "4.3.0",
227 | "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz",
228 | "integrity": "sha1-soqmKIorn8ZRA1x3EfZathkDMaY="
229 | },
230 | "minimatch": {
231 | "version": "3.0.4",
232 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
233 | "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
234 | "requires": {
235 | "brace-expansion": "1.1.11"
236 | }
237 | },
238 | "minimist": {
239 | "version": "0.0.8",
240 | "resolved": "http://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
241 | "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0="
242 | },
243 | "minipass": {
244 | "version": "2.3.5",
245 | "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.3.5.tgz",
246 | "integrity": "sha512-Gi1W4k059gyRbyVUZQ4mEqLm0YIUiGYfvxhF6SIlk3ui1WVxMTGfGdQ2SInh3PDrRTVvPKgULkpJtT4RH10+VA==",
247 | "requires": {
248 | "safe-buffer": "5.1.2",
249 | "yallist": "3.0.2"
250 | }
251 | },
252 | "minizlib": {
253 | "version": "1.1.1",
254 | "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.1.1.tgz",
255 | "integrity": "sha512-TrfjCjk4jLhcJyGMYymBH6oTXcWjYbUAXTHDbtnWHjZC25h0cdajHuPE1zxb4DVmu8crfh+HwH/WMuyLG0nHBg==",
256 | "requires": {
257 | "minipass": "2.3.5"
258 | }
259 | },
260 | "mkdirp": {
261 | "version": "0.5.1",
262 | "resolved": "http://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
263 | "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
264 | "requires": {
265 | "minimist": "0.0.8"
266 | }
267 | },
268 | "ms": {
269 | "version": "2.0.0",
270 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
271 | "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
272 | },
273 | "nan": {
274 | "version": "2.11.1",
275 | "resolved": "https://registry.npmjs.org/nan/-/nan-2.11.1.tgz",
276 | "integrity": "sha512-iji6k87OSXa0CcrLl9z+ZiYSuR2o+c0bGuNmXdrhTQTakxytAFsC56SArGYoiHlJlFoHSnvmhpceZJaXkVuOtA=="
277 | },
278 | "needle": {
279 | "version": "2.2.4",
280 | "resolved": "https://registry.npmjs.org/needle/-/needle-2.2.4.tgz",
281 | "integrity": "sha512-HyoqEb4wr/rsoaIDfTH2aVL9nWtQqba2/HvMv+++m8u0dz808MaagKILxtfeSN7QU7nvbQ79zk3vYOJp9zsNEA==",
282 | "requires": {
283 | "debug": "2.6.9",
284 | "iconv-lite": "0.4.24",
285 | "sax": "1.2.4"
286 | }
287 | },
288 | "node-pre-gyp": {
289 | "version": "0.10.3",
290 | "resolved": "https://registry.npmjs.org/node-pre-gyp/-/node-pre-gyp-0.10.3.tgz",
291 | "integrity": "sha512-d1xFs+C/IPS8Id0qPTZ4bUT8wWryfR/OzzAFxweG+uLN85oPzyo2Iw6bVlLQ/JOdgNonXLCoRyqDzDWq4iw72A==",
292 | "requires": {
293 | "detect-libc": "1.0.3",
294 | "mkdirp": "0.5.1",
295 | "needle": "2.2.4",
296 | "nopt": "4.0.1",
297 | "npm-packlist": "1.1.12",
298 | "npmlog": "4.1.2",
299 | "rc": "1.2.8",
300 | "rimraf": "2.6.2",
301 | "semver": "5.6.0",
302 | "tar": "4.4.6"
303 | }
304 | },
305 | "nopt": {
306 | "version": "4.0.1",
307 | "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.1.tgz",
308 | "integrity": "sha1-0NRoWv1UFRk8jHUFYC0NF81kR00=",
309 | "requires": {
310 | "abbrev": "1.1.1",
311 | "osenv": "0.1.5"
312 | }
313 | },
314 | "npm-bundled": {
315 | "version": "1.0.5",
316 | "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.0.5.tgz",
317 | "integrity": "sha512-m/e6jgWu8/v5niCUKQi9qQl8QdeEduFA96xHDDzFGqly0OOjI7c+60KM/2sppfnUU9JJagf+zs+yGhqSOFj71g=="
318 | },
319 | "npm-packlist": {
320 | "version": "1.1.12",
321 | "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-1.1.12.tgz",
322 | "integrity": "sha512-WJKFOVMeAlsU/pjXuqVdzU0WfgtIBCupkEVwn+1Y0ERAbUfWw8R4GjgVbaKnUjRoD2FoQbHOCbOyT5Mbs9Lw4g==",
323 | "requires": {
324 | "ignore-walk": "3.0.1",
325 | "npm-bundled": "1.0.5"
326 | }
327 | },
328 | "npmlog": {
329 | "version": "4.1.2",
330 | "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz",
331 | "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==",
332 | "requires": {
333 | "are-we-there-yet": "1.1.5",
334 | "console-control-strings": "1.1.0",
335 | "gauge": "2.7.4",
336 | "set-blocking": "2.0.0"
337 | }
338 | },
339 | "number-is-nan": {
340 | "version": "1.0.1",
341 | "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz",
342 | "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0="
343 | },
344 | "object-assign": {
345 | "version": "4.1.1",
346 | "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
347 | "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM="
348 | },
349 | "once": {
350 | "version": "1.4.0",
351 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
352 | "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
353 | "requires": {
354 | "wrappy": "1.0.2"
355 | }
356 | },
357 | "os-homedir": {
358 | "version": "1.0.2",
359 | "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz",
360 | "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M="
361 | },
362 | "os-tmpdir": {
363 | "version": "1.0.2",
364 | "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
365 | "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ="
366 | },
367 | "osenv": {
368 | "version": "0.1.5",
369 | "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz",
370 | "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==",
371 | "requires": {
372 | "os-homedir": "1.0.2",
373 | "os-tmpdir": "1.0.2"
374 | }
375 | },
376 | "path-is-absolute": {
377 | "version": "1.0.1",
378 | "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
379 | "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18="
380 | },
381 | "process-nextick-args": {
382 | "version": "2.0.0",
383 | "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz",
384 | "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw=="
385 | },
386 | "rc": {
387 | "version": "1.2.8",
388 | "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz",
389 | "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==",
390 | "requires": {
391 | "deep-extend": "0.6.0",
392 | "ini": "1.3.5",
393 | "minimist": "1.2.0",
394 | "strip-json-comments": "2.0.1"
395 | },
396 | "dependencies": {
397 | "minimist": {
398 | "version": "1.2.0",
399 | "resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
400 | "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ="
401 | }
402 | }
403 | },
404 | "readable-stream": {
405 | "version": "2.3.6",
406 | "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
407 | "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
408 | "requires": {
409 | "core-util-is": "1.0.2",
410 | "inherits": "2.0.3",
411 | "isarray": "1.0.0",
412 | "process-nextick-args": "2.0.0",
413 | "safe-buffer": "5.1.2",
414 | "string_decoder": "1.1.1",
415 | "util-deprecate": "1.0.2"
416 | }
417 | },
418 | "rgb-color": {
419 | "version": "2.1.2",
420 | "resolved": "https://registry.npmjs.org/rgb-color/-/rgb-color-2.1.2.tgz",
421 | "integrity": "sha512-KnyoQtNgZBn1tk9FQNLdFokLK/ozRHXcqI+VWR0AFUQX9OFUdw3Za89vwVGwmQrRBl9/cA3epAeJPiJ6es9gow=="
422 | },
423 | "rimraf": {
424 | "version": "2.6.2",
425 | "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz",
426 | "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==",
427 | "requires": {
428 | "glob": "7.1.3"
429 | }
430 | },
431 | "safe-buffer": {
432 | "version": "5.1.2",
433 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
434 | "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
435 | },
436 | "safer-buffer": {
437 | "version": "2.1.2",
438 | "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
439 | "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
440 | },
441 | "sax": {
442 | "version": "1.2.4",
443 | "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz",
444 | "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw=="
445 | },
446 | "semver": {
447 | "version": "5.6.0",
448 | "resolved": "https://registry.npmjs.org/semver/-/semver-5.6.0.tgz",
449 | "integrity": "sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg=="
450 | },
451 | "set-blocking": {
452 | "version": "2.0.0",
453 | "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
454 | "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc="
455 | },
456 | "signal-exit": {
457 | "version": "3.0.2",
458 | "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz",
459 | "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0="
460 | },
461 | "string-width": {
462 | "version": "1.0.2",
463 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
464 | "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",
465 | "requires": {
466 | "code-point-at": "1.1.0",
467 | "is-fullwidth-code-point": "1.0.0",
468 | "strip-ansi": "3.0.1"
469 | }
470 | },
471 | "string_decoder": {
472 | "version": "1.1.1",
473 | "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
474 | "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
475 | "requires": {
476 | "safe-buffer": "5.1.2"
477 | }
478 | },
479 | "strip-ansi": {
480 | "version": "3.0.1",
481 | "resolved": "http://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
482 | "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
483 | "requires": {
484 | "ansi-regex": "2.1.1"
485 | }
486 | },
487 | "strip-json-comments": {
488 | "version": "2.0.1",
489 | "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz",
490 | "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo="
491 | },
492 | "tar": {
493 | "version": "4.4.6",
494 | "resolved": "https://registry.npmjs.org/tar/-/tar-4.4.6.tgz",
495 | "integrity": "sha512-tMkTnh9EdzxyfW+6GK6fCahagXsnYk6kE6S9Gr9pjVdys769+laCTbodXDhPAjzVtEBazRgP0gYqOjnk9dQzLg==",
496 | "requires": {
497 | "chownr": "1.1.1",
498 | "fs-minipass": "1.2.5",
499 | "minipass": "2.3.5",
500 | "minizlib": "1.1.1",
501 | "mkdirp": "0.5.1",
502 | "safe-buffer": "5.1.2",
503 | "yallist": "3.0.2"
504 | }
505 | },
506 | "test-value": {
507 | "version": "3.0.0",
508 | "resolved": "https://registry.npmjs.org/test-value/-/test-value-3.0.0.tgz",
509 | "integrity": "sha512-sVACdAWcZkSU9x7AOmJo5TqE+GyNJknHaHsMrR6ZnhjVlVN9Yx6FjHrsKZ3BjIpPCT68zYesPWkakrNupwfOTQ==",
510 | "requires": {
511 | "array-back": "2.0.0",
512 | "typical": "2.6.1"
513 | }
514 | },
515 | "typical": {
516 | "version": "2.6.1",
517 | "resolved": "https://registry.npmjs.org/typical/-/typical-2.6.1.tgz",
518 | "integrity": "sha1-XAgOXWYcu+OCWdLnCjxyU+hziB0="
519 | },
520 | "usb": {
521 | "version": "1.3.3",
522 | "resolved": "https://registry.npmjs.org/usb/-/usb-1.3.3.tgz",
523 | "integrity": "sha512-WRBxI54yEs2QPj28G6kITI3Wu7VxrtHbqiDvDRUDKdg97lcK1pTP8y9LoDWF22OiCCrEvrdeq0lNcr84QOzjXQ==",
524 | "requires": {
525 | "nan": "2.11.1",
526 | "node-pre-gyp": "0.10.3"
527 | }
528 | },
529 | "util-deprecate": {
530 | "version": "1.0.2",
531 | "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
532 | "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
533 | },
534 | "wide-align": {
535 | "version": "1.1.3",
536 | "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz",
537 | "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==",
538 | "requires": {
539 | "string-width": "1.0.2"
540 | }
541 | },
542 | "wrappy": {
543 | "version": "1.0.2",
544 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
545 | "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
546 | },
547 | "yallist": {
548 | "version": "3.0.2",
549 | "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.2.tgz",
550 | "integrity": "sha1-hFK0u36Dx8GI2AQcGoN8dz1ti7k="
551 | }
552 | }
553 | }
554 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "lighting-node-pro",
3 | "version": "1.0.0",
4 | "description": "Lighting Node Pro controller",
5 | "main": "index.js",
6 | "directories": {
7 | "lib": "lib"
8 | },
9 | "dependencies": {
10 | "command-line-args": "^5.0.2",
11 | "rgb-color": "^2.1.2",
12 | "usb": "^1.3.3"
13 | },
14 | "devDependencies": {},
15 | "scripts": {
16 | "test": "echo \"Error: no test specified\" && exit 1"
17 | },
18 | "keywords": [],
19 | "author": "",
20 | "license": "MIT"
21 | }
22 |
--------------------------------------------------------------------------------