UNPKG

appium-adb-test

Version:

Android Debug Bridge interface

497 lines (403 loc) 34.1 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 _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, platforms, _iteratorNormalCompletion2, _didIteratorError2, _iteratorError2, _iterator2, _step2, platform, 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: platforms = _path2['default'].resolve(androidHome, 'platforms'); _iteratorNormalCompletion2 = true; _didIteratorError2 = false; _iteratorError2 = undefined; context$1$0.prev = 8; _iterator2 = _getIterator(_lodash2['default'].clone(androidPlatforms).reverse()); case 10: if (_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done) { context$1$0.next = 20; break; } platform = _step2.value; 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 = 10; break; case 20: context$1$0.next = 26; break; case 22: context$1$0.prev = 22; context$1$0.t0 = context$1$0['catch'](8); _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, [[8, 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; } /* * Reads SurfaceOrientation in dumpsys output */ function getSurfaceOrientation(dumpsys) { var m = /SurfaceOrientation: \d/gi.exec(dumpsys); return m && parseInt(m[0].split(':')[1]); } /* * 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) { // eslint-disable-line no-constant-condition 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.getSurfaceOrientation = getSurfaceOrientation; 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;charset=utf8;base64,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dCI6WyJpbXBvcnQgcGF0aCBmcm9tICdwYXRoJztcclxuaW1wb3J0IHsgc3lzdGVtLCBmcyB9IGZyb20gJ2FwcGl1bS1zdXBwb3J0JztcclxuaW1wb3J0IGxvZyBmcm9tICcuL2xvZ2dlci5qcyc7XHJcbmltcG9ydCBBZG1aaXAgZnJvbSAnYWRtLXppcCc7XHJcbmltcG9ydCB7IGV4ZWMgfSBmcm9tICd0ZWVuX3Byb2Nlc3MnO1xyXG5pbXBvcnQgXyBmcm9tICdsb2Rhc2gnO1xyXG5cclxuXHJcbmNvbnN0IHJvb3REaXIgPSBwYXRoLnJlc29sdmUoX19kaXJuYW1lLCBwcm9jZXNzLmVudi5OT19QUkVDT01QSUxFID8gJy4uJyA6ICcuLi8uLicpO1xyXG5jb25zdCBhbmRyb2lkUGxhdGZvcm1zID0gWydhbmRyb2lkLTQuMicsICdhbmRyb2lkLTE3JywgJ2FuZHJvaWQtNC4zJywgJ2FuZHJvaWQtMTgnLFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICdhbmRyb2lkLTQuNCcsICdhbmRyb2lkLTE5JywgJ2FuZHJvaWQtTCcsICdhbmRyb2lkLTIwJyxcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAnYW5kcm9pZC01LjAnLCAnYW5kcm9pZC0yMScsICdhbmRyb2lkLTIyJywgJ2FuZHJvaWQtTU5DJyxcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAnYW5kcm9pZC0yMycsICdhbmRyb2lkLTYuMCddO1xyXG5cclxuYXN5bmMgZnVuY3Rpb24gZ2V0RGlyZWN0b3JpZXMgKHJvb3RQYXRoKSB7XHJcbiAgbGV0IGZpbGVzID0gYXdhaXQgZnMucmVhZGRpcihyb290UGF0aCk7XHJcbiAgbGV0IGRpcnMgPSBbXTtcclxuICBmb3IgKGxldCBmaWxlIG9mIGZpbGVzKSB7XHJcbiAgICBsZXQgcGF0aFN0cmluZyA9IHBhdGgucmVzb2x2ZShyb290UGF0aCwgZmlsZSk7XHJcbiAgICBpZiAoKGF3YWl0IGZzLmxzdGF0KHBhdGhTdHJpbmcpKS5pc0RpcmVjdG9yeSgpKSB7XHJcbiAgICAgIGRpcnMucHVzaChmaWxlKTtcclxuICAgIH1cclxuICB9XHJcbiAgLy8gSXQgaXMgbm90IGEgY2xlYW4gd2F5IHRvIHNvcnQgaXQsIGJ1dCBpbiB0aGlzIGNhc2Ugd291bGQgd29yayBmaW5lIGJlY2F1c2VcclxuICAvLyB3ZSBoYXZlIG51bWVyaWNzIGFuZCBhbHBoYW51bWVyaWNcclxuICAvLyB3aWxsIHJldHVybiBzb21lIHRoaW5nIGxpa2UgdGhpc1xyXG4gIC8vIFtcIjE3LjAuMFwiLCBcIjE4LjAuMVwiLCBcIjE5LjAuMFwiLCBcIjE5LjAuMVwiLCBcIjE5LjEuMFwiLCBcIjIwLjAuMFwiLFxyXG4gIC8vICBcImFuZHJvaWQtNC4yLjJcIiwgXCJhbmRyb2lkLTQuM1wiLCBcImFuZHJvaWQtNC40XCJdXHJcbiAgcmV0dXJuIGRpcnMuc29ydCgpO1xyXG59XHJcblxyXG5hc3luYyBmdW5jdGlvbiBnZXRBbmRyb2lkUGxhdGZvcm1BbmRQYXRoICgpIHtcclxuICBjb25zdCBhbmRyb2lkSG9tZSA9IHByb2Nlc3MuZW52LkFORFJPSURfSE9NRTtcclxuICBpZiAoIV8uaXNTdHJpbmcoYW5kcm9pZEhvbWUpKSB7XHJcbiAgICBsb2cuZXJyb3IoXCJBTkRST0lEX0hPTUUgd2FzIG5vdCBleHBvcnRlZCFcIik7XHJcbiAgICByZXR1cm4gbnVsbDtcclxuICB9XHJcblxyXG4gIC8vIGdldCB0aGUgbGF0ZXN0IHBsYXRmb3JtIGFuZCBwYXRoXHJcbiAgbGV0IHBsYXRmb3JtcyA9IHBhdGgucmVzb2x2ZShhbmRyb2lkSG9tZSwgJ3BsYXRmb3JtcycpO1xyXG4gIGZvciAobGV0IHBsYXRmb3JtIG9mIF8uY2xvbmUoYW5kcm9pZFBsYXRmb3JtcykucmV2ZXJzZSgpKSB7XHJcbiAgICBsZXQgcGxhdGZvcm1QYXRoID0gcGF0aC5yZXNvbHZlKHBsYXRmb3JtcywgcGxhdGZvcm0pO1xyXG4gICAgaWYgKGF3YWl0IGZzLmV4aXN0cyhwbGF0Zm9ybVBhdGgpKSB7XHJcbiAgICAgIHJldHVybiB7cGxhdGZvcm0sIHBsYXRmb3JtUGF0aH07XHJcbiAgICB9XHJcbiAgfVxyXG4gIHJldHVybiBudWxsO1xyXG59XHJcblxyXG5hc3luYyBmdW5jdGlvbiB1bnppcEZpbGUgKHppcFBhdGgpIHtcclxuICBsb2cuZGVidWcoYFVuemlwcGluZyAke3ppcFBhdGh9YCk7XHJcbiAgdHJ5IHtcclxuICAgIGF3YWl0IGFzc2VydFppcEFyY2hpdmUoemlwUGF0aCk7XHJcbiAgICBpZiAoc3lzdGVtLmlzV2luZG93cygpKSB7XHJcbiAgICAgIGxldCB6aXAgPSBuZXcgQWRtWmlwKHppcFBhdGgpO1xyXG4gICAgICB6aXAuZXh0cmFjdEFsbFRvKHBhdGguZGlybmFtZSh6aXBQYXRoKSwgdHJ1ZSk7XHJcbiAgICAgIGxvZy5kZWJ1ZyhcIlVuemlwIHN1Y2Nlc3NmdWxcIik7XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICBhd2FpdCBleGVjKCd1bnppcCcsIFsnLW8nLCB6aXBQYXRoXSwge2N3ZDogcGF0aC5kaXJuYW1lKHppcFBhdGgpfSk7XHJcbiAgICAgIGxvZy5kZWJ1ZyhcIlVuemlwIHN1Y2Nlc3NmdWxcIik7XHJcbiAgICB9XHJcbiAgfSBjYXRjaCAoZSkge1xyXG4gICAgdGhyb3cgbmV3IEVycm9yKGBFcnJvciBvY2N1cnJlZCB3aGlsZSB1bnppcHBpbmcuIE9yaWdpbmFsIGVycm9yOiAke2UubWVzc2FnZX1gKTtcclxuICB9XHJcbn1cclxuXHJcbmFzeW5jIGZ1bmN0aW9uIGFzc2VydFppcEFyY2hpdmUgKHppcFBhdGgpIHtcclxuICBsb2cuZGVidWcoYFRlc3RpbmcgemlwIGFyY2hpdmU6ICR7emlwUGF0aH1gKTtcclxuICBpZiAoc3lzdGVtLmlzV2luZG93cygpKSB7XHJcbiAgICBpZiAoYXdhaXQgZnMuZXhpc3RzKHppcFBhdGgpKSB7XHJcbiAgICAgIGxvZy5kZWJ1ZyhcIlppcCBhcmNoaXZlIHRlc3RlZCBjbGVhblwiKTtcclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIHRocm93IG5ldyBFcnJvcihgWmlwIGFyY2hpdmUgbm90IHByZXNlbnQgYXQgJHt6aXBQYXRofWApO1xyXG4gICAgfVxyXG4gIH0gZWxzZSB7XHJcbiAgICBsZXQgZXhlY09wdHMgPSB7Y3dkOiBwYXRoLmRpcm5hbWUoemlwUGF0aCl9O1xyXG4gICAgYXdhaXQgZXhlYygndW56aXAnLCBbJy10cScsIHppcFBhdGhdLCBleGVjT3B0cyk7XHJcbiAgfVxyXG59XHJcblxyXG5mdW5jdGlvbiBnZXRJTUVMaXN0RnJvbU91dHB1dCAoc3Rkb3V0KSB7XHJcbiAgbGV0IGVuZ2luZXMgPSBbXTtcclxuICBmb3IgKGxldCBsaW5lIG9mIHN0ZG91dC5zcGxpdCgnXFxuJykpIHtcclxuICAgIGlmIChsaW5lLmxlbmd0aCA+IDAgJiYgbGluZVswXSAhPT0gJyAnKSB7XHJcbiAgICAgIC8vIHJlbW92ZSBuZXdsaW5lIGFuZCB0cmFpbGluZyBjb2xvbiwgYW5kIGFkZCB0byB0aGUgbGlzdFxyXG4gICAgICBlbmdpbmVzLnB1c2gobGluZS50cmltKCkucmVwbGFjZSgvOiQvLCAnJykpO1xyXG4gICAgfVxyXG4gIH1cclxuICByZXR1cm4gZW5naW5lcztcclxufVxyXG5cclxuZnVuY3Rpb24gZ2V0SmF2YUZvck9zICgpIHtcclxuICBjb25zdCBzZXAgPSBwYXRoLnNlcDtcclxuICBsZXQgamF2YSA9IGAke2dldEphdmFIb21lKCl9JHtzZXB9YmluJHtzZXB9amF2YWA7XHJcbiAgaWYgKHN5c3RlbS5pc1dpbmRvd3MoKSkge1xyXG4gICAgamF2YSA9IGphdmEgKyAnLmV4ZSc7XHJcbiAgfVxyXG4gIHJldHVybiBqYXZhO1xyXG59XHJcblxyXG5mdW5jdGlvbiBnZXRKYXZhSG9tZSAoKSB7XHJcbiAgaWYgKHByb2Nlc3MuZW52LkpBVkFfSE9NRSkge1xyXG4gICAgcmV0dXJuIHByb2Nlc3MuZW52LkpBVkFfSE9NRTtcclxuICB9XHJcbiAgdGhyb3cgbmV3IEVycm9yKFwiSkFWQV9IT01FIGlzIG5vdCBzZXQgY3VycmVudGx5LiBQbGVhc2Ugc2V0IEpBVkFfSE9NRS5cIik7XHJcbn1cclxuXHJcbi8qXHJcbiAqIENoZWNrcyBtU2hvd2luZ0xvY2tzY3JlZW4gaW4gZHVtcHN5cyBvdXRwdXQgdG8gZGV0ZXJtaW5lIGlmIGxvY2sgc2NyZWVuIGlzIHNob3dpbmdcclxuICovXHJcbmZ1bmN0aW9uIGlzU2hvd2luZ0xvY2tzY3JlZW4gKGR1bXBzeXMpIHtcclxuICBsZXQgbSA9IC9tU2hvd2luZ0xvY2tzY3JlZW49XFx3Ky9naS5leGVjKGR1bXBzeXMpO1xyXG4gIGxldCByZXQgPSAobSAmJiBtLmxlbmd0aCAmJiBtWzBdLnNwbGl0KCc9JylbMV0gPT09ICd0cnVlJykgfHwgZmFsc2U7XHJcbiAgcmV0dXJuIHJldDtcclxufVxyXG5cclxuLypcclxuICogQ2hlY2tzIG1DdXJyZW50Rm9jdXMgaW4gZHVtcHN5cyBvdXRwdXQgdG8gZGV0ZXJtaW5lIGlmIEtleWd1YXJkIGlzIGFjdGl2YXRlZFxyXG4gKi9cclxuZnVuY3Rpb24gaXNDdXJyZW50Rm9jdXNPbktleWd1YXJkIChkdW1wc3lzKSB7XHJcbiAgbGV0IG0gPSAvbUN1cnJlbnRGb2N1cy4rS2V5Z3VhcmQvZ2kuZXhlYyhkdW1wc3lzKTtcclxuICByZXR1cm4gKG0gJiYgbS5sZW5ndGggJiYgbVswXSkgPyB0cnVlIDogZmFsc2U7XHJcbn1cclxuXHJcbi8qXHJcbiAqIFJlYWRzIFN1cmZhY2VPcmllbnRhdGlvbiBpbiBkdW1wc3lzIG91dHB1dFxyXG4gKi9cclxuZnVuY3Rpb24gZ2V0U3VyZmFjZU9yaWVudGF0aW9uIChkdW1wc3lzKSB7XHJcbiAgbGV0IG0gPSAvU3VyZmFjZU9yaWVudGF0aW9uOiBcXGQvZ2kuZXhlYyhkdW1wc3lzKTtcclxuICByZXR1cm4gbSAmJiBwYXJzZUludChtWzBdLnNwbGl0KCc6JylbMV0pO1xyXG59XHJcblxyXG4vKlxyXG4gKiBDaGVja3MgbVNjcmVlbk9uRnVsbHkgaW4gZHVtcHN5cyBvdXRwdXQgdG8gZGV0ZXJtaW5lIGlmIHNjcmVlbiBpcyBzaG93aW5nXHJcbiAqIERlZmF1bHQgaXMgdHJ1ZVxyXG4gKi9cclxuZnVuY3Rpb24gaXNTY3JlZW5PbkZ1bGx5IChkdW1wc3lzKSB7XHJcbiAgbGV0IG0gPSAvbVNjcmVlbk9uRnVsbHk9XFx3Ky9naS5leGVjKGR1bXBzeXMpO1xyXG4gIHJldHVybiAhbSB8fCAvLyBpZiBpbmZvcm1hdGlvbiBpcyBtaXNzaW5nIHdlIGFzc3VtZSBzY3JlZW4gaXMgZnVsbHkgb25cclxuICAgICAgICAgKG0gJiYgbS5sZW5ndGggPiAwICYmIG1bMF0uc3BsaXQoJz0nKVsxXSA9PT0gJ3RydWUnKSB8fCBmYWxzZTtcclxufVxyXG5cclxuZnVuY3Rpb24gYnVpbGRTdGFydENtZCAoc3RhcnRBcHBPcHRpb25zLCBhcGlMZXZlbCkge1xyXG4gIGxldCBjbWQgPSBbJ2FtJywgJ3N0YXJ0JywgJy1XJywgJy1uJywgYCR7c3RhcnRBcHBPcHRpb25zLnBrZ30vJHtzdGFydEFwcE9wdGlvbnMuYWN0aXZpdHl9YF07XHJcbiAgaWYgKHN0YXJ0QXBwT3B0aW9ucy5zdG9wQXBwICYmIGFwaUxldmVsID49IDE1KSB7XHJcbiAgICBjbWQucHVzaCgnLVMnKTtcclxuICB9XHJcbiAgaWYgKHN0YXJ0QXBwT3B0aW9ucy5hY3Rpb24pIHtcclxuICAgIGNtZC5wdXNoKCctYScsIHN0YXJ0QXBwT3B0aW9ucy5hY3Rpb24pO1xyXG4gIH1cclxuICBpZiAoc3RhcnRBcHBPcHRpb25zLmNhdGVnb3J5KSB7XHJcbiAgICBjbWQucHVzaCgnLWMnLCBzdGFydEFwcE9wdGlvbnMuY2F0ZWdvcnkpO1xyXG4gIH1cclxuICBpZiAoc3RhcnRBcHBPcHRpb25zLmZsYWdzKSB7XHJcbiAgICBjbWQucHVzaCgnLWYnLCBzdGFydEFwcE9wdGlvbnMuZmxhZ3MpO1xyXG4gIH1cclxuICBpZiAoc3RhcnRBcHBPcHRpb25zLm9wdGlvbmFsSW50ZW50QXJndW1lbnRzKSB7XHJcbiAgICAvLyBleHBlY3Qgb3B0aW9uYWxJbnRlbnRBcmd1bWVudHMgdG8gYmUgYSBzaW5nbGUgc3RyaW5nIG9mIHRoZSBmb3JtOlxyXG4gICAgLy8gICAgIFwiLWZsYWcga2V5XCJcclxuICAgIC8vICAgICBcIi1mbGFnIGtleSB2YWx1ZVwiXHJcbiAgICAvLyBvciBhIGNvbWJpbmF0aW9uIG9mIHRoZXNlIChlLmcuLCBcIi1mbGFnMSBrZXkxIC1mbGFnMiBrZXkyIHZhbHVlMlwiKVxyXG5cclxuICAgIC8vIHRha2UgYSBzdHJpbmcgYW5kIHBhcnNlIG91dCB0aGUgcGFydCBiZWZvcmUgYW55IHNwYWNlcywgYW5kIGFueXRoaW5nIGFmdGVyXHJcbiAgICAvLyB0aGUgZmlyc3Qgc3BhY2VcclxuICAgIGxldCBwYXJzZUtleVZhbHVlID0gZnVuY3Rpb24gKHN0cikge1xyXG4gICAgICBzdHIgPSBzdHIudHJpbSgpO1xyXG4gICAgICBsZXQgc3BhY2UgPSBzdHIuaW5kZXhPZignICcpO1xyXG4gICAgICBpZiAoc3BhY2UgPT09IC0xKSB7XHJcbiAgICAgICAgcmV0dXJuIHN0ci5sZW5ndGggPyBbc3RyXSA6IFtdO1xyXG4gICAgICB9IGVsc2Uge1xyXG4gICAgICAgIHJldHVybiBbc3RyLnN1YnN0cmluZygwLCBzcGFjZSkudHJpbSgpLCBzdHIuc3Vic3RyaW5nKHNwYWNlICsgMSkudHJpbSgpXTtcclxuICAgICAgfVxyXG4gICAgfTtcclxuXHJcbiAgICAvLyBjeWNsZSB0aHJvdWdoIHRoZSBvcHRpb25hbEludGVudEFyZ3VtZW50cyBhbmQgcHVsbCBvdXQgdGhlIGFyZ3VtZW50c1xyXG4gICAgLy8gYWRkIGEgc3BhY2UgaW5pdGlhbGx5IHNvIGZsYWdzIGNhbiBiZSBkaXN0aW5ndWlzaGVkIGZyb20gYXJndW1lbnRzIHRoYXRcclxuICAgIC8vIGhhdmUgaW50ZXJuYWwgaHlwaGVuc1xyXG4gICAgbGV0IG9wdGlvbmFsSW50ZW50QXJndW1lbnRzID0gYCAke3N0YXJ0QXBwT3B0aW9ucy5vcHRpb25hbEludGVudEFyZ3VtZW50c31gO1xyXG4gICAgbGV0IHJlID0gLyAoLVteXFxzXSspICguKykvO1xyXG4gICAgd2hpbGUgKHRydWUpIHsgLy8gZXNsaW50LWRpc2FibGUtbGluZSBuby1jb25zdGFudC1jb25kaXRpb25cclxuICAgICAgbGV0IGFyZ3MgPSByZS5leGVjKG9wdGlvbmFsSW50ZW50QXJndW1lbnRzKTtcclxuICAgICAgaWYgKCFhcmdzKSB7XHJcbiAgICAgICAgaWYgKG9wdGlvbmFsSW50ZW50QXJndW1lbnRzLmxlbmd0aCkge1xyXG4gICAgICAgICAgLy8gbm8gbW9yZSBmbGFncywgc28gdGhlIHJlbWFpbmRlciBjYW4gYmUgdHJlYXRlZCBhcyAna2V5JyBvciAna2V5IHZhbHVlJ1xyXG4gICAgICAgICAgY21kLnB1c2guYXBwbHkoY21kLCBwYXJzZUtleVZhbHVlKG9wdGlvbmFsSW50ZW50QXJndW1lbnRzKSk7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIC8vIHdlIGFyZSBkb25lXHJcbiAgICAgICAgYnJlYWs7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIHRha2UgdGhlIGZsYWcgYW5kIHNlZSBpZiBpdCBpcyBhdCB0aGUgYmVnaW5uaW5nIG9mIHRoZSBzdHJpbmdcclxuICAgICAgLy8gaWYgaXQgaXMgbm90LCB0aGVuIGl0IG1lYW5zIHdlIGhhdmUgYmVlbiB0aHJvdWdoIGFscmVhZHksIGFuZFxyXG4gICAgICAvLyB3aGF0IGlzIGJlZm9yZSB0aGUgZmxhZyBpcyB0aGUgYXJndW1lbnQgZm9yIHRoZSBwcmV2aW91cyBmbGFnXHJcbiAgICAgIGxldCBmbGFnID0gYXJnc1sxXTtcclxuICAgICAgbGV0IGZsYWdQb3MgPSBvcHRpb25hbEludGVudEFyZ3VtZW50cy5pbmRleE9mKGZsYWcpO1xyXG4gICAgICBpZiAoZmxhZ1BvcyAhPT0gMCkge1xyXG4gICAgICAgIGxldCBwcmV2QXJncyA9IG9wdGlvbmFsSW50ZW50QXJndW1lbnRzLnN1YnN0cmluZygwLCBmbGFnUG9zKTtcclxuICAgICAgICBjbWQucHVzaC5hcHBseShjbWQsIHBhcnNlS2V5VmFsdWUocHJldkFyZ3MpKTtcclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gYWRkIHRoZSBmbGFnLCBhcyB0aGVyZSBhcmUgbm8gbW9yZSBlYXJsaWVyIGFyZ3VtZW50c1xyXG4gICAgICBjbWQucHVzaChmbGFnKTtcclxuXHJcbiAgICAgIC8vIG1ha2Ugb3B0aW9uYWxJbnRlbnRBcmd1bWVudHMgaG9sZCB0aGUgcmVtYWluZGVyXHJcbiAgICAgIG9wdGlvbmFsSW50ZW50QXJndW1lbnRzID0gYXJnc1syXTtcclxuICAgIH1cclxuICB9XHJcbiAgcmV0dXJuIGNtZDtcclxufVxyXG5cclxuLy8gdHVybnMgcGtnLmFjdGl2aXR5Lm5hbWUgdG8gLmFjdGl2aXR5Lm5hbWVcclxuLy8gYWxzbyB0dXJucyBhY3Rpdml0eS5uYW1lIHRvIC5hY3Rpdml0eS5uYW1lXHJcbmZ1bmN0aW9uIGdldFBvc3NpYmxlQWN0aXZpdHlOYW1lcyAocGtnTmFtZSwgYWN0aXZpdHlOYW1lKSB7XHJcbiAgbGV0IG5hbWVzID0gW2FjdGl2aXR5TmFtZV07XHJcbiAgLy8gbmVlZCB0byBiZXdhcmUgb2YgbmFtZXNwYWNlcyB3aXRoIG92ZXJsYXBwaW5nIGNoYXJzOlxyXG4gIC8vICAgY29tLmZvby5iYXJcclxuICAvLyAgIGNvbS5mb28uYmFyeFxyXG4gIGlmIChhY3Rpdml0eU5hbWUuaW5kZXhPZihgJHtwa2dOYW1lfS5gKSA9PT0gMCkge1xyXG4gICAgbmFtZXMucHVzaChhY3Rpdml0eU5hbWUuc3Vic3RyaW5nKHBrZ05hbWUubGVuZ3RoKSk7XHJcbiAgfVxyXG4gIGlmIChhY3Rpdml0eU5hbWVbMF0gIT09ICcuJykge1xyXG4gICAgbmFtZXMucHVzaChgLiR7YWN0aXZpdHlOYW1lfWApO1xyXG4gIH1cclxuICByZXR1cm4gbmFtZXM7XHJcbn1cclxuXHJcbmV4cG9ydCB7IGdldERpcmVjdG9yaWVzLCBnZXRBbmRyb2lkUGxhdGZvcm1BbmRQYXRoLCB1bnppcEZpbGUsIGFzc2VydFppcEFyY2hpdmUsXHJcbiAgICAgICAgIGdldElNRUxpc3RGcm9tT3V0cHV0LCBnZXRKYXZhRm9yT3MsIGlzU2hvd2luZ0xvY2tzY3JlZW4sIGlzQ3VycmVudEZvY3VzT25LZXlndWFyZCxcclxuICAgICAgICAgZ2V0U3VyZmFjZU9yaWVudGF0aW9uLCBpc1NjcmVlbk9uRnVsbHksIGJ1aWxkU3RhcnRDbWQsIGdldFBvc3NpYmxlQWN0aXZpdHlOYW1lcyxcclxuICAgICAgICAgZ2V0SmF2YUhvbWUsIHJvb3REaXIsIGFuZHJvaWRQbGF0Zm9ybXMgfTtcclxuIl0sInNvdXJjZVJvb3QiOiIuLlxcLi4ifQ==