appium-adb
Version:
Android Debug Bridge interface
486 lines (394 loc) • 32.5 kB
JavaScript
;
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 _path = require('path');
var _path2 = _interopRequireDefault(_path);
var _appiumSupport = require('appium-support');
var _loggerJs = require('./logger.js');
var _loggerJs2 = _interopRequireDefault(_loggerJs);
var _admZip = require('adm-zip');
var _admZip2 = _interopRequireDefault(_admZip);
var _teen_process = require('teen_process');
var _lodash = require('lodash');
var _lodash2 = _interopRequireDefault(_lodash);
var rootDir = _path2['default'].resolve(__dirname, process.env.NO_PRECOMPILE ? '..' : '../..');
var androidPlatforms = ['android-4.2', 'android-17', 'android-4.3', 'android-18', 'android-4.4', 'android-19', 'android-L', 'android-20', 'android-5.0', 'android-21', 'android-22', 'android-MNC', 'android-23', 'android-6.0'];
function getDirectories(rootPath) {
var files, dirs, _iteratorNormalCompletion, _didIteratorError, _iteratorError, _iterator, _step, file, pathString;
return _regeneratorRuntime.async(function getDirectories$(context$1$0) {
while (1) switch (context$1$0.prev = context$1$0.next) {
case 0:
context$1$0.next = 2;
return _regeneratorRuntime.awrap(_appiumSupport.fs.readdir(rootPath));
case 2:
files = context$1$0.sent;
dirs = [];
_iteratorNormalCompletion = true;
_didIteratorError = false;
_iteratorError = undefined;
context$1$0.prev = 7;
_iterator = _getIterator(files);
case 9:
if (_iteratorNormalCompletion = (_step = _iterator.next()).done) {
context$1$0.next = 19;
break;
}
file = _step.value;
pathString = _path2['default'].resolve(rootPath, file);
context$1$0.next = 14;
return _regeneratorRuntime.awrap(_appiumSupport.fs.lstat(pathString));
case 14:
if (!context$1$0.sent.isDirectory()) {
context$1$0.next = 16;
break;
}
dirs.push(file);
case 16:
_iteratorNormalCompletion = true;
context$1$0.next = 9;
break;
case 19:
context$1$0.next = 25;
break;
case 21:
context$1$0.prev = 21;
context$1$0.t0 = context$1$0['catch'](7);
_didIteratorError = true;
_iteratorError = context$1$0.t0;
case 25:
context$1$0.prev = 25;
context$1$0.prev = 26;
if (!_iteratorNormalCompletion && _iterator['return']) {
_iterator['return']();
}
case 28:
context$1$0.prev = 28;
if (!_didIteratorError) {
context$1$0.next = 31;
break;
}
throw _iteratorError;
case 31:
return context$1$0.finish(28);
case 32:
return context$1$0.finish(25);
case 33:
return context$1$0.abrupt('return', dirs.sort());
case 34:
case 'end':
return context$1$0.stop();
}
}, null, this, [[7, 21, 25, 33], [26,, 28, 32]]);
}
function getAndroidPlatformAndPath() {
var androidHome, _iteratorNormalCompletion2, _didIteratorError2, _iteratorError2, _iterator2, _step2, platform, platforms, platformPath;
return _regeneratorRuntime.async(function getAndroidPlatformAndPath$(context$1$0) {
while (1) switch (context$1$0.prev = context$1$0.next) {
case 0:
androidHome = process.env.ANDROID_HOME;
if (_lodash2['default'].isString(androidHome)) {
context$1$0.next = 4;
break;
}
_loggerJs2['default'].error("ANDROID_HOME was not exported!");
return context$1$0.abrupt('return', null);
case 4:
_iteratorNormalCompletion2 = true;
_didIteratorError2 = false;
_iteratorError2 = undefined;
context$1$0.prev = 7;
_iterator2 = _getIterator(_lodash2['default'].clone(androidPlatforms).reverse());
case 9:
if (_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done) {
context$1$0.next = 20;
break;
}
platform = _step2.value;
platforms = _path2['default'].resolve(androidHome, 'platforms');
platformPath = _path2['default'].resolve(platforms, platform);
context$1$0.next = 15;
return _regeneratorRuntime.awrap(_appiumSupport.fs.exists(platformPath));
case 15:
if (!context$1$0.sent) {
context$1$0.next = 17;
break;
}
return context$1$0.abrupt('return', { platform: platform, platformPath: platformPath });
case 17:
_iteratorNormalCompletion2 = true;
context$1$0.next = 9;
break;
case 20:
context$1$0.next = 26;
break;
case 22:
context$1$0.prev = 22;
context$1$0.t0 = context$1$0['catch'](7);
_didIteratorError2 = true;
_iteratorError2 = context$1$0.t0;
case 26:
context$1$0.prev = 26;
context$1$0.prev = 27;
if (!_iteratorNormalCompletion2 && _iterator2['return']) {
_iterator2['return']();
}
case 29:
context$1$0.prev = 29;
if (!_didIteratorError2) {
context$1$0.next = 32;
break;
}
throw _iteratorError2;
case 32:
return context$1$0.finish(29);
case 33:
return context$1$0.finish(26);
case 34:
return context$1$0.abrupt('return', null);
case 35:
case 'end':
return context$1$0.stop();
}
}, null, this, [[7, 22, 26, 34], [27,, 29, 33]]);
}
function unzipFile(zipPath) {
var zip;
return _regeneratorRuntime.async(function unzipFile$(context$1$0) {
while (1) switch (context$1$0.prev = context$1$0.next) {
case 0:
_loggerJs2['default'].debug('Unzipping ' + zipPath);
context$1$0.prev = 1;
context$1$0.next = 4;
return _regeneratorRuntime.awrap(assertZipArchive(zipPath));
case 4:
if (!_appiumSupport.system.isWindows()) {
context$1$0.next = 10;
break;
}
zip = new _admZip2['default'](zipPath);
zip.extractAllTo(_path2['default'].dirname(zipPath), true);
_loggerJs2['default'].debug("Unzip successful");
context$1$0.next = 13;
break;
case 10:
context$1$0.next = 12;
return _regeneratorRuntime.awrap((0, _teen_process.exec)('unzip', ['-o', zipPath], { cwd: _path2['default'].dirname(zipPath) }));
case 12:
_loggerJs2['default'].debug("Unzip successful");
case 13:
context$1$0.next = 18;
break;
case 15:
context$1$0.prev = 15;
context$1$0.t0 = context$1$0['catch'](1);
throw new Error('Error occurred while unzipping. Original error: ' + context$1$0.t0.message);
case 18:
case 'end':
return context$1$0.stop();
}
}, null, this, [[1, 15]]);
}
function assertZipArchive(zipPath) {
var execOpts;
return _regeneratorRuntime.async(function assertZipArchive$(context$1$0) {
while (1) switch (context$1$0.prev = context$1$0.next) {
case 0:
_loggerJs2['default'].debug('Testing zip archive: ' + zipPath);
if (!_appiumSupport.system.isWindows()) {
context$1$0.next = 11;
break;
}
context$1$0.next = 4;
return _regeneratorRuntime.awrap(_appiumSupport.fs.exists(zipPath));
case 4:
if (!context$1$0.sent) {
context$1$0.next = 8;
break;
}
_loggerJs2['default'].debug("Zip archive tested clean");
context$1$0.next = 9;
break;
case 8:
throw new Error('Zip archive not present at ' + zipPath);
case 9:
context$1$0.next = 14;
break;
case 11:
execOpts = { cwd: _path2['default'].dirname(zipPath) };
context$1$0.next = 14;
return _regeneratorRuntime.awrap((0, _teen_process.exec)('unzip', ['-tq', zipPath], execOpts));
case 14:
case 'end':
return context$1$0.stop();
}
}, null, this);
}
function getIMEListFromOutput(stdout) {
var engines = [];
var _iteratorNormalCompletion3 = true;
var _didIteratorError3 = false;
var _iteratorError3 = undefined;
try {
for (var _iterator3 = _getIterator(stdout.split('\n')), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) {
var line = _step3.value;
if (line.length > 0 && line[0] !== ' ') {
// remove newline and trailing colon, and add to the list
engines.push(line.trim().replace(/:$/, ''));
}
}
} catch (err) {
_didIteratorError3 = true;
_iteratorError3 = err;
} finally {
try {
if (!_iteratorNormalCompletion3 && _iterator3['return']) {
_iterator3['return']();
}
} finally {
if (_didIteratorError3) {
throw _iteratorError3;
}
}
}
return engines;
}
function getJavaForOs() {
var sep = _path2['default'].sep;
var java = '' + getJavaHome() + sep + 'bin' + sep + 'java';
if (_appiumSupport.system.isWindows()) {
java = java + '.exe';
}
return java;
}
function getJavaHome() {
if (process.env.JAVA_HOME) {
return process.env.JAVA_HOME;
}
throw new Error("JAVA_HOME is not set currently. Please set JAVA_HOME.");
}
/*
* Checks mShowingLockscreen in dumpsys output to determine if lock screen is showing
*/
function isShowingLockscreen(dumpsys) {
var m = /mShowingLockscreen=\w+/gi.exec(dumpsys);
var ret = m && m.length && m[0].split('=')[1] === 'true' || false;
return ret;
}
/*
* Checks mCurrentFocus in dumpsys output to determine if Keyguard is activated
*/
function isCurrentFocusOnKeyguard(dumpsys) {
var m = /mCurrentFocus.+Keyguard/gi.exec(dumpsys);
return m && m.length && m[0] ? true : false;
}
/*
* Checks mScreenOnFully in dumpsys output to determine if screen is showing
* Default is true
*/
function isScreenOnFully(dumpsys) {
var m = /mScreenOnFully=\w+/gi.exec(dumpsys);
return !m || // if information is missing we assume screen is fully on
m && m.length > 0 && m[0].split('=')[1] === 'true' || false;
}
function buildStartCmd(startAppOptions, apiLevel) {
var cmd = ['am', 'start', '-W', '-n', startAppOptions.pkg + '/' + startAppOptions.activity];
if (startAppOptions.stopApp && apiLevel >= 15) {
cmd.push('-S');
}
if (startAppOptions.action) {
cmd.push('-a', startAppOptions.action);
}
if (startAppOptions.category) {
cmd.push('-c', startAppOptions.category);
}
if (startAppOptions.flags) {
cmd.push('-f', startAppOptions.flags);
}
if (startAppOptions.optionalIntentArguments) {
// expect optionalIntentArguments to be a single string of the form:
// "-flag key"
// "-flag key value"
// or a combination of these (e.g., "-flag1 key1 -flag2 key2 value2")
// take a string and parse out the part before any spaces, and anything after
// the first space
var parseKeyValue = function parseKeyValue(str) {
str = str.trim();
var space = str.indexOf(' ');
if (space === -1) {
return !!str.length ? [str] : [];
} else {
return [str.substring(0, space).trim(), str.substring(space + 1).trim()];
}
};
// cycle through the optionalIntentArguments and pull out the arguments
// add a space initially so flags can be distinguished from arguments that
// have internal hyphens
var optionalIntentArguments = ' ' + startAppOptions.optionalIntentArguments;
var re = / (-[^\s]+) (.+)/;
while (true) {
var args = re.exec(optionalIntentArguments);
if (!args) {
if (optionalIntentArguments.length) {
// no more flags, so the remainder can be treated as 'key' or 'key value'
cmd.push.apply(cmd, parseKeyValue(optionalIntentArguments));
}
// we are done
break;
}
// take the flag and see if it is at the beginning of the string
// if it is not, then it means we have been through already, and
// what is before the flag is the argument for the previous flag
var flag = args[1];
var flagPos = optionalIntentArguments.indexOf(flag);
if (flagPos !== 0) {
var prevArgs = optionalIntentArguments.substring(0, flagPos);
cmd.push.apply(cmd, parseKeyValue(prevArgs));
}
// add the flag, as there are no more earlier arguments
cmd.push(flag);
// make optionalIntentArguments hold the remainder
optionalIntentArguments = args[2];
}
}
return cmd;
}
// turns pkg.activity.name to .activity.name
// also turns activity.name to .activity.name
function getPossibleActivityNames(pkgName, activityName) {
var names = [activityName];
// need to beware of namespaces with overlapping chars:
// com.foo.bar
// com.foo.barx
if (activityName.indexOf(pkgName + '.') === 0) {
names.push(activityName.substring(pkgName.length));
}
if (activityName[0] !== '.') {
names.push('.' + activityName);
}
return names;
}
exports.getDirectories = getDirectories;
exports.getAndroidPlatformAndPath = getAndroidPlatformAndPath;
exports.unzipFile = unzipFile;
exports.assertZipArchive = assertZipArchive;
exports.getIMEListFromOutput = getIMEListFromOutput;
exports.getJavaForOs = getJavaForOs;
exports.isShowingLockscreen = isShowingLockscreen;
exports.isCurrentFocusOnKeyguard = isCurrentFocusOnKeyguard;
exports.isScreenOnFully = isScreenOnFully;
exports.buildStartCmd = buildStartCmd;
exports.getPossibleActivityNames = getPossibleActivityNames;
exports.getJavaHome = getJavaHome;
exports.rootDir = rootDir;
exports.androidPlatforms = androidPlatforms;
// It is not a clean way to sort it, but in this case would work fine because
// we have numerics and alphanumeric
// will return some thing like this
// ["17.0.0", "18.0.1", "19.0.0", "19.0.1", "19.1.0", "20.0.0",
// "android-4.2.2", "android-4.3", "android-4.4"]
// get the latest platform and path
//# sourceMappingURL=data:application/json;base64,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LENBQUUsT0FBTyxFQUFFLFlBQVksRUFBRTtBQUN4RCxNQUFJLEtBQUssR0FBRyxDQUFDLFlBQVksQ0FBQyxDQUFDOzs7O0FBSTNCLE1BQUksWUFBWSxDQUFDLE9BQU8sQ0FBSSxPQUFPLE9BQUksS0FBSyxDQUFDLEVBQUU7QUFDN0MsU0FBSyxDQUFDLElBQUksQ0FBQyxZQUFZLENBQUMsU0FBUyxDQUFDLE9BQU8sQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDO0dBQ3BEO0FBQ0QsTUFBSSxZQUFZLENBQUMsQ0FBQyxDQUFDLEtBQUssR0FBRyxFQUFFO0FBQzNCLFNBQUssQ0FBQyxJQUFJLE9BQUssWUFBWSxDQUFHLENBQUM7R0FDaEM7QUFDRCxTQUFPLEtBQUssQ0FBQztDQUNkOztRQUVRLGNBQWMsR0FBZCxjQUFjO1FBQUUseUJBQXlCLEdBQXpCLHlCQUF5QjtRQUFFLFNBQVMsR0FBVCxTQUFTO1FBQUUsZ0JBQWdCLEdBQWhCLGdCQUFnQjtRQUN0RSxvQkFBb0IsR0FBcEIsb0JBQW9CO1FBQUUsWUFBWSxHQUFaLFlBQVk7UUFBRSxtQkFBbUIsR0FBbkIsbUJBQW1CO1FBQUUsd0JBQXdCLEdBQXhCLHdCQUF3QjtRQUNqRixlQUFlLEdBQWYsZUFBZTtRQUFFLGFBQWEsR0FBYixhQUFhO1FBQUUsd0JBQXdCLEdBQXhCLHdCQUF3QjtRQUFFLFdBQVcsR0FBWCxXQUFXO1FBQ3JFLE9BQU8sR0FBUCxPQUFPO1FBQUUsZ0JBQWdCLEdBQWhCLGdCQUFnQiIsImZpbGUiOiJsaWIvaGVscGVycy5qcyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCBwYXRoIGZyb20gJ3BhdGgnO1xuaW1wb3J0IHsgc3lzdGVtLCBmcyB9IGZyb20gJ2FwcGl1bS1zdXBwb3J0JztcbmltcG9ydCBsb2cgZnJvbSAnLi9sb2dnZXIuanMnO1xuaW1wb3J0IEFkbVppcCBmcm9tICdhZG0temlwJztcbmltcG9ydCB7IGV4ZWMgfSBmcm9tICd0ZWVuX3Byb2Nlc3MnO1xuaW1wb3J0IF8gZnJvbSAnbG9kYXNoJztcblxuXG5jb25zdCByb290RGlyID0gcGF0aC5yZXNvbHZlKF9fZGlybmFtZSwgcHJvY2Vzcy5lbnYuTk9fUFJFQ09NUElMRSA/ICcuLicgOiAnLi4vLi4nKTtcbmNvbnN0IGFuZHJvaWRQbGF0Zm9ybXMgPSBbJ2FuZHJvaWQtNC4yJywgJ2FuZHJvaWQtMTcnLCAnYW5kcm9pZC00LjMnLCAnYW5kcm9pZC0xOCcsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICdhbmRyb2lkLTQuNCcsICdhbmRyb2lkLTE5JywgJ2FuZHJvaWQtTCcsICdhbmRyb2lkLTIwJyxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgJ2FuZHJvaWQtNS4wJywgJ2FuZHJvaWQtMjEnLCAnYW5kcm9pZC0yMicsICdhbmRyb2lkLU1OQycsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICdhbmRyb2lkLTIzJywgJ2FuZHJvaWQtNi4wJ107XG5cbmFzeW5jIGZ1bmN0aW9uIGdldERpcmVjdG9yaWVzIChyb290UGF0aCkge1xuICBsZXQgZmlsZXMgPSBhd2FpdCBmcy5yZWFkZGlyKHJvb3RQYXRoKTtcbiAgbGV0IGRpcnMgPSBbXTtcbiAgZm9yIChsZXQgZmlsZSBvZiBmaWxlcykge1xuICAgIGxldCBwYXRoU3RyaW5nID0gcGF0aC5yZXNvbHZlKHJvb3RQYXRoLCBmaWxlKTtcbiAgICBpZiAoKGF3YWl0IGZzLmxzdGF0KHBhdGhTdHJpbmcpKS5pc0RpcmVjdG9yeSgpKSB7XG4gICAgICBkaXJzLnB1c2goZmlsZSk7XG4gICAgfVxuICB9XG4gIC8vIEl0IGlzIG5vdCBhIGNsZWFuIHdheSB0byBzb3J0IGl0LCBidXQgaW4gdGhpcyBjYXNlIHdvdWxkIHdvcmsgZmluZSBiZWNhdXNlXG4gIC8vIHdlIGhhdmUgbnVtZXJpY3MgYW5kIGFscGhhbnVtZXJpY1xuICAvLyB3aWxsIHJldHVybiBzb21lIHRoaW5nIGxpa2UgdGhpc1xuICAvLyBbXCIxNy4wLjBcIiwgXCIxOC4wLjFcIiwgXCIxOS4wLjBcIiwgXCIxOS4wLjFcIiwgXCIxOS4xLjBcIiwgXCIyMC4wLjBcIixcbiAgLy8gIFwiYW5kcm9pZC00LjIuMlwiLCBcImFuZHJvaWQtNC4zXCIsIFwiYW5kcm9pZC00LjRcIl1cbiAgcmV0dXJuIGRpcnMuc29ydCgpO1xufVxuXG5hc3luYyBmdW5jdGlvbiBnZXRBbmRyb2lkUGxhdGZvcm1BbmRQYXRoICgpIHtcbiAgY29uc3QgYW5kcm9pZEhvbWUgPSBwcm9jZXNzLmVudi5BTkRST0lEX0hPTUU7XG4gIGlmICghXy5pc1N0cmluZyhhbmRyb2lkSG9tZSkpIHtcbiAgICBsb2cuZXJyb3IoXCJBTkRST0lEX0hPTUUgd2FzIG5vdCBleHBvcnRlZCFcIik7XG4gICAgcmV0dXJuIG51bGw7XG4gIH1cblxuICAvLyBnZXQgdGhlIGxhdGVzdCBwbGF0Zm9ybSBhbmQgcGF0aFxuICBmb3IgKGxldCBwbGF0Zm9ybSBvZiBfLmNsb25lKGFuZHJvaWRQbGF0Zm9ybXMpLnJldmVyc2UoKSkge1xuICAgIGxldCBwbGF0Zm9ybXMgPSBwYXRoLnJlc29sdmUoYW5kcm9pZEhvbWUsICdwbGF0Zm9ybXMnKTtcbiAgICBsZXQgcGxhdGZvcm1QYXRoID0gcGF0aC5yZXNvbHZlKHBsYXRmb3JtcywgcGxhdGZvcm0pO1xuICAgIGlmIChhd2FpdCBmcy5leGlzdHMocGxhdGZvcm1QYXRoKSkge1xuICAgICAgcmV0dXJuIHtwbGF0Zm9ybSwgcGxhdGZvcm1QYXRofTtcbiAgICB9XG4gIH1cbiAgcmV0dXJuIG51bGw7XG59XG5cbmFzeW5jIGZ1bmN0aW9uIHVuemlwRmlsZSAoemlwUGF0aCkge1xuICBsb2cuZGVidWcoYFVuemlwcGluZyAke3ppcFBhdGh9YCk7XG4gIHRyeSB7XG4gICAgYXdhaXQgYXNzZXJ0WmlwQXJjaGl2ZSh6aXBQYXRoKTtcbiAgICBpZiAoc3lzdGVtLmlzV2luZG93cygpKSB7XG4gICAgICBsZXQgemlwID0gbmV3IEFkbVppcCh6aXBQYXRoKTtcbiAgICAgIHppcC5leHRyYWN0QWxsVG8ocGF0aC5kaXJuYW1lKHppcFBhdGgpLCB0cnVlKTtcbiAgICAgIGxvZy5kZWJ1ZyhcIlVuemlwIHN1Y2Nlc3NmdWxcIik7XG4gICAgfSBlbHNlIHtcbiAgICAgIGF3YWl0IGV4ZWMoJ3VuemlwJywgWyctbycsIHppcFBhdGhdLCB7Y3dkOiBwYXRoLmRpcm5hbWUoemlwUGF0aCl9KTtcbiAgICAgIGxvZy5kZWJ1ZyhcIlVuemlwIHN1Y2Nlc3NmdWxcIik7XG4gICAgfVxuICB9IGNhdGNoIChlKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKGBFcnJvciBvY2N1cnJlZCB3aGlsZSB1bnppcHBpbmcuIE9yaWdpbmFsIGVycm9yOiAke2UubWVzc2FnZX1gKTtcbiAgfVxufVxuXG5hc3luYyBmdW5jdGlvbiBhc3NlcnRaaXBBcmNoaXZlICh6aXBQYXRoKSB7XG4gIGxvZy5kZWJ1ZyhgVGVzdGluZyB6aXAgYXJjaGl2ZTogJHt6aXBQYXRofWApO1xuICBpZiAoc3lzdGVtLmlzV2luZG93cygpKSB7XG4gICAgaWYgKGF3YWl0IGZzLmV4aXN0cyh6aXBQYXRoKSkge1xuICAgICAgbG9nLmRlYnVnKFwiWmlwIGFyY2hpdmUgdGVzdGVkIGNsZWFuXCIpO1xuICAgIH0gZWxzZSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYFppcCBhcmNoaXZlIG5vdCBwcmVzZW50IGF0ICR7emlwUGF0aH1gKTtcbiAgICB9XG4gIH0gZWxzZSB7XG4gICAgbGV0IGV4ZWNPcHRzID0ge2N3ZDogcGF0aC5kaXJuYW1lKHppcFBhdGgpfTtcbiAgICBhd2FpdCBleGVjKCd1bnppcCcsIFsnLXRxJywgemlwUGF0aF0sIGV4ZWNPcHRzKTtcbiAgfVxufVxuXG5mdW5jdGlvbiBnZXRJTUVMaXN0RnJvbU91dHB1dCAoc3Rkb3V0KSB7XG4gIGxldCBlbmdpbmVzID0gW107XG4gIGZvciAobGV0IGxpbmUgb2Ygc3Rkb3V0LnNwbGl0KCdcXG4nKSkge1xuICAgIGlmIChsaW5lLmxlbmd0aCA+IDAgJiYgbGluZVswXSAhPT0gJyAnKSB7XG4gICAgICAvLyByZW1vdmUgbmV3bGluZSBhbmQgdHJhaWxpbmcgY29sb24sIGFuZCBhZGQgdG8gdGhlIGxpc3RcbiAgICAgIGVuZ2luZXMucHVzaChsaW5lLnRyaW0oKS5yZXBsYWNlKC86JC8sICcnKSk7XG4gICAgfVxuICB9XG4gIHJldHVybiBlbmdpbmVzO1xufVxuXG5mdW5jdGlvbiBnZXRKYXZhRm9yT3MgKCkge1xuICBjb25zdCBzZXAgPSBwYXRoLnNlcDtcbiAgbGV0IGphdmEgPSBgJHtnZXRKYXZhSG9tZSgpfSR7c2VwfWJpbiR7c2VwfWphdmFgO1xuICBpZiAoc3lzdGVtLmlzV2luZG93cygpKSB7XG4gICAgamF2YSA9IGphdmEgKyAnLmV4ZSc7XG4gIH1cbiAgcmV0dXJuIGphdmE7XG59XG5cbmZ1bmN0aW9uIGdldEphdmFIb21lICgpIHtcbiAgaWYgKHByb2Nlc3MuZW52LkpBVkFfSE9NRSkge1xuICAgIHJldHVybiBwcm9jZXNzLmVudi5KQVZBX0hPTUU7XG4gIH1cbiAgdGhyb3cgbmV3IEVycm9yKFwiSkFWQV9IT01FIGlzIG5vdCBzZXQgY3VycmVudGx5LiBQbGVhc2Ugc2V0IEpBVkFfSE9NRS5cIik7XG59XG5cbi8qXG4gKiBDaGVja3MgbVNob3dpbmdMb2Nrc2NyZWVuIGluIGR1bXBzeXMgb3V0cHV0IHRvIGRldGVybWluZSBpZiBsb2NrIHNjcmVlbiBpcyBzaG93aW5nXG4gKi9cbmZ1bmN0aW9uIGlzU2hvd2luZ0xvY2tzY3JlZW4gKGR1bXBzeXMpIHtcbiAgbGV0IG0gPSAvbVNob3dpbmdMb2Nrc2NyZWVuPVxcdysvZ2kuZXhlYyhkdW1wc3lzKTtcbiAgbGV0IHJldCA9IChtICYmIG0ubGVuZ3RoICYmIG1bMF0uc3BsaXQoJz0nKVsxXSA9PT0gJ3RydWUnKSB8fCBmYWxzZTtcbiAgcmV0dXJuIHJldDtcbn1cblxuLypcbiAqIENoZWNrcyBtQ3VycmVudEZvY3VzIGluIGR1bXBzeXMgb3V0cHV0IHRvIGRldGVybWluZSBpZiBLZXlndWFyZCBpcyBhY3RpdmF0ZWRcbiAqL1xuZnVuY3Rpb24gaXNDdXJyZW50Rm9jdXNPbktleWd1YXJkIChkdW1wc3lzKSB7XG4gIGxldCBtID0gL21DdXJyZW50Rm9jdXMuK0tleWd1YXJkL2dpLmV4ZWMoZHVtcHN5cyk7XG4gIHJldHVybiAobSAmJiBtLmxlbmd0aCAmJiBtWzBdKSA/IHRydWUgOiBmYWxzZTtcbn1cblxuLypcbiAqIENoZWNrcyBtU2NyZWVuT25GdWxseSBpbiBkdW1wc3lzIG91dHB1dCB0byBkZXRlcm1pbmUgaWYgc2NyZWVuIGlzIHNob3dpbmdcbiAqIERlZmF1bHQgaXMgdHJ1ZVxuICovXG5mdW5jdGlvbiBpc1NjcmVlbk9uRnVsbHkgKGR1bXBzeXMpIHtcbiAgbGV0IG0gPSAvbVNjcmVlbk9uRnVsbHk9XFx3Ky9naS5leGVjKGR1bXBzeXMpO1xuICByZXR1cm4gIW0gfHwgLy8gaWYgaW5mb3JtYXRpb24gaXMgbWlzc2luZyB3ZSBhc3N1bWUgc2NyZWVuIGlzIGZ1bGx5IG9uXG4gICAgICAgICAobSAmJiBtLmxlbmd0aCA+IDAgJiYgbVswXS5zcGxpdCgnPScpWzFdID09PSAndHJ1ZScpIHx8IGZhbHNlO1xufVxuXG5mdW5jdGlvbiBidWlsZFN0YXJ0Q21kIChzdGFydEFwcE9wdGlvbnMsIGFwaUxldmVsKSB7XG4gIGxldCBjbWQgPSBbJ2FtJywgJ3N0YXJ0JywgJy1XJywgJy1uJywgYCR7c3RhcnRBcHBPcHRpb25zLnBrZ30vJHtzdGFydEFwcE9wdGlvbnMuYWN0aXZpdHl9YF07XG4gIGlmIChzdGFydEFwcE9wdGlvbnMuc3RvcEFwcCAmJiBhcGlMZXZlbCA+PSAxNSkge1xuICAgIGNtZC5wdXNoKCctUycpO1xuICB9XG4gIGlmIChzdGFydEFwcE9wdGlvbnMuYWN0aW9uKSB7XG4gICAgY21kLnB1c2goJy1hJywgc3RhcnRBcHBPcHRpb25zLmFjdGlvbik7XG4gIH1cbiAgaWYgKHN0YXJ0QXBwT3B0aW9ucy5jYXRlZ29yeSkge1xuICAgIGNtZC5wdXNoKCctYycsIHN0YXJ0QXBwT3B0aW9ucy5jYXRlZ29yeSk7XG4gIH1cbiAgaWYgKHN0YXJ0QXBwT3B0aW9ucy5mbGFncykge1xuICAgIGNtZC5wdXNoKCctZicsIHN0YXJ0QXBwT3B0aW9ucy5mbGFncyk7XG4gIH1cbiAgaWYgKHN0YXJ0QXBwT3B0aW9ucy5vcHRpb25hbEludGVudEFyZ3VtZW50cykge1xuICAgIC8vIGV4cGVjdCBvcHRpb25hbEludGVudEFyZ3VtZW50cyB0byBiZSBhIHNpbmdsZSBzdHJpbmcgb2YgdGhlIGZvcm06XG4gICAgLy8gICAgIFwiLWZsYWcga2V5XCJcbiAgICAvLyAgICAgXCItZmxhZyBrZXkgdmFsdWVcIlxuICAgIC8vIG9yIGEgY29tYmluYXRpb24gb2YgdGhlc2UgKGUuZy4sIFwiLWZsYWcxIGtleTEgLWZsYWcyIGtleTIgdmFsdWUyXCIpXG5cbiAgICAvLyB0YWtlIGEgc3RyaW5nIGFuZCBwYXJzZSBvdXQgdGhlIHBhcnQgYmVmb3JlIGFueSBzcGFjZXMsIGFuZCBhbnl0aGluZyBhZnRlclxuICAgIC8vIHRoZSBmaXJzdCBzcGFjZVxuICAgIGxldCBwYXJzZUtleVZhbHVlID0gZnVuY3Rpb24gKHN0cikge1xuICAgICAgc3RyID0gc3RyLnRyaW0oKTtcbiAgICAgIGxldCBzcGFjZSA9IHN0ci5pbmRleE9mKCcgJyk7XG4gICAgICBpZiAoc3BhY2UgPT09IC0xKSB7XG4gICAgICAgIHJldHVybiAhIXN0ci5sZW5ndGggPyBbc3RyXSA6IFtdO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgcmV0dXJuIFtzdHIuc3Vic3RyaW5nKDAsIHNwYWNlKS50cmltKCksIHN0ci5zdWJzdHJpbmcoc3BhY2UgKyAxKS50cmltKCldO1xuICAgICAgfVxuICAgIH07XG5cbiAgICAvLyBjeWNsZSB0aHJvdWdoIHRoZSBvcHRpb25hbEludGVudEFyZ3VtZW50cyBhbmQgcHVsbCBvdXQgdGhlIGFyZ3VtZW50c1xuICAgIC8vIGFkZCBhIHNwYWNlIGluaXRpYWxseSBzbyBmbGFncyBjYW4gYmUgZGlzdGluZ3Vpc2hlZCBmcm9tIGFyZ3VtZW50cyB0aGF0XG4gICAgLy8gaGF2ZSBpbnRlcm5hbCBoeXBoZW5zXG4gICAgbGV0IG9wdGlvbmFsSW50ZW50QXJndW1lbnRzID0gYCAke3N0YXJ0QXBwT3B0aW9ucy5vcHRpb25hbEludGVudEFyZ3VtZW50c31gO1xuICAgIGxldCByZSA9IC8gKC1bXlxcc10rKSAoLispLztcbiAgICB3aGlsZSAodHJ1ZSkge1xuICAgICAgbGV0IGFyZ3MgPSByZS5leGVjKG9wdGlvbmFsSW50ZW50QXJndW1lbnRzKTtcbiAgICAgIGlmICghYXJncykge1xuICAgICAgICBpZiAob3B0aW9uYWxJbnRlbnRBcmd1bWVudHMubGVuZ3RoKSB7XG4gICAgICAgICAgLy8gbm8gbW9yZSBmbGFncywgc28gdGhlIHJlbWFpbmRlciBjYW4gYmUgdHJlYXRlZCBhcyAna2V5JyBvciAna2V5IHZhbHVlJ1xuICAgICAgICAgIGNtZC5wdXNoLmFwcGx5KGNtZCwgcGFyc2VLZXlWYWx1ZShvcHRpb25hbEludGVudEFyZ3VtZW50cykpO1xuICAgICAgICB9XG4gICAgICAgIC8vIHdlIGFyZSBkb25lXG4gICAgICAgIGJyZWFrO1xuICAgICAgfVxuXG4gICAgICAvLyB0YWtlIHRoZSBmbGFnIGFuZCBzZWUgaWYgaXQgaXMgYXQgdGhlIGJlZ2lubmluZyBvZiB0aGUgc3RyaW5nXG4gICAgICAvLyBpZiBpdCBpcyBub3QsIHRoZW4gaXQgbWVhbnMgd2UgaGF2ZSBiZWVuIHRocm91Z2ggYWxyZWFkeSwgYW5kXG4gICAgICAvLyB3aGF0IGlzIGJlZm9yZSB0aGUgZmxhZyBpcyB0aGUgYXJndW1lbnQgZm9yIHRoZSBwcmV2aW91cyBmbGFnXG4gICAgICBsZXQgZmxhZyA9IGFyZ3NbMV07XG4gICAgICBsZXQgZmxhZ1BvcyA9IG9wdGlvbmFsSW50ZW50QXJndW1lbnRzLmluZGV4T2YoZmxhZyk7XG4gICAgICBpZiAoZmxhZ1BvcyAhPT0gMCkge1xuICAgICAgICBsZXQgcHJldkFyZ3MgPSBvcHRpb25hbEludGVudEFyZ3VtZW50cy5zdWJzdHJpbmcoMCwgZmxhZ1Bvcyk7XG4gICAgICAgIGNtZC5wdXNoLmFwcGx5KGNtZCwgcGFyc2VLZXlWYWx1ZShwcmV2QXJncykpO1xuICAgICAgfVxuXG4gICAgICAvLyBhZGQgdGhlIGZsYWcsIGFzIHRoZXJlIGFyZSBubyBtb3JlIGVhcmxpZXIgYXJndW1lbnRzXG4gICAgICBjbWQucHVzaChmbGFnKTtcblxuICAgICAgLy8gbWFrZSBvcHRpb25hbEludGVudEFyZ3VtZW50cyBob2xkIHRoZSByZW1haW5kZXJcbiAgICAgIG9wdGlvbmFsSW50ZW50QXJndW1lbnRzID0gYXJnc1syXTtcbiAgICB9XG4gIH1cbiAgcmV0dXJuIGNtZDtcbn1cblxuLy8gdHVybnMgcGtnLmFjdGl2aXR5Lm5hbWUgdG8gLmFjdGl2aXR5Lm5hbWVcbi8vIGFsc28gdHVybnMgYWN0aXZpdHkubmFtZSB0byAuYWN0aXZpdHkubmFtZVxuZnVuY3Rpb24gZ2V0UG9zc2libGVBY3Rpdml0eU5hbWVzIChwa2dOYW1lLCBhY3Rpdml0eU5hbWUpIHtcbiAgbGV0IG5hbWVzID0gW2FjdGl2aXR5TmFtZV07XG4gIC8vIG5lZWQgdG8gYmV3YXJlIG9mIG5hbWVzcGFjZXMgd2l0aCBvdmVybGFwcGluZyBjaGFyczpcbiAgLy8gICBjb20uZm9vLmJhclxuICAvLyAgIGNvbS5mb28uYmFyeFxuICBpZiAoYWN0aXZpdHlOYW1lLmluZGV4T2YoYCR7cGtnTmFtZX0uYCkgPT09IDApIHtcbiAgICBuYW1lcy5wdXNoKGFjdGl2aXR5TmFtZS5zdWJzdHJpbmcocGtnTmFtZS5sZW5ndGgpKTtcbiAgfVxuICBpZiAoYWN0aXZpdHlOYW1lWzBdICE9PSAnLicpIHtcbiAgICBuYW1lcy5wdXNoKGAuJHthY3Rpdml0eU5hbWV9YCk7XG4gIH1cbiAgcmV0dXJuIG5hbWVzO1xufVxuXG5leHBvcnQgeyBnZXREaXJlY3RvcmllcywgZ2V0QW5kcm9pZFBsYXRmb3JtQW5kUGF0aCwgdW56aXBGaWxlLCBhc3NlcnRaaXBBcmNoaXZlLFxuICAgICAgICAgZ2V0SU1FTGlzdEZyb21PdXRwdXQsIGdldEphdmFGb3JPcywgaXNTaG93aW5nTG9ja3NjcmVlbiwgaXNDdXJyZW50Rm9jdXNPbktleWd1YXJkLFxuICAgICAgICAgaXNTY3JlZW5PbkZ1bGx5LCBidWlsZFN0YXJ0Q21kLCBnZXRQb3NzaWJsZUFjdGl2aXR5TmFtZXMsIGdldEphdmFIb21lLFxuICAgICAgICAgcm9vdERpciwgYW5kcm9pZFBsYXRmb3JtcyB9O1xuIl19