Index: frontend/node_modules/default-gateway/LICENSE
===================================================================
--- frontend/node_modules/default-gateway/LICENSE	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/default-gateway/LICENSE	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,22 @@
+Copyright (c) silverwind
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+   list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+   this list of conditions and the following disclaimer in the documentation
+   and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Index: frontend/node_modules/default-gateway/README.md
===================================================================
--- frontend/node_modules/default-gateway/README.md	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/default-gateway/README.md	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,51 @@
+# default-gateway
+[![](https://img.shields.io/npm/v/default-gateway.svg?style=flat)](https://www.npmjs.org/package/default-gateway) [![](https://img.shields.io/npm/dm/default-gateway.svg)](https://www.npmjs.org/package/default-gateway)
+
+Obtains the machine's default gateway through `exec` calls to OS routing interfaces.
+
+- On Linux and Android, the `ip` command must be available (usually provided by the `iproute2` package).
+- On Windows, `wmic` must be available.
+- On IBM i, the `db2util` command must be available (provided by the `db2util` package).
+- On Unix (and macOS), the `netstat` command must be available.
+
+## Installation
+
+```
+$ npm i default-gateway
+```
+
+## Example
+
+```js
+const defaultGateway = require('default-gateway');
+
+const {gateway, interface} = await defaultGateway.v4();
+// gateway = '1.2.3.4', interface = 'en1'
+
+const {gateway, interface} = await defaultGateway.v6();
+// gateway = '2001:db8::1', interface = 'en2'
+
+const {gateway, interface} = defaultGateway.v4.sync();
+// gateway = '1.2.3.4', interface = 'en1'
+
+const {gateway, interface} = defaultGateway.v6.sync();
+// gateway = '2001:db8::1', interface = 'en2'
+```
+
+## API
+### defaultGateway.v4()
+### defaultGateway.v6()
+### defaultGateway.v4.sync()
+### defaultGateway.v6.sync()
+
+Returns: `result` *Object*
+  - `gateway`: The IP address of the default gateway.
+  - `interface`: The name of the interface. On Windows, this is the network adapter name.
+
+The `.v{4,6}()` methods return a Promise while the `.v{4,6}.sync()` variants will return the result synchronously.
+
+The `gateway` property will always be defined on success, while `interface` can be `null` if it cannot be determined. All methods reject/throw on unexpected conditions.
+
+## License
+
+© [silverwind](https://github.com/silverwind), distributed under BSD licence
Index: frontend/node_modules/default-gateway/android.js
===================================================================
--- frontend/node_modules/default-gateway/android.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/default-gateway/android.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,43 @@
+"use strict";
+
+const {isIP} = require("net");
+const execa = require("execa");
+
+const args = {
+  v4: ["-4", "r"],
+  v6: ["-6", "r"],
+};
+
+const parse = stdout => {
+  let result;
+
+  (stdout || "").trim().split("\n").some(line => {
+    const [_, gateway, iface] = /default via (.+?) dev (.+?)( |$)/.exec(line) || [];
+    if (gateway && isIP(gateway)) {
+      result = {gateway, interface: (iface ? iface : null)};
+      return true;
+    }
+  });
+
+  if (!result) {
+    throw new Error("Unable to determine default gateway");
+  }
+
+  return result;
+};
+
+const promise = async family => {
+  const {stdout} = await execa("ip", args[family]);
+  return parse(stdout, family);
+};
+
+const sync = family => {
+  const {stdout} = execa.sync("ip", args[family]);
+  return parse(stdout);
+};
+
+module.exports.v4 = () => promise("v4");
+module.exports.v6 = () => promise("v6");
+
+module.exports.v4.sync = () => sync("v4");
+module.exports.v6.sync = () => sync("v6");
Index: frontend/node_modules/default-gateway/darwin.js
===================================================================
--- frontend/node_modules/default-gateway/darwin.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/default-gateway/darwin.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,52 @@
+"use strict";
+
+const {isIP} = require("net");
+const {release} = require("os");
+const execa = require("execa");
+const dests = new Set(["default", "0.0.0.0", "0.0.0.0/0", "::", "::/0"]);
+
+const args = {
+  v4: ["-rn", "-f", "inet"],
+  v6: ["-rn", "-f", "inet6"],
+};
+
+// The IPv4 gateway is in column 3 in Darwin 19 (macOS 10.15 Catalina) and higher,
+// previously it was in column 5
+const v4IfaceColumn = parseInt(release()) >= 19 ? 3 : 5;
+
+const parse = (stdout, family) => {
+  let result;
+
+  (stdout || "").trim().split("\n").some(line => {
+    const results = line.split(/ +/) || [];
+    const target = results[0];
+    const gateway = results[1];
+    const iface = results[family === "v4" ? v4IfaceColumn : 3];
+    if (dests.has(target) && gateway && isIP(gateway)) {
+      result = {gateway, interface: (iface ? iface : null)};
+      return true;
+    }
+  });
+
+  if (!result) {
+    throw new Error("Unable to determine default gateway");
+  }
+
+  return result;
+};
+
+const promise = async family => {
+  const {stdout} = await execa("netstat", args[family]);
+  return parse(stdout, family);
+};
+
+const sync = family => {
+  const {stdout} = execa.sync("netstat", args[family]);
+  return parse(stdout, family);
+};
+
+module.exports.v4 = () => promise("v4");
+module.exports.v6 = () => promise("v6");
+
+module.exports.v4.sync = () => sync("v4");
+module.exports.v6.sync = () => sync("v6");
Index: frontend/node_modules/default-gateway/freebsd.js
===================================================================
--- frontend/node_modules/default-gateway/freebsd.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/default-gateway/freebsd.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,44 @@
+"use strict";
+
+const {isIP} = require("net");
+const execa = require("execa");
+const dests = new Set(["default", "0.0.0.0", "0.0.0.0/0", "::", "::/0"]);
+
+const args = {
+  v4: ["-rn", "-f", "inet"],
+  v6: ["-rn", "-f", "inet6"],
+};
+
+const parse = stdout => {
+  let result;
+
+  (stdout || "").trim().split("\n").some(line => {
+    const [target, gateway, _, iface] = line.split(/ +/) || [];
+    if (dests.has(target) && gateway && isIP(gateway)) {
+      result = {gateway, interface: (iface ? iface : null)};
+      return true;
+    }
+  });
+
+  if (!result) {
+    throw new Error("Unable to determine default gateway");
+  }
+
+  return result;
+};
+
+const promise = async family => {
+  const {stdout} = await execa("netstat", args[family]);
+  return parse(stdout);
+};
+
+const sync = family => {
+  const {stdout} = execa.sync("netstat", args[family]);
+  return parse(stdout);
+};
+
+module.exports.v4 = () => promise("v4");
+module.exports.v6 = () => promise("v6");
+
+module.exports.v4.sync = () => sync("v4");
+module.exports.v6.sync = () => sync("v6");
Index: frontend/node_modules/default-gateway/ibmi.js
===================================================================
--- frontend/node_modules/default-gateway/ibmi.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/default-gateway/ibmi.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,36 @@
+"use strict";
+
+const execa = require("execa");
+
+const db2util = "/QOpenSys/pkgs/bin/db2util";
+const sql = "select NEXT_HOP, LOCAL_BINDING_INTERFACE from QSYS2.NETSTAT_ROUTE_INFO where ROUTE_TYPE='DFTROUTE' and NEXT_HOP!='*DIRECT' and CONNECTION_TYPE=?";
+
+const parse = stdout => {
+  let result;
+  try {
+    const resultObj = JSON.parse(stdout);
+    const gateway = resultObj.records[0].NEXT_HOP;
+    const iface = resultObj.records[0].LOCAL_BINDING_INTERFACE;
+    result = {gateway, iface};
+  } catch {}
+  if (!result) {
+    throw new Error("Unable to determine default gateway");
+  }
+  return result;
+};
+
+const promise = async family => {
+  const {stdout} = await execa(db2util, [sql, "-p", family, "-o", "json"]);
+  return parse(stdout);
+};
+
+const sync = family => {
+  const {stdout} = execa.sync(db2util, [sql, "-p", family, "-o", "json"]);
+  return parse(stdout);
+};
+
+module.exports.v4 = () => promise("IPV4");
+module.exports.v6 = () => promise("IPV6");
+
+module.exports.v4.sync = () => sync("IPV4");
+module.exports.v6.sync = () => sync("IPV6");
Index: frontend/node_modules/default-gateway/index.js
===================================================================
--- frontend/node_modules/default-gateway/index.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/default-gateway/index.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,35 @@
+"use strict";
+
+const {platform, type} = require("os");
+
+const supportedPlatforms = new Set([
+  "aix",
+  "android",
+  "darwin",
+  "freebsd",
+  "linux",
+  "openbsd",
+  "sunos",
+  "win32"
+]);
+
+const plat = platform();
+
+if (supportedPlatforms.has(plat)) {
+  let file = plat;
+  if (plat === "aix") {
+    file = type() === "OS400" ? "ibmi" : "sunos"; // AIX `netstat` output is compatible with Solaris
+  }
+
+  const m = require(`./${file}.js`);
+  module.exports.v4 = () => m.v4();
+  module.exports.v6 = () => m.v6();
+  module.exports.v4.sync = () => m.v4.sync();
+  module.exports.v6.sync = () => m.v6.sync();
+} else {
+  const err = new Error(`Unsupported Platform: ${plat}`);
+  module.exports.v4 = () => Promise.reject(err);
+  module.exports.v6 = () => Promise.reject(err);
+  module.exports.v4.sync = () => { throw err; };
+  module.exports.v6.sync = () => { throw err; };
+}
Index: frontend/node_modules/default-gateway/linux.js
===================================================================
--- frontend/node_modules/default-gateway/linux.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/default-gateway/linux.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,57 @@
+"use strict";
+
+const {isIP} = require("net");
+const {networkInterfaces} = require("os");
+const execa = require("execa");
+
+const args = {
+  v4: ["-4", "r"],
+  v6: ["-6", "r"],
+};
+
+const parse = (stdout, family) => {
+  let result;
+
+  (stdout || "").trim().split("\n").some(line => {
+    const results = /default( via .+?)?( dev .+?)( |$)/.exec(line) || [];
+    const gateway = (results[1] || "").substring(5);
+    const iface = (results[2] || "").substring(5);
+    if (gateway && isIP(gateway)) { // default via 1.2.3.4 dev en0
+      result = {gateway, interface: (iface ? iface : null)};
+      return true;
+    } else if (iface && !gateway) { // default via dev en0
+      const interfaces = networkInterfaces();
+      const addresses = interfaces[iface];
+      if (!addresses || !addresses.length) return;
+
+      addresses.some(addr => {
+        if (addr.family.substring(2) === family && isIP(addr.address)) {
+          result = {gateway: addr.address, interface: (iface ? iface : null)};
+          return true;
+        }
+      });
+    }
+  });
+
+  if (!result) {
+    throw new Error("Unable to determine default gateway");
+  }
+
+  return result;
+};
+
+const promise = async family => {
+  const {stdout} = await execa("ip", args[family]);
+  return parse(stdout, family);
+};
+
+const sync = family => {
+  const {stdout} = execa.sync("ip", args[family]);
+  return parse(stdout, family);
+};
+
+module.exports.v4 = () => promise("v4");
+module.exports.v6 = () => promise("v6");
+
+module.exports.v4.sync = () => sync("v4");
+module.exports.v6.sync = () => sync("v6");
Index: frontend/node_modules/default-gateway/openbsd.js
===================================================================
--- frontend/node_modules/default-gateway/openbsd.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/default-gateway/openbsd.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,47 @@
+"use strict";
+
+const {isIP} = require("net");
+const execa = require("execa");
+const dests = new Set(["default", "0.0.0.0", "0.0.0.0/0", "::", "::/0"]);
+
+const args = {
+  v4: ["-rn", "-f", "inet"],
+  v6: ["-rn", "-f", "inet6"],
+};
+
+const parse = stdout => {
+  let result;
+
+  (stdout || "").trim().split("\n").some(line => {
+    const results = line.split(/ +/) || [];
+    const target = results[0];
+    const gateway = results[1];
+    const iface = results[7];
+    if (dests.has(target) && gateway && isIP(gateway)) {
+      result = {gateway, interface: (iface ? iface : null)};
+      return true;
+    }
+  });
+
+  if (!result) {
+    throw new Error("Unable to determine default gateway");
+  }
+
+  return result;
+};
+
+const promise = async family => {
+  const {stdout} = await execa("netstat", args[family]);
+  return parse(stdout);
+};
+
+const sync = family => {
+  const {stdout} = execa.sync("netstat", args[family]);
+  return parse(stdout);
+};
+
+module.exports.v4 = () => promise("v4");
+module.exports.v6 = () => promise("v6");
+
+module.exports.v4.sync = () => sync("v4");
+module.exports.v6.sync = () => sync("v6");
Index: frontend/node_modules/default-gateway/package.json
===================================================================
--- frontend/node_modules/default-gateway/package.json	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/default-gateway/package.json	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,41 @@
+{
+  "name": "default-gateway",
+  "version": "6.0.3",
+  "description": "Get the default network gateway, cross-platform.",
+  "author": "silverwind",
+  "repository": "silverwind/default-gateway",
+  "license": "BSD-2-Clause",
+  "main": "index.js",
+  "engines": {
+    "node": ">= 10"
+  },
+  "files": [
+    "index.js",
+    "android.js",
+    "darwin.js",
+    "freebsd.js",
+    "linux.js",
+    "openbsd.js",
+    "sunos.js",
+    "win32.js",
+    "ibmi.js"
+  ],
+  "dependencies": {
+    "execa": "^5.0.0"
+  },
+  "devDependencies": {
+    "eslint": "7.17.0",
+    "eslint-config-silverwind": "27.0.0",
+    "jest": "26.6.3",
+    "updates": "11.4.2",
+    "versions": "8.4.4"
+  },
+  "keywords": [
+    "default gateway",
+    "network",
+    "default",
+    "gateway",
+    "routing",
+    "route"
+  ]
+}
Index: frontend/node_modules/default-gateway/sunos.js
===================================================================
--- frontend/node_modules/default-gateway/sunos.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/default-gateway/sunos.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,47 @@
+"use strict";
+
+const {isIP} = require("net");
+const execa = require("execa");
+const dests = new Set(["default", "0.0.0.0", "0.0.0.0/0", "::", "::/0"]);
+
+const args = {
+  v4: ["-rn", "-f", "inet"],
+  v6: ["-rn", "-f", "inet6"],
+};
+
+const parse = stdout => {
+  let result;
+
+  (stdout || "").trim().split("\n").some(line => {
+    const results = line.split(/ +/) || [];
+    const target = results[0];
+    const gateway = results[1];
+    const iface = results[5];
+    if (dests.has(target) && gateway && isIP(gateway)) {
+      result = {gateway, interface: (iface ? iface : null)};
+      return true;
+    }
+  });
+
+  if (!result) {
+    throw new Error("Unable to determine default gateway");
+  }
+
+  return result;
+};
+
+const promise = async family => {
+  const {stdout} = await execa("netstat", args[family]);
+  return parse(stdout);
+};
+
+const sync = family => {
+  const {stdout} = execa.sync("netstat", args[family]);
+  return parse(stdout);
+};
+
+module.exports.v4 = () => promise("v4");
+module.exports.v6 = () => promise("v6");
+
+module.exports.v4.sync = () => sync("v4");
+module.exports.v6.sync = () => sync("v6");
Index: frontend/node_modules/default-gateway/win32.js
===================================================================
--- frontend/node_modules/default-gateway/win32.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/default-gateway/win32.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,99 @@
+"use strict";
+
+const {isIP} = require("net");
+const {networkInterfaces} = require("os");
+const execa = require("execa");
+
+const gwArgs = "path Win32_NetworkAdapterConfiguration where IPEnabled=true get DefaultIPGateway,GatewayCostMetric,IPConnectionMetric,Index /format:table".split(" ");
+const ifArgs = index => `path Win32_NetworkAdapter where Index=${index} get NetConnectionID,MACAddress /format:table`.split(" ");
+
+const spawnOpts = {
+  windowsHide: true,
+};
+
+// Parsing tables like this. The final metric is GatewayCostMetric + IPConnectionMetric
+//
+// DefaultIPGateway             GatewayCostMetric  Index  IPConnectionMetric
+// {"1.2.3.4", "2001:db8::1"}   {0, 256}           12     25
+// {"2.3.4.5"}                  {25}               12     55
+function parseGwTable(gwTable, family) {
+  let [bestGw, bestMetric, bestId] = [null, null, null];
+
+  for (let line of (gwTable || "").trim().split(/\r?\n/).splice(1)) {
+    line = line.trim();
+    const [_, gwArr, gwCostsArr, id, ipMetric] = /({.+?}) +?({.+?}) +?([0-9]+) +?([0-9]+)/g.exec(line) || [];
+    if (!gwArr) continue;
+
+    const gateways = (gwArr.match(/"(.+?)"/g) || []).map(match => match.substring(1, match.length - 1));
+    const gatewayCosts = (gwCostsArr.match(/[0-9]+/g) || []);
+
+    for (const [index, gateway] of Object.entries(gateways)) {
+      if (!gateway || `v${isIP(gateway)}` !== family) continue;
+
+      const metric = parseInt(gatewayCosts[index]) + parseInt(ipMetric);
+      if (!bestGw || metric < bestMetric) {
+        [bestGw, bestMetric, bestId] = [gateway, metric, id];
+      }
+    }
+  }
+
+  if (bestGw) return [bestGw, bestId];
+}
+
+function parseIfTable(ifTable) {
+  const line = (ifTable || "").trim().split("\n")[1];
+
+  let [mac, name] = line.trim().split(/\s+/);
+  mac = mac.toLowerCase();
+
+  // try to get the interface name by matching the mac to os.networkInterfaces to avoid wmic's encoding issues
+  // https://github.com/silverwind/default-gateway/issues/14
+  for (const [osname, addrs] of Object.entries(networkInterfaces())) {
+    for (const addr of addrs) {
+      if (addr && addr.mac && addr.mac.toLowerCase() === mac) {
+        return osname;
+      }
+    }
+  }
+  return name;
+}
+
+const promise = async family => {
+  const {stdout} = await execa("wmic", gwArgs, spawnOpts);
+  const [gateway, id] = parseGwTable(stdout, family) || [];
+
+  if (!gateway) {
+    throw new Error("Unable to determine default gateway");
+  }
+
+  let name;
+  if (id) {
+    const {stdout} = await execa("wmic", ifArgs(id), spawnOpts);
+    name = parseIfTable(stdout);
+  }
+
+  return {gateway, interface: name ? name : null};
+};
+
+const sync = family => {
+  const {stdout} = execa.sync("wmic", gwArgs, spawnOpts);
+  const [gateway, id] = parseGwTable(stdout, family) || [];
+
+  if (!gateway) {
+    throw new Error("Unable to determine default gateway");
+  }
+
+  let name;
+  if (id) {
+    const {stdout} = execa.sync("wmic", ifArgs(id), spawnOpts);
+    name = parseIfTable(stdout);
+  }
+
+  return {gateway, interface: name ? name : null};
+};
+
+module.exports.v4 = () => promise("v4");
+module.exports.v6 = () => promise("v6");
+
+module.exports.v4.sync = () => sync("v4");
+module.exports.v6.sync = () => sync("v6");
