webdriverio-automation
Version:
WebdriverIO-Automation android ios project
380 lines (294 loc) • 46.5 kB
JavaScript
;
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = exports.JWProxy = void 0;
require("source-map-support/register");
var _lodash = _interopRequireDefault(require("lodash"));
var _appiumSupport = require("appium-support");
var _requestPromise = _interopRequireDefault(require("request-promise"));
var _status = require("../jsonwp-status/status");
var _errors = require("../protocol/errors");
var _driver = _interopRequireDefault(require("../basedriver/driver"));
var _routes = require("../protocol/routes");
var _protocolConverter = _interopRequireDefault(require("./protocol-converter"));
var _helpers = require("../protocol/helpers");
var _sessionsCache = _interopRequireDefault(require("../protocol/sessions-cache"));
const log = _appiumSupport.logger.getLogger('WD Proxy');
const LOG_OBJ_LENGTH = 1024;
const DEFAULT_REQUEST_TIMEOUT = 240000;
const {
MJSONWP,
W3C
} = _driver.default.DRIVER_PROTOCOL;
class JWProxy {
constructor(opts = {}) {
Object.assign(this, {
scheme: 'http',
server: 'localhost',
port: 4444,
base: '/wd/hub',
sessionId: null,
timeout: DEFAULT_REQUEST_TIMEOUT,
keepAlive: false
}, opts);
this.scheme = this.scheme.toLowerCase();
this._activeRequests = [];
this._downstreamProtocol = null;
this.protocolConverter = new _protocolConverter.default(this.proxy.bind(this));
}
async request(...args) {
const currentRequest = (0, _requestPromise.default)(...args);
this._activeRequests.push(currentRequest);
return await currentRequest.finally(() => _lodash.default.pull(this._activeRequests, currentRequest));
}
getActiveRequestsCount() {
return this._activeRequests.length;
}
cancelActiveRequests() {
try {
for (let r of this._activeRequests) {
r.cancel();
}
} finally {
this._activeRequests = [];
}
}
endpointRequiresSessionId(endpoint) {
return !_lodash.default.includes(['/session', '/sessions', '/status'], endpoint);
}
set downstreamProtocol(value) {
this._downstreamProtocol = value;
this.protocolConverter.downstreamProtocol = value;
}
get downstreamProtocol() {
return this._downstreamProtocol;
}
getUrlForProxy(url) {
if (url === '') {
url = '/';
}
const proxyBase = `${this.scheme}://${this.server}:${this.port}${this.base}`;
const endpointRe = '(/(session|status))';
let remainingUrl = '';
if (/^http/.test(url)) {
const first = new RegExp(`(https?://.+)${endpointRe}`).exec(url);
if (!first) {
throw new Error('Got a complete url but could not extract JWP endpoint');
}
remainingUrl = url.replace(first[1], '');
} else if (new RegExp('^/').test(url)) {
remainingUrl = url;
} else {
throw new Error(`Did not know what to do with url '${url}'`);
}
const stripPrefixRe = new RegExp('^.*?(/(session|status).*)$');
if (stripPrefixRe.test(remainingUrl)) {
remainingUrl = stripPrefixRe.exec(remainingUrl)[1];
}
if (!new RegExp(endpointRe).test(remainingUrl)) {
remainingUrl = `/session/${this.sessionId}${remainingUrl}`;
}
const requiresSessionId = this.endpointRequiresSessionId(remainingUrl);
if (requiresSessionId && this.sessionId === null) {
throw new Error('Trying to proxy a session command without session id');
}
const sessionBaseRe = new RegExp('^/session/([^/]+)');
if (sessionBaseRe.test(remainingUrl)) {
const match = sessionBaseRe.exec(remainingUrl);
remainingUrl = remainingUrl.replace(match[1], this.sessionId);
} else if (requiresSessionId) {
throw new Error(`Could not find :session section for url: ${remainingUrl}`);
}
remainingUrl = remainingUrl.replace(/\/$/, '');
return proxyBase + remainingUrl;
}
syncDownstreamProtocol(resBodyObj, isSessionCreationRequest) {
if (!this.downstreamProtocol) {
this.downstreamProtocol = this.getProtocolFromResBody(resBodyObj);
log.debug(`Determined the downstream protocol as '${this.downstreamProtocol}'`);
} else if (isSessionCreationRequest) {
const previousValue = this.downstreamProtocol;
this.downstreamProtocol = this.getProtocolFromResBody(resBodyObj);
if (previousValue && previousValue !== this.downstreamProtocol) {
log.debug(`Updated the downstream protocol to '${this.downstreamProtocol}' ` + `as per session creation request`);
} else {
log.debug(`Determined the downstream protocol as '${this.downstreamProtocol}' ` + `per session creation request`);
}
}
}
async proxy(url, method, body = null) {
method = method.toUpperCase();
const newUrl = this.getUrlForProxy(url);
const truncateBody = content => _lodash.default.truncate(_lodash.default.isString(content) ? content : JSON.stringify(content), {
length: LOG_OBJ_LENGTH
});
const reqOpts = {
agent: false,
url: newUrl,
method,
headers: {
'content-type': 'application/json; charset=utf-8',
'user-agent': 'appium',
accept: 'application/json, */*'
},
resolveWithFullResponse: true,
timeout: this.timeout,
forever: this.keepAlive
};
if (_appiumSupport.util.hasValue(body)) {
if (typeof body !== 'object') {
try {
reqOpts.json = JSON.parse(body);
} catch (e) {
throw new Error(`Cannot interpret the request body as valid JSON: ${truncateBody(body)}`);
}
} else {
reqOpts.json = body;
}
}
if (method === 'GET') {
reqOpts.json = null;
}
log.debug(`Proxying [${method} ${url || '/'}] to [${method} ${newUrl}] ` + (body ? `with body: ${truncateBody(body)}` : 'with no body'));
const throwProxyError = error => {
const message = `The request to ${url} has failed`;
const err = new Error(message);
err.message = message;
err.error = error;
err.statusCode = 500;
throw err;
};
let isResponseLogged = false;
try {
const res = await this.request(reqOpts);
const resBodyObj = _appiumSupport.util.safeJsonParse(res.body);
if (!_lodash.default.isPlainObject(resBodyObj)) {
throwProxyError(res.body);
}
log.debug(`Got response with status ${res.statusCode}: ${truncateBody(res.body)}`);
isResponseLogged = true;
const isSessionCreationRequest = /\/session$/.test(url) && method === 'POST';
if (isSessionCreationRequest && res.statusCode === 200) {
this.sessionId = resBodyObj.sessionId || (resBodyObj.value || {}).sessionId;
}
this.syncDownstreamProtocol(resBodyObj, isSessionCreationRequest);
if (res.statusCode < 400 && this.downstreamProtocol === MJSONWP && _lodash.default.has(resBodyObj, 'status') && parseInt(resBodyObj.status, 10) !== 0) {
throwProxyError(resBodyObj);
}
return [res, resBodyObj];
} catch (e) {
if (!_appiumSupport.util.hasValue(e.error)) {
log.warn(e.message);
log.debug(e.stack);
} else {
if (!_appiumSupport.util.hasValue(e.statusCode) || !/^\s*\{/.test(e.error)) {
if (isResponseLogged) {
log.info('The response has an unknown format');
} else {
log.info(`Got an unexpected response with status ${e.statusCode}: ${truncateBody(e.error)}`);
}
} else if (!isResponseLogged) {
log.debug(`Got response with status ${e.statusCode}: ${truncateBody(e.error)}`);
isResponseLogged = true;
}
}
throw new _errors.errors.ProxyRequestError(`Could not proxy command to remote server. ` + `Original error: ${e.message}`, e.error, e.statusCode);
}
}
getProtocolFromResBody(resObj) {
if (_lodash.default.isInteger(resObj.status)) {
return MJSONWP;
}
if (!_lodash.default.isUndefined(resObj.value)) {
return W3C;
}
}
requestToCommandName(url, method) {
const extractCommandName = pattern => {
const pathMatch = pattern.exec(url);
return pathMatch ? (0, _routes.routeToCommandName)(pathMatch[1], method) : null;
};
let commandName = (0, _routes.routeToCommandName)(url, method);
if (!commandName && _lodash.default.includes(url, '/wd/hub/session/')) {
commandName = extractCommandName(/\/wd\/hub\/session\/[^/]+(.+)/);
}
if (!commandName && _lodash.default.includes(url, '/wd/hub/')) {
commandName = extractCommandName(/\/wd\/hub(\/.+)/);
}
return commandName;
}
async proxyCommand(url, method, body = null) {
const commandName = this.requestToCommandName(url, method);
if (!commandName) {
return await this.proxy(url, method, body);
}
log.debug(`Matched '${url}' to command name '${commandName}'`);
return await this.protocolConverter.convertAndProxy(commandName, url, method, body);
}
async command(url, method, body = null) {
let response;
let resBodyObj;
try {
[response, resBodyObj] = await this.proxyCommand(url, method, body);
} catch (err) {
if ((0, _errors.isErrorType)(err, _errors.errors.ProxyRequestError)) {
throw err.getActualError();
}
throw new _errors.errors.UnknownError(err.message);
}
const protocol = this.getProtocolFromResBody(resBodyObj);
if (protocol === MJSONWP) {
if (response.statusCode === 200 && resBodyObj.status === 0) {
return resBodyObj.value;
}
const status = parseInt(resBodyObj.status, 10);
if (!isNaN(status) && status !== 0) {
let message = resBodyObj.value;
if (_lodash.default.has(message, 'message')) {
message = message.message;
}
throw (0, _errors.errorFromMJSONWPStatusCode)(status, _lodash.default.isEmpty(message) ? (0, _status.getSummaryByCode)(status) : message);
}
} else if (protocol === W3C) {
if (response.statusCode < 300) {
return resBodyObj.value;
}
if (_lodash.default.isPlainObject(resBodyObj.value) && resBodyObj.value.error) {
throw (0, _errors.errorFromW3CJsonCode)(resBodyObj.value.error, resBodyObj.value.message, resBodyObj.value.stacktrace);
}
} else if (response.statusCode === 200) {
return resBodyObj;
}
throw new _errors.errors.UnknownError(`Did not know what to do with response code '${response.statusCode}' ` + `and response body '${_lodash.default.truncate(JSON.stringify(resBodyObj), {
length: 300
})}'`);
}
getSessionIdFromUrl(url) {
const match = url.match(/\/session\/([^/]+)/);
return match ? match[1] : null;
}
async proxyReqRes(req, res) {
const [response, resBodyObj] = await this.proxyCommand(req.originalUrl, req.method, req.body);
res.headers = response.headers;
res.set('content-type', response.headers['content-type']);
const reqSessionId = this.getSessionIdFromUrl(req.originalUrl);
if (_lodash.default.has(resBodyObj, 'sessionId')) {
if (reqSessionId) {
log.info(`Replacing sessionId ${resBodyObj.sessionId} with ${reqSessionId}`);
resBodyObj.sessionId = reqSessionId;
} else if (this.sessionId) {
log.info(`Replacing sessionId ${resBodyObj.sessionId} with ${this.sessionId}`);
resBodyObj.sessionId = this.sessionId;
}
}
resBodyObj.value = (0, _helpers.formatResponseValue)(resBodyObj.value);
(0, _helpers.formatStatus)(resBodyObj, _sessionsCache.default.getProtocol(reqSessionId));
res.status(response.statusCode).send(JSON.stringify(resBodyObj));
}
}
exports.JWProxy = JWProxy;
var _default = JWProxy;
exports.default = _default;require('source-map-support').install();
//# sourceMappingURL=data:application/json;charset=utf8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbImxpYi9qc29ud3AtcHJveHkvcHJveHkuanMiXSwibmFtZXMiOlsibG9nIiwibG9nZ2VyIiwiZ2V0TG9nZ2VyIiwiTE9HX09CSl9MRU5HVEgiLCJERUZBVUxUX1JFUVVFU1RfVElNRU9VVCIsIk1KU09OV1AiLCJXM0MiLCJCYXNlRHJpdmVyIiwiRFJJVkVSX1BST1RPQ09MIiwiSldQcm94eSIsImNvbnN0cnVjdG9yIiwib3B0cyIsIk9iamVjdCIsImFzc2lnbiIsInNjaGVtZSIsInNlcnZlciIsInBvcnQiLCJiYXNlIiwic2Vzc2lvbklkIiwidGltZW91dCIsImtlZXBBbGl2ZSIsInRvTG93ZXJDYXNlIiwiX2FjdGl2ZVJlcXVlc3RzIiwiX2Rvd25zdHJlYW1Qcm90b2NvbCIsInByb3RvY29sQ29udmVydGVyIiwiUHJvdG9jb2xDb252ZXJ0ZXIiLCJwcm94eSIsImJpbmQiLCJyZXF1ZXN0IiwiYXJncyIsImN1cnJlbnRSZXF1ZXN0IiwicHVzaCIsImZpbmFsbHkiLCJfIiwicHVsbCIsImdldEFjdGl2ZVJlcXVlc3RzQ291bnQiLCJsZW5ndGgiLCJjYW5jZWxBY3RpdmVSZXF1ZXN0cyIsInIiLCJjYW5jZWwiLCJlbmRwb2ludFJlcXVpcmVzU2Vzc2lvbklkIiwiZW5kcG9pbnQiLCJpbmNsdWRlcyIsImRvd25zdHJlYW1Qcm90b2NvbCIsInZhbHVlIiwiZ2V0VXJsRm9yUHJveHkiLCJ1cmwiLCJwcm94eUJhc2UiLCJlbmRwb2ludFJlIiwicmVtYWluaW5nVXJsIiwidGVzdCIsImZpcnN0IiwiUmVnRXhwIiwiZXhlYyIsIkVycm9yIiwicmVwbGFjZSIsInN0cmlwUHJlZml4UmUiLCJyZXF1aXJlc1Nlc3Npb25JZCIsInNlc3Npb25CYXNlUmUiLCJtYXRjaCIsInN5bmNEb3duc3RyZWFtUHJvdG9jb2wiLCJyZXNCb2R5T2JqIiwiaXNTZXNzaW9uQ3JlYXRpb25SZXF1ZXN0IiwiZ2V0UHJvdG9jb2xGcm9tUmVzQm9keSIsImRlYnVnIiwicHJldmlvdXNWYWx1ZSIsIm1ldGhvZCIsImJvZHkiLCJ0b1VwcGVyQ2FzZSIsIm5ld1VybCIsInRydW5jYXRlQm9keSIsImNvbnRlbnQiLCJ0cnVuY2F0ZSIsImlzU3RyaW5nIiwiSlNPTiIsInN0cmluZ2lmeSIsInJlcU9wdHMiLCJhZ2VudCIsImhlYWRlcnMiLCJhY2NlcHQiLCJyZXNvbHZlV2l0aEZ1bGxSZXNwb25zZSIsImZvcmV2ZXIiLCJ1dGlsIiwiaGFzVmFsdWUiLCJqc29uIiwicGFyc2UiLCJlIiwidGhyb3dQcm94eUVycm9yIiwiZXJyb3IiLCJtZXNzYWdlIiwiZXJyIiwic3RhdHVzQ29kZSIsImlzUmVzcG9uc2VMb2dnZWQiLCJyZXMiLCJzYWZlSnNvblBhcnNlIiwiaXNQbGFpbk9iamVjdCIsImhhcyIsInBhcnNlSW50Iiwic3RhdHVzIiwid2FybiIsInN0YWNrIiwiaW5mbyIsImVycm9ycyIsIlByb3h5UmVxdWVzdEVycm9yIiwicmVzT2JqIiwiaXNJbnRlZ2VyIiwiaXNVbmRlZmluZWQiLCJyZXF1ZXN0VG9Db21tYW5kTmFtZSIsImV4dHJhY3RDb21tYW5kTmFtZSIsInBhdHRlcm4iLCJwYXRoTWF0Y2giLCJjb21tYW5kTmFtZSIsInByb3h5Q29tbWFuZCIsImNvbnZlcnRBbmRQcm94eSIsImNvbW1hbmQiLCJyZXNwb25zZSIsImdldEFjdHVhbEVycm9yIiwiVW5rbm93bkVycm9yIiwicHJvdG9jb2wiLCJpc05hTiIsImlzRW1wdHkiLCJzdGFja3RyYWNlIiwiZ2V0U2Vzc2lvbklkRnJvbVVybCIsInByb3h5UmVxUmVzIiwicmVxIiwib3JpZ2luYWxVcmwiLCJzZXQiLCJyZXFTZXNzaW9uSWQiLCJTRVNTSU9OU19DQUNIRSIsImdldFByb3RvY29sIiwic2VuZCJdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7QUFBQTs7QUFDQTs7QUFDQTs7QUFDQTs7QUFDQTs7QUFHQTs7QUFDQTs7QUFDQTs7QUFDQTs7QUFDQTs7QUFFQSxNQUFNQSxHQUFHLEdBQUdDLHNCQUFPQyxTQUFQLENBQWlCLFVBQWpCLENBQVo7O0FB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QkFBZUMsV0FBZixDQUEyQkYsWUFBM0IsQ0FBekI7QUFDQWxDLElBQUFBLEdBQUcsQ0FBQ0ssTUFBSixDQUFXaUIsUUFBUSxDQUFDeEIsVUFBcEIsRUFBZ0N1QyxJQUFoQyxDQUFxQ3hELElBQUksQ0FBQ0MsU0FBTCxDQUFlZCxVQUFmLENBQXJDO0FBQ0Q7O0FBOVRXOzs7ZUFrVUNwRCxPIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IF8gZnJvbSAnbG9kYXNoJztcbmltcG9ydCB7IGxvZ2dlciwgdXRpbCB9IGZyb20gJ2FwcGl1bS1zdXBwb3J0JztcbmltcG9ydCByZXF1ZXN0IGZyb20gJ3JlcXVlc3QtcHJvbWlzZSc7XG5pbXBvcnQgeyBnZXRTdW1tYXJ5QnlDb2RlIH0gZnJvbSAnLi4vanNvbndwLXN0YXR1cy9zdGF0dXMnO1xuaW1wb3J0IHtcbiAgZXJyb3JzLCBpc0Vycm9yVHlwZSwgZXJyb3JGcm9tTUpTT05XUFN0YXR1c0NvZGUsIGVycm9yRnJvbVczQ0pzb25Db2RlXG59IGZyb20gJy4uL3Byb3RvY29sL2Vycm9ycyc7XG5pbXBvcnQgQmFzZURyaXZlciBmcm9tICcuLi9iYXNlZHJpdmVyL2RyaXZlcic7XG5pbXBvcnQgeyByb3V0ZVRvQ29tbWFuZE5hbWUgfSBmcm9tICcuLi9wcm90b2NvbC9yb3V0ZXMnO1xuaW1wb3J0IFByb3RvY29sQ29udmVydGVyIGZyb20gJy4vcHJvdG9jb2wtY29udmVydGVyJztcbmltcG9ydCB7IGZvcm1hdFJlc3BvbnNlVmFsdWUsIGZvcm1hdFN0YXR1cyB9IGZyb20gJy4uL3Byb3RvY29sL2hlbHBlcnMnO1xuaW1wb3J0IFNFU1NJT05TX0NBQ0hFIGZyb20gJy4uL3Byb3RvY29sL3Nlc3Npb25zLWNhY2hlJztcblxuY29uc3QgbG9nID0gbG9nZ2VyLmdldExvZ2dlcignV0QgUHJveHknKTtcbi8vIFRPRE86IE1ha2UgdGhpcyB2YWx1ZSBjb25maWd1cmFibGUgYXMgYSBzZXJ2ZXIgc2lkZSBjYXBhYmlsaXR5XG5jb25zdCBMT0dfT0JKX0xFTkdUSCA9IDEwMjQ7IC8vIE1BWCBMRU5HVEggTG9nZ2VkIHRvIGZpbGUgLyBjb25zb2xlXG5jb25zdCBERUZBVUxUX1JFUVVFU1RfVElNRU9VVCA9IDI0MDAwMDtcblxuY29uc3Qge01KU09OV1AsIFczQ30gPSBCYXNlRHJpdmVyLkRSSVZFUl9QUk9UT0NPTDtcblxuY2xhc3MgSldQcm94eSB7XG4gIGNvbnN0cnVjdG9yIChvcHRzID0ge30pIHtcbiAgICBPYmplY3QuYXNzaWduKHRoaXMsIHtcbiAgICAgIHNjaGVtZTogJ2h0dHAnLFxuICAgICAgc2VydmVyOiAnbG9jYWxob3N0JyxcbiAgICAgIHBvcnQ6IDQ0NDQsXG4gICAgICBiYXNlOiAnL3dkL2h1YicsXG4gICAgICBzZXNzaW9uSWQ6IG51bGwsXG4gICAgICB0aW1lb3V0OiBERUZBVUxUX1JFUVVFU1RfVElNRU9VVCxcbiAgICAgIGtlZXBBbGl2ZTogZmFsc2UsXG4gICAgfSwgb3B0cyk7XG4gICAgdGhpcy5zY2hlbWUgPSB0aGlzLnNjaGVtZS50b0xvd2VyQ2FzZSgpO1xuICAgIHRoaXMuX2FjdGl2ZVJlcXVlc3RzID0gW107XG4gICAgdGhpcy5fZG93bnN0cmVhbVByb3RvY29sID0gbnVsbDtcbiAgICB0aGlzLnByb3RvY29sQ29udmVydGVyID0gbmV3IFByb3RvY29sQ29udmVydGVyKHRoaXMucHJveHkuYmluZCh0aGlzKSk7XG4gIH1cblxuICAvLyBhYnN0cmFjdCB0aGUgY2FsbCBiZWhpbmQgYSBtZW1iZXIgZnVuY3Rpb25cbiAgLy8gc28gdGhhdCB3ZSBjYW4gbW9jayBpdCBpbiB0ZXN0c1xuICBhc3luYyByZXF1ZXN0ICguLi5hcmdzKSB7XG4gICAgY29uc3QgY3VycmVudFJlcXVlc3QgPSByZXF1ZXN0KC4uLmFyZ3MpO1xuICAgIHRoaXMuX2FjdGl2ZVJlcXVlc3RzLnB1c2goY3VycmVudFJlcXVlc3QpO1xuICAgIHJldHVybiBhd2FpdCBjdXJyZW50UmVxdWVzdC5maW5hbGx5KCgpID0+IF8ucHVsbCh0aGlzLl9hY3RpdmVSZXF1ZXN0cywgY3VycmVudFJlcXVlc3QpKTtcbiAgfVxuXG4gIGdldEFjdGl2ZVJlcXVlc3RzQ291bnQgKCkge1xuICAgIHJldHVybiB0aGlzLl9hY3RpdmVSZXF1ZXN0cy5sZW5ndGg7XG4gIH1cblxuICBjYW5jZWxBY3RpdmVSZXF1ZXN0cyAoKSB7XG4gICAgdHJ5IHtcbiAgICAgIGZvciAobGV0IHIgb2YgdGhpcy5fYWN0aXZlUmVxdWVzdHMpIHtcbiAgICAgICAgci5jYW5jZWwoKTtcbiAgICAgIH1cbiAgICB9IGZpbmFsbHkge1xuICAgICAgdGhpcy5fYWN0aXZlUmVxdWVzdHMgPSBbXTtcbiAgICB9XG4gIH1cblxuICBlbmRwb2ludFJlcXVpcmVzU2Vzc2lvbklkIChlbmRwb2ludCkge1xuICAgIHJldHVybiAhXy5pbmNsdWRlcyhbJy9zZXNzaW9uJywgJy9zZXNzaW9ucycsICcvc3RhdHVzJ10sIGVuZHBvaW50KTtcbiAgfVxuXG4gIHNldCBkb3duc3RyZWFtUHJvdG9jb2wgKHZhbHVlKSB7XG4gICAgdGhpcy5fZG93bnN0cmVhbVByb3RvY29sID0gdmFsdWU7XG4gICAgdGhpcy5wcm90b2NvbENvbnZlcnRlci5kb3duc3RyZWFtUHJvdG9jb2wgPSB2YWx1ZTtcbiAgfVxuXG4gIGdldCBkb3duc3RyZWFtUHJvdG9jb2wgKCkge1xuICAgIHJldHVybiB0aGlzLl9kb3duc3RyZWFtUHJvdG9jb2w7XG4gIH1cblxuICBnZXRVcmxGb3JQcm94eSAodXJsKSB7XG4gICAgaWYgKHVybCA9PT0gJycpIHtcbiAgICAgIHVybCA9ICcvJztcbiAgICB9XG4gICAgY29uc3QgcHJveHlCYXNlID0gYCR7dGhpcy5zY2hlbWV9Oi8vJHt0aGlzLnNlcnZlcn06JHt0aGlzLnBvcnR9JHt0aGlzLmJhc2V9YDtcbiAgICBjb25zdCBlbmRwb2ludFJlID0gJygvKHNlc3Npb258c3RhdHVzKSknO1xuICAgIGxldCByZW1haW5pbmdVcmwgPSAnJztcbiAgICBpZiAoL15odHRwLy50ZXN0KHVybCkpIHtcbiAgICAgIGNvbnN0IGZpcnN0ID0gKG5ldyBSZWdFeHAoYChodHRwcz86Ly8uKykke2VuZHBvaW50UmV9YCkpLmV4ZWModXJsKTtcbiAgICAgIGlmICghZmlyc3QpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdHb3QgYSBjb21wbGV0ZSB1cmwgYnV0IGNvdWxkIG5vdCBleHRyYWN0IEpXUCBlbmRwb2ludCcpO1xuICAgICAgfVxuICAgICAgcmVtYWluaW5nVXJsID0gdXJsLnJlcGxhY2UoZmlyc3RbMV0sICcnKTtcbiAgICB9IGVsc2UgaWYgKChuZXcgUmVnRXhwKCdeLycpKS50ZXN0KHVybCkpIHtcbiAgICAgIHJlbWFpbmluZ1VybCA9IHVybDtcbiAgICB9IGVsc2Uge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGBEaWQgbm90IGtub3cgd2hhdCB0byBkbyB3aXRoIHVybCAnJHt1cmx9J2ApO1xuICAgIH1cblxuICAgIGNvbnN0IHN0cmlwUHJlZml4UmUgPSBuZXcgUmVnRXhwKCdeLio/KC8oc2Vzc2lvbnxzdGF0dXMpLiopJCcpO1xuICAgIGlmIChzdHJpcFByZWZpeFJlLnRlc3QocmVtYWluaW5nVXJsKSkge1xuICAgICAgcmVtYWluaW5nVXJsID0gc3RyaXBQcmVmaXhSZS5leGVjKHJlbWFpbmluZ1VybClbMV07XG4gICAgfVxuXG4gICAgaWYgKCEobmV3IFJlZ0V4cChlbmRwb2ludFJlKSkudGVzdChyZW1haW5pbmdVcmwpKSB7XG4gICAgICByZW1haW5pbmdVcmwgPSBgL3Nlc3Npb24vJHt0aGlzLnNlc3Npb25JZH0ke3JlbWFpbmluZ1VybH1gO1xuICAgIH1cblxuICAgIGNvbnN0IHJlcXVpcmVzU2Vzc2lvbklkID0gdGhpcy5lbmRwb2ludFJlcXVpcmVzU2Vzc2lvbklkKHJlbWFpbmluZ1VybCk7XG5cbiAgICBpZiAocmVxdWlyZXNTZXNzaW9uSWQgJiYgdGhpcy5zZXNzaW9uSWQgPT09IG51bGwpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignVHJ5aW5nIHRvIHByb3h5IGEgc2Vzc2lvbiBjb21tYW5kIHdpdGhvdXQgc2Vzc2lvbiBpZCcpO1xuICAgIH1cblxuICAgIGNvbnN0IHNlc3Npb25CYXNlUmUgPSBuZXcgUmVnRXhwKCdeL3Nlc3Npb24vKFteL10rKScpO1xuICAgIGlmIChzZXNzaW9uQmFzZVJlLnRlc3QocmVtYWluaW5nVXJsKSkge1xuICAgICAgLy8gd2UgaGF2ZSBzb21ldGhpbmcgbGlrZSAvc2Vzc2lvbi86aWQvZm9vYmFyLCBzbyB3ZSBuZWVkIHRvIHJlcGxhY2VcbiAgICAgIC8vIHRoZSBzZXNzaW9uIGlkXG4gICAgICBjb25zdCBtYXRjaCA9IHNlc3Npb25CYXNlUmUuZXhlYyhyZW1haW5pbmdVcmwpO1xuICAgICAgcmVtYWluaW5nVXJsID0gcmVtYWluaW5nVXJsLnJlcGxhY2UobWF0Y2hbMV0sIHRoaXMuc2Vzc2lvbklkKTtcbiAgICB9IGVsc2UgaWYgKHJlcXVpcmVzU2Vzc2lvbklkKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYENvdWxkIG5vdCBmaW5kIDpzZXNzaW9uIHNlY3Rpb24gZm9yIHVybDogJHtyZW1haW5pbmdVcmx9YCk7XG4gICAgfVxuICAgIHJlbWFpbmluZ1VybCA9IHJlbWFpbmluZ1VybC5yZXBsYWNlKC9cXC8kLywgJycpOyAvLyBjYW4ndCBoYXZlIHRyYWlsaW5nIHNsYXNoZXNcblxuICAgIHJldHVybiBwcm94eUJhc2UgKyByZW1haW5pbmdVcmw7XG4gIH1cblxuICBzeW5jRG93bnN0cmVhbVByb3RvY29sIChyZXNCb2R5T2JqLCBpc1Nlc3Npb25DcmVhdGlvblJlcXVlc3QpIHtcbiAgICBpZiAoIXRoaXMuZG93bnN0cmVhbVByb3RvY29sKSB7XG4gICAgICB0aGlzLmRvd25zdHJlYW1Qcm90b2NvbCA9IHRoaXMuZ2V0UHJvdG9jb2xGcm9tUmVzQm9keShyZXNCb2R5T2JqKTtcbiAgICAgIGxvZy5kZWJ1ZyhgRGV0ZXJtaW5lZCB0aGUgZG93bnN0cmVhbSBwcm90b2NvbCBhcyAnJHt0aGlzLmRvd25zdHJlYW1Qcm90b2NvbH0nYCk7XG4gICAgfSBlbHNlIGlmIChpc1Nlc3Npb25DcmVhdGlvblJlcXVlc3QpIHtcbiAgICAgIC8vIEl0IG1pZ2h0IGJlIHRoYXQgd2UgcHJveHkgQVBJIGNhbGxzIHRvIHRoZSBkb3duc3RyZWFtIGRyaXZlclxuICAgICAgLy8gd2l0aG91dCBjcmVhdGluZyBhIHNlc3Npb24gZmlyc3RcbiAgICAgIC8vIGFuZCBpdCByZXNwb25kcyB1c2luZyB0aGUgZGVmYXVsdCBwcm90byxcbiAgICAgIC8vIGJ1dCB0aGVuIGFmdGVyIGNyZWF0ZVNlc3Npb24gcmVxdWVzdCBpcyBzZW50IHRoZSBpbnRlcm5hbCBwcm90byBpcyBjaGFuZ2VkXG4gICAgICAvLyB0byB0aGUgb3RoZXIgb25lIGJhc2VkIG9uIHRoZSBhY3R1YWxseSBwcm92aWRlZCBjYXBzXG4gICAgICBjb25zdCBwcmV2aW91c1ZhbHVlID0gdGhpcy5kb3duc3RyZWFtUHJvdG9jb2w7XG4gICAgICB0aGlzLmRvd25zdHJlYW1Qcm90b2NvbCA9IHRoaXMuZ2V0UHJvdG9jb2xGcm9tUmVzQm9keShyZXNCb2R5T2JqKTtcbiAgICAgIGlmIChwcmV2aW91c1ZhbHVlICYmIHByZXZpb3VzVmFsdWUgIT09IHRoaXMuZG93bnN0cmVhbVByb3RvY29sKSB7XG4gICAgICAgIGxvZy5kZWJ1ZyhgVXBkYXRlZCB0aGUgZG93bnN0cmVhbSBwcm90b2NvbCB0byAnJHt0aGlzLmRvd25zdHJlYW1Qcm90b2NvbH0nIGAgK1xuICAgICAgICAgIGBhcyBwZXIgc2Vzc2lvbiBjcmVhdGlvbiByZXF1ZXN0YCk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBsb2cuZGVidWcoYERldGVybWluZWQgdGhlIGRvd25zdHJlYW0gcHJvdG9jb2wgYXMgJyR7dGhpcy5kb3duc3RyZWFtUHJvdG9jb2x9JyBgICtcbiAgICAgICAgICBgcGVyIHNlc3Npb24gY3JlYXRpb24gcmVxdWVzdGApO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIGFzeW5jIHByb3h5ICh1cmwsIG1ldGhvZCwgYm9keSA9IG51bGwpIHtcbiAgICBtZXRob2QgPSBtZXRob2QudG9VcHBlckNhc2UoKTtcbiAgICBjb25zdCBuZXdVcmwgPSB0aGlzLmdldFVybEZvclByb3h5KHVybCk7XG4gICAgY29uc3QgdHJ1bmNhdGVCb2R5ID0gKGNvbnRlbnQpID0+IF8udHJ1bmNhdGUoXG4gICAgICBfLmlzU3RyaW5nKGNvbnRlbnQpID8gY29udGVudCA6IEpTT04uc3RyaW5naWZ5KGNvbnRlbnQpLFxuICAgICAgeyBsZW5ndGg6IExPR19PQkpfTEVOR1RIIH0pO1xuICAgIGNvbnN0IHJlcU9wdHMgPSB7XG4gICAgICBhZ2VudDogZmFsc2UsXG4gICAgICB1cmw6IG5ld1VybCxcbiAgICAgIG1ldGhvZCxcbiAgICAgIGhlYWRlcnM6IHtcbiAgICAgICAgJ2NvbnRlbnQtdHlwZSc6ICdhcHBsaWNhdGlvbi9qc29uOyBjaGFyc2V0PXV0Zi04JyxcbiAgICAgICAgJ3VzZXItYWdlbnQnOiAnYXBwaXVtJyxcbiAgICAgICAgYWNjZXB0OiAnYXBwbGljYXRpb24vanNvbiwgKi8qJyxcbiAgICAgIH0sXG4gICAgICByZXNvbHZlV2l0aEZ1bGxSZXNwb25zZTogdHJ1ZSxcbiAgICAgIHRpbWVvdXQ6IHRoaXMudGltZW91dCxcbiAgICAgIGZvcmV2ZXI6IHRoaXMua2VlcEFsaXZlLFxuICAgIH07XG4gICAgaWYgKHV0aWwuaGFzVmFsdWUoYm9keSkpIHtcbiAgICAgIGlmICh0eXBlb2YgYm9keSAhPT0gJ29iamVjdCcpIHtcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICByZXFPcHRzLmpzb24gPSBKU09OLnBhcnNlKGJvZHkpO1xuICAgICAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBDYW5ub3QgaW50ZXJwcmV0IHRoZSByZXF1ZXN0IGJvZHkgYXMgdmFsaWQgSlNPTjogJHt0cnVuY2F0ZUJvZHkoYm9keSl9YCk7XG4gICAgICAgIH1cbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHJlcU9wdHMuanNvbiA9IGJvZHk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgLy8gR0VUIG1ldGhvZHMgc2hvdWxkbid0IGhhdmUgYW55IGJvZHkuIE1vc3Qgc2VydmVycyBhcmUgT0sgd2l0aCB0aGlzLCBidXQgV2ViRHJpdmVyQWdlbnQgdGhyb3dzIDQwMCBlcnJvcnNcbiAgICBpZiAobWV0aG9kID09PSAnR0VUJykge1xuICAgICAgcmVxT3B0cy5qc29uID0gbnVsbDtcbiAgICB9XG5cbiAgICBsb2cuZGVidWcoYFByb3h5aW5nIFske21ldGhvZH0gJHt1cmwgfHwgJy8nfV0gdG8gWyR7bWV0aG9kfSAke25ld1VybH1dIGAgK1xuICAgICAgKGJvZHkgPyBgd2l0aCBib2R5OiAke3RydW5jYXRlQm9keShib2R5KX1gIDogJ3dpdGggbm8gYm9keScpKTtcblxuICAgIGNvbnN0IHRocm93UHJveHlFcnJvciA9IChlcnJvcikgPT4ge1xuICAgICAgY29uc3QgbWVzc2FnZSA9IGBUaGUgcmVxdWVzdCB0byAke3VybH0gaGFzIGZhaWxlZGA7XG4gICAgICBjb25zdCBlcnIgPSBuZXcgRXJyb3IobWVzc2FnZSk7XG4gICAgICBlcnIubWVzc2FnZSA9IG1lc3NhZ2U7XG4gICAgICBlcnIuZXJyb3IgPSBlcnJvcjtcbiAgICAgIGVyci5zdGF0dXNDb2RlID0gNTAwO1xuICAgICAgdGhyb3cgZXJyO1xuICAgIH07XG4gICAgbGV0IGlzUmVzcG9uc2VMb2dnZWQgPSBmYWxzZTtcbiAgICB0cnkge1xuICAgICAgY29uc3QgcmVzID0gYXdhaXQgdGhpcy5yZXF1ZXN0KHJlcU9wdHMpO1xuICAgICAgLy8gYHJlcy5ib2R5YCBtaWdodCBiZSByZWFsbHkgYmlnXG4gICAgICAvLyBCZSBjYXJlZnVsIHdoaWxlIGhhbmRsaW5nIGl0IHRvIGF2b2lkIG1lbW9yeSBsZWFrc1xuICAgICAgY29uc3QgcmVzQm9keU9iaiA9IHV0aWwuc2FmZUpzb25QYXJzZShyZXMuYm9keSk7XG4gICAgICBpZiAoIV8uaXNQbGFpbk9iamVjdChyZXNCb2R5T2JqKSkge1xuICAgICAgICAvLyBUaGUgcmVzcG9uc2Ugc2hvdWxkIGJlIGEgdmFsaWQgSlNPTiBvYmplY3RcbiAgICAgICAgLy8gSWYgaXQgY2Fubm90IGJlIGNvZXJjZWQgdG8gYW4gb2JqZWN0IHRoZW4gdGhlIHJlc3BvbnNlIGlzIHdyb25nXG4gICAgICAgIHRocm93UHJveHlFcnJvcihyZXMuYm9keSk7XG4gICAgICB9XG4gICAgICBsb2cuZGVidWcoYEdvdCByZXNwb25zZSB3aXRoIHN0YXR1cyAke3Jlcy5zdGF0dXNDb2RlfTogJHt0cnVuY2F0ZUJvZHkocmVzLmJvZHkpfWApO1xuICAgICAgaXNSZXNwb25zZUxvZ2dlZCA9IHRydWU7XG4gICAgICBjb25zdCBpc1Nlc3Npb25DcmVhdGlvblJlcXVlc3QgPSAvXFwvc2Vzc2lvbiQvLnRlc3QodXJsKSAmJiBtZXRob2QgPT09ICdQT1NUJztcbiAgICAgIGlmIChpc1Nlc3Npb25DcmVhdGlvblJlcXVlc3QgJiYgcmVzLnN0YXR1c0NvZGUgPT09IDIwMCkge1xuICAgICAgICB0aGlzLnNlc3Npb25JZCA9IHJlc0JvZHlPYmouc2Vzc2lvbklkIHx8IChyZXNCb2R5T2JqLnZhbHVlIHx8IHt9KS5zZXNzaW9uSWQ7XG4gICAgICB9XG4gICAgICB0aGlzLnN5bmNEb3duc3RyZWFtUHJvdG9jb2wocmVzQm9keU9iaiwgaXNTZXNzaW9uQ3JlYXRpb25SZXF1ZXN0KTtcbiAgICAgIGlmIChyZXMuc3RhdHVzQ29kZSA8IDQwMCAmJiB0aGlzLmRvd25zdHJlYW1Qcm90b2NvbCA9PT0gTUpTT05XUCAmJlxuICAgICAgICBfLmhhcyhyZXNCb2R5T2JqLCAnc3RhdHVzJykgJiYgcGFyc2VJbnQocmVzQm9keU9iai5zdGF0dXMsIDEwKSAhPT0gMCkge1xuICAgICAgICAvLyBTb21lIHNlcnZlcnMsIGxpa2UgY2hyb21lZHJpdmVyIG1heSByZXR1cm4gcmVzcG9uc2UgY29kZSAyMDAgZm9yIG5vbi16ZXJvIEpTT05XUCBzdGF0dXNlc1xuICAgICAgICB0aHJvd1Byb3h5RXJyb3IocmVzQm9keU9iaik7XG4gICAgICB9XG4gICAgICByZXR1cm4gW3JlcywgcmVzQm9keU9ial07XG4gICAgfSBjYXRjaCAoZSkge1xuICAgICAgLy8gV2Ugb25seSBjb25zaWRlciBhbiBlcnJvciB1bmV4cGVjdGVkIGlmIHRoaXMgd2FzIG5vdFxuICAgICAgLy8gYW4gYXN5bmMgcmVxdWVzdCBtb2R1bGUgZXJyb3Igb3IgaWYgdGhlIHJlc3BvbnNlIGNhbm5vdCBiZSBjYXN0IHRvXG4gICAgICAvLyBhIHZhbGlkIEpTT05cbiAgICAgIGlmICghdXRpbC5oYXNWYWx1ZShlLmVycm9yKSkge1xuICAgICAgICBsb2cud2FybihlLm1lc3NhZ2UpO1xuICAgICAgICBsb2cuZGVidWcoZS5zdGFjayk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBpZiAoIXV0aWwuaGFzVmFsdWUoZS5zdGF0dXNDb2RlKSB8fCAhL15cXHMqXFx7Ly50ZXN0KGUuZXJyb3IpKSB7XG4gICAgICAgICAgaWYgKGlzUmVzcG9uc2VMb2dnZWQpIHtcbiAgICAgICAgICAgIGxvZy5pbmZvKCdUaGUgcmVzcG9uc2UgaGFzIGFuIHVua25vd24gZm9ybWF0Jyk7XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIGxvZy5pbmZvKGBHb3QgYW4gdW5leHBlY3RlZCByZXNwb25zZSB3aXRoIHN0YXR1cyAke2Uuc3RhdHVzQ29kZX06ICR7dHJ1bmNhdGVCb2R5KGUuZXJyb3IpfWApO1xuICAgICAgICAgIH1cbiAgICAgICAgfSBlbHNlIGlmICghaXNSZXNwb25zZUxvZ2dlZCkge1xuICAgICAgICAgIGxvZy5kZWJ1ZyhgR290IHJlc3BvbnNlIHdpdGggc3RhdHVzICR7ZS5zdGF0dXNDb2RlfTogJHt0cnVuY2F0ZUJvZHkoZS5lcnJvcil9YCk7XG4gICAgICAgICAgaXNSZXNwb25zZUxvZ2dlZCA9IHRydWU7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICAgIHRocm93IG5ldyBlcnJvcnMuUHJveHlSZXF1ZXN0RXJyb3IoYENvdWxkIG5vdCBwcm94eSBjb21tYW5kIHRvIHJlbW90ZSBzZXJ2ZXIuIGAgK1xuICAgICAgICBgT3JpZ2luYWwgZXJyb3I6ICR7ZS5tZXNzYWdlfWAsIGUuZXJyb3IsIGUuc3RhdHVzQ29kZSk7XG4gICAgfVxuICB9XG5cbiAgZ2V0UHJvdG9jb2xGcm9tUmVzQm9keSAocmVzT2JqKSB7XG4gICAgaWYgKF8uaXNJbnRlZ2VyKHJlc09iai5zdGF0dXMpKSB7XG4gICAgICByZXR1cm4gTUpTT05XUDtcbiAgICB9XG4gICAgaWYgKCFfLmlzVW5kZWZpbmVkKHJlc09iai52YWx1ZSkpIHtcbiAgICAgIHJldHVybiBXM0M7XG4gICAgfVxuICB9XG5cbiAgcmVxdWVzdFRvQ29tbWFuZE5hbWUgKHVybCwgbWV0aG9kKSB7XG4gICAgY29uc3QgZXh0cmFjdENvbW1hbmROYW1lID0gKHBhdHRlcm4pID0+IHtcbiAgICAgIGNvbnN0IHBhdGhNYXRjaCA9IHBhdHRlcm4uZXhlYyh1cmwpO1xuICAgICAgcmV0dXJuIHBhdGhNYXRjaCA/IHJvdXRlVG9Db21tYW5kTmFtZShwYXRoTWF0Y2hbMV0sIG1ldGhvZCkgOiBudWxsO1xuICAgIH07XG4gICAgbGV0IGNvbW1hbmROYW1lID0gcm91dGVUb0NvbW1hbmROYW1lKHVybCwgbWV0aG9kKTtcbiAgICBpZiAoIWNvbW1hbmROYW1lICYmIF8uaW5jbHVkZXModXJsLCAnL3dkL2h1Yi9zZXNzaW9uLycpKSB7XG4gICAgICBjb21tYW5kTmFtZSA9IGV4dHJhY3RDb21tYW5kTmFtZSgvXFwvd2RcXC9odWJcXC9zZXNzaW9uXFwvW14vXSsoLispLyk7XG4gICAgfVxuICAgIGlmICghY29tbWFuZE5hbWUgJiYgXy5pbmNsdWRlcyh1cmwsICcvd2QvaHViLycpKSB7XG4gICAgICBjb21tYW5kTmFtZSA9IGV4dHJhY3RDb21tYW5kTmFtZSgvXFwvd2RcXC9odWIoXFwvLispLyk7XG4gICAgfVxuICAgIHJldHVybiBjb21tYW5kTmFtZTtcbiAgfVxuXG4gIGFzeW5jIHByb3h5Q29tbWFuZCAodXJsLCBtZXRob2QsIGJvZHkgPSBudWxsKSB7XG4gICAgY29uc3QgY29tbWFuZE5hbWUgPSB0aGlzLnJlcXVlc3RUb0NvbW1hbmROYW1lKHVybCwgbWV0aG9kKTtcbiAgICBpZiAoIWNvbW1hbmROYW1lKSB7XG4gICAgICByZXR1cm4gYXdhaXQgdGhpcy5wcm94eSh1cmwsIG1ldGhvZCwgYm9keSk7XG4gICAgfVxuICAgIGxvZy5kZWJ1ZyhgTWF0Y2hlZCAnJHt1cmx9JyB0byBjb21tYW5kIG5hbWUgJyR7Y29tbWFuZE5hbWV9J2ApO1xuXG4gICAgcmV0dXJuIGF3YWl0IHRoaXMucHJvdG9jb2xDb252ZXJ0ZXIuY29udmVydEFuZFByb3h5KGNvbW1hbmROYW1lLCB1cmwsIG1ldGhvZCwgYm9keSk7XG4gIH1cblxuICBhc3luYyBjb21tYW5kICh1cmwsIG1ldGhvZCwgYm9keSA9IG51bGwpIHtcbiAgICBsZXQgcmVzcG9uc2U7XG4gICAgbGV0IHJlc0JvZHlPYmo7XG4gICAgdHJ5IHtcbiAgICAgIFtyZXNwb25zZSwgcmVzQm9keU9ial0gPSBhd2FpdCB0aGlzLnByb3h5Q29tbWFuZCh1cmwsIG1ldGhvZCwgYm9keSk7XG4gICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICBpZiAoaXNFcnJvclR5cGUoZXJyLCBlcnJvcnMuUHJveHlSZXF1ZXN0RXJyb3IpKSB7XG4gICAgICAgIHRocm93IGVyci5nZXRBY3R1YWxFcnJvcigpO1xuICAgICAgfVxuICAgICAgdGhyb3cgbmV3IGVycm9ycy5Vbmtub3duRXJyb3IoZXJyLm1lc3NhZ2UpO1xuICAgIH1cbiAgICBjb25zdCBwcm90b2NvbCA9IHRoaXMuZ2V0UHJvdG9jb2xGcm9tUmVzQm9keShyZXNCb2R5T2JqKTtcbiAgICBpZiAocHJvdG9jb2wgPT09IE1KU09OV1ApIHtcbiAgICAgIC8vIEdvdCByZXNwb25zZSBpbiBNSlNPTldQIGZvcm1hdFxuICAgICAgaWYgKHJlc3BvbnNlLnN0YXR1c0NvZGUgPT09IDIwMCAmJiByZXNCb2R5T2JqLnN0YXR1cyA9PT0gMCkge1xuICAgICAgICByZXR1cm4gcmVzQm9keU9iai52YWx1ZTtcbiAgICAgIH1cbiAgICAgIGNvbnN0IHN0YXR1cyA9IHBhcnNlSW50KHJlc0JvZHlPYmouc3RhdHVzLCAxMCk7XG4gICAgICBpZiAoIWlzTmFOKHN0YXR1cykgJiYgc3RhdHVzICE9PSAwKSB7XG4gICAgICAgIGxldCBtZXNzYWdlID0gcmVzQm9keU9iai52YWx1ZTtcbiAgICAgICAgaWYgKF8uaGFzKG1lc3NhZ2UsICdtZXNzYWdlJykpIHtcbiAgICAgICAgICBtZXNzYWdlID0gbWVzc2FnZS5tZXNzYWdlO1xuICAgICAgICB9XG4gICAgICAgIHRocm93IGVycm9yRnJvbU1KU09OV1BTdGF0dXNDb2RlKHN0YXR1cywgXy5pc0VtcHR5KG1lc3NhZ2UpID8gZ2V0U3VtbWFyeUJ5Q29kZShzdGF0dXMpIDogbWVzc2FnZSk7XG4gICAgICB9XG4gICAgfSBlbHNlIGlmIChwcm90b2NvbCA9PT0gVzNDKSB7XG4gICAgICAvLyBHb3QgcmVzcG9uc2UgaW4gVzNDIGZvcm1hdFxuICAgICAgaWYgKHJlc3BvbnNlLnN0YXR1c0NvZGUgPCAzMDApIHtcbiAgICAgICAgcmV0dXJuIHJlc0JvZHlPYmoudmFsdWU7XG4gICAgICB9XG4gICAgICBpZiAoXy5pc1BsYWluT2JqZWN0KHJlc0JvZHlPYmoudmFsdWUpICYmIHJlc0JvZHlPYmoudmFsdWUuZXJyb3IpIHtcbiAgICAgICAgdGhyb3cgZXJyb3JGcm9tVzNDSnNvbkNvZGUocmVzQm9keU9iai52YWx1ZS5lcnJvciwgcmVzQm9keU9iai52YWx1ZS5tZXNzYWdlLCByZXNCb2R5T2JqLnZhbHVlLnN0YWNrdHJhY2UpO1xuICAgICAgfVxuICAgIH0gZWxzZSBpZiAocmVzcG9uc2Uuc3RhdHVzQ29kZSA9PT0gMjAwKSB7XG4gICAgICAvLyBVbmtub3duIHByb3RvY29sLiBLZWVwaW5nIGl0IGJlY2F1c2Ugb2YgdGhlIGJhY2t3YXJkIGNvbXBhdGliaWxpdHlcbiAgICAgIHJldHVybiByZXNCb2R5T2JqO1xuICAgIH1cbiAgICB0aHJvdyBuZXcgZXJyb3JzLlVua25vd25FcnJvcihgRGlkIG5vdCBrbm93IHdoYXQgdG8gZG8gd2l0aCByZXNwb25zZSBjb2RlICcke3Jlc3BvbnNlLnN0YXR1c0NvZGV9JyBgICtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBgYW5kIHJlc3BvbnNlIGJvZHkgJyR7Xy50cnVuY2F0ZShKU09OLnN0cmluZ2lmeShyZXNCb2R5T2JqKSwge2xlbmd0aDogMzAwfSl9J2ApO1xuICB9XG5cbiAgZ2V0U2Vzc2lvbklkRnJvbVVybCAodXJsKSB7XG4gICAgY29uc3QgbWF0Y2ggPSB1cmwubWF0Y2goL1xcL3Nlc3Npb25cXC8oW14vXSspLyk7XG4gICAgcmV0dXJuIG1hdGNoID8gbWF0Y2hbMV0gOiBudWxsO1xuICB9XG5cbiAgYXN5bmMgcHJveHlSZXFSZXMgKHJlcSwgcmVzKSB7XG4gICAgY29uc3QgW3Jlc3BvbnNlLCByZXNCb2R5T2JqXSA9IGF3YWl0IHRoaXMucHJveHlDb21tYW5kKHJlcS5vcmlnaW5hbFVybCwgcmVxLm1ldGhvZCwgcmVxLmJvZHkpO1xuXG4gICAgcmVzLmhlYWRlcnMgPSByZXNwb25zZS5oZWFkZXJzO1xuICAgIHJlcy5zZXQoJ2NvbnRlbnQtdHlwZScsIHJlc3BvbnNlLmhlYWRlcnNbJ2NvbnRlbnQtdHlwZSddKTtcbiAgICAvLyBpZiB0aGUgcHJveGllZCByZXNwb25zZSBjb250YWlucyBhIHNlc3Npb25JZCB0aGF0IHRoZSBkb3duc3RyZWFtXG4gICAgLy8gZHJpdmVyIGhhcyBnZW5lcmF0ZWQsIHdlIGRvbid0IHdhbnQgdG8gcmV0dXJuIHRoYXQgdG8gdGhlIGNsaWVudC5cbiAgICAvLyBJbnN0ZWFkLCByZXR1cm4gdGhlIGlkIGZyb20gdGhlIHJlcXVlc3Qgb3IgZnJvbSBjdXJyZW50IHNlc3Npb25cbiAgICBjb25zdCByZXFTZXNzaW9uSWQgPSB0aGlzLmdldFNlc3Npb25JZEZyb21VcmwocmVxLm9yaWdpbmFsVXJsKTtcbiAgICBpZiAoXy5oYXMocmVzQm9keU9iaiwgJ3Nlc3Npb25JZCcpKSB7XG4gICAgICBpZiAocmVxU2Vzc2lvbklkKSB7XG4gICAgICAgIGxvZy5pbmZvKGBSZXBsYWNpbmcgc2Vzc2lvbklkICR7cmVzQm9keU9iai5zZXNzaW9uSWR9IHdpdGggJHtyZXFTZXNzaW9uSWR9YCk7XG4gICAgICAgIHJlc0JvZHlPYmouc2Vzc2lvbklkID0gcmVxU2Vzc2lvbklkO1xuICAgICAgfSBlbHNlIGlmICh0aGlzLnNlc3Npb25JZCkge1xuICAgICAgICBsb2cuaW5mbyhgUmVwbGFjaW5nIHNlc3Npb25JZCAke3Jlc0JvZHlPYmouc2Vzc2lvbklkfSB3aXRoICR7dGhpcy5zZXNzaW9uSWR9YCk7XG4gICAgICAgIHJlc0JvZHlPYmouc2Vzc2lvbklkID0gdGhpcy5zZXNzaW9uSWQ7XG4gICAgICB9XG4gICAgfVxuICAgIHJlc0JvZHlPYmoudmFsdWUgPSBmb3JtYXRSZXNwb25zZVZhbHVlKHJlc0JvZHlPYmoudmFsdWUpO1xuICAgIGZvcm1hdFN0YXR1cyhyZXNCb2R5T2JqLCBTRVNTSU9OU19DQUNIRS5nZXRQcm90b2NvbChyZXFTZXNzaW9uSWQpKTtcbiAgICByZXMuc3RhdHVzKHJlc3BvbnNlLnN0YXR1c0NvZGUpLnNlbmQoSlNPTi5zdHJpbmdpZnkocmVzQm9keU9iaikpO1xuICB9XG59XG5cbmV4cG9ydCB7IEpXUHJveHkgfTtcbmV4cG9ydCBkZWZhdWx0IEpXUHJveHk7XG4iXSwiZmlsZSI6ImxpYi9qc29ud3AtcHJveHkvcHJveHkuanMiLCJzb3VyY2VSb290IjoiLi4vLi4vLi4ifQ==