appium-doctor
Version:
Test environment for fitness to run Appium
369 lines (286 loc) • 18.2 kB
JavaScript
var _createClass = require('babel-runtime/helpers/create-class')['default'];
var _classCallCheck = require('babel-runtime/helpers/class-call-check')['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 _appiumSupport = require('appium-support');
var _teen_process = require('teen_process');
var _logger = require('./logger');
var _logger2 = _interopRequireDefault(_logger);
var _path = require('path');
var _path2 = _interopRequireDefault(_path);
var NODE_COMMON_PATHS = [process.env.NODE_BIN, '/usr/local/bin/node', '/opt/local/bin/node'];
// Look for node
var NodeDetector = (function () {
function NodeDetector() {
_classCallCheck(this, NodeDetector);
}
_createClass(NodeDetector, null, [{
key: 'retrieveInCommonPlaces',
value: function retrieveInCommonPlaces() {
var _iteratorNormalCompletion, _didIteratorError, _iteratorError, _iterator, _step, p;
return _regeneratorRuntime.async(function retrieveInCommonPlaces$(context$2$0) {
while (1) switch (context$2$0.prev = context$2$0.next) {
case 0:
_iteratorNormalCompletion = true;
_didIteratorError = false;
_iteratorError = undefined;
context$2$0.prev = 3;
_iterator = _getIterator(NODE_COMMON_PATHS);
case 5:
if (_iteratorNormalCompletion = (_step = _iterator.next()).done) {
context$2$0.next = 18;
break;
}
p = _step.value;
context$2$0.t0 = p;
if (!context$2$0.t0) {
context$2$0.next = 12;
break;
}
context$2$0.next = 11;
return _regeneratorRuntime.awrap(_appiumSupport.fs.exists(p));
case 11:
context$2$0.t0 = context$2$0.sent;
case 12:
if (!context$2$0.t0) {
context$2$0.next = 15;
break;
}
_logger2['default'].debug('Node binary found at common place: ' + p);
return context$2$0.abrupt('return', p);
case 15:
_iteratorNormalCompletion = true;
context$2$0.next = 5;
break;
case 18:
context$2$0.next = 24;
break;
case 20:
context$2$0.prev = 20;
context$2$0.t1 = context$2$0['catch'](3);
_didIteratorError = true;
_iteratorError = context$2$0.t1;
case 24:
context$2$0.prev = 24;
context$2$0.prev = 25;
if (!_iteratorNormalCompletion && _iterator['return']) {
_iterator['return']();
}
case 27:
context$2$0.prev = 27;
if (!_didIteratorError) {
context$2$0.next = 30;
break;
}
throw _iteratorError;
case 30:
return context$2$0.finish(27);
case 31:
return context$2$0.finish(24);
case 32:
_logger2['default'].debug('Node binary wasn\'t found at common places.');
return context$2$0.abrupt('return', null);
case 34:
case 'end':
return context$2$0.stop();
}
}, null, this, [[3, 20, 24, 32], [25,, 27, 31]]);
}
}, {
key: 'retrieveUsingWhichCommand',
value: function retrieveUsingWhichCommand() {
var stdout, nodePath;
return _regeneratorRuntime.async(function retrieveUsingWhichCommand$(context$2$0) {
while (1) switch (context$2$0.prev = context$2$0.next) {
case 0:
stdout = undefined;
context$2$0.prev = 1;
context$2$0.next = 4;
return _regeneratorRuntime.awrap((0, _teen_process.exec)('which', ['node']));
case 4:
stdout = context$2$0.sent.stdout;
context$2$0.next = 9;
break;
case 7:
context$2$0.prev = 7;
context$2$0.t0 = context$2$0['catch'](1);
case 9:
nodePath = stdout.replace("\n", "");
context$2$0.next = 12;
return _regeneratorRuntime.awrap(_appiumSupport.fs.exists(nodePath));
case 12:
if (!context$2$0.sent) {
context$2$0.next = 17;
break;
}
_logger2['default'].debug('Node binary found using which command at: ' + nodePath);
return context$2$0.abrupt('return', nodePath);
case 17:
_logger2['default'].debug('Node binary not found using the which command.');
return context$2$0.abrupt('return', null);
case 19:
case 'end':
return context$2$0.stop();
}
}, null, this, [[1, 7]]);
}
}, {
key: 'retrieveUsingAppleScript',
value: function retrieveUsingAppleScript() {
var appScript, stdout, nodePath;
return _regeneratorRuntime.async(function retrieveUsingAppleScript$(context$2$0) {
while (1) switch (context$2$0.prev = context$2$0.next) {
case 0:
appScript = ['try', ' set appiumIsRunning to false', ' tell application "System Events"', ' set appiumIsRunning to name of every process contains "Appium"', ' end tell', ' if appiumIsRunning then', ' tell application "Appium" to return node path', ' end if', 'end try', 'return "NULL"'].join("\n");
stdout = undefined;
context$2$0.prev = 2;
context$2$0.next = 5;
return _regeneratorRuntime.awrap((0, _teen_process.exec)('osascript', ['-e', appScript]));
case 5:
stdout = context$2$0.sent.stdout;
context$2$0.next = 10;
break;
case 8:
context$2$0.prev = 8;
context$2$0.t0 = context$2$0['catch'](2);
case 10:
nodePath = stdout.replace("\n", "");
context$2$0.next = 13;
return _regeneratorRuntime.awrap(_appiumSupport.fs.exists(nodePath));
case 13:
if (!context$2$0.sent) {
context$2$0.next = 18;
break;
}
_logger2['default'].debug('Node binary found using AppleScript at: ' + nodePath);
return context$2$0.abrupt('return', nodePath);
case 18:
_logger2['default'].debug('Node binary not found using AppleScript.');
return context$2$0.abrupt('return', null);
case 20:
case 'end':
return context$2$0.stop();
}
}, null, this, [[2, 8]]);
}
}, {
key: 'retrieveUsingAppiumConfigFile',
value: function retrieveUsingAppiumConfigFile() {
var jsonobj, appiumConfigPath;
return _regeneratorRuntime.async(function retrieveUsingAppiumConfigFile$(context$2$0) {
while (1) switch (context$2$0.prev = context$2$0.next) {
case 0:
jsonobj = undefined;
context$2$0.prev = 1;
appiumConfigPath = _path2['default'].resolve(__dirname, '..', '..', '.appiumconfig.json');
context$2$0.next = 5;
return _regeneratorRuntime.awrap(_appiumSupport.fs.exists(appiumConfigPath));
case 5:
if (!context$2$0.sent) {
context$2$0.next = 11;
break;
}
context$2$0.t0 = JSON;
context$2$0.next = 9;
return _regeneratorRuntime.awrap(_appiumSupport.fs.readFile(appiumConfigPath, 'utf8'));
case 9:
context$2$0.t1 = context$2$0.sent;
jsonobj = context$2$0.t0.parse.call(context$2$0.t0, context$2$0.t1);
case 11:
context$2$0.next = 15;
break;
case 13:
context$2$0.prev = 13;
context$2$0.t2 = context$2$0['catch'](1);
case 15:
context$2$0.t3 = jsonobj && jsonobj.node_bin;
if (!context$2$0.t3) {
context$2$0.next = 20;
break;
}
context$2$0.next = 19;
return _regeneratorRuntime.awrap(_appiumSupport.fs.exists(jsonobj.node_bin));
case 19:
context$2$0.t3 = context$2$0.sent;
case 20:
if (!context$2$0.t3) {
context$2$0.next = 25;
break;
}
_logger2['default'].debug('Node binary found using .appiumconfig.json at: ' + jsonobj.node_bin);
return context$2$0.abrupt('return', jsonobj.node_bin);
case 25:
_logger2['default'].debug('Node binary not found in the .appiumconfig.json file.');
return context$2$0.abrupt('return', null);
case 27:
case 'end':
return context$2$0.stop();
}
}, null, this, [[1, 13]]);
}
}, {
key: 'detect',
value: function detect() {
var nodePath;
return _regeneratorRuntime.async(function detect$(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.retrieveInCommonPlaces());
case 2:
context$2$0.t2 = context$2$0.sent;
if (context$2$0.t2) {
context$2$0.next = 7;
break;
}
context$2$0.next = 6;
return _regeneratorRuntime.awrap(NodeDetector.retrieveUsingWhichCommand());
case 6:
context$2$0.t2 = context$2$0.sent;
case 7:
context$2$0.t1 = context$2$0.t2;
if (context$2$0.t1) {
context$2$0.next = 12;
break;
}
context$2$0.next = 11;
return _regeneratorRuntime.awrap(NodeDetector.retrieveUsingAppleScript());
case 11:
context$2$0.t1 = context$2$0.sent;
case 12:
context$2$0.t0 = context$2$0.t1;
if (context$2$0.t0) {
context$2$0.next = 17;
break;
}
context$2$0.next = 16;
return _regeneratorRuntime.awrap(NodeDetector.retrieveUsingAppiumConfigFile());
case 16:
context$2$0.t0 = context$2$0.sent;
case 17:
nodePath = context$2$0.t0;
if (!nodePath) {
context$2$0.next = 22;
break;
}
return context$2$0.abrupt('return', nodePath);
case 22:
_logger2['default'].warn('The node binary could not be found.');
return context$2$0.abrupt('return', null);
case 24:
case 'end':
return context$2$0.stop();
}
}, null, this);
}
}]);
return NodeDetector;
})();
exports['default'] = NodeDetector;
module.exports = exports['default'];
//# sourceMappingURL=data:application/json;charset=utf8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbImxpYi9ub2RlLWRldGVjdG9yLmpzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7Ozs7Ozs7NkJBQW1CLGdCQUFnQjs7NEJBQ2QsY0FBYzs7c0JBQ25CLFVBQVU7Ozs7b0JBQ1QsTUFBTTs7OztBQUV2QixJQUFNLGlCQUFpQixHQUFHLENBQ3hCLE9BQU8sQ0FBQyxHQUFHLENBQUMsUUFBUSxFQUNwQixxQkFBcUIsRUFDckIscUJBQXFCLENBQ3RCLENBQUM7Ozs7SUFHSSxZQUFZO1dBQVosWUFBWTswQkFBWixZQUFZOzs7ZUFBWixZQUFZOztXQUNvQjswRkFDekIsQ0FBQzs7Ozs7Ozs7O3FDQUFJLGlCQUFpQjs7Ozs7Ozs7QUFBdEIsYUFBQzs2QkFDSixDQUFDOzs7Ozs7Ozs2Q0FBVSxrQkFBRyxNQUFNLENBQUMsQ0FBQyxDQUFDOzs7Ozs7Ozs7OztBQUN6QixnQ0FBSSxLQUFLLHlDQUF1QyxDQUFDLENBQUcsQ0FBQztnREFDOUMsQ0FBQzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0FBR1osZ0NBQUksS0FBSyxDQUFDLDZDQUE2QyxDQUFDLENBQUM7Z0RBQ2xELElBQUk7Ozs7Ozs7S0FDWjs7O1dBRXNDO1VBQ2pDLE1BQU0sRUFJTixRQUFROzs7O0FBSlIsa0JBQU07Ozs2Q0FFUSx3QkFBSyxPQUFPLEVBQUUsQ0FBQyxNQUFNLENBQUMsQ0FBQzs7O0FBQXZDLGtCQUFNLG9CQUFtQyxNQUFNOzs7Ozs7Ozs7QUFFN0Msb0JBQVEsR0FBRyxNQUFNLENBQUMsT0FBTyxDQUFDLElBQUksRUFBRSxFQUFFLENBQUM7OzZDQUM3QixrQkFBRyxNQUFNLENBQUMsUUFBUSxDQUFDOzs7Ozs7OztBQUMzQixnQ0FBSSxLQUFLLGdEQUE4QyxRQUFRLENBQUcsQ0FBQztnREFDNUQsUUFBUTs7O0FBRWYsZ0NBQUksS0FBSyxDQUFDLGdEQUFnRCxDQUFDLENBQUM7Z0RBQ3JELElBQUk7Ozs7Ozs7S0FFZDs7O1dBRXFDO1VBQ2hDLFNBQVMsRUFZVCxNQUFNLEVBSU4sUUFBUTs7OztBQWhCUixxQkFBUyxHQUFHLENBQ2QsS0FBSyxFQUNILGdDQUFnQyxFQUNoQyxvQ0FBb0MsRUFDcEMsb0VBQW9FLEVBQ3BFLFlBQVksRUFDWiwyQkFBMkIsRUFDM0IsbURBQW1ELEVBQ25ELFVBQVUsRUFDVixTQUFTLEVBQ1QsZUFBZSxDQUNsQixDQUFDLElBQUksQ0FBQyxJQUFJLENBQUM7QUFDUixrQkFBTTs7OzZDQUVRLHdCQUFLLFdBQVcsRUFBRSxDQUFDLElBQUksRUFBRSxTQUFTLENBQUMsQ0FBQzs7O0FBQXBELGtCQUFNLG9CQUFnRCxNQUFNOzs7Ozs7Ozs7QUFFMUQsb0JBQVEsR0FBRyxNQUFNLENBQUMsT0FBTyxDQUFDLElBQUksRUFBRSxFQUFFLENBQUM7OzZDQUM3QixrQkFBRyxNQUFNLENBQUMsUUFBUSxDQUFDOzs7Ozs7OztBQUMzQixnQ0FBSSxLQUFLLDhDQUE0QyxRQUFRLENBQUcsQ0FBQztnREFDMUQsUUFBUTs7O0FBRWYsZ0NBQUksS0FBSyxDQUFDLDBDQUEwQyxDQUFDLENBQUM7Z0RBQy9DLElBQUk7Ozs7Ozs7S0FFZDs7O1dBRTBDO1VBQ3JDLE9BQU8sRUFFTCxnQkFBZ0I7Ozs7QUFGbEIsbUJBQU87O0FBRUwsNEJBQWdCLEdBQUcsa0JBQUssT0FBTyxDQUFDLFNBQVMsRUFBRSxJQUFJLEVBQUUsSUFBSSxFQUFFLG9CQUFvQixDQUFDOzs2Q0FDdEUsa0JBQUcsTUFBTSxDQUFDLGdCQUFnQixDQUFDOzs7Ozs7Ozs2QkFDekIsSUFBSTs7NkNBQWEsa0JBQUcsUUFBUSxDQUFDLGdCQUFnQixFQUFFLE1BQU0sQ0FBQzs7OztBQUFoRSxtQkFBTyxrQkFBUSxLQUFLOzs7Ozs7Ozs7Ozs2QkFHcEIsT0FBTyxJQUFJLE9BQU8sQ0FBQyxRQUFROzs7Ozs7Ozs2Q0FBVSxrQkFBRyxNQUFNLENBQUMsT0FBTyxDQUFDLFFBQVEsQ0FBQzs7Ozs7Ozs7Ozs7QUFDbEUsZ0NBQUksS0FBSyxxREFBbUQsT0FBTyxDQUFDLFFBQVEsQ0FBRyxDQUFDO2dEQUN6RSxPQUFPLENBQUMsUUFBUTs7O0FBRXZCLGdDQUFJLEtBQUssQ0FBQyx1REFBdUQsQ0FBQyxDQUFDO2dEQUM1RCxJQUFJOzs7Ozs7O0tBRWQ7OztXQUVtQjtVQUNkLFFBQVE7Ozs7OzZDQUFTLElBQUksQ0FBQyxzQkFBc0IsRUFBRTs7Ozs7Ozs7Ozs7NkNBQzFDLFlBQVksQ0FBQyx5QkFBeUIsRUFBRTs7Ozs7Ozs7Ozs7Ozs7NkNBQ3hDLFlBQVksQ0FBQyx3QkFBd0IsRUFBRTs7Ozs7Ozs7Ozs7Ozs7NkNBQ3ZDLFlBQVksQ0FBQyw2QkFBNkIsRUFBRTs7Ozs7O0FBSGhELG9CQUFROztpQkFJUixRQUFROzs7OztnREFDSCxRQUFROzs7QUFFZixnQ0FBSSxJQUFJLENBQUMscUNBQXFDLENBQUMsQ0FBQztnREFDekMsSUFBSTs7Ozs7OztLQUVkOzs7U0FsRkcsWUFBWTs7O3FCQXFGSCxZQUFZIiwiZmlsZSI6ImxpYi9ub2RlLWRldGVjdG9yLmpzIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgZnMgfSBmcm9tICdhcHBpdW0tc3VwcG9ydCc7XG5pbXBvcnQgeyBleGVjIH0gZnJvbSAndGVlbl9wcm9jZXNzJztcbmltcG9ydCBsb2cgZnJvbSAnLi9sb2dnZXInO1xuaW1wb3J0IHBhdGggZnJvbSAncGF0aCc7XG5cbmNvbnN0IE5PREVfQ09NTU9OX1BBVEhTID0gW1xuICBwcm9jZXNzLmVudi5OT0RFX0JJTixcbiAgJy91c3IvbG9jYWwvYmluL25vZGUnLFxuICAnL29wdC9sb2NhbC9iaW4vbm9kZScsXG5dO1xuXG4vLyBMb29rIGZvciBub2RlXG5jbGFzcyBOb2RlRGV0ZWN0b3Ige1xuICBzdGF0aWMgYXN5bmMgcmV0cmlldmVJbkNvbW1vblBsYWNlcyAoKSB7XG4gICAgZm9yIChsZXQgcCBvZiBOT0RFX0NPTU1PTl9QQVRIUykge1xuICAgICAgaWYgKHAgJiYgYXdhaXQgZnMuZXhpc3RzKHApKSB7XG4gICAgICAgIGxvZy5kZWJ1ZyhgTm9kZSBiaW5hcnkgZm91bmQgYXQgY29tbW9uIHBsYWNlOiAke3B9YCk7XG4gICAgICAgIHJldHVybiBwO1xuICAgICAgfVxuICAgIH1cbiAgICBsb2cuZGVidWcoJ05vZGUgYmluYXJ5IHdhc25cXCd0IGZvdW5kIGF0IGNvbW1vbiBwbGFjZXMuJyk7XG4gICAgcmV0dXJuIG51bGw7XG4gIH1cblxuICBzdGF0aWMgYXN5bmMgcmV0cmlldmVVc2luZ1doaWNoQ29tbWFuZCAoKSB7XG4gICAgbGV0IHN0ZG91dDtcbiAgICB0cnkge1xuICAgICAgc3Rkb3V0ID0gKGF3YWl0IGV4ZWMoJ3doaWNoJywgWydub2RlJ10pKS5zdGRvdXQ7XG4gICAgfSBjYXRjaCAoaWduKSB7fVxuICAgIGxldCBub2RlUGF0aCA9IHN0ZG91dC5yZXBsYWNlKFwiXFxuXCIsIFwiXCIpO1xuICAgIGlmIChhd2FpdCBmcy5leGlzdHMobm9kZVBhdGgpKSB7XG4gICAgICBsb2cuZGVidWcoYE5vZGUgYmluYXJ5IGZvdW5kIHVzaW5nIHdoaWNoIGNvbW1hbmQgYXQ6ICR7bm9kZVBhdGh9YCk7XG4gICAgICByZXR1cm4gbm9kZVBhdGg7XG4gICAgfSBlbHNlIHtcbiAgICAgIGxvZy5kZWJ1ZygnTm9kZSBiaW5hcnkgbm90IGZvdW5kIHVzaW5nIHRoZSB3aGljaCBjb21tYW5kLicpO1xuICAgICAgcmV0dXJuIG51bGw7XG4gICAgfVxuICB9XG5cbiAgc3RhdGljIGFzeW5jIHJldHJpZXZlVXNpbmdBcHBsZVNjcmlwdCAoKSB7XG4gICAgdmFyIGFwcFNjcmlwdCA9IFtcbiAgICAgICd0cnknXG4gICAgICAsICcgIHNldCBhcHBpdW1Jc1J1bm5pbmcgdG8gZmFsc2UnXG4gICAgICAsICcgIHRlbGwgYXBwbGljYXRpb24gXCJTeXN0ZW0gRXZlbnRzXCInXG4gICAgICAsICcgICAgc2V0IGFwcGl1bUlzUnVubmluZyB0byBuYW1lIG9mIGV2ZXJ5IHByb2Nlc3MgY29udGFpbnMgXCJBcHBpdW1cIidcbiAgICAgICwgJyAgZW5kIHRlbGwnXG4gICAgICAsICcgIGlmIGFwcGl1bUlzUnVubmluZyB0aGVuJ1xuICAgICAgLCAnICAgIHRlbGwgYXBwbGljYXRpb24gXCJBcHBpdW1cIiB0byByZXR1cm4gbm9kZSBwYXRoJ1xuICAgICAgLCAnICBlbmQgaWYnXG4gICAgICAsICdlbmQgdHJ5J1xuICAgICAgLCAncmV0dXJuIFwiTlVMTFwiJ1xuICAgIF0uam9pbihcIlxcblwiKTtcbiAgICBsZXQgc3Rkb3V0O1xuICAgIHRyeSB7XG4gICAgICBzdGRvdXQgPSAoYXdhaXQgZXhlYygnb3Nhc2NyaXB0JywgWyctZScsIGFwcFNjcmlwdF0pKS5zdGRvdXQ7XG4gICAgfSBjYXRjaCAoaWduKSB7fVxuICAgIGxldCBub2RlUGF0aCA9IHN0ZG91dC5yZXBsYWNlKFwiXFxuXCIsIFwiXCIpO1xuICAgIGlmIChhd2FpdCBmcy5leGlzdHMobm9kZVBhdGgpKSB7XG4gICAgICBsb2cuZGVidWcoYE5vZGUgYmluYXJ5IGZvdW5kIHVzaW5nIEFwcGxlU2NyaXB0IGF0OiAke25vZGVQYXRofWApO1xuICAgICAgcmV0dXJuIG5vZGVQYXRoO1xuICAgIH0gZWxzZSB7XG4gICAgICBsb2cuZGVidWcoJ05vZGUgYmluYXJ5IG5vdCBmb3VuZCB1c2luZyBBcHBsZVNjcmlwdC4nKTtcbiAgICAgIHJldHVybiBudWxsO1xuICAgIH1cbiAgfVxuXG4gIHN0YXRpYyBhc3luYyByZXRyaWV2ZVVzaW5nQXBwaXVtQ29uZmlnRmlsZSAoKSB7XG4gICAgbGV0IGpzb25vYmo7XG4gICAgdHJ5IHtcbiAgICAgIHZhciBhcHBpdW1Db25maWdQYXRoID0gcGF0aC5yZXNvbHZlKF9fZGlybmFtZSwgJy4uJywgJy4uJywgJy5hcHBpdW1jb25maWcuanNvbicpO1xuICAgICAgaWYgKGF3YWl0IGZzLmV4aXN0cyhhcHBpdW1Db25maWdQYXRoKSkge1xuICAgICAgICBqc29ub2JqID0gSlNPTi5wYXJzZShhd2FpdCBmcy5yZWFkRmlsZShhcHBpdW1Db25maWdQYXRoLCAndXRmOCcpKTtcbiAgICAgIH1cbiAgICB9IGNhdGNoIChpZ24pIHt9XG4gICAgaWYgKGpzb25vYmogJiYganNvbm9iai5ub2RlX2JpbiAmJiBhd2FpdCBmcy5leGlzdHMoanNvbm9iai5ub2RlX2JpbikgKSB7XG4gICAgICBsb2cuZGVidWcoYE5vZGUgYmluYXJ5IGZvdW5kIHVzaW5nIC5hcHBpdW1jb25maWcuanNvbiBhdDogJHtqc29ub2JqLm5vZGVfYmlufWApO1xuICAgICAgcmV0dXJuIGpzb25vYmoubm9kZV9iaW47XG4gICAgfSBlbHNlIHtcbiAgICAgIGxvZy5kZWJ1ZygnTm9kZSBiaW5hcnkgbm90IGZvdW5kIGluIHRoZSAuYXBwaXVtY29uZmlnLmpzb24gZmlsZS4nKTtcbiAgICAgIHJldHVybiBudWxsO1xuICAgIH1cbiAgfVxuXG4gIHN0YXRpYyBhc3luYyBkZXRlY3QgKCkge1xuICAgIGxldCBub2RlUGF0aCA9IGF3YWl0IHRoaXMucmV0cmlldmVJbkNvbW1vblBsYWNlcygpIHx8XG4gICAgICBhd2FpdCBOb2RlRGV0ZWN0b3IucmV0cmlldmVVc2luZ1doaWNoQ29tbWFuZCgpIHx8XG4gICAgICBhd2FpdCBOb2RlRGV0ZWN0b3IucmV0cmlldmVVc2luZ0FwcGxlU2NyaXB0KCkgfHxcbiAgICAgIGF3YWl0IE5vZGVEZXRlY3Rvci5yZXRyaWV2ZVVzaW5nQXBwaXVtQ29uZmlnRmlsZSgpO1xuICAgIGlmIChub2RlUGF0aCkge1xuICAgICAgcmV0dXJuIG5vZGVQYXRoO1xuICAgIH0gZWxzZSB7XG4gICAgICBsb2cud2FybignVGhlIG5vZGUgYmluYXJ5IGNvdWxkIG5vdCBiZSBmb3VuZC4nKTtcbiAgICAgIHJldHVybiBudWxsO1xuICAgIH1cbiAgfVxufVxuXG5leHBvcnQgZGVmYXVsdCBOb2RlRGV0ZWN0b3I7XG4iXSwic291cmNlUm9vdCI6Ii4uLy4uIn0=
;