UNPKG

appium-adb-test

Version:

Android Debug Bridge interface

853 lines (663 loc) 51.6 kB
'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