init, all in 1 file

This commit is contained in:
Lewis Diamond 2020-10-21 19:56:04 -04:00
commit d7e01322a1
9 changed files with 604 additions and 0 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
node_modules/

6
.prettierrc Normal file
View File

@ -0,0 +1,6 @@
{
"trailingComma": "all",
"tabWidth": 4,
"printWidth": 80,
"arrowParens": "avoid"
}

16
package.json Normal file
View File

@ -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"
}
}

17
src/colors.js Normal file
View File

@ -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,
};

125
src/dbus.js Normal file
View File

@ -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,
};

193
src/index.js Executable file
View File

@ -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();

18
src/mpd.js Normal file
View File

@ -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);
});
});

0
src/pulse.js Normal file
View File

228
yarn.lock Normal file
View File

@ -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==