UNPKG

appium-adb

Version:
572 lines (446 loc) 37.9 kB
'use strict'; 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 = 2; context$1$0.next = 5; return _regeneratorRuntime.awrap(this.shell(cmd)); case 5: stdout = context$1$0.sent; foundNullMatch = false; _iteratorNormalCompletion = true; _didIteratorError = false; _iteratorError = undefined; context$1$0.prev = 10; _iterator = _getIterator(stdout.split("\n")); case 12: if (_iteratorNormalCompletion = (_step = _iterator.next()).done) { context$1$0.next = 23; break; } line = _step.value; foundMatch = searchRe.exec(line); if (!foundMatch) { context$1$0.next = 19; break; } return context$1$0.abrupt('return', { appPackage: foundMatch[1].trim(), appActivity: foundMatch[2].trim() }); case 19: if (nullRe.test(line)) { foundNullMatch = true; } case 20: _iteratorNormalCompletion = true; context$1$0.next = 12; break; case 23: context$1$0.next = 29; break; case 25: context$1$0.prev = 25; context$1$0.t0 = context$1$0['catch'](10); _didIteratorError = true; _iteratorError = context$1$0.t0; case 29: context$1$0.prev = 29; context$1$0.prev = 30; if (!_iteratorNormalCompletion && _iterator['return']) { _iterator['return'](); } case 32: context$1$0.prev = 32; if (!_didIteratorError) { context$1$0.next = 35; break; } throw _iteratorError; case 35: return context$1$0.finish(32); case 36: return context$1$0.finish(29); case 37: if (!foundNullMatch) { context$1$0.next = 41; break; } return context$1$0.abrupt('return', { appPackage: null, appActivity: null }); case 41: _loggerJs2['default'].errorAndThrow("Could not parse activity from dumpsys"); case 42: context$1$0.next = 47; break; case 44: context$1$0.prev = 44; context$1$0.t1 = context$1$0['catch'](2); _loggerJs2['default'].errorAndThrow('Could not get focusPackageAndActivity. Original error: ' + context$1$0.t1.message); case 47: case 'end': return context$1$0.stop(); } }, null, this, [[2, 44], [10, 25, 29, 37], [30,, 32, 36]]); }; apkUtilsMethods.waitForActivityOrNot = function callee$0$0(pkg, activity, not) { var waitMs = arguments.length <= 3 || arguments[3] === undefined ? 20000 : arguments[3]; var endAt, activityRelativeName, _ref, appPackage, appActivity, foundAct; return _regeneratorRuntime.async(function callee$0$0$(context$1$0) { 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; activityRelativeName = (0, _helpersJs.getActivityRelativeName)(pkg, activity); case 5: if (!(Date.now() < endAt)) { context$1$0.next = 18; break; } context$1$0.next = 8; return _regeneratorRuntime.awrap(this.getFocusedPackageAndActivity()); case 8: _ref = context$1$0.sent; appPackage = _ref.appPackage; appActivity = _ref.appActivity; foundAct = appPackage === pkg && activityRelativeName === appActivity; if (!(!not && foundAct || not && !foundAct)) { context$1$0.next = 14; break; } return context$1$0.abrupt('return'); case 14: context$1$0.next = 16; return _regeneratorRuntime.awrap((0, _asyncbox.sleep)(750)); case 16: context$1$0.next = 5; break; case 18: _loggerJs2['default'].errorAndThrow(pkg + '/' + activityRelativeName + ' never ' + ('' + (not ? 'stopped' : 'started'))); case 19: case 'end': return context$1$0.stop(); } }, null, this); }; 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]]); }; exports['default'] = apkUtilsMethods; module.exports = exports['default']; // cool down so we're not overloading device with requests //# sourceMappingURL=data:application/json;base64,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RyxFQUFFLFdBQVcsQ0FBQyxDQUFDOzt5Q0FDdkIsa0JBQUcsUUFBUSxDQUFDLFNBQVMsRUFBRSxNQUFNLENBQUM7OztBQUEvQyxnQkFBUTs7QUFDUixrQkFBVSxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsUUFBUSxDQUFDLENBQUM7Ozs7Ozs7O0FBRWxDLFlBQUksUUFBUSxFQUFFO0FBQ1osZ0NBQUksS0FBSyw0QkFBMEIsUUFBUSxDQUFDLEtBQUssQ0FBQyxDQUFDLEVBQUUsR0FBRyxDQUFDLENBQUcsQ0FBQztTQUM5RDtBQUNHLFdBQUcsR0FBRyxzRUFDVSxlQUFFLE9BQU8sQ0FBRTs7QUFDL0IsOEJBQUksYUFBYSxDQUFDLEdBQUcsQ0FBQyxDQUFDOzs7NENBRWxCLEVBQUMsVUFBVSxFQUFWLFVBQVUsRUFBRSxTQUFTLEVBQVQsU0FBUyxFQUFDOzs7Ozs7O0NBQy9CLENBQUM7O3FCQUVhLGVBQWUiLCJmaWxlIjoibGliL3Rvb2xzL2Fway11dGlscy5qcyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IGJ1aWxkU3RhcnRDbWQsIGdldEFjdGl2aXR5UmVsYXRpdmVOYW1lIH0gZnJvbSAnLi4vaGVscGVycy5qcyc7XG5pbXBvcnQgeyBleGVjIH0gZnJvbSAndGVlbl9wcm9jZXNzJztcbmltcG9ydCBsb2cgZnJvbSAnLi4vbG9nZ2VyLmpzJztcbmltcG9ydCBwYXRoIGZyb20gJ3BhdGgnO1xuaW1wb3J0IF8gZnJvbSAnbG9kYXNoJztcbmltcG9ydCB7IHNsZWVwIH0gZnJvbSAnYXN5bmNib3gnO1xuaW1wb3J0IHsgZnMgfSBmcm9tICdhcHBpdW0tc3VwcG9ydCc7XG5cbmxldCBhcGtVdGlsc01ldGhvZHMgPSB7fTtcblxuYXBrVXRpbHNNZXRob2RzLmlzQXBwSW5zdGFsbGVkID0gYXN5bmMgZnVuY3Rpb24gKHBrZykge1xuICB0cnkge1xuICAgIGxldCBpbnN0YWxsZWQgPSBmYWxzZTtcbiAgICBsb2cuZGVidWcoYEdldHRpbmcgaW5zdGFsbCBzdGF0dXMgZm9yICR7cGtnfWApO1xuICAgIGxldCBhcGlMZXZlbCA9IGF3YWl0IHRoaXMuZ2V0QXBpTGV2ZWwoKTtcbiAgICBsZXQgdGhpcmRwYXJ0eSA9IGFwaUxldmVsID49IDE1ID8gXCItM1wiIDogXCJcIjtcbiAgICBsZXQgc3Rkb3V0ID0gYXdhaXQgdGhpcy5zaGVsbChbJ3BtJywgJ2xpc3QnLCAncGFja2FnZXMnLCB0aGlyZHBhcnR5LCBwa2ddKTtcbiAgICBsZXQgYXBrSW5zdGFsbGVkUmd4ID0gbmV3IFJlZ0V4cChgXnBhY2thZ2U6JHtwa2cucmVwbGFjZSgvKFxcLikvZywgXCJcXFxcJDFcIil9JGAsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ20nKTtcbiAgICBpbnN0YWxsZWQgPSBhcGtJbnN0YWxsZWRSZ3gudGVzdChzdGRvdXQpO1xuICAgIGxvZy5kZWJ1ZyhgQXBwIGlzICR7IWluc3RhbGxlZCA/IFwiIG5vdFwiIDogXCJcIn0gaW5zdGFsbGVkYCk7XG4gICAgcmV0dXJuIGluc3RhbGxlZDtcbiAgfSBjYXRjaCAoZSkge1xuICAgIGxvZy5lcnJvckFuZFRocm93KGBFcnJvciBmaW5kaW5nIGlmIGFwcCBpcyBpbnN0YWxsZWQuIE9yaWdpbmFsIGVycm9yOiAke2UubWVzc2FnZX1gKTtcbiAgfVxufTtcblxuYXBrVXRpbHNNZXRob2RzLnN0YXJ0VXJpID0gYXN5bmMgZnVuY3Rpb24gKHVyaSwgcGtnKSB7XG4gIGlmICghdXJpIHx8ICFwa2cpIHtcbiAgICBsb2cuZXJyb3JBbmRUaHJvdyhcIlVSSSBhbmQgcGFja2FnZSBhcmd1bWVudHMgYXJlIHJlcXVpcmVkXCIpO1xuICB9XG4gIHRyeSB7XG4gICAgbGV0IGFyZ3MgPSBbXCJhbVwiLCBcInN0YXJ0XCIsIFwiLVdcIiwgXCItYVwiLCBcImFuZHJvaWQuaW50ZW50LmFjdGlvbi5WSUVXXCIsIFwiLWRcIixcbiAgICAgICAgICAgICAgICB1cmksIHBrZ107XG4gICAgYXdhaXQgdGhpcy5zaGVsbChhcmdzKTtcbiAgfSBjYXRjaCAoZSkge1xuICAgIGxvZy5lcnJvckFuZFRocm93KGBFcnJvciBhdHRlbXB0aW5nIHRvIHN0YXJ0IFVSSS4gT3JpZ2luYWwgZXJyb3I6ICR7ZX1gKTtcbiAgfVxufTtcblxuYXBrVXRpbHNNZXRob2RzLnN0YXJ0QXBwID0gYXN5bmMgZnVuY3Rpb24gKHN0YXJ0QXBwT3B0aW9ucyA9IHt9KSB7XG4gIHRyeSB7XG4gICAgaWYgKCFzdGFydEFwcE9wdGlvbnMuYWN0aXZpdHkgfHwgIXN0YXJ0QXBwT3B0aW9ucy5wa2cpIHtcbiAgICAgIGxvZy5lcnJvckFuZFRocm93KFwiYWN0aXZpdHkgYW5kIHBrZyBpcyByZXF1aXJlZCBmb3IgbGF1bmNoaW5nIGFwcGxpY2F0aW9uXCIpO1xuICAgIH1cbiAgICBzdGFydEFwcE9wdGlvbnMgPSBfLmNsb25lKHN0YXJ0QXBwT3B0aW9ucyk7XG4gICAgLy8gaW5pdGlhbGl6aW5nIGRlZmF1bHRzXG4gICAgXy5kZWZhdWx0cyhzdGFydEFwcE9wdGlvbnMsIHtcbiAgICAgICAgd2FpdFBrZzogc3RhcnRBcHBPcHRpb25zLnBrZyxcbiAgICAgICAgd2FpdEFjdGl2aXR5OiBmYWxzZSxcbiAgICAgICAgcmV0cnk6IHRydWUsXG4gICAgICAgIHN0b3BBcHA6IHRydWVcbiAgICB9KTtcbiAgICAvLyBwcmV2ZW50aW5nIG51bGwgd2FpdHBrZ1xuICAgIHN0YXJ0QXBwT3B0aW9ucy53YWl0UGtnID0gc3RhcnRBcHBPcHRpb25zLndhaXRQa2cgfHwgc3RhcnRBcHBPcHRpb25zLnBrZztcbiAgICBsZXQgYXBpTGV2ZWwgPSBhd2FpdCB0aGlzLmdldEFwaUxldmVsKCk7XG4gICAgbGV0IGNtZCA9IGJ1aWxkU3RhcnRDbWQoc3RhcnRBcHBPcHRpb25zLCBhcGlMZXZlbCk7XG4gICAgbGV0IHN0ZG91dCA9IGF3YWl0IHRoaXMuc2hlbGwoY21kKTtcbiAgICBpZiAoc3Rkb3V0LmluZGV4T2YoXCJFcnJvcjogQWN0aXZpdHkgY2xhc3NcIikgIT09IC0xICYmXG4gICAgICAgIHN0ZG91dC5pbmRleE9mKFwiZG9lcyBub3QgZXhpc3RcIikgIT09IC0xKSB7XG4gICAgICBpZiAoc3RhcnRBcHBPcHRpb25zLnJldHJ5ICYmIHN0YXJ0QXBwT3B0aW9ucy5hY3Rpdml0eVswXSAhPT0gXCIuXCIpIHtcbiAgICAgICAgbG9nLmRlYnVnKFwiV2UgdHJpZWQgdG8gc3RhcnQgYW4gYWN0aXZpdHkgdGhhdCBkb2Vzbid0IGV4aXN0LCBcIiArXG4gICAgICAgICAgICAgICAgICBcInJldHJ5aW5nIHdpdGggLiBwcmVwZW5kZWQgdG8gYWN0aXZpdHlcIik7XG4gICAgICAgIHN0YXJ0QXBwT3B0aW9ucy5hY3Rpdml0eSA9IFwiLlwiICsgc3RhcnRBcHBPcHRpb25zLmFjdGl2aXR5O1xuICAgICAgICBzdGFydEFwcE9wdGlvbnMucmV0cnkgPSBmYWxzZTtcbiAgICAgICAgcmV0dXJuIHRoaXMuc3RhcnRBcHAoc3RhcnRBcHBPcHRpb25zKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGxvZy5lcnJvckFuZFRocm93KFwiQWN0aXZpdHkgdXNlZCB0byBzdGFydCBhcHAgZG9lc24ndCBleGlzdCBvciBjYW5ub3QgYmUgXCIgK1xuICAgICAgICAgICAgICAgICAgICAgICAgICBcImxhdW5jaGVkISBNYWtlIHN1cmUgaXQgZXhpc3RzIGFuZCBpcyBhIGxhdW5jaGFibGUgYWN0aXZpdHlcIik7XG4gICAgICB9XG4gICAgfSBlbHNlIGlmIChzdGRvdXQuaW5kZXhPZihcImphdmEubGFuZy5TZWN1cml0eUV4Y2VwdGlvblwiKSAhPT0gLTEpIHtcbiAgICAgIC8vIGlmIHRoZSBhcHAgaXMgZGlzYWJsZWQgb24gYSByZWFsIGRldmljZSBpdCB3aWxsIHRocm93IGEgc2VjdXJpdHkgZXhjZXB0aW9uXG4gICAgICBsb2cuZXJyb3JBbmRUaHJvdyhcIlBlcm1pc3Npb24gdG8gc3RhcnQgYWN0aXZpdHkgZGVuaWVkLlwiKTtcbiAgICB9XG4gICAgaWYgKHN0YXJ0QXBwT3B0aW9ucy53YWl0QWN0aXZpdHkpIHtcbiAgICAgIGF3YWl0IHRoaXMud2FpdEZvckFjdGl2aXR5KHN0YXJ0QXBwT3B0aW9ucy53YWl0UGtnLCBzdGFydEFwcE9wdGlvbnMud2FpdEFjdGl2aXR5LFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RhcnRBcHBPcHRpb25zLndhaXREdXJhdGlvbik7XG4gICAgfVxuICB9IGNhdGNoIChlKSB7XG4gICAgbG9nLmVycm9yQW5kVGhyb3coYEVycm9yIG9jY3VyZWQgd2hpbGUgc3RhcnRpbmcgQXBwLiBPcmlnaW5hbCBlcnJvcjogJHtlLm1lc3NhZ2V9YCk7XG4gIH1cbn07XG5cblxuYXBrVXRpbHNNZXRob2RzLmdldEZvY3VzZWRQYWNrYWdlQW5kQWN0aXZpdHkgPSBhc3luYyBmdW5jdGlvbiAoKSB7XG4gIGxvZy5kZWJ1ZyhcIkdldHRpbmcgZm9jdXNlZCBwYWNrYWdlIGFuZCBhY3Rpdml0eVwiKTtcbiAgbGV0IGNtZCA9IFsnZHVtcHN5cycsICd3aW5kb3cnLCAnd2luZG93cyddLFxuICAgICAgbnVsbFJlID0gbmV3IFJlZ0V4cCgvbUZvY3VzZWRBcHA9bnVsbC8pLFxuICAgICAgc2VhcmNoUmUgPSBuZXcgUmVnRXhwKCdtRm9jdXNlZEFwcC4rUmVjb3JkXFxcXHsuKlxcXFxzKFteXFxcXHNcXFxcL1xcXFx9XSspJyArXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgJ1xcXFwvKFteXFxcXHNcXFxcL1xcXFx9XSspKFxcXFxzW15cXFxcc1xcXFwvXFxcXH1dKykqXFxcXH0nKTtcbiAgdHJ5IHtcbiAgICBsZXQgc3Rkb3V0ID0gYXdhaXQgdGhpcy5zaGVsbChjbWQpO1xuICAgIGxldCBmb3VuZE51bGxNYXRjaCA9IGZhbHNlO1xuICAgIGZvciAobGV0IGxpbmUgb2Ygc3Rkb3V0LnNwbGl0KFwiXFxuXCIpKSB7XG4gICAgICBsZXQgZm91bmRNYXRjaCA9IHNlYXJjaFJlLmV4ZWMobGluZSk7XG4gICAgICBpZiAoZm91bmRNYXRjaCkge1xuICAgICAgICByZXR1cm4ge2FwcFBhY2thZ2U6IGZvdW5kTWF0Y2hbMV0udHJpbSgpLCBhcHBBY3Rpdml0eTogZm91bmRNYXRjaFsyXS50cmltKCl9O1xuICAgICAgfSBlbHNlIGlmIChudWxsUmUudGVzdChsaW5lKSkge1xuICAgICAgICBmb3VuZE51bGxNYXRjaCA9IHRydWU7XG4gICAgICB9XG4gICAgfVxuICAgIGlmIChmb3VuZE51bGxNYXRjaCkge1xuICAgICAgcmV0dXJuIHthcHBQYWNrYWdlOiBudWxsLCBhcHBBY3Rpdml0eTogbnVsbH07XG4gICAgfSBlbHNlIHtcbiAgICAgIGxvZy5lcnJvckFuZFRocm93KFwiQ291bGQgbm90IHBhcnNlIGFjdGl2aXR5IGZyb20gZHVtcHN5c1wiKTtcbiAgICB9XG4gIH0gY2F0Y2ggKGUpIHtcbiAgICBsb2cuZXJyb3JBbmRUaHJvdyhgQ291bGQgbm90IGdldCBmb2N1c1BhY2thZ2VBbmRBY3Rpdml0eS4gT3JpZ2luYWwgZXJyb3I6ICR7ZS5tZXNzYWdlfWApO1xuICB9XG59O1xuXG5hcGtVdGlsc01ldGhvZHMud2FpdEZvckFjdGl2aXR5T3JOb3QgPSBhc3luYyBmdW5jdGlvbiAocGtnLCBhY3Rpdml0eSwgbm90LFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHdhaXRNcyA9IDIwMDAwKSB7XG4gIGlmICghcGtnIHx8ICFhY3Rpdml0eSkge1xuICAgIHRocm93IG5ldyBFcnJvcihcIlBhY2thZ2UgYW5kIGFjdGl2aXR5IHJlcXVpcmVkLlwiKTtcbiAgfVxuICBsb2cuZGVidWcoYFdhaXRpbmcgZm9yIHBrZzogJHtwa2d9IGFuZCBhY3Rpdml0eTogJHthY3Rpdml0eX1gICtcbiAgICAgICAgICAgIGAke25vdCA/ICcgbm90JyA6ICcnfSB0byBiZSBmb2N1c2VkYCk7XG4gIGxldCBlbmRBdCA9IERhdGUubm93KCkgKyB3YWl0TXM7XG4gIGxldCBhY3Rpdml0eVJlbGF0aXZlTmFtZSA9IGdldEFjdGl2aXR5UmVsYXRpdmVOYW1lKHBrZywgYWN0aXZpdHkpO1xuICB3aGlsZSAoRGF0ZS5ub3coKSA8IGVuZEF0KSB7XG4gICAgbGV0IHthcHBQYWNrYWdlLCBhcHBBY3Rpdml0eX0gPSBhd2FpdCB0aGlzLmdldEZvY3VzZWRQYWNrYWdlQW5kQWN0aXZpdHkoKTtcbiAgICBsZXQgZm91bmRBY3QgPSAoKGFwcFBhY2thZ2UgPT09IHBrZykgJiYgKGFjdGl2aXR5UmVsYXRpdmVOYW1lID09PSBhcHBBY3Rpdml0eSkpO1xuICAgIGlmICgoIW5vdCAmJiBmb3VuZEFjdCkgfHwgKG5vdCAmJiAhZm91bmRBY3QpKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIC8vIGNvb2wgZG93biBzbyB3ZSdyZSBub3Qgb3ZlcmxvYWRpbmcgZGV2aWNlIHdpdGggcmVxdWVzdHNcbiAgICBhd2FpdCBzbGVlcCg3NTApO1xuICB9XG4gIGxvZy5lcnJvckFuZFRocm93KGAke3BrZ30vJHthY3Rpdml0eVJlbGF0aXZlTmFtZX0gbmV2ZXIgYCArXG4gICAgICAgICAgICAgICAgICAgIGAke25vdCA/ICdzdG9wcGVkJyA6ICdzdGFydGVkJ31gKTtcbn07XG5cbmFwa1V0aWxzTWV0aG9kcy53YWl0Rm9yQWN0aXZpdHkgPSBhc3luYyBmdW5jdGlvbiAocGtnLCBhY3QsIHdhaXRNcyA9IDIwMDAwKSB7XG4gIGF3YWl0IHRoaXMud2FpdEZvckFjdGl2aXR5T3JOb3QocGtnLCBhY3QsIGZhbHNlLCB3YWl0TXMpO1xufTtcblxuYXBrVXRpbHNNZXRob2RzLndhaXRGb3JOb3RBY3Rpdml0eSA9IGFzeW5jIGZ1bmN0aW9uIChwa2csIGFjdCwgd2FpdE1zID0gMjAwMDApIHtcbiAgYXdhaXQgdGhpcy53YWl0Rm9yQWN0aXZpdHlPck5vdChwa2csIGFjdCwgdHJ1ZSwgd2FpdE1zKTtcbn07XG5cbmFwa1V0aWxzTWV0aG9kcy51bmluc3RhbGxBcGsgPSBhc3luYyBmdW5jdGlvbiAocGtnKSB7XG4gIGxvZy5kZWJ1ZyhgVW5pbnN0YWxsaW5nICR7cGtnfWApO1xuICB0cnkge1xuICAgIGF3YWl0IHRoaXMuZm9yY2VTdG9wKHBrZyk7XG4gICAgbGV0IHN0ZG91dCA9IGF3YWl0IHRoaXMuYWRiRXhlYyhbJ3VuaW5zdGFsbCcsIHBrZ10sIHt0aW1lb3V0OiAyMDAwMH0pO1xuICAgIHN0ZG91dCA9IHN0ZG91dC50cmltKCk7XG4gICAgLy8gc3Rkb3V0IG1heSBjb250YWluIHdhcm5pbmdzIG1lYW5pbmcgc3VjY2VzcyBpcyBub3Qgb24gdGhlIGZpcnN0IGxpbmUuXG4gICAgaWYgKHN0ZG91dC5pbmRleE9mKFwiU3VjY2Vzc1wiKSAhPT0gLTEpIHtcbiAgICAgIGxvZy5pbmZvKFwiQXBwIHdhcyB1bmluc3RhbGxlZFwiKTtcbiAgICAgIHJldHVybiB0cnVlO1xuICAgIH0gZWxzZSB7XG4gICAgICBsb2cuaW5mbyhcIkFwcCB3YXMgbm90IHVuaW5zdGFsbGVkLCBtYXliZSBpdCB3YXNuJ3Qgb24gZGV2aWNlP1wiKTtcbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG4gIH0gY2F0Y2ggKGUpIHtcbiAgICBsb2cuZXJyb3JBbmRUaHJvdyhgVW5hYmxlIHRvIHVuaW5zdGFsbCBBUEsuIE9yaWdpbmFsIGVycm9yOiAke2UubWVzc2FnZX1gKTtcbiAgfVxufTtcblxuYXBrVXRpbHNNZXRob2RzLmluc3RhbGxGcm9tRGV2aWNlUGF0aCA9IGFzeW5jIGZ1bmN0aW9uIChhcGtQYXRoT25EZXZpY2UsIG9wdHMgPSB7fSkge1xuICBsZXQgc3Rkb3V0ID0gYXdhaXQgdGhpcy5zaGVsbChbJ3BtJywgJ2luc3RhbGwnLCAnLXInLCBhcGtQYXRoT25EZXZpY2VdLCBvcHRzKTtcbiAgaWYgKHN0ZG91dC5pbmRleE9mKFwiRmFpbHVyZVwiKSAhPT0gLTEpIHtcbiAgICBsb2cuZXJyb3JBbmRUaHJvdyhgUmVtb3RlIGluc3RhbGwgZmFpbGVkOiAke3N0ZG91dH1gKTtcbiAgfVxufTtcblxuYXBrVXRpbHNNZXRob2RzLmluc3RhbGwgPSBhc3luYyBmdW5jdGlvbiAoYXBrLCByZXBsYWNlID0gdHJ1ZSwgdGltZW91dCA9IDYwMDAwKSB7XG4gIGlmIChyZXBsYWNlKSB7XG4gICAgYXdhaXQgdGhpcy5hZGJFeGVjKFsnaW5zdGFsbCcsICctcicsIGFwa10sIHt0aW1lb3V0fSk7XG4gIH0gZWxzZSB7XG4gICAgYXdhaXQgdGhpcy5hZGJFeGVjKFsnaW5zdGFsbCcsIGFwa10sIHt0aW1lb3V0fSk7XG4gIH1cbn07XG5cbmFwa1V0aWxzTWV0aG9kcy5leHRyYWN0U3RyaW5nc0Zyb21BcGsgPSBhc3luYyBmdW5jdGlvbiAoYXBrLCBsYW5ndWFnZSwgb3V0KSB7XG4gIGxvZy5kZWJ1ZyhgRXh0cmFjdGluZyBzdHJpbmdzIGZvciBsYW5ndWFnZTogJHtsYW5ndWFnZSB8fCBcImRlZmF1bHRcIn1gKTtcbiAgbGV0IHN0cmluZ3NKc29uID0gJ3N0cmluZ3MuanNvbic7XG4gIGxldCBsb2NhbFBhdGg7XG4gIGlmICghbGFuZ3VhZ2UpIHtcbiAgICBsYW5ndWFnZSA9IGF3YWl0IHRoaXMuZ2V0RGV2aWNlTGFuZ3VhZ2UoKTtcbiAgfVxuICBsZXQgYXBrVG9vbHMgPSB0aGlzLmphcnNbJ2FwcGl1bV9hcGtfdG9vbHMuamFyJ107XG4gIGxldCBhcmdzID0gWyctamFyJywgYXBrVG9vbHMsICdzdHJpbmdzRnJvbUFwaycsIGFwaywgb3V0LCBsYW5ndWFnZV07XG4gIGxldCBmaWxlRGF0YSwgYXBrU3RyaW5ncztcbiAgdHJ5IHtcbiAgICBhd2FpdCBleGVjKCdqYXZhJywgYXJncyk7XG4gIH0gY2F0Y2ggKGUpIHtcbiAgICBsb2cuZGVidWcoYE5vIHN0cmluZ3MueG1sIGZvciBsYW5ndWFnZSAnJHtsYW5ndWFnZX0nLCBnZXR0aW5nIGRlZmF1bHQgYCArXG4gICAgICAgICAgICAgIGBzdHJpbmdzLnhtbGApO1xuICAgIGFyZ3MucG9wKCk7XG4gICAgYXdhaXQgZXhlYygnamF2YScsIGFyZ3MpO1xuICB9XG5cbiAgdHJ5IHtcbiAgICBsb2cuZGVidWcoXCJSZWFkaW5nIHN0cmluZ3MgZnJvbSBjb252ZXJ0ZWQgc3RyaW5ncy5qc29uXCIpO1xuICAgIGxvY2FsUGF0aCA9IHBhdGguam9pbihvdXQsIHN0cmluZ3NKc29uKTtcbiAgICBmaWxlRGF0YSA9IGF3YWl0IGZzLnJlYWRGaWxlKGxvY2FsUGF0aCwgJ3V0ZjgnKTtcbiAgICBhcGtTdHJpbmdzID0gSlNPTi5wYXJzZShmaWxlRGF0YSk7XG4gIH0gY2F0Y2ggKGUpIHtcbiAgICBpZiAoZmlsZURhdGEpIHtcbiAgICAgIGxvZy5kZWJ1ZyhgQ29udGVudCBzdGFydGVkIHdpdGg6ICR7ZmlsZURhdGEuc2xpY2UoMCwgMzAwKX1gKTtcbiAgICB9XG4gICAgbGV0IG1zZyA9IGBDb3VsZCBub3QgcGFyc2Ugc3RyaW5ncyBmcm9tIHN0cmluZ3MuanNvbi4gT3JpZ2luYWwgYCArXG4gICAgICAgICAgICAgIGBlcnJvcjogJHtlLm1lc3NhZ2V9YDtcbiAgICBsb2cuZXJyb3JBbmRUaHJvdyhtc2cpO1xuICB9XG4gIHJldHVybiB7YXBrU3RyaW5ncywgbG9jYWxQYXRofTtcbn07XG5cbmV4cG9ydCBkZWZhdWx0IGFwa1V0aWxzTWV0aG9kcztcbiJdfQ==