From d7e01322a14c3a7731d91e8779dec019fd1c4c46 Mon Sep 17 00:00:00 2001 From: Lewis Diamond Date: Wed, 21 Oct 2020 19:56:04 -0400 Subject: [PATCH] init, all in 1 file --- .gitignore | 1 + .prettierrc | 6 ++ package.json | 16 ++++ src/colors.js | 17 ++++ src/dbus.js | 125 +++++++++++++++++++++++++++ src/index.js | 193 ++++++++++++++++++++++++++++++++++++++++++ src/mpd.js | 18 ++++ src/pulse.js | 0 yarn.lock | 228 ++++++++++++++++++++++++++++++++++++++++++++++++++ 9 files changed, 604 insertions(+) create mode 100644 .gitignore create mode 100644 .prettierrc create mode 100644 package.json create mode 100644 src/colors.js create mode 100644 src/dbus.js create mode 100755 src/index.js create mode 100644 src/mpd.js create mode 100644 src/pulse.js create mode 100644 yarn.lock diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c2658d7 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +node_modules/ diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..4432e33 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,6 @@ +{ + "trailingComma": "all", + "tabWidth": 4, + "printWidth": 80, + "arrowParens": "avoid" +} \ No newline at end of file diff --git a/package.json b/package.json new file mode 100644 index 0000000..ca1d4fd --- /dev/null +++ b/package.json @@ -0,0 +1,16 @@ +{ + "name": "keyboard", + "version": "1.0.0", + "main": "index.js", + "license": "MIT", + "dependencies": { + "chroma-js": "^2.1.0", + "dbus": "^1.0.7", + "dbus-native": "^0.4.0", + "mpd": "^1.3.0", + "suncalc": "^1.8.0" + }, + "devDependencies": { + "prettier": "^2.1.2" + } +} diff --git a/src/colors.js b/src/colors.js new file mode 100644 index 0000000..4bc9923 --- /dev/null +++ b/src/colors.js @@ -0,0 +1,17 @@ +const chroma = require("chroma-js"); +const colors = { + BASE_COLOR: chroma([186, 81, 0]), + WARNING_COLOR: chroma([150, 30, 30]), + ALERT_COLOR: chroma([250, 10, 10]), + SAFE_COLOR: chroma([10, 220, 30]), + BLUE: chroma([10, 20, 200]), +}; + +function brightness(color, pct) { + return chroma(color).set("hsv.v", pct); +} + +module.exports = { + colors, + brightness, +}; diff --git a/src/dbus.js b/src/dbus.js new file mode 100644 index 0000000..38fbdff --- /dev/null +++ b/src/dbus.js @@ -0,0 +1,125 @@ +const util = require("util"); +const dbus = require("dbus"); +const SERVICE_NAME = "org.razer"; +const OBJECT_PATH_DEVICES = "/org/razer"; +const OBJECT_PATH_DEVICE = "/org/razer/device/"; +const DEVICE = "IO2033F28201257"; +const INTERFACES = { + DEVICES: { + iface: "razer.devices", + methods: ["getDevices"], + path: OBJECT_PATH_DEVICES, + }, + BRIGHTNESS: { + iface: "razer.device.lighting.brightness", + methods: ["setBrightness", "getBrightness"], + path: OBJECT_PATH_DEVICE, + deviceSpecific: true, + }, + CHROMA: { + iface: "razer.device.lighting.chroma", + methods: [ + "setBreathDual", + "setBreathRandom", + "setBreathSingle", + "setCustom", + "setKeyRow", + "setNone", + "setReactive", + "setSpectrum", + "setStarlightDual", + "setStarlightRandom", + "setStarlightSingle", + "setStatic", + "setWave", + ], + path: OBJECT_PATH_DEVICE, + deviceSpecific: true, + }, + CUSTOM: { + iface: "razer.device.lighting.custom", + methods: ["setRipple", "setRippleRandomColour"], + path: OBJECT_PATH_DEVICE, + deviceSpecific: true, + }, + MACRO: { + iface: "razer.device.macro", + methods: ["addMacro", "deleteMacro", "getMacros"], + path: OBJECT_PATH_DEVICE, + deviceSpecific: true, + }, + MISC: { + iface: "razer.device.misc", + methods: [ + "getDeviceMode", + "getDeviceName", + "getDeviceType", + "getDriverVersion", + "getFirmware", + "getKeyboardLayout", + "getMatrixDimensions", + "getRazerUrls", + "getSerial", + "getVidPid", + "hasDedicatedMacroKeys", + "hasMatrix", + "resumeDevice", + "setDeviceMode", + "suspendDevice", + ], + path: OBJECT_PATH_DEVICE, + deviceSpecific: true, + }, +}; +function bindPromisify(obj, ...fn) { + fn.forEach(fn => (obj[fn] = util.promisify(obj[fn]).bind(obj))); +} + +function staticMatrix(r, g, b, rows, cols) { + const color = [r, g, b]; + const row = [].concat(00, 0x15, ...new Array(cols).fill(color)); + const matrix = []; + for (let i = 0; i < rows; ++i) { + matrix.push(...[i, ...row]); + } + matrix.rows = rows; + matrix.cols = cols; + return matrix; +} + +function setKey(matrix, row, col, r, g, b) { + const idx = row * (col + 1) * 3 + (col + 1) * 3; + matrix[idx] = r; + matrix[idx + 1] = g; + matrix[idx + 2] = b; +} + +module.exports = { + connect(device = DEVICE) { + bus = this.bus = dbus.getBus("session"); + + this.getInterface = util.promisify(bus.getInterface).bind(bus); + return this.initializeDeviceInterfaces(device); + }, + async initializeDeviceInterfaces(device) { + const interfaces = {}; + const p = Object.entries(INTERFACES).map( + async ([label, { iface, path, methods, deviceSpecific }]) => { + const interface = await this.getInterface( + SERVICE_NAME, + deviceSpecific ? path + device : path, + iface, + ); + bindPromisify(interface, ...methods); + interfaces[label.toLowerCase()] = interface; + }, + ); + await Promise.all(p); + return interfaces; + }, + disconnect() { + this.bus.disconnect(); + }, + staticMatrix, + setKey, +}; diff --git a/src/index.js b/src/index.js new file mode 100755 index 0000000..52c2582 --- /dev/null +++ b/src/index.js @@ -0,0 +1,193 @@ +#!/bin/env node +const { execSync, spawnSync } = require("child_process"); +const chroma = require("chroma-js"); +const suncalc = require("suncalc"); +const util = require("util"); +const dbus = require("dbus"); +const bus = dbus.getBus("session"); +const SERVICE_NAME = "org.razer"; +const OBJECT_PATH_DEVICES = "/org/razer"; +const OBJECT_PATH_DEVICE = "/org/razer/device/"; +const DEVICE = "IO2033F28201257"; +const DANGEROUS_VOLUME = 40; +const BASE_COLOR = [186, 81, 0]; +const WARNING_COLOR = [150, 30, 30]; +const ALERT_COLOR = [250, 10, 10]; +const SAFE_COLOR = [10, 220, 30]; +const BLUE = [10, 20, 200]; +const AUDIO_NAME = "analog-surround-51"; +const MIC_NAME = "C-Media_Electronics_Inc._USB_PnP_Sound_Device"; +const INTERFACES = { + DEVICES: { + iface: "razer.devices", + methods: ["getDevices"], + path: OBJECT_PATH_DEVICES, + }, + BRIGHTNESS: { + iface: "razer.device.lighting.brightness", + methods: ["setBrightness", "getBrightness"], + path: OBJECT_PATH_DEVICE + DEVICE, + }, + CHROMA: { + iface: "razer.device.lighting.chroma", + methods: [ + "setBreathDual", + "setBreathRandom", + "setBreathSingle", + "setCustom", + "setKeyRow", + "setNone", + "setReactive", + "setSpectrum", + "setStarlightDual", + "setStarlightRandom", + "setStarlightSingle", + "setStatic", + "setWave", + ], + path: OBJECT_PATH_DEVICE + DEVICE, + }, + CUSTOM: { + iface: "razer.device.lighting.custom", + methods: ["setRipple", "setRippleRandomColour"], + path: OBJECT_PATH_DEVICE + DEVICE, + }, + MACRO: { + iface: "razer.device.macro", + methods: ["addMacro", "deleteMacro", "getMacros"], + path: OBJECT_PATH_DEVICE + DEVICE, + }, + MISC: { + iface: "razer.device.misc", + methods: [ + "getDeviceMode", + "getDeviceName", + "getDeviceType", + "getDriverVersion", + "getFirmware", + "getKeyboardLayout", + "getMatrixDimensions", + "getRazerUrls", + "getSerial", + "getVidPid", + "hasDedicatedMacroKeys", + "hasMatrix", + "resumeDevice", + "setDeviceMode", + "suspendDevice", + ], + path: OBJECT_PATH_DEVICE + DEVICE, + }, +}; + +function isNight() { + const now = new Date(); + const night = suncalc.getTimes(now, 45.524128, -73.735409); + const isnight = now >= night.sunset || now <= night.sunrise; + return isnight; +} + +const getInterface = util.promisify(bus.getInterface).bind(bus); +const interfaces = {}; +function bindPromisify(obj, ...fn) { + fn.forEach(fn => (obj[fn] = util.promisify(obj[fn]).bind(obj))); +} +async function initializeDeviceInterfaces() { + const p = Object.entries(INTERFACES).map( + async ([label, { iface, path, methods }]) => { + const interface = await getInterface(SERVICE_NAME, path, iface); + bindPromisify(interface, ...methods); + interfaces[label.toLowerCase()] = interface; + }, + ); + await Promise.all(p); +} +async function initialize() { + await initializeDeviceInterfaces(); +} + +function staticMatrix(r, g, b, rows, cols) { + const color = [r, g, b]; + const row = [].concat(00, 0x15, ...new Array(cols).fill(color)); + const matrix = []; + for (let i = 0; i < rows; ++i) { + matrix.push(...[i, ...row]); + } + matrix.rows = rows; + matrix.cols = cols; + return matrix; +} +function setKey(matrix, row, col, r, g, b) { + const idx = row * (col + 1) * 3 + (col + 1) * 3; + matrix[idx] = r; + matrix[idx + 1] = g; + matrix[idx + 2] = b; +} + +function setPlaying(matrix) { + const playing = !spawnSync("mpc | grep playing", { shell: true }).status; + [18, 19, 20].forEach(x => + setKey(matrix, 0, x, ...(playing ? ALERT_COLOR : BASE_COLOR)), + ); +} + +function getBrightness() { + console.log(isNight()); + return isNight() ? 60 : 100; +} +const volume = + (Math.min( + parseInt( + spawnSync( + `pactl list | grep -E "Name: .*${AUDIO_NAME}$|Volume" | grep "Name:" -A1 | tail -1 | cut -d% -f1 | cut -d/ -f2 | tr -d " "`, + { shell: true }, + ).stdout, + ), + 30, + ) / + 30) * + 100; +async function setMutedMic() { + const muted = !spawnSync( + `pacmd dump | grep ^set-source-mute.*${MIC_NAME}.*yes`, + { shell: true }, + ).status; + await interfaces.brightness.setBrightness(muted ? getBrightness() : 100); + return staticMatrix(...(muted ? BASE_COLOR : ALERT_COLOR), 6, 22); +} + +async function setAudio(matrix) { + const keys = [21]; + const muted = !spawnSync( + `pacmd dump | grep ^set-sink-mute.*${AUDIO_NAME}.*yes`, + { shell: true }, + ).status; + if (muted) { + keys.forEach(x => setKey(matrix, 0, x, ...SAFE_COLOR)); + } else if (volume === 0) { + keys.forEach(x => setKey(matrix, 0, x, ...BLUE)); + } else { + const volume = parseInt( + spawnSync( + `pactl list | grep -E "Name: .*${AUDIO_NAME}$|Volume" | grep "Name:" -A1 | tail -1 | cut -d% -f1 | cut -d/ -f2 | tr -d " "`, + { shell: true }, + ).stdout, + ); + const c = chroma(volume < DANGEROUS_VOLUME ? BASE_COLOR : ALERT_COLOR) + .set("hsv.v", volume / 50) + .rgb(); + keys.forEach(x => setKey(matrix, 0, x, ...c)); + } +} + +async function run() { + await initialize(); + + const matrix = await setMutedMic(); + setAudio(matrix); + setPlaying(matrix); + await interfaces.chroma.setKeyRow(matrix); + bus.disconnect(); +} + +run(); diff --git a/src/mpd.js b/src/mpd.js new file mode 100644 index 0000000..8a002d7 --- /dev/null +++ b/src/mpd.js @@ -0,0 +1,18 @@ +var mpd = require('mpd'), + cmd = mpd.cmd +var client = mpd.connect({ + port: 6600, + host: 'localhost', +}); +client.on('ready', function() { + console.log("ready"); +}); +client.on('system', function(name) { + console.log("update", name); +}); +client.on('system-player', function() { + client.sendCommand(cmd("status", []), function(err, msg) { + if (err) throw err; + console.log(msg); + }); +}); diff --git a/src/pulse.js b/src/pulse.js new file mode 100644 index 0000000..e69de29 diff --git a/yarn.lock b/yarn.lock new file mode 100644 index 0000000..16f27e0 --- /dev/null +++ b/yarn.lock @@ -0,0 +1,228 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +abstract-socket@^2.0.0: + version "2.1.1" + resolved "https://npm.dev.jogogo.co/abstract-socket/-/abstract-socket-2.1.1.tgz#243a7e6e6ff65bb9eab16a22fa90699b91e528f7" + integrity sha512-YZJizsvS1aBua5Gd01woe4zuyYBGgSMeqDOB6/ChwdTI904KP6QGtJswXl4hcqWxbz86hQBe++HWV0hF1aGUtA== + dependencies: + bindings "^1.2.1" + nan "^2.12.1" + +bindings@^1.2.1: + version "1.5.0" + resolved "https://npm.dev.jogogo.co/bindings/-/bindings-1.5.0.tgz#10353c9e945334bc0511a6d90b38fbc7c9c504df" + integrity sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ== + dependencies: + file-uri-to-path "1.0.0" + +chroma-js@^2.1.0: + version "2.1.0" + resolved "https://npm.dev.jogogo.co/chroma-js/-/chroma-js-2.1.0.tgz#c0be48a21fe797ef8965608c1c4f911ef2da49d5" + integrity sha512-uiRdh4ZZy+UTPSrAdp8hqEdVb1EllLtTHOt5TMaOjJUvi+O54/83Fc5K2ld1P+TJX+dw5B+8/sCgzI6eaur/lg== + dependencies: + cross-env "^6.0.3" + +cross-env@^6.0.3: + version "6.0.3" + resolved "https://npm.dev.jogogo.co/cross-env/-/cross-env-6.0.3.tgz#4256b71e49b3a40637a0ce70768a6ef5c72ae941" + integrity sha512-+KqxF6LCvfhWvADcDPqo64yVIB31gv/jQulX2NGzKS/g3GEVz6/pt4wjHFtFWsHMddebWD/sDthJemzM4MaAag== + dependencies: + cross-spawn "^7.0.0" + +cross-spawn@^7.0.0: + version "7.0.3" + resolved "https://npm.dev.jogogo.co/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" + integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== + dependencies: + path-key "^3.1.0" + shebang-command "^2.0.0" + which "^2.0.1" + +dbus-native@^0.4.0: + version "0.4.0" + resolved "https://npm.dev.jogogo.co/dbus-native/-/dbus-native-0.4.0.tgz#2fea91da60db3073272b18735245e23ea6b84940" + integrity sha512-i3zvY3tdPEOaMgmK4riwupjDYRJ53rcE1Kj8rAgnLOFmBd0DekUih59qv8v+Oyils/U9p+s4sSsaBzHWLztI+Q== + dependencies: + event-stream "^4.0.0" + hexy "^0.2.10" + long "^4.0.0" + optimist "^0.6.1" + put "0.0.6" + safe-buffer "^5.1.1" + xml2js "^0.4.17" + optionalDependencies: + abstract-socket "^2.0.0" + +dbus@^1.0.7: + version "1.0.7" + resolved "https://npm.dev.jogogo.co/dbus/-/dbus-1.0.7.tgz#8ec719b0943f1e77deab2d13ce74a6e5e9839e83" + integrity sha512-qba6/ajLoqzCy3Kl3aFgLXLP4TTf0qfgNjib1qoCJG/8HbSs0lDvxkz4nJU63CURZVzxvpK/VpQpT40KA8Kr3A== + dependencies: + nan "^2.14.0" + +duplexer@^0.1.1, duplexer@~0.1.1: + version "0.1.2" + resolved "https://npm.dev.jogogo.co/duplexer/-/duplexer-0.1.2.tgz#3abe43aef3835f8ae077d136ddce0f276b0400e6" + integrity sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg== + +event-stream@^4.0.0: + version "4.0.1" + resolved "https://npm.dev.jogogo.co/event-stream/-/event-stream-4.0.1.tgz#4092808ec995d0dd75ea4580c1df6a74db2cde65" + integrity sha512-qACXdu/9VHPBzcyhdOWR5/IahhGMf0roTeZJfzz077GwylcDd90yOHLouhmv7GJ5XzPi6ekaQWd8AvPP2nOvpA== + dependencies: + duplexer "^0.1.1" + from "^0.1.7" + map-stream "0.0.7" + pause-stream "^0.0.11" + split "^1.0.1" + stream-combiner "^0.2.2" + through "^2.3.8" + +file-uri-to-path@1.0.0: + version "1.0.0" + resolved "https://npm.dev.jogogo.co/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz#553a7b8446ff6f684359c445f1e37a05dacc33dd" + integrity sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw== + +from@^0.1.7: + version "0.1.7" + resolved "https://npm.dev.jogogo.co/from/-/from-0.1.7.tgz#83c60afc58b9c56997007ed1a768b3ab303a44fe" + integrity sha1-g8YK/Fi5xWmXAH7Rp2izqzA6RP4= + +hexy@^0.2.10: + version "0.2.11" + resolved "https://npm.dev.jogogo.co/hexy/-/hexy-0.2.11.tgz#9939c25cb6f86a91302f22b8a8a72573518e25b4" + integrity sha512-ciq6hFsSG/Bpt2DmrZJtv+56zpPdnq+NQ4ijEFrveKN0ZG1mhl/LdT1NQZ9se6ty1fACcI4d4vYqC9v8EYpH2A== + +isexe@^2.0.0: + version "2.0.0" + resolved "https://npm.dev.jogogo.co/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= + +long@^4.0.0: + version "4.0.0" + resolved "https://npm.dev.jogogo.co/long/-/long-4.0.0.tgz#9a7b71cfb7d361a194ea555241c92f7468d5bf28" + integrity sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA== + +map-stream@0.0.7: + version "0.0.7" + resolved "https://npm.dev.jogogo.co/map-stream/-/map-stream-0.0.7.tgz#8a1f07896d82b10926bd3744a2420009f88974a8" + integrity sha1-ih8HiW2CsQkmvTdEokIACfiJdKg= + +minimist@~0.0.1: + version "0.0.10" + resolved "https://npm.dev.jogogo.co/minimist/-/minimist-0.0.10.tgz#de3f98543dbf96082be48ad1a0c7cda836301dcf" + integrity sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8= + +mpd@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/mpd/-/mpd-1.3.0.tgz#a9a0e028f6808e5594f76fa9f0c574ad86f0c0dd" + integrity sha1-qaDgKPaAjlWU92+p8MV0rYbwwN0= + +nan@^2.12.1, nan@^2.14.0: + version "2.14.2" + resolved "https://npm.dev.jogogo.co/nan/-/nan-2.14.2.tgz#f5376400695168f4cc694ac9393d0c9585eeea19" + integrity sha512-M2ufzIiINKCuDfBSAUr1vWQ+vuVcA9kqx8JJUsbQi6yf1uGRyb7HfpdfUr5qLXf3B/t8dPvcjhKMmlfnP47EzQ== + +optimist@^0.6.1: + version "0.6.1" + resolved "https://npm.dev.jogogo.co/optimist/-/optimist-0.6.1.tgz#da3ea74686fa21a19a111c326e90eb15a0196686" + integrity sha1-2j6nRob6IaGaERwybpDrFaAZZoY= + dependencies: + minimist "~0.0.1" + wordwrap "~0.0.2" + +path-key@^3.1.0: + version "3.1.1" + resolved "https://npm.dev.jogogo.co/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" + integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== + +pause-stream@^0.0.11: + version "0.0.11" + resolved "https://npm.dev.jogogo.co/pause-stream/-/pause-stream-0.0.11.tgz#fe5a34b0cbce12b5aa6a2b403ee2e73b602f1445" + integrity sha1-/lo0sMvOErWqaitAPuLnO2AvFEU= + dependencies: + through "~2.3" + +prettier@^2.1.2: + version "2.1.2" + resolved "https://npm.dev.jogogo.co/prettier/-/prettier-2.1.2.tgz#3050700dae2e4c8b67c4c3f666cdb8af405e1ce5" + integrity sha512-16c7K+x4qVlJg9rEbXl7HEGmQyZlG4R9AgP+oHKRMsMsuk8s+ATStlf1NpDqyBI1HpVyfjLOeMhH2LvuNvV5Vg== + +put@0.0.6: + version "0.0.6" + resolved "https://npm.dev.jogogo.co/put/-/put-0.0.6.tgz#30f5f60bd6e4389bd329e16a25386cbb2e4a00a3" + integrity sha1-MPX2C9bkOJvTKeFqJThsuy5KAKM= + +safe-buffer@^5.1.1: + version "5.2.1" + resolved "https://npm.dev.jogogo.co/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" + integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== + +sax@>=0.6.0: + version "1.2.4" + resolved "https://npm.dev.jogogo.co/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" + integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== + +shebang-command@^2.0.0: + version "2.0.0" + resolved "https://npm.dev.jogogo.co/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" + integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== + dependencies: + shebang-regex "^3.0.0" + +shebang-regex@^3.0.0: + version "3.0.0" + resolved "https://npm.dev.jogogo.co/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" + integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== + +split@^1.0.1: + version "1.0.1" + resolved "https://npm.dev.jogogo.co/split/-/split-1.0.1.tgz#605bd9be303aa59fb35f9229fbea0ddec9ea07d9" + integrity sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg== + dependencies: + through "2" + +stream-combiner@^0.2.2: + version "0.2.2" + resolved "https://npm.dev.jogogo.co/stream-combiner/-/stream-combiner-0.2.2.tgz#aec8cbac177b56b6f4fa479ced8c1912cee52858" + integrity sha1-rsjLrBd7Vrb0+kec7YwZEs7lKFg= + dependencies: + duplexer "~0.1.1" + through "~2.3.4" + +suncalc@^1.8.0: + version "1.8.0" + resolved "https://npm.dev.jogogo.co/suncalc/-/suncalc-1.8.0.tgz#1d9898109563078750f4994a959e654d876acbf5" + integrity sha1-HZiYEJVjB4dQ9JlKlZ5lTYdqy/U= + +through@2, through@^2.3.8, through@~2.3, through@~2.3.4: + version "2.3.8" + resolved "https://npm.dev.jogogo.co/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" + integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU= + +which@^2.0.1: + version "2.0.2" + resolved "https://npm.dev.jogogo.co/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" + integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== + dependencies: + isexe "^2.0.0" + +wordwrap@~0.0.2: + version "0.0.3" + resolved "https://npm.dev.jogogo.co/wordwrap/-/wordwrap-0.0.3.tgz#a3d5da6cd5c0bc0008d37234bbaf1bed63059107" + integrity sha1-o9XabNXAvAAI03I0u68b7WMFkQc= + +xml2js@^0.4.17: + version "0.4.23" + resolved "https://npm.dev.jogogo.co/xml2js/-/xml2js-0.4.23.tgz#a0c69516752421eb2ac758ee4d4ccf58843eac66" + integrity sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug== + dependencies: + sax ">=0.6.0" + xmlbuilder "~11.0.0" + +xmlbuilder@~11.0.0: + version "11.0.1" + resolved "https://npm.dev.jogogo.co/xmlbuilder/-/xmlbuilder-11.0.1.tgz#be9bae1c8a046e76b31127726347d0ad7002beb3" + integrity sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==