UNPKG

hostapd_switch

Version:

Utility to easy switch between client mode and ap mode.

203 lines (201 loc) 30.7 kB
"use strict"; var __extends = (this && this.__extends) || function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; function __() { this.constructor = d; } d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); }; var Promise = require("bluebird"); var pathExists = require("path-exists"); var dnsmasqconf = require("dnsmasq-conf"); var json_add_1 = require("json-add"); var promise_test_connection_1 = require('promise-test-connection'); var wpasupplicant_manager_1 = require('wpasupplicant-manager'); var listwificlients_1 = require("listwificlients"); var netw_1 = require("netw"); var verb = require('verbo'); var exec = require('promised-exec'); var hostapdjs_1 = require("hostapdjs"); function testconn(d, testint) { return new Promise(function (resolve, reject) { netw_1.default().then(function (n) { var dev = false; var ip = false; for (var ns = 0; ns < n.length; ns++) { if (n[ns].interface == d) { dev = d; if (n[ns].ip) { ip = n[ns].ip; } } } if (!dev) { reject('no interface'); } else if (!ip) { reject(dev + ' can\'t get an ip address'); } else { if (testint) { promise_test_connection_1.default().then(function () { resolve(true); }).catch(function (err) { reject(err); }); } else { console.log("no internet test"); resolve(true); } } }).catch(function (err) { reject('netw' + err); }); }); } ; ; ; ; ; ; ; var HostapdSwitch = (function (_super) { __extends(HostapdSwitch, _super); function HostapdSwitch(options, init) { var config = { interface: "wlan0", wpasupplicant_path: "/etc/wpa_supplicant/wpa_supplicant.conf", redirect: true, hostapd: { interface: "wlan0", wpa_passphrase: false, ssid: "hapd111" }, dnsmasq: { interface: "wlan0" }, init: false }; json_add_1.default(config, options); if (config.interface !== 'auto' && (!options || !options.hostapd || !options.hostapd.interface)) { config.hostapd.interface = config.interface; } if (config.interface !== 'auto' && (!options || !options.dnsmasq || !options.dnsmasq.interface)) { config.dnsmasq.interface = config.interface; } if (!pathExists.sync('/etc/default/hostapd')) { throw Error('no default conf file was founded for hostapd'); } if (!config.hostapd.ssid) { throw Error('No ssid was provided'); } if (!config.hostapd.wpa_passphrase) { throw Error('No wpa_passphrase was provided'); } _super.call(this, config.wpasupplicant_path); this.config = config; this.dnsmasq = new dnsmasqconf(config.dnsmasq); if (init) { hostapdjs_1.default(config.hostapd).then(function () { console.log('hostapd is now configured'); }); } ; } ; HostapdSwitch.prototype.host = function (e) { var that = this; var dnsmasq = this.dnsmasq; var hostIp = dnsmasq.hostIp; var cmd = 'ifconfig ' + this.config.interface + ' down && sleep 2 ; pkill wpa_supplicant && systemctl restart hostapd ; systemctl restart dnsmasq && ifconfig ' + this.config.interface + ' ' + hostIp + ' netmask 255.255.255.0 up && sleep 5'; return new Promise(function (resolve, reject) { dnsmasq.host().then(function () { exec(cmd).then(function () { exec('iptables -t nat -A PREROUTING -p tcp --dport 80 -j DNAT --to-destination ' + hostIp + ':80 && iptables -t nat -A PREROUTING -p tcp --dport 443 -j DNAT --to-destination ' + hostIp + ':80').then(function () { that.wifimode = "host"; resolve(true); }).catch(function (err) { verb(err, 'error', 'hostapd_switch ipfilter host switch'); }); }).catch(function (err) { verb(err, 'error', 'hostapd_switch executing host switch'); }); }).catch(function (err) { verb(err, 'error', 'hostapd_switch executing dnsmasq host switch'); }); }); }; ; HostapdSwitch.prototype.ap = function (e) { var that = this; var dnsmasq = this.dnsmasq; var hostIp = dnsmasq.hostIp; var cmd = 'ifconfig ' + this.config.interface + ' down && sleep 2 ; pkill wpa_supplicant && systemctl restart hostapd ; systemctl restart dnsmasq && ifconfig ' + this.config.interface + ' ' + hostIp + ' netmask 255.255.255.0 up && for i in $( iptables -t nat --line-numbers -L | grep ^[0-9] | awk \'{ print $1 }\' | tac ); do iptables -t nat -D PREROUTING $i; done'; return new Promise(function (resolve, reject) { dnsmasq.ap().then(function () { exec(cmd).then(function () { that.wifimode = "ap"; resolve(true); }).catch(function (err) { verb(err, 'error', 'hostapd_switch executing ap switch'); }); }).catch(function (err) { verb(err, 'error', 'hostapd_switch executing dnsmasq before ap switch'); }); }); }; ; HostapdSwitch.prototype.client = function (testnetw, testint) { var that = this; var dev = this.config.interface; var driver; if (this.config.hostapd.driver === 'nl80211') { driver = 'nl80211'; } else { driver = 'wext'; } var cmd = 'ifconfig ' + dev + ' down && sleep 2 ; pkill wpa_supplicant ; dhclient -r ' + dev + ' ; systemctl stop hostapd ; systemctl stop dnsmasq ; sleep 2; ifconfig ' + dev + ' up && wpa_supplicant -B -i ' + dev + ' -c ' + this.config.wpasupplicant_path + ' -D ' + driver + ' && dhclient ' + dev + ' && for i in $( iptables -t nat --line-numbers -L | grep ^[0-9] | awk \'{ print $1 }\' | tac ); do iptables -t nat -D PREROUTING $i; done; sleep 10'; return new Promise(function (resolve, reject) { exec(cmd).then(function () { that.wifimode = "client"; if (testnetw) { testconn(dev, testint).then(function (answer) { resolve(answer); }).catch(function (err) { reject(err); }); } else { resolve(true); } }).catch(function (err) { verb(err, 'warn', 'hostapd_switch exec'); if (testnetw) { testconn(dev, testint).then(function (answer) { resolve(answer); }).catch(function (err) { reject(err); }); } else { resolve(true); } }); }); }; ; HostapdSwitch.prototype.listwificlients = function () { var that = this; return new Promise(function (resolve, reject) { if (that.wifimode === 'host' || that.wifimode === 'ap') { listwificlients_1.default(that.config.interface).then(function (a) { resolve(a); }).catch(function (err) { reject(err); }); } else { reject('wifimode is ' + that.wifimode); } }); }; return HostapdSwitch; }(wpasupplicant_manager_1.default)); Object.defineProperty(exports, "__esModule", { value: true }); exports.default = HostapdSwitch; //# sourceMappingURL=data:application/json;charset=utf8;base64,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Q0FBZ0IsVUFBVSxPQUFPLEVBQUUsTUFBTTtZQUN2RCxFQUFFLENBQUMsQ0FBQyxJQUFJLENBQUMsUUFBUSxLQUFLLE1BQU0sSUFBSSxJQUFJLENBQUMsUUFBUSxLQUFLLElBQUksQ0FBQyxDQUFDLENBQUM7Z0JBQ3JELHlCQUFlLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxTQUFTLENBQUMsQ0FBQyxJQUFJLENBQUMsVUFBQyxDQUFDO29CQUMxQyxPQUFPLENBQUMsQ0FBQyxDQUFDLENBQUE7Z0JBQ2QsQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLFVBQUMsR0FBRztvQkFDVCxNQUFNLENBQUMsR0FBRyxDQUFDLENBQUE7Z0JBQ2YsQ0FBQyxDQUFDLENBQUE7WUFDTixDQUFDO1lBQUMsSUFBSSxDQUFDLENBQUM7Z0JBQ0osTUFBTSxDQUFDLGNBQWMsR0FBRyxJQUFJLENBQUMsUUFBUSxDQUFDLENBQUE7WUFDMUMsQ0FBQztRQUNMLENBQUMsQ0FBQyxDQUFBO0lBQ04sQ0FBQztJQUlMLG9CQUFDO0FBQUQsQ0E5SkEsQUE4SkMsQ0E5SjBDLCtCQUFVLEdBOEpwRDtBQTlKRDsrQkE4SkMsQ0FBQSIsImZpbGUiOiJpbmRleC5qcyIsInNvdXJjZXNDb250ZW50IjpbIlxuaW1wb3J0ICogYXMgUHJvbWlzZSBmcm9tIFwiYmx1ZWJpcmRcIjtcbmltcG9ydCAqIGFzIHBhdGhFeGlzdHMgZnJvbSBcInBhdGgtZXhpc3RzXCI7XG5pbXBvcnQgKiBhcyBkbnNtYXNxY29uZiBmcm9tIFwiZG5zbWFzcS1jb25mXCI7XG5pbXBvcnQgbWVyZ2UgZnJvbSBcImpzb24tYWRkXCI7XG5pbXBvcnQgdGVzdGludGVybmV0IGZyb20gJ3Byb21pc2UtdGVzdC1jb25uZWN0aW9uJztcbmltcG9ydCB3cGFtYW5hZ2VyIGZyb20gJ3dwYXN1cHBsaWNhbnQtbWFuYWdlcic7XG5pbXBvcnQgbGlzdHdpZmljbGllbnRzIGZyb20gXCJsaXN0d2lmaWNsaWVudHNcIlxuXG5pbXBvcnQgbmV0dyBmcm9tIFwibmV0d1wiO1xuY29uc3QgdmVyYiA9IHJlcXVpcmUoJ3ZlcmJvJyk7XG5jb25zdCBleGVjID0gcmVxdWlyZSgncHJvbWlzZWQtZXhlYycpO1xuaW1wb3J0IGhvc3RhcGRjb25mIGZyb20gXCJob3N0YXBkanNcIjtcblxuaW50ZXJmYWNlIElTY2FuIHtcbiAgICBlc3NpZDogc3RyaW5nO1xuICAgIG1hYzogc3RyaW5nO1xuICAgIHNpZ25hbDogc3RyaW5nO1xufVxuXG50eXBlIElOZXR3b3JrVHlwZSA9ICd3aWZpJyB8ICd3aXJlZCdcblxuaW50ZXJmYWNlIElOZXR3b3JrIHtcbiAgICB0eXBlOiBJTmV0d29ya1R5cGU7XG4gICAgbWFjOiBzdHJpbmc7XG4gICAgaW50ZXJmYWNlOiBzdHJpbmc7XG4gICAgZXNzaWQ/OiBzdHJpbmc7XG4gICAgc2Nhbj86IElTY2FuW107XG4gICAgaXA/OiBzdHJpbmc7XG4gICAgZ2F0ZXdheT86IHN0cmluZztcbn1cblxuXG50eXBlIEl3aWZpbW9kZSA9ICdhcCcgfCAnaG9zdCcgfCAnY2xpZW50JyB8ICd1bm1hbmFnZWQnXG5cblxuaW50ZXJmYWNlIElXaWZpQ2xpZW50IHtcbiAgICBtYWM6IHN0cmluZztcbiAgICBzaWduYWw6IHN0cmluZztcbiAgICBzaWduYWxNaW4/OiBzdHJpbmc7XG4gICAgc2lnbmFsTWF4Pzogc3RyaW5nO1xuXG59XG5cbmZ1bmN0aW9uIHRlc3Rjb25uKGQ6IHN0cmluZywgdGVzdGludD86IGJvb2xlYW4pIHtcblxuICAgIHJldHVybiBuZXcgUHJvbWlzZTxib29sZWFuPihmdW5jdGlvbiAocmVzb2x2ZSwgcmVqZWN0KSB7XG4gICAgICAgIG5ldHcoKS50aGVuKGZ1bmN0aW9uIChuKSB7XG4gICAgICAgICAgICBsZXQgZGV2OiBhbnkgPSBmYWxzZTtcbiAgICAgICAgICAgIGxldCBpcDogYW55ID0gZmFsc2U7XG5cblxuXG4gICAgICAgICAgICBmb3IgKGxldCBucyA9IDA7IG5zIDwgbi5sZW5ndGg7IG5zKyspIHtcbiAgICAgICAgICAgICAgICBpZiAobltuc10uaW50ZXJmYWNlID09IGQpIHtcblxuXG4gICAgICAgICAgICAgICAgICAgIGRldiA9IGQ7XG4gICAgICAgICAgICAgICAgICAgIGlmIChuW25zXS5pcCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgaXAgPSBuW25zXS5pcFxuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIC8vICAgICAgaWYgKG4ubmV0d29ya3NbbnNdLmdhdGV3YXkpIHtcbiAgICAgICAgICAgICAgICAgICAgLy8gICAgICAgICBndyA9IG4ubmV0d29ya3NbbnNdLmdhdGV3YXlcbiAgICAgICAgICAgICAgICAgICAgLy8gICAgfVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmICghZGV2KSB7XG4gICAgICAgICAgICAgICAgcmVqZWN0KCdubyBpbnRlcmZhY2UnKTtcbiAgICAgICAgICAgIH0gZWxzZSBpZiAoIWlwKSB7XG4gICAgICAgICAgICAgICAgcmVqZWN0KGRldiArICcgY2FuXFwndCBnZXQgYW4gaXAgYWRkcmVzcycpO1xuICAgICAgICAgICAgICAgIC8vICB9IGVsc2UgaWYgKCFndykge1xuICAgICAgICAgICAgICAgIC8vICAgICByZWplY3QoZGV2ICsgJyBoYXMgbm8gZ2F0ZXdheScpXG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIGlmICh0ZXN0aW50KSB7XG4gICAgICAgICAgICAgICAgICAgIHRlc3RpbnRlcm5ldCgpLnRoZW4oZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgcmVzb2x2ZSh0cnVlKTtcbiAgICAgICAgICAgICAgICAgICAgfSkuY2F0Y2goZnVuY3Rpb24gKGVycikge1xuICAgICAgICAgICAgICAgICAgICAgICAgcmVqZWN0KGVycik7XG4gICAgICAgICAgICAgICAgICAgIH0pXG4gICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgY29uc29sZS5sb2coXCJubyBpbnRlcm5ldCB0ZXN0XCIpO1xuICAgICAgICAgICAgICAgICAgICByZXNvbHZlKHRydWUpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cblxuICAgICAgICB9KS5jYXRjaChmdW5jdGlvbiAoZXJyKSB7XG4gICAgICAgICAgICByZWplY3QoJ25ldHcnICsgZXJyKTtcbiAgICAgICAgfSlcbiAgICB9KVxuXG59XG5cbmludGVyZmFjZSBJSG9zdGFwZCB7XG4gICAgaW50ZXJmYWNlOiBzdHJpbmc7XG4gICAgc3NpZDogc3RyaW5nO1xuICAgIHdwYV9wYXNzcGhyYXNlOiBhbnk7XG4gICAgZHJpdmVyPzogc3RyaW5nO1xufTtcblxuaW50ZXJmYWNlIElIb3N0YXBkQ2Yge1xuICAgIGRyaXZlcj86IHN0cmluZztcbiAgICBzc2lkPzogc3RyaW5nO1xuICAgIHdwYV9wYXNzcGhyYXNlPzogc3RyaW5nO1xuICAgIGludGVyZmFjZT86IHN0cmluZztcblxufTtcblxuaW50ZXJmYWNlIElEbnNtYXNxIHtcbiAgICBpbnRlcmZhY2U6IHN0cmluZztcbn07XG5cbmludGVyZmFjZSBJRG5zbWFzcUNmIHtcbiAgICBpbnRlcmZhY2U/OiBzdHJpbmc7XG59O1xuXG5pbnRlcmZhY2UgSUNsYXNzT3B0IHtcbiAgICBpbnRlcmZhY2U/OiBzdHJpbmc7XG4gICAgd3Bhc3VwcGxpY2FudF9wYXRoPzogc3RyaW5nO1xuICAgIGhvc3RhcGQ/OiBJSG9zdGFwZENmO1xuICAgIHJlZGlyZWN0PzogYm9vbGVhbjtcbiAgICBkbnNtYXNxPzogSURuc21hc3FDZjtcbn07XG5cbmludGVyZmFjZSBJQ2xhc3NDb25mIHtcbiAgICBpbnRlcmZhY2U6IHN0cmluZztcbiAgICB3cGFzdXBwbGljYW50X3BhdGg6IHN0cmluZztcbiAgICBob3N0YXBkOiBJSG9zdGFwZDtcbiAgICBkbnNtYXNxOiBJRG5zbWFzcTtcbiAgICBpbml0OiBib29sZWFuO1xuICAgIHJlZGlyZWN0OiBib29sZWFuO1xufTtcblxuaW50ZXJmYWNlIElEbnNNb2RlcyB7XG4gICAgYXA6IElEbnNNb2RlO1xuICAgIGxpbms6IElEbnNNb2RlO1xuICAgIGhvc3Q6IElEbnNNb2RlXG59O1xuXG5pbnRlcmZhY2UgSURuc01vZGUge1xuICAgIG5vcmVzb2x2OiBib29sZWFuLFxuICAgIGRuczogW3N0cmluZ10sXG4gICAgZGhjcDoge1xuICAgICAgICBzdG9wOiBudW1iZXI7XG4gICAgICAgIHN0YXJ0OiBudW1iZXI7XG4gICAgICAgIGxlYXNlOiBzdHJpbmc7XG4gICAgfTtcbiAgICBob3N0SXA6IHN0cmluZyxcbiAgICB0ZXN0OiBib29sZWFuLFxuICAgIGludGVyZmFjZTogYW55LFxuICAgIGFkZHJlc3M/OiBzdHJpbmdcbn1cblxuXG5cbmludGVyZmFjZSBJRG5zIHtcbiAgICBtb2RlczogSURuc01vZGVzO1xuICAgIG1vZGU/OiBzdHJpbmc7XG4gICAgcGF0aDogc3RyaW5nO1xuICAgIGludGVyZmFjZTogYW55O1xuICAgIHRlc3Q6IGJvb2xlYW47XG4gICAgZGhjcDoge1xuICAgICAgICBzdG9wOiBudW1iZXI7XG4gICAgICAgIHN0YXJ0OiBudW1iZXI7XG4gICAgICAgIGxlYXNlOiBzdHJpbmc7XG4gICAgfTtcbiAgICBkbnM6IFtzdHJpbmddO1xuICAgIGhvc3RJcDogc3RyaW5nO1xuICAgIGFwOiBGdW5jdGlvbjtcbiAgICBob3N0OiBGdW5jdGlvbjtcbiAgICBsaW5rOiBGdW5jdGlvbjtcbiAgICBzZXRtb2RlKHN0cmluZyk7XG59XG5cblxuZXhwb3J0IGRlZmF1bHQgY2xhc3MgSG9zdGFwZFN3aXRjaCBleHRlbmRzIHdwYW1hbmFnZXIge1xuICAgIGNvbmZpZzogSUNsYXNzQ29uZjtcbiAgICBkbnNtYXNxOiBJRG5zO1xuICAgIHdpZmltb2RlOiBJd2lmaW1vZGU7XG5cbiAgICBjb25zdHJ1Y3RvcihvcHRpb25zOiBJQ2xhc3NPcHQsIGluaXQ/OiBib29sZWFuKSB7XG5cbiAgICAgICAgY29uc3QgY29uZmlnOiBJQ2xhc3NDb25mID0ge1xuICAgICAgICAgICAgaW50ZXJmYWNlOiBcIndsYW4wXCIsXG4gICAgICAgICAgICB3cGFzdXBwbGljYW50X3BhdGg6IFwiL2V0Yy93cGFfc3VwcGxpY2FudC93cGFfc3VwcGxpY2FudC5jb25mXCIsXG4gICAgICAgICAgICByZWRpcmVjdDogdHJ1ZSxcbiAgICAgICAgICAgIGhvc3RhcGQ6IHsgaW50ZXJmYWNlOiBcIndsYW4wXCIsIHdwYV9wYXNzcGhyYXNlOiBmYWxzZSwgc3NpZDogXCJoYXBkMTExXCIgfSxcbiAgICAgICAgICAgIGRuc21hc3E6IHsgaW50ZXJmYWNlOiBcIndsYW4wXCIgfSxcbiAgICAgICAgICAgIGluaXQ6IGZhbHNlXG4gICAgICAgIH07XG5cblxuICAgICAgICBtZXJnZShjb25maWcsIG9wdGlvbnMpXG5cbiAgICAgICAgaWYgKGNvbmZpZy5pbnRlcmZhY2UgIT09ICdhdXRvJyAmJiAoIW9wdGlvbnMgfHwgIW9wdGlvbnMuaG9zdGFwZCB8fCAhb3B0aW9ucy5ob3N0YXBkLmludGVyZmFjZSkpIHtcbiAgICAgICAgICAgIGNvbmZpZy5ob3N0YXBkLmludGVyZmFjZSA9IGNvbmZpZy5pbnRlcmZhY2VcbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChjb25maWcuaW50ZXJmYWNlICE9PSAnYXV0bycgJiYgKCFvcHRpb25zIHx8ICFvcHRpb25zLmRuc21hc3EgfHwgIW9wdGlvbnMuZG5zbWFzcS5pbnRlcmZhY2UpKSB7XG4gICAgICAgICAgICBjb25maWcuZG5zbWFzcS5pbnRlcmZhY2UgPSBjb25maWcuaW50ZXJmYWNlXG4gICAgICAgIH1cblxuXG4gICAgICAgIGlmICghcGF0aEV4aXN0cy5zeW5jKCcvZXRjL2RlZmF1bHQvaG9zdGFwZCcpKSB7XG4gICAgICAgICAgICB0aHJvdyBFcnJvcignbm8gZGVmYXVsdCBjb25mIGZpbGUgd2FzIGZvdW5kZWQgZm9yIGhvc3RhcGQnKVxuICAgICAgICB9XG4gICAgICAgIGlmICghY29uZmlnLmhvc3RhcGQuc3NpZCkge1xuICAgICAgICAgICAgdGhyb3cgRXJyb3IoJ05vIHNzaWQgd2FzIHByb3ZpZGVkJylcbiAgICAgICAgfVxuICAgICAgICBpZiAoIWNvbmZpZy5ob3N0YXBkLndwYV9wYXNzcGhyYXNlKSB7XG4gICAgICAgICAgICB0aHJvdyBFcnJvcignTm8gd3BhX3Bhc3NwaHJhc2Ugd2FzIHByb3ZpZGVkJylcbiAgICAgICAgfVxuXG4gICAgICAgIHN1cGVyKGNvbmZpZy53cGFzdXBwbGljYW50X3BhdGgpXG5cblxuICAgICAgICB0aGlzLmNvbmZpZyA9IGNvbmZpZztcblxuICAgICAgICB0aGlzLmRuc21hc3EgPSBuZXcgZG5zbWFzcWNvbmYoY29uZmlnLmRuc21hc3EpO1xuXG4gICAgICAgIGlmIChpbml0KSB7XG4gICAgICAgICAgICBob3N0YXBkY29uZihjb25maWcuaG9zdGFwZCkudGhlbihmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgY29uc29sZS5sb2coJ2hvc3RhcGQgaXMgbm93IGNvbmZpZ3VyZWQnKVxuICAgICAgICAgICAgfSk7XG4gICAgICAgIH07XG5cbiAgICB9O1xuXG4gICAgaG9zdChlPzogYW55KSB7XG4gICAgICAgIGNvbnN0IHRoYXQgPSB0aGlzXG4gICAgICAgIGxldCBkbnNtYXNxID0gdGhpcy5kbnNtYXNxO1xuICAgICAgICBsZXQgaG9zdElwID0gZG5zbWFzcS5ob3N0SXA7XG4gICAgICAgIGxldCBjbWQgPSAnaWZjb25maWcgJyArIHRoaXMuY29uZmlnLmludGVyZmFjZSArICcgZG93biAmJiBzbGVlcCAyIDsgcGtpbGwgd3BhX3N1cHBsaWNhbnQgJiYgc3lzdGVtY3RsIHJlc3RhcnQgaG9zdGFwZCA7IHN5c3RlbWN0bCByZXN0YXJ0IGRuc21hc3EgJiYgaWZjb25maWcgJyArIHRoaXMuY29uZmlnLmludGVyZmFjZSArICcgJyArIGhvc3RJcCArICcgbmV0bWFzayAyNTUuMjU1LjI1NS4wIHVwICYmIHNsZWVwIDUnO1xuICAgICAgICByZXR1cm4gbmV3IFByb21pc2U8Ym9vbGVhbj4oZnVuY3Rpb24gKHJlc29sdmUsIHJlamVjdCkge1xuICAgICAgICAgICAgZG5zbWFzcS5ob3N0KCkudGhlbihmdW5jdGlvbiAoKSB7XG5cbiAgICAgICAgICAgICAgICBleGVjKGNtZCkudGhlbihmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgICAgIGV4ZWMoJ2lwdGFibGVzIC10IG5hdCAtQSBQUkVST1VUSU5HIC1wIHRjcCAtLWRwb3J0IDgwIC1qIEROQVQgLS10by1kZXN0aW5hdGlvbiAnICsgaG9zdElwICsgJzo4MCAmJiBpcHRhYmxlcyAtdCBuYXQgLUEgUFJFUk9VVElORyAtcCB0Y3AgLS1kcG9ydCA0NDMgLWogRE5BVCAtLXRvLWRlc3RpbmF0aW9uICcgKyBob3N0SXAgKyAnOjgwJykudGhlbihmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICB0aGF0LndpZmltb2RlID0gXCJob3N0XCI7XG4gICAgICAgICAgICAgICAgICAgICAgICByZXNvbHZlKHRydWUpXG4gICAgICAgICAgICAgICAgICAgIH0pLmNhdGNoKGZ1bmN0aW9uIChlcnIpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHZlcmIoZXJyLCAnZXJyb3InLCAnaG9zdGFwZF9zd2l0Y2ggaXBmaWx0ZXIgaG9zdCBzd2l0Y2gnKVxuICAgICAgICAgICAgICAgICAgICB9KVxuICAgICAgICAgICAgICAgIH0pLmNhdGNoKGZ1bmN0aW9uIChlcnIpIHtcbiAgICAgICAgICAgICAgICAgICAgdmVyYihlcnIsICdlcnJvcicsICdob3N0YXBkX3N3aXRjaCBleGVjdXRpbmcgaG9zdCBzd2l0Y2gnKVxuICAgICAgICAgICAgICAgIH0pXG4gICAgICAgICAgICB9KS5jYXRjaChmdW5jdGlvbiAoZXJyKSB7XG4gICAgICAgICAgICAgICAgdmVyYihlcnIsICdlcnJvcicsICdob3N0YXBkX3N3aXRjaCBleGVjdXRpbmcgZG5zbWFzcSBob3N0IHN3aXRjaCcpXG4gICAgICAgICAgICB9KVxuICAgICAgICB9KVxuICAgIH07XG5cblxuICAgIGFwKGU/OiBhbnkpIHtcbiAgICAgICAgY29uc3QgdGhhdCA9IHRoaXNcblxuICAgICAgICBsZXQgZG5zbWFzcSA9IHRoaXMuZG5zbWFzcTtcbiAgICAgICAgbGV0IGhvc3RJcCA9IGRuc21hc3EuaG9zdElwO1xuICAgICAgICBsZXQgY21kID0gJ2lmY29uZmlnICcgKyB0aGlzLmNvbmZpZy5pbnRlcmZhY2UgKyAnIGRvd24gJiYgc2xlZXAgMiA7IHBraWxsIHdwYV9zdXBwbGljYW50ICYmIHN5c3RlbWN0bCByZXN0YXJ0IGhvc3RhcGQgOyBzeXN0ZW1jdGwgcmVzdGFydCBkbnNtYXNxICYmIGlmY29uZmlnICcgKyB0aGlzLmNvbmZpZy5pbnRlcmZhY2UgKyAnICcgKyBob3N0SXAgKyAnIG5ldG1hc2sgMjU1LjI1NS4yNTUuMCB1cCAmJiBmb3IgaSBpbiAkKCBpcHRhYmxlcyAtdCBuYXQgLS1saW5lLW51bWJlcnMgLUwgfCBncmVwIF5bMC05XSB8IGF3ayBcXCd7IHByaW50ICQxIH1cXCcgfCB0YWMgKTsgZG8gaXB0YWJsZXMgLXQgbmF0IC1EIFBSRVJPVVRJTkcgJGk7IGRvbmUnXG4gICAgICAgIHJldHVybiBuZXcgUHJvbWlzZTxib29sZWFuPihmdW5jdGlvbiAocmVzb2x2ZSwgcmVqZWN0KSB7XG4gICAgICAgICAgICBkbnNtYXNxLmFwKCkudGhlbihmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgZXhlYyhjbWQpLnRoZW4oZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgICAgICB0aGF0LndpZmltb2RlID0gXCJhcFwiO1xuICAgICAgICAgICAgICAgICAgICByZXNvbHZlKHRydWUpXG4gICAgICAgICAgICAgICAgfSkuY2F0Y2goZnVuY3Rpb24gKGVycikge1xuICAgICAgICAgICAgICAgICAgICB2ZXJiKGVyciwgJ2Vycm9yJywgJ2hvc3RhcGRfc3dpdGNoIGV4ZWN1dGluZyBhcCBzd2l0Y2gnKVxuICAgICAgICAgICAgICAgIH0pXG4gICAgICAgICAgICB9KS5jYXRjaChmdW5jdGlvbiAoZXJyKSB7XG4gICAgICAgICAgICAgICAgdmVyYihlcnIsICdlcnJvcicsICdob3N0YXBkX3N3aXRjaCBleGVjdXRpbmcgZG5zbWFzcSBiZWZvcmUgYXAgc3dpdGNoJylcbiAgICAgICAgICAgIH0pXG4gICAgICAgIH0pXG4gICAgfTtcblxuICAgIGNsaWVudCh0ZXN0bmV0dz86IGJvb2xlYW4sIHRlc3RpbnQ/OiBib29sZWFuKSB7XG4gICAgICAgIGNvbnN0IHRoYXQgPSB0aGlzXG5cbiAgICAgICAgY29uc3QgZGV2ID0gdGhpcy5jb25maWcuaW50ZXJmYWNlO1xuICAgICAgICBsZXQgZHJpdmVyOiBzdHJpbmc7XG4gICAgICAgIGlmICh0aGlzLmNvbmZpZy5ob3N0YXBkLmRyaXZlciA9PT0gJ25sODAyMTEnKSB7XG4gICAgICAgICAgICBkcml2ZXIgPSAnbmw4MDIxMSc7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBkcml2ZXIgPSAnd2V4dCc7XG4gICAgICAgIH1cbiAgICAgICAgbGV0IGNtZCA9ICdpZmNvbmZpZyAnICsgZGV2ICsgJyBkb3duICYmIHNsZWVwIDIgOyBwa2lsbCB3cGFfc3VwcGxpY2FudCA7ICBkaGNsaWVudCAtciAnICsgZGV2ICsgJyA7IHN5c3RlbWN0bCBzdG9wIGhvc3RhcGQgOyBzeXN0ZW1jdGwgc3RvcCBkbnNtYXNxIDsgc2xlZXAgMjsgaWZjb25maWcgJyArIGRldiArICcgdXAgJiYgd3BhX3N1cHBsaWNhbnQgLUIgLWkgJyArIGRldiArICcgLWMgJyArIHRoaXMuY29uZmlnLndwYXN1cHBsaWNhbnRfcGF0aCArICcgLUQgJyArIGRyaXZlciArICcgJiYgZGhjbGllbnQgJyArIGRldiArICcgJiYgZm9yIGkgaW4gJCggaXB0YWJsZXMgLXQgbmF0IC0tbGluZS1udW1iZXJzIC1MIHwgZ3JlcCBeWzAtOV0gfCBhd2sgXFwneyBwcmludCAkMSB9XFwnIHwgdGFjICk7IGRvIGlwdGFibGVzIC10IG5hdCAtRCBQUkVST1VUSU5HICRpOyBkb25lOyBzbGVlcCAxMCc7XG5cbiAgICAgICAgcmV0dXJuIG5ldyBQcm9taXNlPGJvb2xlYW4+KGZ1bmN0aW9uIChyZXNvbHZlLCByZWplY3QpIHtcblxuICAgICAgICAgICAgZXhlYyhjbWQpLnRoZW4oZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgIHRoYXQud2lmaW1vZGUgPSBcImNsaWVudFwiO1xuXG4gICAgICAgICAgICAgICAgaWYgKHRlc3RuZXR3KSB7XG4gICAgICAgICAgICAgICAgICAgIHRlc3Rjb25uKGRldiwgdGVzdGludCkudGhlbihmdW5jdGlvbiAoYW5zd2VyKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICByZXNvbHZlKGFuc3dlcilcbiAgICAgICAgICAgICAgICAgICAgfSkuY2F0Y2goZnVuY3Rpb24gKGVycikge1xuICAgICAgICAgICAgICAgICAgICAgICAgcmVqZWN0KGVycilcbiAgICAgICAgICAgICAgICAgICAgfSlcbiAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICByZXNvbHZlKHRydWUpXG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSkuY2F0Y2goZnVuY3Rpb24gKGVycikge1xuICAgICAgICAgICAgICAgIHZlcmIoZXJyLCAnd2FybicsICdob3N0YXBkX3N3aXRjaCBleGVjJylcbiAgICAgICAgICAgICAgICBpZiAodGVzdG5ldHcpIHtcbiAgICAgICAgICAgICAgICAgICAgdGVzdGNvbm4oZGV2LCB0ZXN0aW50KS50aGVuKGZ1bmN0aW9uIChhbnN3ZXIpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJlc29sdmUoYW5zd2VyKVxuICAgICAgICAgICAgICAgICAgICB9KS5jYXRjaChmdW5jdGlvbiAoZXJyKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICByZWplY3QoZXJyKVxuICAgICAgICAgICAgICAgICAgICB9KVxuICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIHJlc29sdmUodHJ1ZSlcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9KVxuXG5cbiAgICAgICAgfSlcblxuICAgIH07XG4gICAgbGlzdHdpZmljbGllbnRzKCk6IFByb21pc2U8SVdpZmlDbGllbnRbXT4ge1xuICAgICAgICBjb25zdCB0aGF0ID0gdGhpc1xuICAgICAgICByZXR1cm4gbmV3IFByb21pc2U8SVdpZmlDbGllbnRbXT4oZnVuY3Rpb24gKHJlc29sdmUsIHJlamVjdCkge1xuICAgICAgICAgICAgaWYgKHRoYXQud2lmaW1vZGUgPT09ICdob3N0JyB8fCB0aGF0LndpZmltb2RlID09PSAnYXAnKSB7XG4gICAgICAgICAgICAgICAgbGlzdHdpZmljbGllbnRzKHRoYXQuY29uZmlnLmludGVyZmFjZSkudGhlbigoYSkgPT4ge1xuICAgICAgICAgICAgICAgICAgICByZXNvbHZlKGEpXG4gICAgICAgICAgICAgICAgfSkuY2F0Y2goKGVycikgPT4ge1xuICAgICAgICAgICAgICAgICAgICByZWplY3QoZXJyKVxuICAgICAgICAgICAgICAgIH0pXG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIHJlamVjdCgnd2lmaW1vZGUgaXMgJyArIHRoYXQud2lmaW1vZGUpXG4gICAgICAgICAgICB9XG4gICAgICAgIH0pXG4gICAgfVxuXG5cblxufVxuXG5cblxuXG5cblxuIl19