appium-adb
Version:
Android Debug Bridge interface
831 lines (647 loc) • 49.7 kB
JavaScript
;
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 = 7;
break;
case 5:
context$1$0.next = 7;
return _regeneratorRuntime.awrap(this.adbExec(['install', apk], { timeout: timeout }));
case 7:
case 'end':
return context$1$0.stop();
}
}, null, this);
};
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
// 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;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbImxpYi90b29scy9hcGstdXRpbHMuanMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7eUJBQXdELGVBQWU7OzRCQUNsRCxjQUFjOzt3QkFDbkIsY0FBYzs7OztvQkFDYixNQUFNOzs7O3NCQUNULFFBQVE7Ozs7d0JBQ0EsVUFBVTs7NkJBQ2IsZ0JBQWdCOztBQUVuQyxJQUFJLGVBQWUsR0FBRyxFQUFFLENBQUM7O0FBRXpCLGVBQWUsQ0FBQyxjQUFjLEdBQUcsb0JBQWdCLEdBQUc7TUFFNUMsU0FBUyxFQUVULFFBQVEsRUFDUixVQUFVLEVBQ1YsTUFBTSxFQUNOLGVBQWU7Ozs7O0FBTGYsaUJBQVMsR0FBRyxLQUFLOztBQUNyQiw4QkFBSSxLQUFLLGlDQUErQixHQUFHLENBQUcsQ0FBQzs7eUNBQzFCLElBQUksQ0FBQyxXQUFXLEVBQUU7OztBQUFuQyxnQkFBUTtBQUNSLGtCQUFVLEdBQUcsUUFBUSxJQUFJLEVBQUUsR0FBRyxJQUFJLEdBQUcsRUFBRTs7eUNBQ3hCLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQyxJQUFJLEVBQUUsTUFBTSxFQUFFLFVBQVUsRUFBRSxVQUFVLEVBQUUsR0FBRyxDQUFDLENBQUM7OztBQUF0RSxjQUFNO0FBQ04sdUJBQWUsR0FBRyxJQUFJLE1BQU0sZUFBYSxHQUFHLENBQUMsT0FBTyxDQUFDLE9BQU8sRUFBRSxNQUFNLENBQUMsUUFDeEMsR0FBRyxDQUFDOztBQUNyQyxpQkFBUyxHQUFHLGVBQWUsQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLENBQUM7QUFDekMsOEJBQUksS0FBSyxjQUFXLENBQUMsU0FBUyxHQUFHLE1BQU0sR0FBRyxFQUFFLENBQUEsZ0JBQWEsQ0FBQzs0Q0FDbkQsU0FBUzs7Ozs7O0FBRWhCLDhCQUFJLGFBQWEseURBQXVELGVBQUUsT0FBTyxDQUFHLENBQUM7Ozs7Ozs7Q0FFeEYsQ0FBQzs7QUFFRixlQUFlLENBQUMsUUFBUSxHQUFHLG9CQUFnQixHQUFHLEVBQUUsR0FBRztNQUsz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RixlQUFlLENBQUMsZUFBZSxHQUFHLG9CQUFnQixNQUFNOzs7Ozt5Q0FFaEQsSUFBSSxDQUFDLGtCQUFrQixDQUFDLE1BQU0sQ0FBQzs7Ozs7OztDQUN0QyxDQUFDOztxQkFFYSxlQUFlIiwiZmlsZSI6ImxpYi90b29scy9hcGstdXRpbHMuanMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBidWlsZFN0YXJ0Q21kLCBnZXRQb3NzaWJsZUFjdGl2aXR5TmFtZXMgfSBmcm9tICcuLi9oZWxwZXJzLmpzJztcbmltcG9ydCB7IGV4ZWMgfSBmcm9tICd0ZWVuX3Byb2Nlc3MnO1xuaW1wb3J0IGxvZyBmcm9tICcuLi9sb2dnZXIuanMnO1xuaW1wb3J0IHBhdGggZnJvbSAncGF0aCc7XG5pbXBvcnQgXyBmcm9tICdsb2Rhc2gnO1xuaW1wb3J0IHsgc2xlZXAgfSBmcm9tICdhc3luY2JveCc7XG5pbXBvcnQgeyBmcyB9IGZyb20gJ2FwcGl1bS1zdXBwb3J0JztcblxubGV0IGFwa1V0aWxzTWV0aG9kcyA9IHt9O1xuXG5hcGtVdGlsc01ldGhvZHMuaXNBcHBJbnN0YWxsZWQgPSBhc3luYyBmdW5jdGlvbiAocGtnKSB7XG4gIHRyeSB7XG4gICAgbGV0IGluc3RhbGxlZCA9IGZhbHNlO1xuICAgIGxvZy5kZWJ1ZyhgR2V0dGluZyBpbnN0YWxsIHN0YXR1cyBmb3IgJHtwa2d9YCk7XG4gICAgbGV0IGFwaUxldmVsID0gYXdhaXQgdGhpcy5nZXRBcGlMZXZlbCgpO1xuICAgIGxldCB0aGlyZHBhcnR5ID0gYXBpTGV2ZWwgPj0gMTUgPyBcIi0zXCIgOiBcIlwiO1xuICAgIGxldCBzdGRvdXQgPSBhd2FpdCB0aGlzLnNoZWxsKFsncG0nLCAnbGlzdCcsICdwYWNrYWdlcycsIHRoaXJkcGFydHksIHBrZ10pO1xuICAgIGxldCBhcGtJbnN0YWxsZWRSZ3ggPSBuZXcgUmVnRXhwKGBecGFja2FnZToke3BrZy5yZXBsYWNlKC8oXFwuKS9nLCBcIlxcXFwkMVwiKX0kYCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnbScpO1xuICAgIGluc3RhbGxlZCA9IGFwa0luc3RhbGxlZFJneC50ZXN0KHN0ZG91dCk7XG4gICAgbG9nLmRlYnVnKGBBcHAgaXMgJHshaW5zdGFsbGVkID8gXCIgbm90XCIgOiBcIlwifSBpbnN0YWxsZWRgKTtcbiAgICByZXR1cm4gaW5zdGFsbGVkO1xuICB9IGNhdGNoIChlKSB7XG4gICAgbG9nLmVycm9yQW5kVGhyb3coYEVycm9yIGZpbmRpbmcgaWYgYXBwIGlzIGluc3RhbGxlZC4gT3JpZ2luYWwgZXJyb3I6ICR7ZS5tZXNzYWdlfWApO1xuICB9XG59O1xuXG5hcGtVdGlsc01ldGhvZHMuc3RhcnRVcmkgPSBhc3luYyBmdW5jdGlvbiAodXJpLCBwa2cpIHtcbiAgaWYgKCF1cmkgfHwgIXBrZykge1xuICAgIGxvZy5lcnJvckFuZFRocm93KFwiVVJJIGFuZCBwYWNrYWdlIGFyZ3VtZW50cyBhcmUgcmVxdWlyZWRcIik7XG4gIH1cbiAgdHJ5IHtcbiAgICBsZXQgYXJncyA9IFtcImFtXCIsIFwic3RhcnRcIiwgXCItV1wiLCBcIi1hXCIsIFwiYW5kcm9pZC5pbnRlbnQuYWN0aW9uLlZJRVdcIiwgXCItZFwiLFxuICAgICAgICAgICAgICAgIHVyaSwgcGtnXTtcbiAgICBhd2FpdCB0aGlzLnNoZWxsKGFyZ3MpO1xuICB9IGNhdGNoIChlKSB7XG4gICAgbG9nLmVycm9yQW5kVGhyb3coYEVycm9yIGF0dGVtcHRpbmcgdG8gc3RhcnQgVVJJLiBPcmlnaW5hbCBlcnJvcjogJHtlfWApO1xuICB9XG59O1xuXG5hcGtVdGlsc01ldGhvZHMuc3RhcnRBcHAgPSBhc3luYyBmdW5jdGlvbiAoc3RhcnRBcHBPcHRpb25zID0ge30pIHtcbiAgdHJ5IHtcbiAgICBpZiAoIXN0YXJ0QXBwT3B0aW9ucy5hY3Rpdml0eSB8fCAhc3RhcnRBcHBPcHRpb25zLnBrZykge1xuICAgICAgbG9nLmVycm9yQW5kVGhyb3coXCJhY3Rpdml0eSBhbmQgcGtnIGlzIHJlcXVpcmVkIGZvciBsYXVuY2hpbmcgYXBwbGljYXRpb25cIik7XG4gICAgfVxuICAgIHN0YXJ0QXBwT3B0aW9ucyA9IF8uY2xvbmUoc3RhcnRBcHBPcHRpb25zKTtcbiAgICAvLyBpbml0aWFsaXppbmcgZGVmYXVsdHNcbiAgICBfLmRlZmF1bHRzKHN0YXJ0QXBwT3B0aW9ucywge1xuICAgICAgICB3YWl0UGtnOiBzdGFydEFwcE9wdGlvbnMucGtnLFxuICAgICAgICB3YWl0QWN0aXZpdHk6IGZhbHNlLFxuICAgICAgICByZXRyeTogdHJ1ZSxcbiAgICAgICAgc3RvcEFwcDogdHJ1ZVxuICAgIH0pO1xuICAgIC8vIHByZXZlbnRpbmcgbnVsbCB3YWl0cGtnXG4gICAgc3RhcnRBcHBPcHRpb25zLndhaXRQa2cgPSBzdGFydEFwcE9wdGlvbnMud2FpdFBrZyB8fCBzdGFydEFwcE9wdGlvbnMucGtnO1xuICAgIGxldCBhcGlMZXZlbCA9IGF3YWl0IHRoaXMuZ2V0QXBpTGV2ZWwoKTtcbiAgICBsZXQgY21kID0gYnVpbGRTdGFydENtZChzdGFydEFwcE9wdGlvbnMsIGFwaUxldmVsKTtcbiAgICBsZXQgc3Rkb3V0ID0gYXdhaXQgdGhpcy5zaGVsbChjbWQpO1xuICAgIGlmIChzdGRvdXQuaW5kZXhPZihcIkVycm9yOiBBY3Rpdml0eSBjbGFzc1wiKSAhPT0gLTEgJiZcbiAgICAgICAgc3Rkb3V0LmluZGV4T2YoXCJkb2VzIG5vdCBleGlzdFwiKSAhPT0gLTEpIHtcbiAgICAgIGlmIChzdGFydEFwcE9wdGlvbnMucmV0cnkgJiYgc3RhcnRBcHBPcHRpb25zLmFjdGl2aXR5WzBdICE9PSBcIi5cIikge1xuICAgICAgICBsb2cuZGVidWcoXCJXZSB0cmllZCB0byBzdGFydCBhbiBhY3Rpdml0eSB0aGF0IGRvZXNuJ3QgZXhpc3QsIFwiICtcbiAgICAgICAgICAgICAgICAgIFwicmV0cnlpbmcgd2l0aCAuIHByZXBlbmRlZCB0byBhY3Rpdml0eVwiKTtcbiAgICAgICAgc3RhcnRBcHBPcHRpb25zLmFjdGl2aXR5ID0gYC4ke3N0YXJ0QXBwT3B0aW9ucy5hY3Rpdml0eX1gO1xuICAgICAgICBzdGFydEFwcE9wdGlvbnMucmV0cnkgPSBmYWxzZTtcbiAgICAgICAgcmV0dXJuIHRoaXMuc3RhcnRBcHAoc3RhcnRBcHBPcHRpb25zKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGxvZy5lcnJvckFuZFRocm93KFwiQWN0aXZpdHkgdXNlZCB0byBzdGFydCBhcHAgZG9lc24ndCBleGlzdCBvciBjYW5ub3QgYmUgXCIgK1xuICAgICAgICAgICAgICAgICAgICAgICAgICBcImxhdW5jaGVkISBNYWtlIHN1cmUgaXQgZXhpc3RzIGFuZCBpcyBhIGxhdW5jaGFibGUgYWN0aXZpdHlcIik7XG4gICAgICB9XG4gICAgfSBlbHNlIGlmIChzdGRvdXQuaW5kZXhPZihcImphdmEubGFuZy5TZWN1cml0eUV4Y2VwdGlvblwiKSAhPT0gLTEpIHtcbiAgICAgIC8vIGlmIHRoZSBhcHAgaXMgZGlzYWJsZWQgb24gYSByZWFsIGRldmljZSBpdCB3aWxsIHRocm93IGEgc2VjdXJpdHkgZXhjZXB0aW9uXG4gICAgICBsb2cuZXJyb3JBbmRUaHJvdyhcIlBlcm1pc3Npb24gdG8gc3RhcnQgYWN0aXZpdHkgZGVuaWVkLlwiKTtcbiAgICB9XG4gICAgaWYgKHN0YXJ0QXBwT3B0aW9ucy53YWl0QWN0aXZpdHkpIHtcbiAgICAgIGF3YWl0IHRoaXMud2FpdEZvckFjdGl2aXR5KHN0YXJ0QXBwT3B0aW9ucy53YWl0UGtnLCBzdGFydEFwcE9wdGlvbnMud2FpdEFjdGl2aXR5LFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RhcnRBcHBPcHRpb25zLndhaXREdXJhdGlvbik7XG4gICAgfVxuICB9IGNhdGNoIChlKSB7XG4gICAgbG9nLmVycm9yQW5kVGhyb3coYEVycm9yIG9jY3VyZWQgd2hpbGUgc3RhcnRpbmcgQXBwLiBPcmlnaW5hbCBlcnJvcjogJHtlLm1lc3NhZ2V9YCk7XG4gIH1cbn07XG5cblxuYXBrVXRpbHNNZXRob2RzLmdldEZvY3VzZWRQYWNrYWdlQW5kQWN0aXZpdHkgPSBhc3luYyBmdW5jdGlvbiAoKSB7XG4gIGxvZy5kZWJ1ZyhcIkdldHRpbmcgZm9jdXNlZCBwYWNrYWdlIGFuZCBhY3Rpdml0eVwiKTtcbiAgbGV0IGNtZCA9IFsnZHVtcHN5cycsICd3aW5kb3cnLCAnd2luZG93cyddO1xuICBsZXQgbnVsbFJlID0gbmV3IFJlZ0V4cCgvbUZvY3VzZWRBcHA9bnVsbC8pO1xuICBsZXQgc2VhcmNoUmUgPSBuZXcgUmVnRXhwKCdtRm9jdXNlZEFwcC4rUmVjb3JkXFxcXHsuKlxcXFxzKFteXFxcXHNcXFxcL1xcXFx9XSspJyArXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgJ1xcXFwvKFteXFxcXHNcXFxcL1xcXFx9XFxcXCxdKylcXFxcLD8oXFxcXHNbXlxcXFxzXFxcXC9cXFxcfV0rKSpcXFxcfScpOyAvLyBodHRwczovL3JlZ2V4MTAxLmNvbS9yL3haOHZGNy8xXG4gIHRyeSB7XG4gICAgbGV0IHN0ZG91dCA9IGF3YWl0IHRoaXMuc2hlbGwoY21kKTtcbiAgICBsZXQgZm91bmROdWxsTWF0Y2ggPSBmYWxzZTtcbiAgICBmb3IgKGxldCBsaW5lIG9mIHN0ZG91dC5zcGxpdChcIlxcblwiKSkge1xuICAgICAgbGV0IGZvdW5kTWF0Y2ggPSBzZWFyY2hSZS5leGVjKGxpbmUpO1xuICAgICAgaWYgKGZvdW5kTWF0Y2gpIHtcbiAgICAgICAgcmV0dXJuIHthcHBQYWNrYWdlOiBmb3VuZE1hdGNoWzFdLnRyaW0oKSwgYXBwQWN0aXZpdHk6IGZvdW5kTWF0Y2hbMl0udHJpbSgpfTtcbiAgICAgIH0gZWxzZSBpZiAobnVsbFJlLnRlc3QobGluZSkpIHtcbiAgICAgICAgZm91bmROdWxsTWF0Y2ggPSB0cnVlO1xuICAgICAgfVxuICAgIH1cbiAgICBpZiAoZm91bmROdWxsTWF0Y2gpIHtcbiAgICAgIHJldHVybiB7YXBwUGFja2FnZTogbnVsbCwgYXBwQWN0aXZpdHk6IG51bGx9O1xuICAgIH0gZWxzZSB7XG4gICAgICBsb2cuZXJyb3JBbmRUaHJvdyhcIkNvdWxkIG5vdCBwYXJzZSBhY3Rpdml0eSBmcm9tIGR1bXBzeXNcIik7XG4gICAgfVxuICB9IGNhdGNoIChlKSB7XG4gICAgbG9nLmVycm9yQW5kVGhyb3coYENvdWxkIG5vdCBnZXQgZm9jdXNQYWNrYWdlQW5kQWN0aXZpdHkuIE9yaWdpbmFsIGVycm9yOiAke2UubWVzc2FnZX1gKTtcbiAgfVxufTtcblxuYXBrVXRpbHNNZXRob2RzLndhaXRGb3JBY3Rpdml0eU9yTm90ID0gYXN5bmMgZnVuY3Rpb24gKHBrZywgYWN0aXZpdHksIG5vdCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB3YWl0TXMgPSAyMDAwMCkge1xuICBpZiAoIXBrZyB8fCAhYWN0aXZpdHkpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoXCJQYWNrYWdlIGFuZCBhY3Rpdml0eSByZXF1aXJlZC5cIik7XG4gIH1cbiAgbG9nLmRlYnVnKGBXYWl0aW5nIGZvciBwa2c6ICcke3BrZ30nIGFuZCBhY3Rpdml0eTogJyR7YWN0aXZpdHl9J2AgK1xuICAgICAgICAgICAgYCR7bm90ID8gJyBub3QnIDogJyd9IHRvIGJlIGZvY3VzZWRgKTtcbiAgbGV0IGVuZEF0ID0gRGF0ZS5ub3coKSArIHdhaXRNcztcbiAgXG4gIGxldCBwb3NzaWJsZUFjdGl2aXR5TmFtZXMgPSBbXTtcbiAgbGV0IGFsbEFjdGl2aXRpZXMgPSBhY3Rpdml0eS5zcGxpdChcIixcIik7XG4gIGZvciAobGV0IG9uZUFjdGl2aXR5IG9mIGFsbEFjdGl2aXRpZXMpIHtcbiAgICBvbmVBY3Rpdml0eSA9IG9uZUFjdGl2aXR5LnRyaW0oKTtcbiAgICBwb3NzaWJsZUFjdGl2aXR5TmFtZXMucHVzaCguLi5nZXRQb3NzaWJsZUFjdGl2aXR5TmFtZXMocGtnLCBvbmVBY3Rpdml0eSkpO1xuICB9XG4gIGxvZy5kZWJ1ZyhgUG9zc2libGUgYWN0aXZpdGllcywgdG8gYmUgY2hlY2tlZDogJHtwb3NzaWJsZUFjdGl2aXR5TmFtZXMuam9pbignLCAnKX1gKTtcblxuICB3aGlsZSAoRGF0ZS5ub3coKSA8IGVuZEF0KSB7XG4gICAgbGV0IHthcHBQYWNrYWdlLCBhcHBBY3Rpdml0eX0gPSBhd2FpdCB0aGlzLmdldEZvY3VzZWRQYWNrYWdlQW5kQWN0aXZpdHkoKTtcbiAgICBsb2cuZGVidWcoYEZvdW5kIHBhY2thZ2U6ICcke2FwcFBhY2thZ2V9JyBhbmQgYWN0aXZpdHk6ICcke2FwcEFjdGl2aXR5fSdgKTtcbiAgICBsZXQgZm91bmRBY3QgPSAoKGFwcFBhY2thZ2UgPT09IHBrZykgJiZcbiAgICAgICAgICAgICAgICAgICAgKF8uZmluZEluZGV4KHBvc3NpYmxlQWN0aXZpdHlOYW1lcywgcG9zc2libGVBY3Rpdml0eSA9PiBwb3NzaWJsZUFjdGl2aXR5ID09PSBhcHBBY3Rpdml0eSkgIT09IC0xKSk7XG4gICAgaWYgKCghbm90ICYmIGZvdW5kQWN0KSB8fCAobm90ICYmICFmb3VuZEFjdCkpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgbG9nLmRlYnVnKCdJbmNvcnJlY3QgcGFja2FnZSBhbmQgYWN0aXZpdHkuIFJldHJ5aW5nLicpO1xuICAgIC8vIGNvb2wgZG93biBzbyB3ZSdyZSBub3Qgb3ZlcmxvYWRpbmcgZGV2aWNlIHdpdGggcmVxdWVzdHNcbiAgICBhd2FpdCBzbGVlcCg3NTApO1xuICB9XG4gIGxldCBhY3Rpdml0eU1lc3NhZ2UgPSBwb3NzaWJsZUFjdGl2aXR5TmFtZXMuam9pbihcIiBvciBcIik7XG4gIGxvZy5lcnJvckFuZFRocm93KGAke3BrZ30vJHthY3Rpdml0eU1lc3NhZ2V9IG5ldmVyICR7bm90ID8gJ3N0b3BwZWQnIDogJ3N0YXJ0ZWQnfWApO1xufTtcblxuYXBrVXRpbHNNZXRob2RzLndhaXRGb3JBY3Rpdml0eSA9IGFzeW5jIGZ1bmN0aW9uIChwa2csIGFjdCwgd2FpdE1zID0gMjAwMDApIHtcbiAgYXdhaXQgdGhpcy53YWl0Rm9yQWN0aXZpdHlPck5vdChwa2csIGFjdCwgZmFsc2UsIHdhaXRNcyk7XG59O1xuXG5hcGtVdGlsc01ldGhvZHMud2FpdEZvck5vdEFjdGl2aXR5ID0gYXN5bmMgZnVuY3Rpb24gKHBrZywgYWN0LCB3YWl0TXMgPSAyMDAwMCkge1xuICBhd2FpdCB0aGlzLndhaXRGb3JBY3Rpdml0eU9yTm90KHBrZywgYWN0LCB0cnVlLCB3YWl0TXMpO1xufTtcblxuYXBrVXRpbHNNZXRob2RzLnVuaW5zdGFsbEFwayA9IGFzeW5jIGZ1bmN0aW9uIChwa2cpIHtcbiAgbG9nLmRlYnVnKGBVbmluc3RhbGxpbmcgJHtwa2d9YCk7XG4gIHRyeSB7XG4gICAgYXdhaXQgdGhpcy5mb3JjZVN0b3AocGtnKTtcbiAgICBsZXQgc3Rkb3V0ID0gYXdhaXQgdGhpcy5hZGJFeGVjKFsndW5pbnN0YWxsJywgcGtnXSwge3RpbWVvdXQ6IDIwMDAwfSk7XG4gICAgc3Rkb3V0ID0gc3Rkb3V0LnRyaW0oKTtcbiAgICAvLyBzdGRvdXQgbWF5IGNvbnRhaW4gd2FybmluZ3MgbWVhbmluZyBzdWNjZXNzIGlzIG5vdCBvbiB0aGUgZmlyc3QgbGluZS5cbiAgICBpZiAoc3Rkb3V0LmluZGV4T2YoXCJTdWNjZXNzXCIpICE9PSAtMSkge1xuICAgICAgbG9nLmluZm8oXCJBcHAgd2FzIHVuaW5zdGFsbGVkXCIpO1xuICAgICAgcmV0dXJuIHRydWU7XG4gICAgfSBlbHNlIHtcbiAgICAgIGxvZy5pbmZvKFwiQXBwIHdhcyBub3QgdW5pbnN0YWxsZWQsIG1heWJlIGl0IHdhc24ndCBvbiBkZXZpY2U/XCIpO1xuICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cbiAgfSBjYXRjaCAoZSkge1xuICAgIGxvZy5lcnJvckFuZFRocm93KGBVbmFibGUgdG8gdW5pbnN0YWxsIEFQSy4gT3JpZ2luYWwgZXJyb3I6ICR7ZS5tZXNzYWdlfWApO1xuICB9XG59O1xuXG5hcGtVdGlsc01ldGhvZHMuaW5zdGFsbEZyb21EZXZpY2VQYXRoID0gYXN5bmMgZnVuY3Rpb24gKGFwa1BhdGhPbkRldmljZSwgb3B0cyA9IHt9KSB7XG4gIGxldCBzdGRvdXQgPSBhd2FpdCB0aGlzLnNoZWxsKFsncG0nLCAnaW5zdGFsbCcsICctcicsIGFwa1BhdGhPbkRldmljZV0sIG9wdHMpO1xuICBpZiAoc3Rkb3V0LmluZGV4T2YoXCJGYWlsdXJlXCIpICE9PSAtMSkge1xuICAgIGxvZy5lcnJvckFuZFRocm93KGBSZW1vdGUgaW5zdGFsbCBmYWlsZWQ6ICR7c3Rkb3V0fWApO1xuICB9XG59O1xuXG5hcGtVdGlsc01ldGhvZHMuaW5zdGFsbCA9IGFzeW5jIGZ1bmN0aW9uIChhcGssIHJlcGxhY2UgPSB0cnVlLCB0aW1lb3V0ID0gNjAwMDApIHtcbiAgaWYgKHJlcGxhY2UpIHtcbiAgICBhd2FpdCB0aGlzLmFkYkV4ZWMoWydpbnN0YWxsJywgJy1yJywgYXBrXSwge3RpbWVvdXR9KTtcbiAgfSBlbHNlIHtcbiAgICBhd2FpdCB0aGlzLmFkYkV4ZWMoWydpbnN0YWxsJywgYXBrXSwge3RpbWVvdXR9KTtcbiAgfVxufTtcblxuYXBrVXRpbHNNZXRob2RzLmV4dHJhY3RTdHJpbmdzRnJvbUFwayA9IGFzeW5jIGZ1bmN0aW9uIChhcGssIGxhbmd1YWdlLCBvdXQpIHtcbiAgbG9nLmRlYnVnKGBFeHRyYWN0aW5nIHN0cmluZ3MgZm9yIGxhbmd1YWdlOiAke2xhbmd1YWdlIHx8IFwiZGVmYXVsdFwifWApO1xuICBsZXQgc3RyaW5nc0pzb24gPSAnc3RyaW5ncy5qc29uJztcbiAgbGV0IGxvY2FsUGF0aDtcbiAgaWYgKCFsYW5ndWFnZSkge1xuICAgIGxhbmd1YWdlID0gYXdhaXQgdGhpcy5nZXREZXZpY2VMYW5ndWFnZSgpO1xuICB9XG4gIGxldCBhcGtUb29scyA9IHRoaXMuamFyc1snYXBwaXVtX2Fwa190b29scy5qYXInXTtcbiAgbGV0IGFyZ3MgPSBbJy1qYXInLCBhcGtUb29scywgJ3N0cmluZ3NGcm9tQXBrJywgYXBrLCBvdXQsIGxhbmd1YWdlXTtcbiAgbGV0IGZpbGVEYXRhLCBhcGtTdHJpbmdzO1xuICB0cnkge1xuICAgIGF3YWl0IGV4ZWMoJ2phdmEnLCBhcmdzKTtcbiAgfSBjYXRjaCAoZSkge1xuICAgIGxvZy5kZWJ1ZyhgTm8gc3RyaW5ncy54bWwgZm9yIGxhbmd1YWdlICcke2xhbmd1YWdlfScsIGdldHRpbmcgZGVmYXVsdCBgICtcbiAgICAgICAgICAgICAgYHN0cmluZ3MueG1sYCk7XG4gICAgYXJncy5wb3AoKTtcbiAgICBhd2FpdCBleGVjKCdqYXZhJywgYXJncyk7XG4gIH1cblxuICB0cnkge1xuICAgIGxvZy5kZWJ1ZyhcIlJlYWRpbmcgc3RyaW5ncyBmcm9tIGNvbnZlcnRlZCBzdHJpbmdzLmpzb25cIik7XG4gICAgbG9jYWxQYXRoID0gcGF0aC5qb2luKG91dCwgc3RyaW5nc0pzb24pO1xuICAgIGZpbGVEYXRhID0gYXdhaXQgZnMucmVhZEZpbGUobG9jYWxQYXRoLCAndXRmOCcpO1xuICAgIGFwa1N0cmluZ3MgPSBKU09OLnBhcnNlKGZpbGVEYXRhKTtcbiAgfSBjYXRjaCAoZSkge1xuICAgIGlmIChmaWxlRGF0YSkge1xuICAgICAgbG9nLmRlYnVnKGBDb250ZW50IHN0YXJ0ZWQgd2l0aDogJHtmaWxlRGF0YS5zbGljZSgwLCAzMDApfWApO1xuICAgIH1cbiAgICBsZXQgbXNnID0gYENvdWxkIG5vdCBwYXJzZSBzdHJpbmdzIGZyb20gc3RyaW5ncy5qc29uLiBPcmlnaW5hbCBgICtcbiAgICAgICAgICAgICAgYGVycm9yOiAke2UubWVzc2FnZX1gO1xuICAgIGxvZy5lcnJvckFuZFRocm93KG1zZyk7XG4gIH1cbiAgcmV0dXJuIHthcGtTdHJpbmdzLCBsb2NhbFBhdGh9O1xufTtcblxuYXBrVXRpbHNNZXRob2RzLmdldERldmljZUxhbmd1YWdlID0gYXN5bmMgZnVuY3Rpb24gKCkge1xuICBsZXQgbGFuZ3VhZ2U7XG4gIGlmIChhd2FpdCB0aGlzLmdldEFwaUxldmVsKCkgPCAyMykge1xuICAgIGxhbmd1YWdlID0gYXdhaXQgdGhpcy5nZXREZXZpY2VTeXNMYW5ndWFnZSgpO1xuICAgIGlmICghbGFuZ3VhZ2UpIHtcbiAgICAgIGxhbmd1YWdlID0gYXdhaXQgdGhpcy5nZXREZXZpY2VQcm9kdWN0TGFuZ3VhZ2UoKTtcbiAgICB9XG4gIH0gZWxzZSB7XG4gICAgbGFuZ3VhZ2UgPSAoYXdhaXQgdGhpcy5nZXREZXZpY2VMb2NhbGUoKSkuc3BsaXQoXCItXCIpWzBdO1xuICB9XG4gIHJldHVybiBsYW5ndWFnZTtcbn07XG5cbmFwa1V0aWxzTWV0aG9kcy5zZXREZXZpY2VMYW5ndWFnZSA9IGFzeW5jIGZ1bmN0aW9uIChsYW5ndWFnZSkge1xuICAvLyB0aGlzIG1ldGhvZCBpcyBvbmx5IHVzZWQgaW4gQVBJIDwgMjNcbiAgYXdhaXQgdGhpcy5zZXREZXZpY2VTeXNMYW5ndWFnZShsYW5ndWFnZSk7XG59O1xuXG5hcGtVdGlsc01ldGhvZHMuZ2V0RGV2aWNlQ291bnRyeSA9IGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgLy8gdGhpcyBtZXRob2QgaXMgb25seSB1c2VkIGluIEFQSSA8IDIzXG4gIGxldCBjb3VudHJ5ID0gYXdhaXQgdGhpcy5nZXREZXZpY2VTeXNDb3VudHJ5KCk7XG4gIGlmICghY291bnRyeSkge1xuICAgIGNvdW50cnkgPSBhd2FpdCB0aGlzLmdldERldmljZVByb2R1Y3RDb3VudHJ5KCk7XG4gIH1cbiAgcmV0dXJuIGNvdW50cnk7XG59O1xuXG5hcGtVdGlsc01ldGhvZHMuc2V0RGV2aWNlQ291bnRyeSA9IGFzeW5jIGZ1bmN0aW9uIChjb3VudHJ5KSB7XG4gIC8vIHRoaXMgbWV0aG9kIGlzIG9ubHkgdXNlZCBpbiBBUEkgPCAyM1xuICBhd2FpdCB0aGlzLnNldERldmljZVN5c0NvdW50cnkoY291bnRyeSk7XG59O1xuXG5hcGtVdGlsc01ldGhvZHMuZ2V0RGV2aWNlTG9jYWxlID0gYXN5bmMgZnVuY3Rpb24gKCkge1xuICAvLyB0aGlzIG1ldGhvZCBpcyBvbmx5IHVzZWQgaW4gQVBJID49IDIzXG4gIGxldCBsb2NhbGUgPSBhd2FpdCB0aGlzLmdldERldmljZVN5c0xvY2FsZSgpO1xuICBpZiAoIWxvY2FsZSkge1xuICAgIGxvY2FsZSA9IGF3YWl0IHRoaXMuZ2V0RGV2aWNlUHJvZHVjdExvY2FsZSgpO1xuICB9XG4gIHJldHVybiBsb2NhbGU7XG59O1xuXG5hcGtVdGlsc01ldGhvZHMuc2V0RGV2aWNlTG9jYWxlID0gYXN5bmMgZnVuY3Rpb24gKGxvY2FsZSkge1xuICAvLyB0aGlzIG1ldGhvZCBpcyBvbmx5IHVzZWQgaW4gQVBJID49IDIzXG4gIGF3YWl0IHRoaXMuc2V0RGV2aWNlU3lzTG9jYWxlKGxvY2FsZSk7XG59O1xuXG5leHBvcnQgZGVmYXVsdCBhcGtVdGlsc01ldGhvZHM7XG4iXX0=