From 45e363536a89a4fd6cfa9373cbd9f9397c97de1e Mon Sep 17 00:00:00 2001 From: Lewis Diamond Date: Sat, 19 Dec 2020 19:34:27 -0500 Subject: [PATCH] Before cleanup --- package.json | 5 +- src/colors.js | 2 +- src/dbus.js | 2 +- src/index.js | 89 +++++++++++++++++++++++++++-------- src/logger.js | 22 +++++++++ src/mpd.js | 112 ++++++++++++++++++++++++++++++++++++-------- src/pulse.js | 95 ++++++++++++++++++++++++++++++++++++++ yarn.lock | 125 +++++++++++++++++++++++++++++++++++++++++++++++++- 8 files changed, 412 insertions(+), 40 deletions(-) create mode 100644 src/logger.js diff --git a/package.json b/package.json index ca1d4fd..8705b2e 100644 --- a/package.json +++ b/package.json @@ -7,8 +7,11 @@ "chroma-js": "^2.1.0", "dbus": "^1.0.7", "dbus-native": "^0.4.0", + "debug": "^4.3.1", "mpd": "^1.3.0", - "suncalc": "^1.8.0" + "paclient": "^0.0.2", + "suncalc": "^1.8.0", + "yargs": "^16.2.0" }, "devDependencies": { "prettier": "^2.1.2" diff --git a/src/colors.js b/src/colors.js index 4bc9923..83e0b06 100644 --- a/src/colors.js +++ b/src/colors.js @@ -8,7 +8,7 @@ const colors = { }; function brightness(color, pct) { - return chroma(color).set("hsv.v", pct); + return chroma(color).set("hsv.v", pct / 100); } module.exports = { diff --git a/src/dbus.js b/src/dbus.js index 38fbdff..089ed69 100644 --- a/src/dbus.js +++ b/src/dbus.js @@ -88,7 +88,7 @@ function staticMatrix(r, g, b, rows, cols) { } function setKey(matrix, row, col, r, g, b) { - const idx = row * (col + 1) * 3 + (col + 1) * 3; + const idx = row * (matrix.cols + 1) * 3 + (col + 1) * 3; matrix[idx] = r; matrix[idx + 1] = g; matrix[idx + 2] = b; diff --git a/src/index.js b/src/index.js index 0458d86..4c413cd 100755 --- a/src/index.js +++ b/src/index.js @@ -1,11 +1,54 @@ #!/bin/env node -const { execSync, spawnSync } = require("child_process"); +const debug = require("debug"); +const { spawnSync } = require("child_process"); +const yargs = require("yargs"); const suncalc = require("suncalc"); const dbus = require("./dbus"); +const pulse = require("./pulse"); +const mpd = require("./mpd"); const { colors, brightness } = require("./colors"); -const DANGEROUS_VOLUME = 40; -const AUDIO_NAME = "analog-surround-51"; -const MIC_NAME = "C-Media_Electronics_Inc._USB_PnP_Sound_Device"; + +const o = yargs.options({ + a: { + alias: "audio", + default: "analog-surround-51", + describe: "String used to match the pulse audio device", + type: "string", + }, + m: { + alias: ["mic", "record"], + default: "C-Media_Electronics_Inc._USB_PnP_Sound_Device", + describe: "String used to match the pulse microphone device", + type: "string", + }, + v: { + alias: "verbose", + default: 0, + describe: "Verbosity level, add more -v for more verbosity", + type: "count", + }, + mpdport: { + alias: "p", + default: 6600, + describe: "MPD port", + type: "number", + }, + mpdhost: { + alias: "h", + default: "localhost", + describe: "MPD Host", + type: "string", + }, +}).argv; +const AUDIO_NAME = o.a; +const MIC_NAME = o.m; + +const levels = ["*:error", "*:warn", "*:info", "*:log", "*:debug"].slice( + 0, + o.v + 1, +); + +debug.enable(levels.join(",")); function isNight() { const now = new Date(); @@ -14,18 +57,6 @@ function isNight() { return isnight; } -function setPlaying(matrix) { - const playing = !spawnSync("mpc | grep playing", { shell: true }).status; - [18, 19, 20].forEach(x => - dbus.setKey( - matrix, - 0, - x, - ...(playing ? colors.ALERT_COLOR.rgb() : colors.BASE_COLOR.rgb()), - ), - ); -} - function getBrightness() { return isNight() ? 60 : 100; } @@ -79,7 +110,7 @@ async function setAudio(matrix) { volume < DANGEROUS_VOLUME ? colors.BASE_COLOR.rgb() : colors.ALERT_COLOR.rgb(), - volume / 50, + (volume / 50) * 100, ); keys.forEach(x => dbus.setKey(matrix, 0, x, ...c.rgb())); } @@ -96,4 +127,26 @@ async function run() { dbus.disconnect(); } -run(); +async function daemon() { + const matrix = dbus.staticMatrix(...colors.BASE_COLOR.rgb(), 6, 22); + const setKey = (...args) => { + dbus.setKey(matrix, ...args); + }; + const interfaces = await dbus.connect(); + const draw = async () => await interfaces.chroma.setKeyRow(matrix); + + const mpdDisconnect = mpd( + { host: o.mpdhost, port: o.mpdport }, + setKey, + draw, + )(); + const p = pulse.connect({ out: AUDIO_NAME, mic: MIC_NAME, setKey, draw }); + + process.on("SIGINT", () => { + mpdDisconnect(); + dbus.disconnect(); + p.disconnect(); + }); +} + +daemon(); diff --git a/src/logger.js b/src/logger.js new file mode 100644 index 0000000..abae7f0 --- /dev/null +++ b/src/logger.js @@ -0,0 +1,22 @@ +const _debug = require("debug"); +const application = "kb.js"; + +module.exports = ({ prefix = "global" } = {}) => { + const log = _debug(`${application}:${prefix}:log`); + const debug = _debug(`${application}:${prefix}:debug`); + const info = _debug(`${application}:${prefix}:info`); + const error = _debug(`${application}:${prefix}:error`); + const warn = _debug(`${application}:${prefix}:warn`); + log.log = console.log.bind(console); + debug.log = console.log.bind(console); + info.log = console.info.bind(console); + warn.log = console.warn.bind(console); + error.log = console.error.bind(console); + return { + log, + debug, + info, + warn, + error, + }; +}; diff --git a/src/mpd.js b/src/mpd.js index 8a002d7..b824280 100644 --- a/src/mpd.js +++ b/src/mpd.js @@ -1,18 +1,94 @@ -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); - }); -}); +const { EventEmitter } = require("events"); +const net = require("net"); +const { spawnSync } = require("child_process"); +const { colors } = require("./colors"); +const { debug, log, info, error } = require("./logger")("mpd"); + +class Client extends EventEmitter { + socket; + constructor(host, port, retry = true) { + super(); + this.options = { host, port }; + this.connect(); + this.retry = retry; + } + + connect() { + if (this.socket) { + try { + this.socket.destroy(); + } catch (e) { + error(e); + } + } + this.socket = net.connect(this.options, this.onConnect.bind(this)); + this.socket.setEncoding("utf8"); + this.socket.on("data", this.onData.bind(this)); + this.socket.on("close", this.onClose.bind(this)); + this.socket.on("error", this.onError.bind(this)); + } + + close() { + this.retry = false; + this.socket.destroy(); + this.removeAllListeners(); + } + + onConnect(...args) { + this.emit("connect"); + this.socket.write("status\n"); + } + onData(m) { + debug("data", m); + if (m.includes("changed: player")) { + this.socket.write("status\n"); + } else if (m.includes("state: ")) { + this.emit("playing", m.includes("state: play")); + this.socket.write("idle player\n"); + } + } + onClose(...args) { + this.emit("playing", false); + if (this.retry) { + error("Retrying in close"); + setTimeout(this.connect.bind(this), 2000); + } + debug("close", ...args); + } + onError(...args) { + error("error", ...args); + this.emit("playing", false); + } +} + +module.exports = ({ host, port }, setKey, draw) => { + const setPlaying = playing => { + info("playing", playing); + [18, 19, 20].forEach(x => + setKey( + 0, + x, + ...(playing + ? colors.ALERT_COLOR.rgb() + : colors.BASE_COLOR.rgb()), + ), + ); + draw(); + }; + const connect = () => { + const c = new Client(host, port); + c.on("connect", () => { + info("Connected to MPD"); + }); + c.on("playing", setPlaying); + return () => { + try { + c.close(); + log("Closing mpd"); + } catch (e) { + error(e); + } + }; + }; + return connect; +}; diff --git a/src/pulse.js b/src/pulse.js index e69de29..a404a6c 100644 --- a/src/pulse.js +++ b/src/pulse.js @@ -0,0 +1,95 @@ +const PAClient = require("paclient"); +const { colors, brightness } = require("./colors"); +const { readFileSync } = require("fs"); +const DANGEROUS_VOLUME = 0.4; +function getFnFromType(type) { + var fn; + switch (type) { + case "sink": + case "card": + case "source": + fn = type; + break; + case "sinkInput": + case "sourceOutput": + case "client": + case "module": + fn = `${type}ByIndex`; + break; + default: + throw new Error("Unexpected type: " + type); + } + return "get" + fn[0].toUpperCase() + fn.slice(1); +} + +const setColor = (muted, volume, setKey) => { + const keys = [21]; + if (muted) { + keys.forEach(x => setKey(0, x, ...colors.SAFE_COLOR.rgb())); + } else if (volume === 0) { + keys.forEach(x => setKey(0, x, ...colors.BLUE.rgb())); + } else { + const c = brightness( + volume < DANGEROUS_VOLUME + ? colors.BASE_COLOR.rgb() + : colors.ALERT_COLOR.rgb(), + (volume / DANGEROUS_VOLUME) * 100, + ); + keys.forEach(x => setKey(0, x, ...c.rgb())); + } +}; +module.exports = { + connect({ + host = "127.0.0.1", + cookiePath = `${process.env.HOME}/.config/pulse/cookie`, + setKey = (...args) => { + console.log("setKey", ...args); + }, + draw = () => {}, + } = {}) { + const pa = new PAClient(); + const cookie = Buffer.from( + readFileSync(cookiePath, "binary"), + "binary", + ); + pa.connect({ host: "127.0.0.1", cookie }); + pa.on("ready", () => { + pa.subscribe(["sink", "source"]); + }) + .on("change", (type, index) => { + pa[getFnFromType(type)](index, (err, info) => { + if (err) { + return; + } + if (info.name.includes("analog-surround-51")) { + const { muted, baseVolume, channelVolumes } = info; + const vol = Math.max(...channelVolumes) / baseVolume; + setColor(muted, vol, setKey); + draw(); + } + if (info.name.includes("USB_PnP_Sound_Device")) { + const { muted } = info; + const c = muted + ? colors.BASE_COLOR + : colors.ALERT_COLOR; + + const rgb = c.rgb(); + for (let i = 0; i < 6; ++i) { + for (let j = 0; j < 18; ++j) { + setKey(i, j, ...rgb); + } + } + draw(); + } + }); + }) + .on("remove", (type, index) => { + console.log(`Removed ${type}, index #${index}`); + }); + return { + disconnect() { + pa.end(); + }, + }; + }, +}; diff --git a/yarn.lock b/yarn.lock index 16f27e0..d815425 100644 --- a/yarn.lock +++ b/yarn.lock @@ -10,6 +10,18 @@ abstract-socket@^2.0.0: bindings "^1.2.1" nan "^2.12.1" +ansi-regex@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.0.tgz#388539f55179bf39339c81af30a654d69f87cb75" + integrity sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg== + +ansi-styles@^4.0.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" + integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== + dependencies: + color-convert "^2.0.1" + bindings@^1.2.1: version "1.5.0" resolved "https://npm.dev.jogogo.co/bindings/-/bindings-1.5.0.tgz#10353c9e945334bc0511a6d90b38fbc7c9c504df" @@ -24,6 +36,27 @@ chroma-js@^2.1.0: dependencies: cross-env "^6.0.3" +cliui@^7.0.2: + version "7.0.4" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-7.0.4.tgz#a0265ee655476fc807aea9df3df8df7783808b4f" + integrity sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ== + dependencies: + string-width "^4.2.0" + strip-ansi "^6.0.0" + wrap-ansi "^7.0.0" + +color-convert@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" + integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== + dependencies: + color-name "~1.1.4" + +color-name@~1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" + integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== + cross-env@^6.0.3: version "6.0.3" resolved "https://npm.dev.jogogo.co/cross-env/-/cross-env-6.0.3.tgz#4256b71e49b3a40637a0ce70768a6ef5c72ae941" @@ -57,16 +90,33 @@ dbus-native@^0.4.0: dbus@^1.0.7: version "1.0.7" - resolved "https://npm.dev.jogogo.co/dbus/-/dbus-1.0.7.tgz#8ec719b0943f1e77deab2d13ce74a6e5e9839e83" + resolved "https://registry.yarnpkg.com/dbus/-/dbus-1.0.7.tgz#8ec719b0943f1e77deab2d13ce74a6e5e9839e83" integrity sha512-qba6/ajLoqzCy3Kl3aFgLXLP4TTf0qfgNjib1qoCJG/8HbSs0lDvxkz4nJU63CURZVzxvpK/VpQpT40KA8Kr3A== dependencies: nan "^2.14.0" +debug@^4.3.1: + version "4.3.1" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.1.tgz#f0d229c505e0c6d8c49ac553d1b13dc183f6b2ee" + integrity sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ== + dependencies: + ms "2.1.2" + 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== +emoji-regex@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" + integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== + +escalade@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" + integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== + event-stream@^4.0.0: version "4.0.1" resolved "https://npm.dev.jogogo.co/event-stream/-/event-stream-4.0.1.tgz#4092808ec995d0dd75ea4580c1df6a74db2cde65" @@ -90,11 +140,21 @@ from@^0.1.7: resolved "https://npm.dev.jogogo.co/from/-/from-0.1.7.tgz#83c60afc58b9c56997007ed1a768b3ab303a44fe" integrity sha1-g8YK/Fi5xWmXAH7Rp2izqzA6RP4= +get-caller-file@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" + integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== + 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== +is-fullwidth-code-point@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" + integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== + isexe@^2.0.0: version "2.0.0" resolved "https://npm.dev.jogogo.co/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" @@ -120,6 +180,11 @@ mpd@^1.3.0: resolved "https://registry.yarnpkg.com/mpd/-/mpd-1.3.0.tgz#a9a0e028f6808e5594f76fa9f0c574ad86f0c0dd" integrity sha1-qaDgKPaAjlWU92+p8MV0rYbwwN0= +ms@2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" + integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== + 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" @@ -133,6 +198,11 @@ optimist@^0.6.1: minimist "~0.0.1" wordwrap "~0.0.2" +paclient@^0.0.2: + version "0.0.2" + resolved "https://registry.yarnpkg.com/paclient/-/paclient-0.0.2.tgz#1ab74a4bb8aa8b4de0f492c2f2bfc7b28629a0a2" + integrity sha1-GrdKS7iqi03g9JLC8r/HsoYpoKI= + path-key@^3.1.0: version "3.1.1" resolved "https://npm.dev.jogogo.co/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" @@ -155,6 +225,11 @@ put@0.0.6: resolved "https://npm.dev.jogogo.co/put/-/put-0.0.6.tgz#30f5f60bd6e4389bd329e16a25386cbb2e4a00a3" integrity sha1-MPX2C9bkOJvTKeFqJThsuy5KAKM= +require-directory@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" + integrity sha1-jGStX9MNqxyXbiNE/+f3kqam30I= + safe-buffer@^5.1.1: version "5.2.1" resolved "https://npm.dev.jogogo.co/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" @@ -192,6 +267,22 @@ stream-combiner@^0.2.2: duplexer "~0.1.1" through "~2.3.4" +string-width@^4.1.0, string-width@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.0.tgz#952182c46cc7b2c313d1596e623992bd163b72b5" + integrity sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.0" + +strip-ansi@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.0.tgz#0b1571dd7669ccd4f3e06e14ef1eed26225ae532" + integrity sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w== + dependencies: + ansi-regex "^5.0.0" + suncalc@^1.8.0: version "1.8.0" resolved "https://npm.dev.jogogo.co/suncalc/-/suncalc-1.8.0.tgz#1d9898109563078750f4994a959e654d876acbf5" @@ -214,6 +305,15 @@ wordwrap@~0.0.2: resolved "https://npm.dev.jogogo.co/wordwrap/-/wordwrap-0.0.3.tgz#a3d5da6cd5c0bc0008d37234bbaf1bed63059107" integrity sha1-o9XabNXAvAAI03I0u68b7WMFkQc= +wrap-ansi@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + xml2js@^0.4.17: version "0.4.23" resolved "https://npm.dev.jogogo.co/xml2js/-/xml2js-0.4.23.tgz#a0c69516752421eb2ac758ee4d4ccf58843eac66" @@ -226,3 +326,26 @@ 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== + +y18n@^5.0.5: + version "5.0.5" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.5.tgz#8769ec08d03b1ea2df2500acef561743bbb9ab18" + integrity sha512-hsRUr4FFrvhhRH12wOdfs38Gy7k2FFzB9qgN9v3aLykRq0dRcdcpz5C9FxdS2NuhOrI/628b/KSTJ3rwHysYSg== + +yargs-parser@^20.2.2: + version "20.2.4" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.4.tgz#b42890f14566796f85ae8e3a25290d205f154a54" + integrity sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA== + +yargs@^16.2.0: + version "16.2.0" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-16.2.0.tgz#1c82bf0f6b6a66eafce7ef30e376f49a12477f66" + integrity sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw== + dependencies: + cliui "^7.0.2" + escalade "^3.1.1" + get-caller-file "^2.0.5" + require-directory "^2.1.1" + string-width "^4.2.0" + y18n "^5.0.5" + yargs-parser "^20.2.2"