wdio-lambdatest-service
Version:
A WebdriverIO service that manages tunnel and job metadata for LambdaTest.
181 lines (180 loc) • 29.6 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
require("source-map-support/register");
var _formData = _interopRequireDefault(require("form-data"));
var _fs = _interopRequireDefault(require("fs"));
var _axios = _interopRequireDefault(require("axios"));
var _perf_hooks = require("perf_hooks");
var _logger = _interopRequireDefault(require("@wdio/logger"));
var _nodeTunnel = _interopRequireDefault(require("@lambdatest/node-tunnel"));
var _constants = require("./constants.js");
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
const log = (0, _logger.default)('@wdio/lambdatest-service');
const colors = require('colors');
class LambdaTestLauncher {
constructor(options) {
_defineProperty(this, "lambdatestTunnelProcess", void 0);
_defineProperty(this, "options", void 0);
this.options = options;
}
configureCapabilities(capabilities, key, value) {
const updateCapability = capability => {
if (capability['lt:options']) {
capability['LT:Options'] = {
...capability['lt:options']
};
delete capability['lt:options'];
}
if (capability['LT:Options'] === undefined) {
capability[key] = value;
} else {
capability['LT:Options'][key] = value;
}
};
if (Array.isArray(capabilities)) {
capabilities.forEach(updateCapability);
} else if (typeof capabilities === 'object') {
updateCapability(capabilities);
}
}
async onPrepare(config, capabilities) {
if (this.options.app_upload) {
try {
var _this$options$app, _this$options$app$app, _this$options$app2, _this$options$app$app2, _this$options$app3, _this$options$app$cus, _this$options$app4;
const appName = (_this$options$app = this.options.app) === null || _this$options$app === void 0 ? void 0 : _this$options$app.app_name;
if (!appName) throw new Error(colors.yellow('App name is missing.\n'));
const appPath = (_this$options$app$app = (_this$options$app2 = this.options.app) === null || _this$options$app2 === void 0 ? void 0 : _this$options$app2.app_path) !== null && _this$options$app$app !== void 0 ? _this$options$app$app : null;
const appUrl = (_this$options$app$app2 = (_this$options$app3 = this.options.app) === null || _this$options$app3 === void 0 ? void 0 : _this$options$app3.app_url) !== null && _this$options$app$app2 !== void 0 ? _this$options$app$app2 : null;
const customId = (_this$options$app$cus = (_this$options$app4 = this.options.app) === null || _this$options$app4 === void 0 ? void 0 : _this$options$app4.custom_id) !== null && _this$options$app$cus !== void 0 ? _this$options$app$cus : null;
let data = new _formData.default();
data.append('name', appName);
data.append(appPath !== null ? 'appFile' : 'url', appPath !== null ? _fs.default.createReadStream(appPath) : appUrl);
if (customId !== null) data.append('custom_id', customId);
let headerEnv = `Basic ${Buffer.from(config.user + ':' + config.key).toString('base64')}`;
let body = {
method: 'post',
maxBodyLength: Infinity,
url: 'https://manual-api.lambdatest.com/app/upload/realDevice',
headers: {
'Authorization': headerEnv,
...data.getHeaders()
},
data: data
};
const response = await _axios.default.request(body);
console.log(colors.green(JSON.stringify(response.data)));
const envAppUrl = response.data.app_url;
if (this.options.app.enableCapability) {
this.configureCapabilities(capabilities, 'app', envAppUrl);
}
const appId = response.data.app_id;
if (appPath && appPath.includes('.apk') || appUrl && appUrl.includes('.apk')) {
await checkPatchUrl(appId, headerEnv);
}
} catch (error) {
console.error(error.message);
}
}
if (!this.options.tunnel) {
return;
}
const tunnelArguments = {
user: config.user,
key: config.key,
...this.options.lambdatestOpts
};
this.lambdatestTunnelProcess = new _nodeTunnel.default();
this.configureCapabilities(capabilities, 'tunnel', true);
const obs = new _perf_hooks.PerformanceObserver(list => {
const entry = list.getEntries()[0];
log.info(`LambdaTest Tunnel successfully started after ${entry.duration}ms`);
});
obs.observe({
entryTypes: ['measure'],
buffered: false
});
let timer;
_perf_hooks.performance.mark('ltTunnelStart');
return Promise.race([(new Promise((resolve, reject) => {
this.lambdatestTunnelProcess.start(tunnelArguments, err => {
if (err) {
obs.disconnect();
return reject(err);
}
this.lambdatestTunnelProcess.getTunnelName(tunnelName => {
this.configureCapabilities(capabilities, 'tunnelName', tunnelName);
obs.disconnect();
resolve();
});
});
})), new Promise((resolve, reject) => {
timer = setTimeout(() => {
obs.disconnect();
reject(new Error(_constants.TUNNEL_START_FAILED));
}, _constants.TUNNEL_STOP_TIMEOUT);
})]).then(result => {
clearTimeout(timer);
_perf_hooks.performance.mark('ltTunnelEnd');
_perf_hooks.performance.measure('bootTime', 'ltTunnelStart', 'ltTunnelEnd');
obs.disconnect();
return Promise.resolve(result);
}, err => {
clearTimeout(timer);
obs.disconnect();
return Promise.reject(err);
});
}
onComplete() {
if (!this.lambdatestTunnelProcess || typeof this.lambdatestTunnelProcess.isRunning !== 'function' || !this.lambdatestTunnelProcess.isRunning()) {
return;
}
let timer;
return Promise.race([new Promise((resolve, reject) => {
this.lambdatestTunnelProcess.stop(err => {
if (err) return reject(err);
resolve();
});
}), new Promise((resolve, reject) => {
timer = setTimeout(() => reject(new Error(_constants.TUNNEL_STOP_FAILED)), _constants.TUNNEL_STOP_TIMEOUT);
})]).then(() => {
clearTimeout(timer);
return Promise.resolve();
}, err => {
clearTimeout(timer);
return Promise.reject(err);
});
}
}
exports.default = LambdaTestLauncher;
async function checkPatchUrl(appId, headerEnv) {
let config = {
method: 'get',
maxBodyLength: Infinity,
url: `https://manual-api.lambdatest.com/app/${appId}/url?reinstall=true`,
headers: {
'Authorization': headerEnv
}
};
let isLoaded = false;
while (!isLoaded) {
try {
const response = await _axios.default.request(config);
const patchedUrl = response.data.patched_url;
if (patchedUrl !== null) {
isLoaded = true;
break;
}
console.log('Waiting for app to be loaded...');
} catch (error) {
console.error('Error occurred:', error.message);
}
await new Promise(resolve => setTimeout(resolve, 15000));
}
}
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfZm9ybURhdGEiLCJfaW50ZXJvcFJlcXVpcmVEZWZhdWx0IiwicmVxdWlyZSIsIl9mcyIsIl9heGlvcyIsIl9wZXJmX2hvb2tzIiwiX2xvZ2dlciIsIl9ub2RlVHVubmVsIiwiX2NvbnN0YW50cyIsImUiLCJfX2VzTW9kdWxlIiwiZGVmYXVsdCIsIl9kZWZpbmVQcm9wZXJ0eSIsInIiLCJ0IiwiX3RvUHJvcGVydHlLZXkiLCJPYmplY3QiLCJkZWZpbmVQcm9wZXJ0eSIsInZhbHVlIiwiZW51bWVyYWJsZSIsImNvbmZpZ3VyYWJsZSIsIndyaXRhYmxlIiwiaSIsIl90b1ByaW1pdGl2ZSIsIlN5bWJvbCIsInRvUHJpbWl0aXZlIiwiY2FsbCIsIlR5cGVFcnJvciIsIlN0cmluZyIsIk51bWJlciIsImxvZyIsImxvZ2dlciIsImNvbG9ycyIsIkxhbWJkYVRlc3RMYXVuY2hlciIsImNvbnN0cnVjdG9yIiwib3B0aW9ucyIsImNvbmZpZ3VyZUNhcGFiaWxpdGllcyIsImNhcGFiaWxpdGllcyIsImtleSIsInVwZGF0ZUNhcGFiaWxpdHkiLCJjYXBhYmlsaXR5IiwidW5kZWZpbmVkIiwiQXJyYXkiLCJpc0FycmF5IiwiZm9yRWFjaCIsIm9uUHJlcGFyZSIsImNvbmZpZyIsImFwcF91cGxvYWQiLCJfdGhpcyRvcHRpb25zJGFwcCIsIl90aGlzJG9wdGlvbnMkYXBwJGFwcCIsIl90aGlzJG9wdGlvbnMkYXBwMiIsIl90aGlzJG9wdGlvbnMkYXBwJGFwcDIiLCJfdGhpcyRvcHRpb25zJGFwcDMiLCJfdGhpcyRvcHRpb25zJGFwcCRjdXMiLCJfdGhpcyRvcHRpb25zJGFwcDQiLCJhcHBOYW1lIiwiYXBwIiwiYXBwX25hbWUiLCJFcnJvciIsInllbGxvdyIsImFwcFBhdGgiLCJhcHBfcGF0aCIsImFwcFVybCIsImFwcF91cmwiLCJjdXN0b21JZCIsImN1c3RvbV9pZCIsImRhdGEiLCJGb3JtRGF0YSIsImFwcGVuZCIsImZzIiwiY3JlYXRlUmVhZFN0cmVhbSIsImhlYWRlckVudiIsIkJ1ZmZlciIsImZyb20iLCJ1c2VyIiwidG9TdHJpbmciLCJib2R5IiwibWV0aG9kIiwibWF4Qm9keUxlbmd0aCIsIkluZmluaXR5IiwidXJsIiwiaGVhZGVycyIsImdldEhlYWRlcnMiLCJyZXNwb25zZSIsImF4aW9zIiwicmVxdWVzdCIsImNvbnNvbGUiLCJncmVlbiIsIkpTT04iLCJzdHJpbmdpZnkiLCJlbnZBcHBVcmwiLCJlbmFibGVDYXBhYmlsaXR5IiwiYXBwSWQiLCJhcHBfaWQiLCJpbmNsdWRlcyIsImNoZWNrUGF0Y2hVcmwiLCJlcnJvciIsIm1lc3NhZ2UiLCJ0dW5uZWwiLCJ0dW5uZWxBcmd1bWVudHMiLCJsYW1iZGF0ZXN0T3B0cyIsImxhbWJkYXRlc3RUdW5uZWxQcm9jZXNzIiwiTGFtYmRhVGVzdFR1bm5lbExhdW5jaGVyIiwib2JzIiwiUGVyZm9ybWFuY2VPYnNlcnZlciIsImxpc3QiLCJlbnRyeSIsImdldEVudHJpZXMiLCJpbmZvIiwiZHVyYXRpb24iLCJvYnNlcnZlIiwiZW50cnlUeXBlcyIsImJ1ZmZlcmVkIiwidGltZXIiLCJwZXJmb3JtYW5jZSIsIm1hcmsiLCJQcm9taXNlIiwicmFjZSIsInJlc29sdmUiLCJyZWplY3QiLCJzdGFydCIsImVyciIsImRpc2Nvbm5lY3QiLCJnZXRUdW5uZWxOYW1lIiwidHVubmVsTmFtZSIsInNldFRpbWVvdXQiLCJUVU5ORUxfU1RBUlRfRkFJTEVEIiwiVFVOTkVMX1NUT1BfVElNRU9VVCIsInRoZW4iLCJyZXN1bHQiLCJjbGVhclRpbWVvdXQiLCJtZWFzdXJlIiwib25Db21wbGV0ZSIsImlzUnVubmluZyIsInN0b3AiLCJUVU5ORUxfU1RPUF9GQUlMRUQiLCJleHBvcnRzIiwiaXNMb2FkZWQiLCJwYXRjaGVkVXJsIiwicGF0Y2hlZF91cmwiXSwic291cmNlcyI6WyIuLi9zcmMvbGF1bmNoZXIuanMiXSwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IEZvcm1EYXRhIGZyb20gJ2Zvcm0tZGF0YSc7XG5pbXBvcnQgZnMgZnJvbSAnZnMnO1xuaW1wb3J0IGF4aW9zIGZyb20gJ2F4aW9zJztcblxuaW1wb3J0IHsgcGVyZm9ybWFuY2UsIFBlcmZvcm1hbmNlT2JzZXJ2ZXIgfSBmcm9tICdwZXJmX2hvb2tzJ1xuaW1wb3J0IGxvZ2dlciBmcm9tICdAd2Rpby9sb2dnZXInXG5pbXBvcnQgTGFtYmRhVGVzdFR1bm5lbExhdW5jaGVyIGZyb20gJ0BsYW1iZGF0ZXN0L25vZGUtdHVubmVsJ1xuaW1wb3J0IHsgVFVOTkVMX1NUQVJUX0ZBSUxFRCwgVFVOTkVMX1NUT1BfRkFJTEVELCBUVU5ORUxfU1RPUF9USU1FT1VUIH0gZnJvbSAnLi9jb25zdGFudHMuanMnXG5jb25zdCBsb2cgPSBsb2dnZXIoJ0B3ZGlvL2xhbWJkYXRlc3Qtc2VydmljZScpXG5jb25zdCBjb2xvcnMgPSByZXF1aXJlKCdjb2xvcnMnKTtcbmV4cG9ydCBkZWZhdWx0IGNsYXNzIExhbWJkYVRlc3RMYXVuY2hlciB7XG4gICAgbGFtYmRhdGVzdFR1bm5lbFByb2Nlc3NcbiAgICBvcHRpb25zXG5cbiAgICBjb25zdHJ1Y3RvcihvcHRpb25zKSB7XG4gICAgICAgIHRoaXMub3B0aW9ucyA9IG9wdGlvbnNcbiAgICB9XG5cbiAgICBjb25maWd1cmVDYXBhYmlsaXRpZXMoY2FwYWJpbGl0aWVzLCBrZXksIHZhbHVlKSB7XG4gICAgICAgIGNvbnN0IHVwZGF0ZUNhcGFiaWxpdHkgPSAoY2FwYWJpbGl0eSkgPT4ge1xuICAgICAgICAgICAgaWYgKGNhcGFiaWxpdHlbJ2x0Om9wdGlvbnMnXSkge1xuICAgICAgICAgICAgICAgIGNhcGFiaWxpdHlbJ0xUOk9wdGlvbnMnXSA9IHsgLi4uY2FwYWJpbGl0eVsnbHQ6b3B0aW9ucyddIH07XG4gICAgICAgICAgICAgICAgZGVsZXRlIGNhcGFiaWxpdHlbJ2x0Om9wdGlvbnMnXTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmIChjYXBhYmlsaXR5WydMVDpPcHRpb25zJ10gPT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgICAgICAgIGNhcGFiaWxpdHlba2V5XSA9IHZhbHVlO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBjYXBhYmlsaXR5WydMVDpPcHRpb25zJ11ba2V5XSA9IHZhbHVlO1xuICAgICAgICAgICAgfVxuICAgICAgICB9O1xuICAgIFxuICAgICAgICBpZiAoQXJyYXkuaXNBcnJheShjYXBhYmlsaXRpZXMpKSB7XG4gICAgICAgICAgICBjYXBhYmlsaXRpZXMuZm9yRWFjaCh1cGRhdGVDYXBhYmlsaXR5KTtcbiAgICAgICAgfSBlbHNlIGlmICh0eXBlb2YgY2FwYWJpbGl0aWVzID09PSAnb2JqZWN0Jykge1xuICAgICAgICAgICAgdXBkYXRlQ2FwYWJpbGl0eShjYXBhYmlsaXRpZXMpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgLy8gbW9kaWZ5IGNvbmZpZyBhbmQgbGF1bmNoIHR1bm5lbFxuICAgIGFzeW5jIG9uUHJlcGFyZShjb25maWcsIGNhcGFiaWxpdGllcykge1xuXG4gICAgICAgIGlmICh0aGlzLm9wdGlvbnMuYXBwX3VwbG9hZCkge1xuICAgICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgICAgY29uc3QgYXBwTmFtZSA9IHRoaXMub3B0aW9ucy5hcHA/LmFwcF9uYW1lO1xuICAgICAgICAgICAgICBpZiAoIWFwcE5hbWUpIHRocm93IG5ldyBFcnJvcihjb2xvcnMueWVsbG93KCdBcHAgbmFtZSBpcyBtaXNzaW5nLlxcbicpKTtcbiAgICAgICAgICAgICAgXG4gICAgICAgICAgICAgIGNvbnN0IGFwcFBhdGggPSB0aGlzLm9wdGlvbnMuYXBwPy5hcHBfcGF0aCA/PyBudWxsO1xuICAgICAgICAgICAgICBjb25zdCBhcHBVcmwgPSB0aGlzLm9wdGlvbnMuYXBwPy5hcHBfdXJsID8/IG51bGw7XG4gICAgICAgICAgICAgIGNvbnN0IGN1c3RvbUlkID0gdGhpcy5vcHRpb25zLmFwcD8uY3VzdG9tX2lkID8/IG51bGw7XG4gICAgICAgICAgICBcbiAgICAgICAgICAgICAgbGV0IGRhdGEgPSBuZXcgRm9ybURhdGEoKTtcbiAgICAgICAgICAgICAgZGF0YS5hcHBlbmQoJ25hbWUnLCBhcHBOYW1lKTtcbiAgICAgICAgICAgIFxuICAgICAgICAgICAgICBkYXRhLmFwcGVuZChhcHBQYXRoICE9PSBudWxsID8gJ2FwcEZpbGUnIDogJ3VybCcsIGFwcFBhdGggIT09IG51bGwgPyBmcy5jcmVhdGVSZWFkU3RyZWFtKGFwcFBhdGgpIDogYXBwVXJsKTtcbiAgICAgICAgICAgIFxuICAgICAgICAgICAgICBpZiAoY3VzdG9tSWQgIT09IG51bGwpIGRhdGEuYXBwZW5kKCdjdXN0b21faWQnLCBjdXN0b21JZCk7XG4gICAgICAgICAgICBcbiAgICAgICAgICAgICAgbGV0IGhlYWRlckVudiA9IGBCYXNpYyAke0J1ZmZlci5mcm9tKGNvbmZpZy51c2VyICsgJzonICsgY29uZmlnLmtleSkudG9TdHJpbmcoJ2Jhc2U2NCcpfWA7XG4gICAgICAgICAgICAgIGxldCBib2R5ID0ge1xuICAgICAgICAgICAgICAgIG1ldGhvZDogJ3Bvc3QnLFxuICAgICAgICAgICAgICAgIG1heEJvZHlMZW5ndGg6IEluZmluaXR5LFxuICAgICAgICAgICAgICAgIHVybDogJ2h0dHBzOi8vbWFudWFsLWFwaS5sYW1iZGF0ZXN0LmNvbS9hcHAvdXBsb2FkL3JlYWxEZXZpY2UnLFxuICAgICAgICAgICAgICAgIGhlYWRlcnM6IHtcbiAgICAgICAgICAgICAgICAgICdBdXRob3JpemF0aW9uJzogaGVhZGVyRW52LFxuICAgICAgICAgICAgICAgICAgLi4uZGF0YS5nZXRIZWFkZXJzKClcbiAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgIGRhdGE6IGRhdGFcbiAgICAgICAgICAgICAgfTtcblxuICAgICAgICAgICAgICBjb25zdCByZXNwb25zZSA9IGF3YWl0IGF4aW9zLnJlcXVlc3QoYm9keSk7XG4gICAgICAgICAgICAgIGNvbnNvbGUubG9nKGNvbG9ycy5ncmVlbihKU09OLnN0cmluZ2lmeShyZXNwb25zZS5kYXRhKSkpO1xuICAgICAgICAgICAgXG4gICAgICAgICAgICAgIGNvbnN0IGVudkFwcFVybCA9IHJlc3BvbnNlLmRhdGEuYXBwX3VybDtcbiAgICAgICAgICAgICAgaWYodGhpcy5vcHRpb25zLmFwcC5lbmFibGVDYXBhYmlsaXR5KSB7XG4gICAgICAgICAgICAgICAgdGhpcy5jb25maWd1cmVDYXBhYmlsaXRpZXMoY2FwYWJpbGl0aWVzLCAnYXBwJywgZW52QXBwVXJsKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGNvbnN0IGFwcElkID0gcmVzcG9uc2UuZGF0YS5hcHBfaWQ7XG4gICAgICAgICAgICBpZigoYXBwUGF0aCAmJiBhcHBQYXRoLmluY2x1ZGVzKCcuYXBrJykpIHx8IChhcHBVcmwgJiYgYXBwVXJsLmluY2x1ZGVzKCcuYXBrJykpKVxuICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgIGF3YWl0IGNoZWNrUGF0Y2hVcmwoYXBwSWQsIGhlYWRlckVudik7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IoZXJyb3IubWVzc2FnZSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoIXRoaXMub3B0aW9ucy50dW5uZWwpIHtcbiAgICAgICAgICAgIHJldHVyblxuICAgICAgICB9XG5cbiAgICAgICAgY29uc3QgdHVubmVsQXJndW1lbnRzID0ge1xuICAgICAgICAgICAgdXNlcjogY29uZmlnLnVzZXIsXG4gICAgICAgICAgICBrZXk6IGNvbmZpZy5rZXksXG4gICAgICAgICAgICAuLi50aGlzLm9wdGlvbnMubGFtYmRhdGVzdE9wdHNcbiAgICAgICAgfVxuXG4gICAgICAgIHRoaXMubGFtYmRhdGVzdFR1bm5lbFByb2Nlc3MgPSBuZXcgTGFtYmRhVGVzdFR1bm5lbExhdW5jaGVyKClcblxuICAgICAgICB0aGlzLmNvbmZpZ3VyZUNhcGFiaWxpdGllcyhjYXBhYmlsaXRpZXMsICd0dW5uZWwnLCB0cnVlKTtcbiAgICAgICAgLy8gbWVhc3VyZSBMVCBib290IHRpbWVcbiAgICAgICAgY29uc3Qgb2JzID0gbmV3IFBlcmZvcm1hbmNlT2JzZXJ2ZXIobGlzdCA9PiB7XG4gICAgICAgICAgICBjb25zdCBlbnRyeSA9IGxpc3QuZ2V0RW50cmllcygpWzBdXG4gICAgICAgICAgICBsb2cuaW5mbyhcbiAgICAgICAgICAgICAgICBgTGFtYmRhVGVzdCBUdW5uZWwgc3VjY2Vzc2Z1bGx5IHN0YXJ0ZWQgYWZ0ZXIgJHtlbnRyeS5kdXJhdGlvbn1tc2BcbiAgICAgICAgICAgIClcbiAgICAgICAgfSlcbiAgICAgICAgb2JzLm9ic2VydmUoeyBlbnRyeVR5cGVzOiBbJ21lYXN1cmUnXSwgYnVmZmVyZWQ6IGZhbHNlIH0pXG5cbiAgICAgICAgbGV0IHRpbWVyXG4gICAgICAgIHBlcmZvcm1hbmNlLm1hcmsoJ2x0VHVubmVsU3RhcnQnKVxuICAgICAgICByZXR1cm4gUHJvbWlzZS5yYWNlKFtcbiAgICAgICAgICAgIC8qKiBAdHlwZSB7UHJvbWlzZTx2b2lkPn0gKi8obmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCkgPT4ge1xuICAgICAgICAgICAgICAgIHRoaXMubGFtYmRhdGVzdFR1bm5lbFByb2Nlc3Muc3RhcnQodHVubmVsQXJndW1lbnRzLCBlcnIgPT4ge1xuICAgICAgICAgICAgICAgICAgICBpZiAoZXJyKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBvYnMuZGlzY29ubmVjdCgpXG4gICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gcmVqZWN0KGVycilcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAvKiBpc3RhbmJ1bCBpZ25vcmUgbmV4dCAqL1xuICAgICAgICAgICAgICAgICAgICB0aGlzLmxhbWJkYXRlc3RUdW5uZWxQcm9jZXNzLmdldFR1bm5lbE5hbWUodHVubmVsTmFtZSA9PiB7XG5cbiAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMuY29uZmlndXJlQ2FwYWJpbGl0aWVzKGNhcGFiaWxpdGllcywgJ3R1bm5lbE5hbWUnLCB0dW5uZWxOYW1lKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIFxuICAgICAgICAgICAgICAgICAgICAgICAgb2JzLmRpc2Nvbm5lY3QoKVxuICAgICAgICAgICAgICAgICAgICAgICAgcmVzb2x2ZSgpXG4gICAgICAgICAgICAgICAgICAgIH0pXG4gICAgICAgICAgICAgICAgfSlcbiAgICAgICAgICAgIH0pKSxcbiAgICAgICAgICAgIG5ldyBQcm9taXNlKChyZXNvbHZlLCByZWplY3QpID0+IHtcbiAgICAgICAgICAgICAgICAvKiBpc3RhbmJ1bCBpZ25vcmUgbmV4dCAqL1xuICAgICAgICAgICAgICAgIHRpbWVyID0gc2V0VGltZW91dCgoKSA9PiB7XG4gICAgICAgICAgICAgICAgICAgIG9icy5kaXNjb25uZWN0KClcbiAgICAgICAgICAgICAgICAgICAgcmVqZWN0KG5ldyBFcnJvcihUVU5ORUxfU1RBUlRfRkFJTEVEKSlcbiAgICAgICAgICAgICAgICB9LCBUVU5ORUxfU1RPUF9USU1FT1VUKVxuICAgICAgICAgICAgfSlcbiAgICAgICAgXSkudGhlbihcbiAgICAgICAgICAgIC8qIGlzdGFuYnVsIGlnbm9yZSBuZXh0ICovXG4gICAgICAgICAgICAocmVzdWx0KSA9PiB7XG4gICAgICAgICAgICAgICAgY2xlYXJUaW1lb3V0KHRpbWVyKVxuICAgICAgICAgICAgICAgIHBlcmZvcm1hbmNlLm1hcmsoJ2x0VHVubmVsRW5kJylcbiAgICAgICAgICAgICAgICBwZXJmb3JtYW5jZS5tZWFzdXJlKCdib290VGltZScsICdsdFR1bm5lbFN0YXJ0JywgJ2x0VHVubmVsRW5kJylcbiAgICAgICAgICAgICAgICBvYnMuZGlzY29ubmVjdCgpXG4gICAgICAgICAgICAgICAgcmV0dXJuIFByb21pc2UucmVzb2x2ZShyZXN1bHQpXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgKGVycikgPT4ge1xuICAgICAgICAgICAgICAgIGNsZWFyVGltZW91dCh0aW1lcilcbiAgICAgICAgICAgICAgICBvYnMuZGlzY29ubmVjdCgpXG4gICAgICAgICAgICAgICAgcmV0dXJuIFByb21pc2UucmVqZWN0KGVycilcbiAgICAgICAgICAgIH1cbiAgICAgICAgKVxuICAgIH1cblxuICAgIG9uQ29tcGxldGUoKSB7XG4gICAgICAgIGlmIChcbiAgICAgICAgICAgICF0aGlzLmxhbWJkYXRlc3RUdW5uZWxQcm9jZXNzIHx8XG4gICAgICAgICAgICB0eXBlb2YgdGhpcy5sYW1iZGF0ZXN0VHVubmVsUHJvY2Vzcy5pc1J1bm5pbmcgIT09ICdmdW5jdGlvbicgfHxcbiAgICAgICAgICAgICF0aGlzLmxhbWJkYXRlc3RUdW5uZWxQcm9jZXNzLmlzUnVubmluZygpXG4gICAgICAgICkge1xuICAgICAgICAgICAgcmV0dXJuXG4gICAgICAgIH1cblxuICAgICAgICBsZXQgdGltZXJcbiAgICAgICAgcmV0dXJuIFByb21pc2UucmFjZShbXG4gICAgICAgICAgICBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XG4gICAgICAgICAgICAgICAgdGhpcy5sYW1iZGF0ZXN0VHVubmVsUHJvY2Vzcy5zdG9wKGVyciA9PiB7XG4gICAgICAgICAgICAgICAgICAgIGlmIChlcnIpIHJldHVybiByZWplY3QoZXJyKVxuICAgICAgICAgICAgICAgICAgICByZXNvbHZlKClcbiAgICAgICAgICAgICAgICB9KVxuICAgICAgICAgICAgfSksXG4gICAgICAgICAgICBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XG4gICAgICAgICAgICAgICAgLyogaXN0YW5idWwgaWdub3JlIG5leHQgKi9cbiAgICAgICAgICAgICAgICB0aW1lciA9IHNldFRpbWVvdXQoKCkgPT4gcmVqZWN0KCBuZXcgRXJyb3IoVFVOTkVMX1NUT1BfRkFJTEVEKSksIFRVTk5FTF9TVE9QX1RJTUVPVVQpXG4gICAgICAgICAgICB9KVxuICAgICAgICBdKS50aGVuKFxuICAgICAgICAgICAgKCkgPT4ge1xuICAgICAgICAgICAgICAgIGNsZWFyVGltZW91dCh0aW1lcilcbiAgICAgICAgICAgICAgICByZXR1cm4gUHJvbWlzZS5yZXNvbHZlKClcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAvKiBpc3RhbmJ1bCBpZ25vcmUgbmV4dCAqL1xuICAgICAgICAgICAgKGVycikgPT4ge1xuICAgICAgICAgICAgICAgIGNsZWFyVGltZW91dCh0aW1lcilcbiAgICAgICAgICAgICAgICByZXR1cm4gUHJvbWlzZS5yZWplY3QoZXJyKVxuICAgICAgICAgICAgfVxuICAgICAgICApXG4gICAgfVxuXG59XG5cbmFzeW5jIGZ1bmN0aW9uIGNoZWNrUGF0Y2hVcmwoYXBwSWQsIGhlYWRlckVudikge1xuICAgIGxldCBjb25maWcgPSB7XG4gICAgICAgIG1ldGhvZDogJ2dldCcsXG4gICAgICAgIG1heEJvZHlMZW5ndGg6IEluZmluaXR5LFxuICAgICAgICB1cmw6IGBodHRwczovL21hbnVhbC1hcGkubGFtYmRhdGVzdC5jb20vYXBwLyR7YXBwSWR9L3VybD9yZWluc3RhbGw9dHJ1ZWAsXG4gICAgICAgIGhlYWRlcnM6IHsgXG4gICAgICAgICAgJ0F1dGhvcml6YXRpb24nOiBoZWFkZXJFbnZcbiAgICAgICAgfVxuICAgICAgfTtcbiAgICBsZXQgaXNMb2FkZWQgPSBmYWxzZTtcbiAgICB3aGlsZSAoIWlzTG9hZGVkKSB7XG4gICAgICAgIHRyeSB7XG4gICAgICAgIGNvbnN0IHJlc3BvbnNlID0gYXdhaXQgYXhpb3MucmVxdWVzdChjb25maWcpO1xuICAgICAgICBjb25zdCBwYXRjaGVkVXJsID0gcmVzcG9uc2UuZGF0YS5wYXRjaGVkX3VybDtcblxuICAgICAgICBpZiAocGF0Y2hlZFVybCAhPT0gbnVsbCkge1xuICAgICAgICAgICAgaXNMb2FkZWQgPSB0cnVlO1xuICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgIH1cblxuICAgICAgICBjb25zb2xlLmxvZygnV2FpdGluZyBmb3IgYXBwIHRvIGJlIGxvYWRlZC4uLicpO1xuICAgICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICBjb25zb2xlLmVycm9yKCdFcnJvciBvY2N1cnJlZDonLCBlcnJvci5tZXNzYWdlKTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIFdhaXQgZm9yIDE1IHNlY29uZHMgYmVmb3JlIG1ha2luZyB0aGUgbmV4dCByZXF1ZXN0XG4gICAgICAgIGF3YWl0IG5ldyBQcm9taXNlKHJlc29sdmUgPT4gc2V0VGltZW91dChyZXNvbHZlLCAxNTAwMCkpO1xuICAgIH1cbn0iXSwibWFwcGluZ3MiOiI7Ozs7Ozs7QUFBQSxJQUFBQSxTQUFBLEdBQUFDLHNCQUFBLENBQUFDLE9BQUE7QUFDQSxJQUFBQyxHQUFBLEdBQUFGLHNCQUFBLENBQUFDLE9BQUE7QUFDQSxJQUFBRSxNQUFBLEdBQUFILHNCQUFBLENBQUFDLE9BQUE7QUFFQSxJQUFBRyxXQUFBLEdBQUFILE9BQUE7QUFDQSxJQUFBSSxPQUFBLEdBQUFMLHNCQUFBLENBQUFDLE9BQUE7QUFDQSxJQUFBSyxXQUFBLEdBQUFOLHNCQUFBLENBQUFDLE9BQUE7QUFDQSxJQUFBTSxVQUFBLEdBQUFOLE9BQUE7QUFBNkYsU0FBQUQsdUJBQUFRLENBQUEsV0FBQUEsQ0FBQSxJQUFBQSxDQUFBLENBQUFDLFVBQUEsR0FBQUQsQ0FBQSxLQUFBRSxPQUFBLEVBQUFGLENBQUE7QUFBQSxTQUFBRyxnQkFBQUgsQ0FBQSxFQUFBSSxDQUFBLEVBQUFDLENBQUEsWUFBQUQsQ0FBQSxHQUFBRSxjQUFBLENBQUFGLENBQUEsTUFBQUosQ0FBQSxHQUFBTyxNQUFBLENBQUFDLGNBQUEsQ0FBQVIsQ0FBQSxFQUFBSSxDQUFBLElBQUFLLEtBQUEsRUFBQUosQ0FBQSxFQUFBSyxVQUFBLE1BQUFDLFlBQUEsTUFBQUMsUUFBQSxVQUFBWixDQUFBLENBQUFJLENBQUEsSUFBQUMsQ0FBQSxFQUFBTCxDQUFBO0FBQUEsU0FBQU0sZUFBQUQsQ0FBQSxRQUFBUSxDQUFB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QUFPLEVBQUVDLE1BQU0sS0FBSztNQUU3Qk4sS0FBSyxHQUFHWSxVQUFVLENBQUMsTUFBTU4sTUFBTSxDQUFFLElBQUk3RCxLQUFLLENBQUM2RSw2QkFBa0IsQ0FBQyxDQUFDLEVBQUVSLDhCQUFtQixDQUFDO0lBQ3pGLENBQUMsQ0FBQyxDQUNMLENBQUMsQ0FBQ0MsSUFBSSxDQUNILE1BQU07TUFDRkUsWUFBWSxDQUFDakIsS0FBSyxDQUFDO01BQ25CLE9BQU9HLE9BQU8sQ0FBQ0UsT0FBTyxDQUFDLENBQUM7SUFDNUIsQ0FBQyxFQUVBRyxHQUFHLElBQUs7TUFDTFMsWUFBWSxDQUFDakIsS0FBSyxDQUFDO01BQ25CLE9BQU9HLE9BQU8sQ0FBQ0csTUFBTSxDQUFDRSxHQUFHLENBQUM7SUFDOUIsQ0FDSixDQUFDO0VBQ0w7QUFFSjtBQUFDZSxPQUFBLENBQUE3SCxPQUFBLEdBQUFzQixrQkFBQTtBQUVELGVBQWU4RCxhQUFhQSxDQUFDSCxLQUFLLEVBQUVyQixTQUFTLEVBQUU7RUFDM0MsSUFBSXpCLE1BQU0sR0FBRztJQUNUK0IsTUFBTSxFQUFFLEtBQUs7SUFDYkMsYUFBYSxFQUFFQyxRQUFRO0lBQ3ZCQyxHQUFHLEVBQUUseUNBQXlDWSxLQUFLLHFCQUFxQjtJQUN4RVgsT0FBTyxFQUFFO01BQ1AsZUFBZSxFQUFFVjtJQUNuQjtFQUNGLENBQUM7RUFDSCxJQUFJa0UsUUFBUSxHQUFHLEtBQUs7RUFDcEIsT0FBTyxDQUFDQSxRQUFRLEVBQUU7SUFDZCxJQUFJO01BQ0osTUFBTXRELFFBQVEsR0FBRyxNQUFNQyxjQUFLLENBQUNDLE9BQU8sQ0FBQ3ZDLE1BQU0sQ0FBQztNQUM1QyxNQUFNNEYsVUFBVSxHQUFHdkQsUUFBUSxDQUFDakIsSUFBSSxDQUFDeUUsV0FBVztNQUU1QyxJQUFJRCxVQUFVLEtBQUssSUFBSSxFQUFFO1FBQ3JCRCxRQUFRLEdBQUcsSUFBSTtRQUNmO01BQ0o7TUFFQW5ELE9BQU8sQ0FBQ3hELEdBQUcsQ0FBQyxpQ0FBaUMsQ0FBQztJQUM5QyxDQUFDLENBQUMsT0FBT2tFLEtBQUssRUFBRTtNQUNoQlYsT0FBTyxDQUFDVSxLQUFLLENBQUMsaUJBQWlCLEVBQUVBLEtBQUssQ0FBQ0MsT0FBTyxDQUFDO0lBQy9DO0lBR0EsTUFBTSxJQUFJbUIsT0FBTyxDQUFDRSxPQUFPLElBQUlPLFVBQVUsQ0FBQ1AsT0FBTyxFQUFFLEtBQUssQ0FBQyxDQUFDO0VBQzVEO0FBQ0oiLCJpZ25vcmVMaXN0IjpbXX0=