appium-adb-test
Version:
Android Debug Bridge interface
853 lines (663 loc) • 51.6 kB
JavaScript
'use strict';
var _toConsumableArray = require('babel-runtime/helpers/to-consumable-array')['default'];
var _regeneratorRuntime = require('babel-runtime/regenerator')['default'];
var _getIterator = require('babel-runtime/core-js/get-iterator')['default'];
var _interopRequireDefault = require('babel-runtime/helpers/interop-require-default')['default'];
Object.defineProperty(exports, '__esModule', {
value: true
});
var _helpersJs = require('../helpers.js');
var _teen_process = require('teen_process');
var _loggerJs = require('../logger.js');
var _loggerJs2 = _interopRequireDefault(_loggerJs);
var _path = require('path');
var _path2 = _interopRequireDefault(_path);
var _lodash = require('lodash');
var _lodash2 = _interopRequireDefault(_lodash);
var _asyncbox = require('asyncbox');
var _appiumSupport = require('appium-support');
var apkUtilsMethods = {};
apkUtilsMethods.isAppInstalled = function callee$0$0(pkg) {
var installed, apiLevel, thirdparty, stdout, apkInstalledRgx;
return _regeneratorRuntime.async(function callee$0$0$(context$1$0) {
while (1) switch (context$1$0.prev = context$1$0.next) {
case 0:
context$1$0.prev = 0;
installed = false;
_loggerJs2['default'].debug('Getting install status for ' + pkg);
context$1$0.next = 5;
return _regeneratorRuntime.awrap(this.getApiLevel());
case 5:
apiLevel = context$1$0.sent;
thirdparty = apiLevel >= 15 ? "-3" : "";
context$1$0.next = 9;
return _regeneratorRuntime.awrap(this.shell(['pm', 'list', 'packages', thirdparty, pkg]));
case 9:
stdout = context$1$0.sent;
apkInstalledRgx = new RegExp('^package:' + pkg.replace(/(\.)/g, "\\$1") + '$', 'm');
installed = apkInstalledRgx.test(stdout);
_loggerJs2['default'].debug('App is ' + (!installed ? " not" : "") + ' installed');
return context$1$0.abrupt('return', installed);
case 16:
context$1$0.prev = 16;
context$1$0.t0 = context$1$0['catch'](0);
_loggerJs2['default'].errorAndThrow('Error finding if app is installed. Original error: ' + context$1$0.t0.message);
case 19:
case 'end':
return context$1$0.stop();
}
}, null, this, [[0, 16]]);
};
apkUtilsMethods.startUri = function callee$0$0(uri, pkg) {
var args;
return _regeneratorRuntime.async(function callee$0$0$(context$1$0) {
while (1) switch (context$1$0.prev = context$1$0.next) {
case 0:
if (!uri || !pkg) {
_loggerJs2['default'].errorAndThrow("URI and package arguments are required");
}
context$1$0.prev = 1;
args = ["am", "start", "-W", "-a", "android.intent.action.VIEW", "-d", uri, pkg];
context$1$0.next = 5;
return _regeneratorRuntime.awrap(this.shell(args));
case 5:
context$1$0.next = 10;
break;
case 7:
context$1$0.prev = 7;
context$1$0.t0 = context$1$0['catch'](1);
_loggerJs2['default'].errorAndThrow('Error attempting to start URI. Original error: ' + context$1$0.t0);
case 10:
case 'end':
return context$1$0.stop();
}
}, null, this, [[1, 7]]);
};
apkUtilsMethods.startApp = function callee$0$0() {
var startAppOptions = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0];
var apiLevel, cmd, stdout;
return _regeneratorRuntime.async(function callee$0$0$(context$1$0) {
while (1) switch (context$1$0.prev = context$1$0.next) {
case 0:
context$1$0.prev = 0;
if (!startAppOptions.activity || !startAppOptions.pkg) {
_loggerJs2['default'].errorAndThrow("activity and pkg is required for launching application");
}
startAppOptions = _lodash2['default'].clone(startAppOptions);
// initializing defaults
_lodash2['default'].defaults(startAppOptions, {
waitPkg: startAppOptions.pkg,
waitActivity: false,
retry: true,
stopApp: true
});
// preventing null waitpkg
startAppOptions.waitPkg = startAppOptions.waitPkg || startAppOptions.pkg;
context$1$0.next = 7;
return _regeneratorRuntime.awrap(this.getApiLevel());
case 7:
apiLevel = context$1$0.sent;
cmd = (0, _helpersJs.buildStartCmd)(startAppOptions, apiLevel);
context$1$0.next = 11;
return _regeneratorRuntime.awrap(this.shell(cmd));
case 11:
stdout = context$1$0.sent;
if (!(stdout.indexOf("Error: Activity class") !== -1 && stdout.indexOf("does not exist") !== -1)) {
context$1$0.next = 23;
break;
}
if (!(startAppOptions.retry && startAppOptions.activity[0] !== ".")) {
context$1$0.next = 20;
break;
}
_loggerJs2['default'].debug("We tried to start an activity that doesn't exist, " + "retrying with . prepended to activity");
startAppOptions.activity = '.' + startAppOptions.activity;
startAppOptions.retry = false;
return context$1$0.abrupt('return', this.startApp(startAppOptions));
case 20:
_loggerJs2['default'].errorAndThrow("Activity used to start app doesn't exist or cannot be " + "launched! Make sure it exists and is a launchable activity");
case 21:
context$1$0.next = 24;
break;
case 23:
if (stdout.indexOf("java.lang.SecurityException") !== -1) {
// if the app is disabled on a real device it will throw a security exception
_loggerJs2['default'].errorAndThrow("Permission to start activity denied.");
}
case 24:
if (!startAppOptions.waitActivity) {
context$1$0.next = 27;
break;
}
context$1$0.next = 27;
return _regeneratorRuntime.awrap(this.waitForActivity(startAppOptions.waitPkg, startAppOptions.waitActivity, startAppOptions.waitDuration));
case 27:
context$1$0.next = 32;
break;
case 29:
context$1$0.prev = 29;
context$1$0.t0 = context$1$0['catch'](0);
_loggerJs2['default'].errorAndThrow('Error occured while starting App. Original error: ' + context$1$0.t0.message);
case 32:
case 'end':
return context$1$0.stop();
}
}, null, this, [[0, 29]]);
};
apkUtilsMethods.getFocusedPackageAndActivity = function callee$0$0() {
var cmd, nullRe, searchRe, stdout, foundNullMatch, _iteratorNormalCompletion, _didIteratorError, _iteratorError, _iterator, _step, line, foundMatch;
return _regeneratorRuntime.async(function callee$0$0$(context$1$0) {
while (1) switch (context$1$0.prev = context$1$0.next) {
case 0:
_loggerJs2['default'].debug("Getting focused package and activity");
cmd = ['dumpsys', 'window', 'windows'];
nullRe = new RegExp(/mFocusedApp=null/);
searchRe = new RegExp('mFocusedApp.+Record\\{.*\\s([^\\s\\/\\}]+)' + '\\/([^\\s\\/\\}\\,]+)\\,?(\\s[^\\s\\/\\}]+)*\\}');
context$1$0.prev = 4;
context$1$0.next = 7;
return _regeneratorRuntime.awrap(this.shell(cmd));
case 7:
stdout = context$1$0.sent;
foundNullMatch = false;
_iteratorNormalCompletion = true;
_didIteratorError = false;
_iteratorError = undefined;
context$1$0.prev = 12;
_iterator = _getIterator(stdout.split("\n"));
case 14:
if (_iteratorNormalCompletion = (_step = _iterator.next()).done) {
context$1$0.next = 25;
break;
}
line = _step.value;
foundMatch = searchRe.exec(line);
if (!foundMatch) {
context$1$0.next = 21;
break;
}
return context$1$0.abrupt('return', { appPackage: foundMatch[1].trim(), appActivity: foundMatch[2].trim() });
case 21:
if (nullRe.test(line)) {
foundNullMatch = true;
}
case 22:
_iteratorNormalCompletion = true;
context$1$0.next = 14;
break;
case 25:
context$1$0.next = 31;
break;
case 27:
context$1$0.prev = 27;
context$1$0.t0 = context$1$0['catch'](12);
_didIteratorError = true;
_iteratorError = context$1$0.t0;
case 31:
context$1$0.prev = 31;
context$1$0.prev = 32;
if (!_iteratorNormalCompletion && _iterator['return']) {
_iterator['return']();
}
case 34:
context$1$0.prev = 34;
if (!_didIteratorError) {
context$1$0.next = 37;
break;
}
throw _iteratorError;
case 37:
return context$1$0.finish(34);
case 38:
return context$1$0.finish(31);
case 39:
if (!foundNullMatch) {
context$1$0.next = 43;
break;
}
return context$1$0.abrupt('return', { appPackage: null, appActivity: null });
case 43:
_loggerJs2['default'].errorAndThrow("Could not parse activity from dumpsys");
case 44:
context$1$0.next = 49;
break;
case 46:
context$1$0.prev = 46;
context$1$0.t1 = context$1$0['catch'](4);
_loggerJs2['default'].errorAndThrow('Could not get focusPackageAndActivity. Original error: ' + context$1$0.t1.message);
case 49:
case 'end':
return context$1$0.stop();
}
}, null, this, [[4, 46], [12, 27, 31, 39], [32,, 34, 38]]);
};
apkUtilsMethods.waitForActivityOrNot = function callee$0$0(pkg, activity, not) {
var waitMs = arguments.length <= 3 || arguments[3] === undefined ? 20000 : arguments[3];
var endAt, possibleActivityNames, allActivities, _iteratorNormalCompletion2, _didIteratorError2, _iteratorError2, _iterator2, _step2, oneActivity, _loop, _ret, activityMessage;
return _regeneratorRuntime.async(function callee$0$0$(context$1$0) {
var _this = this;
while (1) switch (context$1$0.prev = context$1$0.next) {
case 0:
if (!(!pkg || !activity)) {
context$1$0.next = 2;
break;
}
throw new Error("Package and activity required.");
case 2:
_loggerJs2['default'].debug('Waiting for pkg: \'' + pkg + '\' and activity: \'' + activity + '\'' + ((not ? ' not' : '') + ' to be focused'));
endAt = Date.now() + waitMs;
possibleActivityNames = [];
allActivities = activity.split(",");
_iteratorNormalCompletion2 = true;
_didIteratorError2 = false;
_iteratorError2 = undefined;
context$1$0.prev = 9;
for (_iterator2 = _getIterator(allActivities); !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
oneActivity = _step2.value;
oneActivity = oneActivity.trim();
possibleActivityNames.push.apply(possibleActivityNames, _toConsumableArray((0, _helpersJs.getPossibleActivityNames)(pkg, oneActivity)));
}
context$1$0.next = 17;
break;
case 13:
context$1$0.prev = 13;
context$1$0.t0 = context$1$0['catch'](9);
_didIteratorError2 = true;
_iteratorError2 = context$1$0.t0;
case 17:
context$1$0.prev = 17;
context$1$0.prev = 18;
if (!_iteratorNormalCompletion2 && _iterator2['return']) {
_iterator2['return']();
}
case 20:
context$1$0.prev = 20;
if (!_didIteratorError2) {
context$1$0.next = 23;
break;
}
throw _iteratorError2;
case 23:
return context$1$0.finish(20);
case 24:
return context$1$0.finish(17);
case 25:
_loggerJs2['default'].debug('Possible activities, to be checked: ' + possibleActivityNames.join(', '));
_loop = function callee$1$0() {
var _ref, appPackage, appActivity, foundAct;
return _regeneratorRuntime.async(function callee$1$0$(context$2$0) {
while (1) switch (context$2$0.prev = context$2$0.next) {
case 0:
context$2$0.next = 2;
return _regeneratorRuntime.awrap(this.getFocusedPackageAndActivity());
case 2:
_ref = context$2$0.sent;
appPackage = _ref.appPackage;
appActivity = _ref.appActivity;
_loggerJs2['default'].debug('Found package: \'' + appPackage + '\' and activity: \'' + appActivity + '\'');
foundAct = appPackage === pkg && _lodash2['default'].findIndex(possibleActivityNames, function (possibleActivity) {
return possibleActivity === appActivity;
}) !== -1;
if (!(!not && foundAct || not && !foundAct)) {
context$2$0.next = 9;
break;
}
return context$2$0.abrupt('return', {
v: undefined
});
case 9:
_loggerJs2['default'].debug('Incorrect package and activity. Retrying.');
// cool down so we're not overloading device with requests
context$2$0.next = 12;
return _regeneratorRuntime.awrap((0, _asyncbox.sleep)(750));
case 12:
case 'end':
return context$2$0.stop();
}
}, null, _this);
};
case 27:
if (!(Date.now() < endAt)) {
context$1$0.next = 35;
break;
}
context$1$0.next = 30;
return _regeneratorRuntime.awrap(_loop());
case 30:
_ret = context$1$0.sent;
if (!(typeof _ret === 'object')) {
context$1$0.next = 33;
break;
}
return context$1$0.abrupt('return', _ret.v);
case 33:
context$1$0.next = 27;
break;
case 35:
activityMessage = possibleActivityNames.join(" or ");
_loggerJs2['default'].errorAndThrow(pkg + '/' + activityMessage + ' never ' + (not ? 'stopped' : 'started'));
case 37:
case 'end':
return context$1$0.stop();
}
}, null, this, [[9, 13, 17, 25], [18,, 20, 24]]);
};
apkUtilsMethods.waitForActivity = function callee$0$0(pkg, act) {
var waitMs = arguments.length <= 2 || arguments[2] === undefined ? 20000 : arguments[2];
return _regeneratorRuntime.async(function callee$0$0$(context$1$0) {
while (1) switch (context$1$0.prev = context$1$0.next) {
case 0:
context$1$0.next = 2;
return _regeneratorRuntime.awrap(this.waitForActivityOrNot(pkg, act, false, waitMs));
case 2:
case 'end':
return context$1$0.stop();
}
}, null, this);
};
apkUtilsMethods.waitForNotActivity = function callee$0$0(pkg, act) {
var waitMs = arguments.length <= 2 || arguments[2] === undefined ? 20000 : arguments[2];
return _regeneratorRuntime.async(function callee$0$0$(context$1$0) {
while (1) switch (context$1$0.prev = context$1$0.next) {
case 0:
context$1$0.next = 2;
return _regeneratorRuntime.awrap(this.waitForActivityOrNot(pkg, act, true, waitMs));
case 2:
case 'end':
return context$1$0.stop();
}
}, null, this);
};
apkUtilsMethods.uninstallApk = function callee$0$0(pkg) {
var stdout;
return _regeneratorRuntime.async(function callee$0$0$(context$1$0) {
while (1) switch (context$1$0.prev = context$1$0.next) {
case 0:
_loggerJs2['default'].debug('Uninstalling ' + pkg);
context$1$0.prev = 1;
context$1$0.next = 4;
return _regeneratorRuntime.awrap(this.forceStop(pkg));
case 4:
context$1$0.next = 6;
return _regeneratorRuntime.awrap(this.adbExec(['uninstall', pkg], { timeout: 20000 }));
case 6:
stdout = context$1$0.sent;
stdout = stdout.trim();
// stdout may contain warnings meaning success is not on the first line.
if (!(stdout.indexOf("Success") !== -1)) {
context$1$0.next = 13;
break;
}
_loggerJs2['default'].info("App was uninstalled");
return context$1$0.abrupt('return', true);
case 13:
_loggerJs2['default'].info("App was not uninstalled, maybe it wasn't on device?");
return context$1$0.abrupt('return', false);
case 15:
context$1$0.next = 20;
break;
case 17:
context$1$0.prev = 17;
context$1$0.t0 = context$1$0['catch'](1);
_loggerJs2['default'].errorAndThrow('Unable to uninstall APK. Original error: ' + context$1$0.t0.message);
case 20:
case 'end':
return context$1$0.stop();
}
}, null, this, [[1, 17]]);
};
apkUtilsMethods.installFromDevicePath = function callee$0$0(apkPathOnDevice) {
var opts = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1];
var stdout;
return _regeneratorRuntime.async(function callee$0$0$(context$1$0) {
while (1) switch (context$1$0.prev = context$1$0.next) {
case 0:
context$1$0.next = 2;
return _regeneratorRuntime.awrap(this.shell(['pm', 'install', '-r', apkPathOnDevice], opts));
case 2:
stdout = context$1$0.sent;
if (stdout.indexOf("Failure") !== -1) {
_loggerJs2['default'].errorAndThrow('Remote install failed: ' + stdout);
}
case 4:
case 'end':
return context$1$0.stop();
}
}, null, this);
};
apkUtilsMethods.install = function callee$0$0(apk) {
var replace = arguments.length <= 1 || arguments[1] === undefined ? true : arguments[1];
var timeout = arguments.length <= 2 || arguments[2] === undefined ? 60000 : arguments[2];
return _regeneratorRuntime.async(function callee$0$0$(context$1$0) {
while (1) switch (context$1$0.prev = context$1$0.next) {
case 0:
if (!replace) {
context$1$0.next = 5;
break;
}
context$1$0.next = 3;
return _regeneratorRuntime.awrap(this.adbExec(['install', '-r', apk], { timeout: timeout }));
case 3:
context$1$0.next = 15;
break;
case 5:
context$1$0.prev = 5;
context$1$0.next = 8;
return _regeneratorRuntime.awrap(this.adbExec(['install', apk], { timeout: timeout }));
case 8:
context$1$0.next = 15;
break;
case 10:
context$1$0.prev = 10;
context$1$0.t0 = context$1$0['catch'](5);
if (!(context$1$0.t0.message.indexOf('INSTALL_FAILED_ALREADY_EXISTS') === -1)) {
context$1$0.next = 14;
break;
}
throw context$1$0.t0;
case 14:
_loggerJs2['default'].debug('Application \'' + apk + '\' already installed. Continuing.');
case 15:
case 'end':
return context$1$0.stop();
}
}, null, this, [[5, 10]]);
};
apkUtilsMethods.extractStringsFromApk = function callee$0$0(apk, language, out) {
var stringsJson, localPath, apkTools, args, fileData, apkStrings, msg;
return _regeneratorRuntime.async(function callee$0$0$(context$1$0) {
while (1) switch (context$1$0.prev = context$1$0.next) {
case 0:
_loggerJs2['default'].debug('Extracting strings for language: ' + (language || "default"));
stringsJson = 'strings.json';
localPath = undefined;
if (language) {
context$1$0.next = 7;
break;
}
context$1$0.next = 6;
return _regeneratorRuntime.awrap(this.getDeviceLanguage());
case 6:
language = context$1$0.sent;
case 7:
apkTools = this.jars['appium_apk_tools.jar'];
args = ['-jar', apkTools, 'stringsFromApk', apk, out, language];
fileData = undefined, apkStrings = undefined;
context$1$0.prev = 10;
context$1$0.next = 13;
return _regeneratorRuntime.awrap((0, _teen_process.exec)('java', args));
case 13:
context$1$0.next = 21;
break;
case 15:
context$1$0.prev = 15;
context$1$0.t0 = context$1$0['catch'](10);
_loggerJs2['default'].debug('No strings.xml for language \'' + language + '\', getting default ' + 'strings.xml');
args.pop();
context$1$0.next = 21;
return _regeneratorRuntime.awrap((0, _teen_process.exec)('java', args));
case 21:
context$1$0.prev = 21;
_loggerJs2['default'].debug("Reading strings from converted strings.json");
localPath = _path2['default'].join(out, stringsJson);
context$1$0.next = 26;
return _regeneratorRuntime.awrap(_appiumSupport.fs.readFile(localPath, 'utf8'));
case 26:
fileData = context$1$0.sent;
apkStrings = JSON.parse(fileData);
context$1$0.next = 35;
break;
case 30:
context$1$0.prev = 30;
context$1$0.t1 = context$1$0['catch'](21);
if (fileData) {
_loggerJs2['default'].debug('Content started with: ' + fileData.slice(0, 300));
}
msg = 'Could not parse strings from strings.json. Original ' + ('error: ' + context$1$0.t1.message);
_loggerJs2['default'].errorAndThrow(msg);
case 35:
return context$1$0.abrupt('return', { apkStrings: apkStrings, localPath: localPath });
case 36:
case 'end':
return context$1$0.stop();
}
}, null, this, [[10, 15], [21, 30]]);
};
apkUtilsMethods.getDeviceLanguage = function callee$0$0() {
var language;
return _regeneratorRuntime.async(function callee$0$0$(context$1$0) {
while (1) switch (context$1$0.prev = context$1$0.next) {
case 0:
language = undefined;
context$1$0.next = 3;
return _regeneratorRuntime.awrap(this.getApiLevel());
case 3:
context$1$0.t0 = context$1$0.sent;
if (!(context$1$0.t0 < 23)) {
context$1$0.next = 14;
break;
}
context$1$0.next = 7;
return _regeneratorRuntime.awrap(this.getDeviceSysLanguage());
case 7:
language = context$1$0.sent;
if (language) {
context$1$0.next = 12;
break;
}
context$1$0.next = 11;
return _regeneratorRuntime.awrap(this.getDeviceProductLanguage());
case 11:
language = context$1$0.sent;
case 12:
context$1$0.next = 17;
break;
case 14:
context$1$0.next = 16;
return _regeneratorRuntime.awrap(this.getDeviceLocale());
case 16:
language = context$1$0.sent.split("-")[0];
case 17:
return context$1$0.abrupt('return', language);
case 18:
case 'end':
return context$1$0.stop();
}
}, null, this);
};
apkUtilsMethods.setDeviceLanguage = function callee$0$0(language) {
return _regeneratorRuntime.async(function callee$0$0$(context$1$0) {
while (1) switch (context$1$0.prev = context$1$0.next) {
case 0:
context$1$0.next = 2;
return _regeneratorRuntime.awrap(this.setDeviceSysLanguage(language));
case 2:
case 'end':
return context$1$0.stop();
}
}, null, this);
};
apkUtilsMethods.getDeviceCountry = function callee$0$0() {
var country;
return _regeneratorRuntime.async(function callee$0$0$(context$1$0) {
while (1) switch (context$1$0.prev = context$1$0.next) {
case 0:
context$1$0.next = 2;
return _regeneratorRuntime.awrap(this.getDeviceSysCountry());
case 2:
country = context$1$0.sent;
if (country) {
context$1$0.next = 7;
break;
}
context$1$0.next = 6;
return _regeneratorRuntime.awrap(this.getDeviceProductCountry());
case 6:
country = context$1$0.sent;
case 7:
return context$1$0.abrupt('return', country);
case 8:
case 'end':
return context$1$0.stop();
}
}, null, this);
};
apkUtilsMethods.setDeviceCountry = function callee$0$0(country) {
return _regeneratorRuntime.async(function callee$0$0$(context$1$0) {
while (1) switch (context$1$0.prev = context$1$0.next) {
case 0:
context$1$0.next = 2;
return _regeneratorRuntime.awrap(this.setDeviceSysCountry(country));
case 2:
case 'end':
return context$1$0.stop();
}
}, null, this);
};
apkUtilsMethods.getDeviceLocale = function callee$0$0() {
var locale;
return _regeneratorRuntime.async(function callee$0$0$(context$1$0) {
while (1) switch (context$1$0.prev = context$1$0.next) {
case 0:
context$1$0.next = 2;
return _regeneratorRuntime.awrap(this.getDeviceSysLocale());
case 2:
locale = context$1$0.sent;
if (locale) {
context$1$0.next = 7;
break;
}
context$1$0.next = 6;
return _regeneratorRuntime.awrap(this.getDeviceProductLocale());
case 6:
locale = context$1$0.sent;
case 7:
return context$1$0.abrupt('return', locale);
case 8:
case 'end':
return context$1$0.stop();
}
}, null, this);
};
apkUtilsMethods.setDeviceLocale = function callee$0$0(locale) {
return _regeneratorRuntime.async(function callee$0$0$(context$1$0) {
while (1) switch (context$1$0.prev = context$1$0.next) {
case 0:
context$1$0.next = 2;
return _regeneratorRuntime.awrap(this.setDeviceSysLocale(locale));
case 2:
case 'end':
return context$1$0.stop();
}
}, null, this);
};
exports['default'] = apkUtilsMethods;
module.exports = exports['default'];
// https://regex101.com/r/xZ8vF7/1
// on some systems this will throw an error if the app already
// exists
// this method is only used in API < 23
// this method is only used in API < 23
// this method is only used in API < 23
// this method is only used in API >= 23
// this method is only used in API >= 23
//# sourceMappingURL=data:application/json;charset=utf8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbImxpYi90b29scy9hcGstdXRpbHMuanMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7eUJBQXdELGVBQWU7OzRCQUNsRCxjQUFjOzt3QkFDbkIsY0FBYzs7OztvQkFDYixNQUFNOzs7O3NCQUNULFFBQVE7Ozs7d0JBQ0EsVUFBVTs7NkJBQ2IsZ0JBQWdCOztBQUVuQyxJQUFJLGVBQWUsR0FBRyxFQUFFLENBQUM7O0FBRXpCLGVBQWUsQ0FBQyxjQUFjLEdBQUcsb0JBQWdCLEdBQUc7TUFFNUMsU0FBUyxFQUVULFFBQVEsRUFDUixVQUFVLEVBQ1YsTUFBTSxFQUNOLGVBQWU7Ozs7O0FBTGYsaUJBQVMsR0FBRyxLQUFLOztBQUNyQiw4QkFBSSxLQUFLLGlDQUErQixHQUFHLENBQUcsQ0FBQzs7eUNBQzFCLElBQUksQ0FBQyxXQUFXLEVBQUU7OztBQUFuQyxnQkFBUTtBQUNSLGtCQUFVLEdBQUcsUUFBUSxJQUFJLEVBQUUsR0FBRyxJQUFJLEdBQUcsRUFBRTs7eUNBQ3hCLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQyxJQUFJLEVBQUUsTUFBTSxFQUFFLFVBQVUsRUFBRSxVQUFVLEVBQUUsR0FBRyxDQUFDLENBQUM7OztBQUF0RSxjQUFNO0FBQ04sdUJBQWUsR0FBRyxJQUFJLE1BQU0sZUFBYSxHQUFHLENBQUMsT0FBTyxDQUFDLE9BQU8sRUFBRSxNQUFNLENBQUMsUUFDeEMsR0FBRyxDQUFDOztBQUNyQyxpQkFBUyxHQUFHLGVBQWUsQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLENBQUM7QUFDekMsOEJBQUksS0FBSyxjQUFXLENBQUMsU0FBUyxHQUFHLE1BQU0sR0FBRyxFQUFFLENBQUEsZ0JBQWEsQ0FBQzs0Q0FDbkQsU0FBUzs7Ozs7O0FBRWhCLDhCQUFJLGFBQWEseURBQXVELGVBQUUsT0FBTyxDQUFHLENBQUM7Ozs7Ozs7Q0FFeEYsQ0FBQzs7QUFFRixlQUFlLENBQUMsUUFBUSxHQUFHLG9CQUFnQixHQUFHLEVBQUUsR0FBRztNQUsz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Q0FBQyxrQkFBa0IsRUFBRTs7O0FBQXhDLGNBQU07O1lBQ0wsTUFBTTs7Ozs7O3lDQUNNLElBQUksQ0FBQyxzQkFBc0IsRUFBRTs7O0FBQTVDLGNBQU07Ozs0Q0FFRCxNQUFNOzs7Ozs7O0NBQ2QsQ0FBQzs7QUFFRixlQUFlLENBQUMsZUFBZSxHQUFHLG9CQUFnQixNQUFNOzs7Ozt5Q0FFaEQsSUFBSSxDQUFDLGtCQUFrQixDQUFDLE1BQU0sQ0FBQzs7Ozs7OztDQUN0QyxDQUFDOztxQkFFYSxlQUFlIiwiZmlsZSI6ImxpYi90b29scy9hcGstdXRpbHMuanMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBidWlsZFN0YXJ0Q21kLCBnZXRQb3NzaWJsZUFjdGl2aXR5TmFtZXMgfSBmcm9tICcuLi9oZWxwZXJzLmpzJztcclxuaW1wb3J0IHsgZXhlYyB9IGZyb20gJ3RlZW5fcHJvY2Vzcyc7XHJcbmltcG9ydCBsb2cgZnJvbSAnLi4vbG9nZ2VyLmpzJztcclxuaW1wb3J0IHBhdGggZnJvbSAncGF0aCc7XHJcbmltcG9ydCBfIGZyb20gJ2xvZGFzaCc7XHJcbmltcG9ydCB7IHNsZWVwIH0gZnJvbSAnYXN5bmNib3gnO1xyXG5pbXBvcnQgeyBmcyB9IGZyb20gJ2FwcGl1bS1zdXBwb3J0JztcclxuXHJcbmxldCBhcGtVdGlsc01ldGhvZHMgPSB7fTtcclxuXHJcbmFwa1V0aWxzTWV0aG9kcy5pc0FwcEluc3RhbGxlZCA9IGFzeW5jIGZ1bmN0aW9uIChwa2cpIHtcclxuICB0cnkge1xyXG4gICAgbGV0IGluc3RhbGxlZCA9IGZhbHNlO1xyXG4gICAgbG9nLmRlYnVnKGBHZXR0aW5nIGluc3RhbGwgc3RhdHVzIGZvciAke3BrZ31gKTtcclxuICAgIGxldCBhcGlMZXZlbCA9IGF3YWl0IHRoaXMuZ2V0QXBpTGV2ZWwoKTtcclxuICAgIGxldCB0aGlyZHBhcnR5ID0gYXBpTGV2ZWwgPj0gMTUgPyBcIi0zXCIgOiBcIlwiO1xyXG4gICAgbGV0IHN0ZG91dCA9IGF3YWl0IHRoaXMuc2hlbGwoWydwbScsICdsaXN0JywgJ3BhY2thZ2VzJywgdGhpcmRwYXJ0eSwgcGtnXSk7XHJcbiAgICBsZXQgYXBrSW5zdGFsbGVkUmd4ID0gbmV3IFJlZ0V4cChgXnBhY2thZ2U6JHtwa2cucmVwbGFjZSgvKFxcLikvZywgXCJcXFxcJDFcIil9JGAsXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnbScpO1xyXG4gICAgaW5zdGFsbGVkID0gYXBrSW5zdGFsbGVkUmd4LnRlc3Qoc3Rkb3V0KTtcclxuICAgIGxvZy5kZWJ1ZyhgQXBwIGlzICR7IWluc3RhbGxlZCA/IFwiIG5vdFwiIDogXCJcIn0gaW5zdGFsbGVkYCk7XHJcbiAgICByZXR1cm4gaW5zdGFsbGVkO1xyXG4gIH0gY2F0Y2ggKGUpIHtcclxuICAgIGxvZy5lcnJvckFuZFRocm93KGBFcnJvciBmaW5kaW5nIGlmIGFwcCBpcyBpbnN0YWxsZWQuIE9yaWdpbmFsIGVycm9yOiAke2UubWVzc2FnZX1gKTtcclxuICB9XHJcbn07XHJcblxyXG5hcGtVdGlsc01ldGhvZHMuc3RhcnRVcmkgPSBhc3luYyBmdW5jdGlvbiAodXJpLCBwa2cpIHtcclxuICBpZiAoIXVyaSB8fCAhcGtnKSB7XHJcbiAgICBsb2cuZXJyb3JBbmRUaHJvdyhcIlVSSSBhbmQgcGFja2FnZSBhcmd1bWVudHMgYXJlIHJlcXVpcmVkXCIpO1xyXG4gIH1cclxuICB0cnkge1xyXG4gICAgbGV0IGFyZ3MgPSBbXCJhbVwiLCBcInN0YXJ0XCIsIFwiLVdcIiwgXCItYVwiLCBcImFuZHJvaWQuaW50ZW50LmFjdGlvbi5WSUVXXCIsIFwiLWRcIixcclxuICAgICAgICAgICAgICAgIHVyaSwgcGtnXTtcclxuICAgIGF3YWl0IHRoaXMuc2hlbGwoYXJncyk7XHJcbiAgfSBjYXRjaCAoZSkge1xyXG4gICAgbG9nLmVycm9yQW5kVGhyb3coYEVycm9yIGF0dGVtcHRpbmcgdG8gc3RhcnQgVVJJLiBPcmlnaW5hbCBlcnJvcjogJHtlfWApO1xyXG4gIH1cclxufTtcclxuXHJcbmFwa1V0aWxzTWV0aG9kcy5zdGFydEFwcCA9IGFzeW5jIGZ1bmN0aW9uIChzdGFydEFwcE9wdGlvbnMgPSB7fSkge1xyXG4gIHRyeSB7XHJcbiAgICBpZiAoIXN0YXJ0QXBwT3B0aW9ucy5hY3Rpdml0eSB8fCAhc3RhcnRBcHBPcHRpb25zLnBrZykge1xyXG4gICAgICBsb2cuZXJyb3JBbmRUaHJvdyhcImFjdGl2aXR5IGFuZCBwa2cgaXMgcmVxdWlyZWQgZm9yIGxhdW5jaGluZyBhcHBsaWNhdGlvblwiKTtcclxuICAgIH1cclxuICAgIHN0YXJ0QXBwT3B0aW9ucyA9IF8uY2xvbmUoc3RhcnRBcHBPcHRpb25zKTtcclxuICAgIC8vIGluaXRpYWxpemluZyBkZWZhdWx0c1xyXG4gICAgXy5kZWZhdWx0cyhzdGFydEFwcE9wdGlvbnMsIHtcclxuICAgICAgd2FpdFBrZzogc3RhcnRBcHBPcHRpb25zLnBrZyxcclxuICAgICAgd2FpdEFjdGl2aXR5OiBmYWxzZSxcclxuICAgICAgcmV0cnk6IHRydWUsXHJcbiAgICAgIHN0b3BBcHA6IHRydWVcclxuICAgIH0pO1xyXG4gICAgLy8gcHJldmVudGluZyBudWxsIHdhaXRwa2dcclxuICAgIHN0YXJ0QXBwT3B0aW9ucy53YWl0UGtnID0gc3RhcnRBcHBPcHRpb25zLndhaXRQa2cgfHwgc3RhcnRBcHBPcHRpb25zLnBrZztcclxuICAgIGxldCBhcGlMZXZlbCA9IGF3YWl0IHRoaXMuZ2V0QXBpTGV2ZWwoKTtcclxuICAgIGxldCBjbWQgPSBidWlsZFN0YXJ0Q21kKHN0YXJ0QXBwT3B0aW9ucywgYXBpTGV2ZWwpO1xyXG4gICAgbGV0IHN0ZG91dCA9IGF3YWl0IHRoaXMuc2hlbGwoY21kKTtcclxuICAgIGlmIChzdGRvdXQuaW5kZXhPZihcIkVycm9yOiBBY3Rpdml0eSBjbGFzc1wiKSAhPT0gLTEgJiZcclxuICAgICAgICBzdGRvdXQuaW5kZXhPZihcImRvZXMgbm90IGV4aXN0XCIpICE9PSAtMSkge1xyXG4gICAgICBpZiAoc3RhcnRBcHBPcHRpb25zLnJldHJ5ICYmIHN0YXJ0QXBwT3B0aW9ucy5hY3Rpdml0eVswXSAhPT0gXCIuXCIpIHtcclxuICAgICAgICBsb2cuZGVidWcoXCJXZSB0cmllZCB0byBzdGFydCBhbiBhY3Rpdml0eSB0aGF0IGRvZXNuJ3QgZXhpc3QsIFwiICtcclxuICAgICAgICAgICAgICAgICAgXCJyZXRyeWluZyB3aXRoIC4gcHJlcGVuZGVkIHRvIGFjdGl2aXR5XCIpO1xyXG4gICAgICAgIHN0YXJ0QXBwT3B0aW9ucy5hY3Rpdml0eSA9IGAuJHtzdGFydEFwcE9wdGlvbnMuYWN0aXZpdHl9YDtcclxuICAgICAgICBzdGFydEFwcE9wdGlvbnMucmV0cnkgPSBmYWxzZTtcclxuICAgICAgICByZXR1cm4gdGhpcy5zdGFydEFwcChzdGFydEFwcE9wdGlvbnMpO1xyXG4gICAgICB9IGVsc2Uge1xyXG4gICAgICAgIGxvZy5lcnJvckFuZFRocm93KFwiQWN0aXZpdHkgdXNlZCB0byBzdGFydCBhcHAgZG9lc24ndCBleGlzdCBvciBjYW5ub3QgYmUgXCIgK1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgIFwibGF1bmNoZWQhIE1ha2Ugc3VyZSBpdCBleGlzdHMgYW5kIGlzIGEgbGF1bmNoYWJsZSBhY3Rpdml0eVwiKTtcclxuICAgICAgfVxyXG4gICAgfSBlbHNlIGlmIChzdGRvdXQuaW5kZXhPZihcImphdmEubGFuZy5TZWN1cml0eUV4Y2VwdGlvblwiKSAhPT0gLTEpIHtcclxuICAgICAgLy8gaWYgdGhlIGFwcCBpcyBkaXNhYmxlZCBvbiBhIHJlYWwgZGV2aWNlIGl0IHdpbGwgdGhyb3cgYSBzZWN1cml0eSBleGNlcHRpb25cclxuICAgICAgbG9nLmVycm9yQW5kVGhyb3coXCJQZXJtaXNzaW9uIHRvIHN0YXJ0IGFjdGl2aXR5IGRlbmllZC5cIik7XHJcbiAgICB9XHJcbiAgICBpZiAoc3RhcnRBcHBPcHRpb25zLndhaXRBY3Rpdml0eSkge1xyXG4gICAgICBhd2FpdCB0aGlzLndhaXRGb3JBY3Rpdml0eShzdGFydEFwcE9wdGlvbnMud2FpdFBrZywgc3RhcnRBcHBPcHRpb25zLndhaXRBY3Rpdml0eSxcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RhcnRBcHBPcHRpb25zLndhaXREdXJhdGlvbik7XHJcbiAgICB9XHJcbiAgfSBjYXRjaCAoZSkge1xyXG4gICAgbG9nLmVycm9yQW5kVGhyb3coYEVycm9yIG9jY3VyZWQgd2hpbGUgc3RhcnRpbmcgQXBwLiBPcmlnaW5hbCBlcnJvcjogJHtlLm1lc3NhZ2V9YCk7XHJcbiAgfVxyXG59O1xyXG5cclxuXHJcbmFwa1V0aWxzTWV0aG9kcy5nZXRGb2N1c2VkUGFja2FnZUFuZEFjdGl2aXR5ID0gYXN5bmMgZnVuY3Rpb24gKCkge1xyXG4gIGxvZy5kZWJ1ZyhcIkdldHRpbmcgZm9jdXNlZCBwYWNrYWdlIGFuZCBhY3Rpdml0eVwiKTtcclxuICBsZXQgY21kID0gWydkdW1wc3lzJywgJ3dpbmRvdycsICd3aW5kb3dzJ107XHJcbiAgbGV0IG51bGxSZSA9IG5ldyBSZWdFeHAoL21Gb2N1c2VkQXBwPW51bGwvKTtcclxuICBsZXQgc2VhcmNoUmUgPSBuZXcgUmVnRXhwKCdtRm9jdXNlZEFwcC4rUmVjb3JkXFxcXHsuKlxcXFxzKFteXFxcXHNcXFxcL1xcXFx9XSspJyArXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAnXFxcXC8oW15cXFxcc1xcXFwvXFxcXH1cXFxcLF0rKVxcXFwsPyhcXFxcc1teXFxcXHNcXFxcL1xcXFx9XSspKlxcXFx9Jyk7IC8vIGh0dHBzOi8vcmVnZXgxMDEuY29tL3IveFo4dkY3LzFcclxuICB0cnkge1xyXG4gICAgbGV0IHN0ZG91dCA9IGF3YWl0IHRoaXMuc2hlbGwoY21kKTtcclxuICAgIGxldCBmb3VuZE51bGxNYXRjaCA9IGZhbHNlO1xyXG4gICAgZm9yIChsZXQgbGluZSBvZiBzdGRvdXQuc3BsaXQoXCJcXG5cIikpIHtcclxuICAgICAgbGV0IGZvdW5kTWF0Y2ggPSBzZWFyY2hSZS5leGVjKGxpbmUpO1xyXG4gICAgICBpZiAoZm91bmRNYXRjaCkge1xyXG4gICAgICAgIHJldHVybiB7YXBwUGFja2FnZTogZm91bmRNYXRjaFsxXS50cmltKCksIGFwcEFjdGl2aXR5OiBmb3VuZE1hdGNoWzJdLnRyaW0oKX07XHJcbiAgICAgIH0gZWxzZSBpZiAobnVsbFJlLnRlc3QobGluZSkpIHtcclxuICAgICAgICBmb3VuZE51bGxNYXRjaCA9IHRydWU7XHJcbiAgICAgIH1cclxuICAgIH1cclxuICAgIGlmIChmb3VuZE51bGxNYXRjaCkge1xyXG4gICAgICByZXR1cm4ge2FwcFBhY2thZ2U6IG51bGwsIGFwcEFjdGl2aXR5OiBudWxsfTtcclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIGxvZy5lcnJvckFuZFRocm93KFwiQ291bGQgbm90IHBhcnNlIGFjdGl2aXR5IGZyb20gZHVtcHN5c1wiKTtcclxuICAgIH1cclxuICB9IGNhdGNoIChlKSB7XHJcbiAgICBsb2cuZXJyb3JBbmRUaHJvdyhgQ291bGQgbm90IGdldCBmb2N1c1BhY2thZ2VBbmRBY3Rpdml0eS4gT3JpZ2luYWwgZXJyb3I6ICR7ZS5tZXNzYWdlfWApO1xyXG4gIH1cclxufTtcclxuXHJcbmFwa1V0aWxzTWV0aG9kcy53YWl0Rm9yQWN0aXZpdHlPck5vdCA9IGFzeW5jIGZ1bmN0aW9uIChwa2csIGFjdGl2aXR5LCBub3QsXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB3YWl0TXMgPSAyMDAwMCkge1xyXG4gIGlmICghcGtnIHx8ICFhY3Rpdml0eSkge1xyXG4gICAgdGhyb3cgbmV3IEVycm9yKFwiUGFja2FnZSBhbmQgYWN0aXZpdHkgcmVxdWlyZWQuXCIpO1xyXG4gIH1cclxuICBsb2cuZGVidWcoYFdhaXRpbmcgZm9yIHBrZzogJyR7cGtnfScgYW5kIGFjdGl2aXR5OiAnJHthY3Rpdml0eX0nYCArXHJcbiAgICAgICAgICAgIGAke25vdCA/ICcgbm90JyA6ICcnfSB0byBiZSBmb2N1c2VkYCk7XHJcbiAgbGV0IGVuZEF0ID0gRGF0ZS5ub3coKSArIHdhaXRNcztcclxuXHJcbiAgbGV0IHBvc3NpYmxlQWN0aXZpdHlOYW1lcyA9IFtdO1xyXG4gIGxldCBhbGxBY3Rpdml0aWVzID0gYWN0aXZpdHkuc3BsaXQoXCIsXCIpO1xyXG4gIGZvciAobGV0IG9uZUFjdGl2aXR5IG9mIGFsbEFjdGl2aXRpZXMpIHtcclxuICAgIG9uZUFjdGl2aXR5ID0gb25lQWN0aXZpdHkudHJpbSgpO1xyXG4gICAgcG9zc2libGVBY3Rpdml0eU5hbWVzLnB1c2goLi4uZ2V0UG9zc2libGVBY3Rpdml0eU5hbWVzKHBrZywgb25lQWN0aXZpdHkpKTtcclxuICB9XHJcbiAgbG9nLmRlYnVnKGBQb3NzaWJsZSBhY3Rpdml0aWVzLCB0byBiZSBjaGVja2VkOiAke3Bvc3NpYmxlQWN0aXZpdHlOYW1lcy5qb2luKCcsICcpfWApO1xyXG5cclxuICB3aGlsZSAoRGF0ZS5ub3coKSA8IGVuZEF0KSB7XHJcbiAgICBsZXQge2FwcFBhY2thZ2UsIGFwcEFjdGl2aXR5fSA9IGF3YWl0IHRoaXMuZ2V0Rm9jdXNlZFBhY2thZ2VBbmRBY3Rpdml0eSgpO1xyXG4gICAgbG9nLmRlYnVnKGBGb3VuZCBwYWNrYWdlOiAnJHthcHBQYWNrYWdlfScgYW5kIGFjdGl2aXR5OiAnJHthcHBBY3Rpdml0eX0nYCk7XHJcbiAgICBsZXQgZm91bmRBY3QgPSAoKGFwcFBhY2thZ2UgPT09IHBrZykgJiZcclxuICAgICAgICAgICAgICAgICAgICAoXy5maW5kSW5kZXgocG9zc2libGVBY3Rpdml0eU5hbWVzLCAocG9zc2libGVBY3Rpdml0eSkgPT4gcG9zc2libGVBY3Rpdml0eSA9PT0gYXBwQWN0aXZpdHkpICE9PSAtMSkpO1xyXG4gICAgaWYgKCghbm90ICYmIGZvdW5kQWN0KSB8fCAobm90ICYmICFmb3VuZEFjdCkpIHtcclxuICAgICAgcmV0dXJuO1xyXG4gICAgfVxyXG4gICAgbG9nLmRlYnVnKCdJbmNvcnJlY3QgcGFja2FnZSBhbmQgYWN0aXZpdHkuIFJldHJ5aW5nLicpO1xyXG4gICAgLy8gY29vbCBkb3duIHNvIHdlJ3JlIG5vdCBvdmVybG9hZGluZyBkZXZpY2Ugd2l0aCByZXF1ZXN0c1xyXG4gICAgYXdhaXQgc2xlZXAoNzUwKTtcclxuICB9XHJcbiAgbGV0IGFjdGl2aXR5TWVzc2FnZSA9IHBvc3NpYmxlQWN0aXZpdHlOYW1lcy5qb2luKFwiIG9yIFwiKTtcclxuICBsb2cuZXJyb3JBbmRUaHJvdyhgJHtwa2d9LyR7YWN0aXZpdHlNZXNzYWdlfSBuZXZlciAke25vdCA/ICdzdG9wcGVkJyA6ICdzdGFydGVkJ31gKTtcclxufTtcclxuXHJcbmFwa1V0aWxzTWV0aG9kcy53YWl0Rm9yQWN0aXZpdHkgPSBhc3luYyBmdW5jdGlvbiAocGtnLCBhY3QsIHdhaXRNcyA9IDIwMDAwKSB7XHJcbiAgYXdhaXQgdGhpcy53YWl0Rm9yQWN0aXZpdHlPck5vdChwa2csIGFjdCwgZmFsc2UsIHdhaXRNcyk7XHJcbn07XHJcblxyXG5hcGtVdGlsc01ldGhvZHMud2FpdEZvck5vdEFjdGl2aXR5ID0gYXN5bmMgZnVuY3Rpb24gKHBrZywgYWN0LCB3YWl0TXMgPSAyMDAwMCkge1xyXG4gIGF3YWl0IHRoaXMud2FpdEZvckFjdGl2aXR5T3JOb3QocGtnLCBhY3QsIHRydWUsIHdhaXRNcyk7XHJcbn07XHJcblxyXG5hcGtVdGlsc01ldGhvZHMudW5pbnN0YWxsQXBrID0gYXN5bmMgZnVuY3Rpb24gKHBrZykge1xyXG4gIGxvZy5kZWJ1ZyhgVW5pbnN0YWxsaW5nICR7cGtnfWApO1xyXG4gIHRyeSB7XHJcbiAgICBhd2FpdCB0aGlzLmZvcmNlU3RvcChwa2cpO1xyXG4gICAgbGV0IHN0ZG91dCA9IGF3YWl0IHRoaXMuYWRiRXhlYyhbJ3VuaW5zdGFsbCcsIHBrZ10sIHt0aW1lb3V0OiAyMDAwMH0pO1xyXG4gICAgc3Rkb3V0ID0gc3Rkb3V0LnRyaW0oKTtcclxuICAgIC8vIHN0ZG91dCBtYXkgY29udGFpbiB3YXJuaW5ncyBtZWFuaW5nIHN1Y2Nlc3MgaXMgbm90IG9uIHRoZSBmaXJzdCBsaW5lLlxyXG4gICAgaWYgKHN0ZG91dC5pbmRleE9mKFwiU3VjY2Vzc1wiKSAhPT0gLTEpIHtcclxuICAgICAgbG9nLmluZm8oXCJBcHAgd2FzIHVuaW5zdGFsbGVkXCIpO1xyXG4gICAgICByZXR1cm4gdHJ1ZTtcclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIGxvZy5pbmZvKFwiQXBwIHdhcyBub3QgdW5pbnN0YWxsZWQsIG1heWJlIGl0IHdhc24ndCBvbiBkZXZpY2U/XCIpO1xyXG4gICAgICByZXR1cm4gZmFsc2U7XHJcbiAgICB9XHJcbiAgfSBjYXRjaCAoZSkge1xyXG4gICAgbG9nLmVycm9yQW5kVGhyb3coYFVuYWJsZSB0byB1bmluc3RhbGwgQVBLLiBPcmlnaW5hbCBlcnJvcjogJHtlLm1lc3NhZ2V9YCk7XHJcbiAgfVxyXG59O1xyXG5cclxuYXBrVXRpbHNNZXRob2RzLmluc3RhbGxGcm9tRGV2aWNlUGF0aCA9IGFzeW5jIGZ1bmN0aW9uIChhcGtQYXRoT25EZXZpY2UsIG9wdHMgPSB7fSkge1xyXG4gIGxldCBzdGRvdXQgPSBhd2FpdCB0aGlzLnNoZWxsKFsncG0nLCAnaW5zdGFsbCcsICctcicsIGFwa1BhdGhPbkRldmljZV0sIG9wdHMpO1xyXG4gIGlmIChzdGRvdXQuaW5kZXhPZihcIkZhaWx1cmVcIikgIT09IC0xKSB7XHJcbiAgICBsb2cuZXJyb3JBbmRUaHJvdyhgUmVtb3RlIGluc3RhbGwgZmFpbGVkOiAke3N0ZG91dH1gKTtcclxuICB9XHJcbn07XHJcblxyXG5hcGtVdGlsc01ldGhvZHMuaW5zdGFsbCA9IGFzeW5jIGZ1bmN0aW9uIChhcGssIHJlcGxhY2UgPSB0cnVlLCB0aW1lb3V0ID0gNjAwMDApIHtcclxuICBpZiAocmVwbGFjZSkge1xyXG4gICAgYXdhaXQgdGhpcy5hZGJFeGVjKFsnaW5zdGFsbCcsICctcicsIGFwa10sIHt0aW1lb3V0fSk7XHJcbiAgfSBlbHNlIHtcclxuICAgIHRyeSB7XHJcbiAgICAgIGF3YWl0IHRoaXMuYWRiRXhlYyhbJ2luc3RhbGwnLCBhcGtdLCB7dGltZW91dH0pO1xyXG4gICAgfSBjYXRjaCAoZXJyKSB7XHJcbiAgICAgIC8vIG9uIHNvbWUgc3lzdGVtcyB0aGlzIHdpbGwgdGhyb3cgYW4gZXJyb3IgaWYgdGhlIGFwcCBhbHJlYWR5XHJcbiAgICAgIC8vIGV4aXN0c1xyXG4gICAgICBpZiAoZXJyLm1lc3NhZ2UuaW5kZXhPZignSU5TVEFMTF9GQUlMRURfQUxSRUFEWV9FWElTVFMnKSA9PT0gLTEpIHtcclxuICAgICAgICB0aHJvdyBlcnI7XHJcbiAgICAgIH1cclxuICAgICAgbG9nLmRlYnVnKGBBcHBsaWNhdGlvbiAnJHthcGt9JyBhbHJlYWR5IGluc3RhbGxlZC4gQ29udGludWluZy5gKTtcclxuICAgIH1cclxuICB9XHJcbn07XHJcblxyXG5hcGtVdGlsc01ldGhvZHMuZXh0cmFjdFN0cmluZ3NGcm9tQXBrID0gYXN5bmMgZnVuY3Rpb24gKGFwaywgbGFuZ3VhZ2UsIG91dCkge1xyXG4gIGxvZy5kZWJ1ZyhgRXh0cmFjdGluZyBzdHJpbmdzIGZvciBsYW5ndWFnZTogJHtsYW5ndWFnZSB8fCBcImRlZmF1bHRcIn1gKTtcclxuICBsZXQgc3RyaW5nc0pzb24gPSAnc3RyaW5ncy5qc29uJztcclxuICBsZXQgbG9jYWxQYXRoO1xyXG4gIGlmICghbGFuZ3VhZ2UpIHtcclxuICAgIGxhbmd1YWdlID0gYXdhaXQgdGhpcy5nZXREZXZpY2VMYW5ndWFnZSgpO1xyXG4gIH1cclxuICBsZXQgYXBrVG9vbHMgPSB0aGlzLmphcnNbJ2FwcGl1bV9hcGtfdG9vbHMuamFyJ107XHJcbiAgbGV0IGFyZ3MgPSBbJy1qYXInLCBhcGtUb29scywgJ3N0cmluZ3NGcm9tQXBrJywgYXBrLCBvdXQsIGxhbmd1YWdlXTtcclxuICBsZXQgZmlsZURhdGEsIGFwa1N0cmluZ3M7XHJcbiAgdHJ5IHtcclxuICAgIGF3YWl0IGV4ZWMoJ2phdmEnLCBhcmdzKTtcclxuICB9IGNhdGNoIChlKSB7XHJcbiAgICBsb2cuZGVidWcoYE5vIHN0cmluZ3MueG1sIGZvciBsYW5ndWFnZSAnJHtsYW5ndWFnZX0nLCBnZXR0aW5nIGRlZmF1bHQgYCArXHJcbiAgICAgICAgICAgICAgYHN0cmluZ3MueG1sYCk7XHJcbiAgICBhcmdzLnBvcCgpO1xyXG4gICAgYXdhaXQgZXhlYygnamF2YScsIGFyZ3MpO1xyXG4gIH1cclxuXHJcbiAgdHJ5IHtcclxuICAgIGxvZy5kZWJ1ZyhcIlJlYWRpbmcgc3RyaW5ncyBmcm9tIGNvbnZlcnRlZCBzdHJpbmdzLmpzb25cIik7XHJcbiAgICBsb2NhbFBhdGggPSBwYXRoLmpvaW4ob3V0LCBzdHJpbmdzSnNvbik7XHJcbiAgICBmaWxlRGF0YSA9IGF3YWl0IGZzLnJlYWRGaWxlKGxvY2FsUGF0aCwgJ3V0ZjgnKTtcclxuICAgIGFwa1N0cmluZ3MgPSBKU09OLnBhcnNlKGZpbGVEYXRhKTtcclxuICB9IGNhdGNoIChlKSB7XHJcbiAgICBpZiAoZmlsZURhdGEpIHtcclxuICAgICAgbG9nLmRlYnVnKGBDb250ZW50IHN0YXJ0ZWQgd2l0aDogJHtmaWxlRGF0YS5zbGljZSgwLCAzMDApfWApO1xyXG4gICAgfVxyXG4gICAgbGV0IG1zZyA9IGBDb3VsZCBub3QgcGFyc2Ugc3RyaW5ncyBmcm9tIHN0cmluZ3MuanNvbi4gT3JpZ2luYWwgYCArXHJcbiAgICAgICAgICAgICAgYGVycm9yOiAke2UubWVzc2FnZX1gO1xyXG4gICAgbG9nLmVycm9yQW5kVGhyb3cobXNnKTtcclxuICB9XHJcbiAgcmV0dXJuIHthcGtTdHJpbmdzLCBsb2NhbFBhdGh9O1xyXG59O1xyXG5cclxuYXBrVXRpbHNNZXRob2RzLmdldERldmljZUxhbmd1YWdlID0gYXN5bmMgZnVuY3Rpb24gKCkge1xyXG4gIGxldCBsYW5ndWFnZTtcclxuICBpZiAoYXdhaXQgdGhpcy5nZXRBcGlMZXZlbCgpIDwgMjMpIHtcclxuICAgIGxhbmd1YWdlID0gYXdhaXQgdGhpcy5nZXREZXZpY2VTeXNMYW5ndWFnZSgpO1xyXG4gICAgaWYgKCFsYW5ndWFnZSkge1xyXG4gICAgICBsYW5ndWFnZSA9IGF3YWl0IHRoaXMuZ2V0RGV2aWNlUHJvZHVjdExhbmd1YWdlKCk7XHJcbiAgICB9XHJcbiAgfSBlbHNlIHtcclxuIC