230 lines
41 KiB
JavaScript
230 lines
41 KiB
JavaScript
"use strict";
|
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
};
|
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
const lodash_1 = require("lodash");
|
|
const event_provider_1 = __importDefault(require("../request-hooks/event-provider"));
|
|
const resource_injector_1 = __importDefault(require("../resource-injector"));
|
|
const headers_1 = require("../utils/headers");
|
|
const cdp_1 = require("../utils/cdp");
|
|
const error_route_1 = __importDefault(require("../error-route"));
|
|
const debug_loggers_1 = require("../../utils/debug-loggers");
|
|
const testcafe_hammerhead_1 = require("testcafe-hammerhead");
|
|
const default_setup_options_1 = __importDefault(require("../default-setup-options"));
|
|
const special_handlers_1 = __importDefault(require("./special-handlers"));
|
|
const safe_api_1 = require("./safe-api");
|
|
const api_base_1 = __importDefault(require("../api-base"));
|
|
const resendAuthRequest_1 = require("./resendAuthRequest");
|
|
const test_run_bridge_1 = __importDefault(require("./test-run-bridge"));
|
|
const context_info_1 = __importDefault(require("./context-info"));
|
|
class ProxylessRequestPipeline extends api_base_1.default {
|
|
constructor(browserId, client) {
|
|
super(browserId, client);
|
|
this._testRunBridge = new test_run_bridge_1.default(browserId);
|
|
this._contextInfo = new context_info_1.default(this._testRunBridge);
|
|
this._specialServiceRoutes = this._getSpecialServiceRoutes();
|
|
this.requestHookEventProvider = new event_provider_1.default();
|
|
this._resourceInjector = new resource_injector_1.default(this._testRunBridge, this._specialServiceRoutes);
|
|
this._options = default_setup_options_1.default;
|
|
this._stopped = false;
|
|
this._currentFrameTree = null;
|
|
this._failedRequestIds = [];
|
|
this.restoringStorages = null;
|
|
this.contextStorage = null;
|
|
}
|
|
_getSpecialServiceRoutes() {
|
|
const browserConnection = this._testRunBridge.getBrowserConnection();
|
|
const proxy = browserConnection.browserConnectionGateway.proxy;
|
|
return {
|
|
errorPage1: proxy.resolveRelativeServiceUrl(error_route_1.default, proxy.server1Info.domain),
|
|
errorPage2: proxy.resolveRelativeServiceUrl(error_route_1.default, proxy.server2Info.domain),
|
|
idlePage: browserConnection.idleUrl,
|
|
openFileProtocolUrl: browserConnection.openFileProtocolUrl,
|
|
};
|
|
}
|
|
async _handleMockErrorIfNecessary(pipelineContext, event) {
|
|
if (!pipelineContext.mock.hasError)
|
|
return;
|
|
await pipelineContext.handleMockError(this.requestHookEventProvider);
|
|
(0, debug_loggers_1.requestPipelineMockLogger)('%s\n%s', event.networkId, pipelineContext.mock.error);
|
|
}
|
|
async _handleMockResponse(mockedResponse, pipelineContext, event) {
|
|
const mockedResponseBodyStr = mockedResponse.getBody().toString();
|
|
const fulfillInfo = {
|
|
requestId: event.requestId,
|
|
responseCode: mockedResponse.statusCode,
|
|
responseHeaders: (0, headers_1.convertToHeaderEntries)(mockedResponse.headers),
|
|
body: mockedResponseBodyStr,
|
|
};
|
|
if (pipelineContext.reqOpts.isAjax)
|
|
await this._resourceInjector.processNonProxiedContent(fulfillInfo, this._client);
|
|
else {
|
|
await this._resourceInjector.processHTMLPageContent(fulfillInfo, {
|
|
isIframe: false,
|
|
contextStorage: this.contextStorage,
|
|
}, this._client);
|
|
}
|
|
(0, debug_loggers_1.requestPipelineMockLogger)(`Mock request ${event.requestId}`);
|
|
}
|
|
_createContinueResponseRequest(event, modified) {
|
|
const continueResponseRequest = {
|
|
requestId: event.requestId,
|
|
};
|
|
if (modified) {
|
|
continueResponseRequest.responseHeaders = event.responseHeaders;
|
|
continueResponseRequest.responseCode = event.responseStatusCode;
|
|
}
|
|
return continueResponseRequest;
|
|
}
|
|
_shouldRedirectToErrorPage(event) {
|
|
return event.resourceType === 'Document'
|
|
&& !this._isIframe(event.frameId);
|
|
}
|
|
async _getUserScripts(event) {
|
|
const { pipelineContext, eventFactory } = this._contextInfo.getContextData(event);
|
|
await pipelineContext.prepareInjectableUserScripts(eventFactory, this._testRunBridge.getUserScripts());
|
|
return pipelineContext.injectableUserScripts;
|
|
}
|
|
async _respondToOtherRequest(event) {
|
|
if ((0, testcafe_hammerhead_1.isRedirectStatusCode)(event.responseStatusCode)) {
|
|
await (0, safe_api_1.safeContinueResponse)(this._client, { requestId: event.requestId });
|
|
return;
|
|
}
|
|
const resourceInfo = await this._resourceInjector.getDocumentResourceInfo(event, this._client);
|
|
if (resourceInfo.error) {
|
|
if (this._shouldRedirectToErrorPage(event)) {
|
|
await this._resourceInjector.redirectToErrorPage(this._client, resourceInfo.error, event.request.url);
|
|
this._contextInfo.dispose((0, cdp_1.getRequestId)(event));
|
|
}
|
|
return;
|
|
}
|
|
const modified = await this.requestHookEventProvider.onResponse(event, resourceInfo.body, this._contextInfo, this._client);
|
|
if (event.resourceType !== 'Document') {
|
|
const continueResponseRequest = this._createContinueResponseRequest(event, modified);
|
|
await (0, safe_api_1.safeContinueResponse)(this._client, continueResponseRequest);
|
|
this._contextInfo.dispose((0, cdp_1.getRequestId)(event));
|
|
}
|
|
else {
|
|
const fulfillInfo = {
|
|
requestId: event.requestId,
|
|
responseHeaders: event.responseHeaders,
|
|
responseCode: event.responseStatusCode,
|
|
body: resourceInfo.body.toString(),
|
|
};
|
|
// NOTE: Strange behavior of the CDP API:
|
|
// if we pass the empty "responseStatusText" value, we get an error 'Invalid status code or phrase'.
|
|
if (event.responseStatusText !== '')
|
|
fulfillInfo.responsePhrase = event.responseStatusText;
|
|
if ((0, cdp_1.isUnauthorized)(event.responseStatusCode))
|
|
await this._tryAuthorizeWithHttpBasicAuthCredentials(event, fulfillInfo);
|
|
const userScripts = await this._getUserScripts(event);
|
|
await this._resourceInjector.processHTMLPageContent(fulfillInfo, {
|
|
isIframe: this._isIframe(event.frameId),
|
|
url: event.request.url,
|
|
restoringStorages: this.restoringStorages,
|
|
contextStorage: this.contextStorage,
|
|
userScripts,
|
|
}, this._client);
|
|
this._contextInfo.dispose((0, cdp_1.getRequestId)(event));
|
|
this.restoringStorages = null;
|
|
}
|
|
}
|
|
async _tryAuthorizeWithHttpBasicAuthCredentials(event, fulfillInfo) {
|
|
const credentials = this._testRun.getAuthCredentials();
|
|
if (!credentials)
|
|
return;
|
|
const authRequest = await (0, resendAuthRequest_1.resendAuthRequest)(event.request, credentials);
|
|
if (typeof authRequest !== 'string' && !(0, cdp_1.isUnauthorized)(authRequest.status)) {
|
|
fulfillInfo.responseCode = authRequest.status;
|
|
fulfillInfo.body = authRequest.body.toString();
|
|
fulfillInfo.responsePhrase = authRequest.statusText;
|
|
}
|
|
}
|
|
async _tryRespondToOtherRequest(event) {
|
|
try {
|
|
await this._respondToOtherRequest(event);
|
|
}
|
|
catch (err) {
|
|
if (event.networkId && this._failedRequestIds.includes(event.networkId)) {
|
|
(0, lodash_1.remove)(this._failedRequestIds, event.networkId);
|
|
return;
|
|
}
|
|
throw err;
|
|
}
|
|
}
|
|
async _handleOtherRequests(event) {
|
|
(0, debug_loggers_1.requestPipelineOtherRequestLogger)('%r', event);
|
|
if (!event.responseErrorReason && ((0, cdp_1.isRequest)(event) || (0, testcafe_hammerhead_1.isRedirectStatusCode)(event.responseStatusCode))) {
|
|
this._contextInfo.init(event);
|
|
await this.requestHookEventProvider.onRequest(event, this._contextInfo);
|
|
const pipelineContext = this._contextInfo.getPipelineContext(event.networkId);
|
|
if (!pipelineContext || !pipelineContext.mock)
|
|
await (0, safe_api_1.safeContinueRequest)(this._client, event);
|
|
else {
|
|
const mockedResponse = await pipelineContext.getMockResponse();
|
|
await this._handleMockErrorIfNecessary(pipelineContext, event);
|
|
const mockedResponseEvent = (0, cdp_1.createRequestPausedEventForResponse)(mockedResponse, event);
|
|
await this.requestHookEventProvider.onResponse(mockedResponseEvent, mockedResponse.getBody(), this._contextInfo, this._client);
|
|
await this._handleMockResponse(mockedResponse, pipelineContext, event);
|
|
this._contextInfo.dispose((0, cdp_1.getRequestId)(event));
|
|
}
|
|
}
|
|
else
|
|
await this._tryRespondToOtherRequest(event);
|
|
}
|
|
_topFrameNavigation(event) {
|
|
return event.type === 'Navigation'
|
|
&& !event.frame.parentId;
|
|
}
|
|
async _updateCurrentFrameTree() {
|
|
// NOTE: Due to CDP restrictions (it hangs), we can't get the frame tree
|
|
// right before injecting service scripts.
|
|
// So, we are forced tracking frames tree.
|
|
const result = await this._client.Page.getFrameTree();
|
|
this._currentFrameTree = result.frameTree;
|
|
}
|
|
_isIframe(frameId) {
|
|
if (!this._currentFrameTree)
|
|
return false;
|
|
return this._currentFrameTree.frame.id !== frameId;
|
|
}
|
|
async init(options) {
|
|
this._options = options;
|
|
this._client.Fetch.on('requestPaused', async (event) => {
|
|
if (this._stopped)
|
|
return;
|
|
const specialRequestHandler = (0, special_handlers_1.default)(event, this._options, this._specialServiceRoutes);
|
|
if (specialRequestHandler)
|
|
await specialRequestHandler(event, this._client, this._options);
|
|
else
|
|
await this._handleOtherRequests(event);
|
|
});
|
|
this._client.Page.on('frameNavigated', async (event) => {
|
|
(0, debug_loggers_1.requestPipelineLogger)('%f', event);
|
|
if (!this._topFrameNavigation(event)
|
|
|| event.frame.url !== testcafe_hammerhead_1.SPECIAL_BLANK_PAGE)
|
|
return;
|
|
this._contextInfo.init(event);
|
|
const userScripts = await this._getUserScripts(event);
|
|
await this._resourceInjector.processAboutBlankPage(event, userScripts, this._client);
|
|
this._contextInfo.dispose((0, cdp_1.getRequestId)(event));
|
|
});
|
|
this._client.Page.on('frameStartedLoading', async () => {
|
|
await this._updateCurrentFrameTree();
|
|
});
|
|
this._client.Network.on('loadingFailed', async (event) => {
|
|
(0, debug_loggers_1.requestPipelineLogger)('%l', event);
|
|
this._failedRequestIds.push(event.requestId);
|
|
if (event.requestId)
|
|
this._contextInfo.dispose(event.requestId);
|
|
});
|
|
await this._client.Page.setBypassCSP({ enabled: true });
|
|
}
|
|
stop() {
|
|
this._stopped = true;
|
|
}
|
|
}
|
|
exports.default = ProxylessRequestPipeline;
|
|
module.exports = exports.default;
|
|
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvcHJveHlsZXNzL3JlcXVlc3QtcGlwZWxpbmUvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7QUFBQSxtQ0FBZ0M7QUFTaEMscUZBQWdGO0FBQ2hGLDZFQUFvRDtBQUNwRCw4Q0FBMEQ7QUFFMUQsc0NBS3NCO0FBRXRCLGlFQUF5QztBQUV6Qyw2REFJbUM7QUFFbkMsNkRBSzZCO0FBSTdCLHFGQUF1RTtBQUN2RSwwRUFBMEQ7QUFDMUQseUNBQXVFO0FBQ3ZFLDJEQUEyQztBQUMzQywyREFBd0Q7QUFDeEQsd0VBQThDO0FBQzlDLGtFQUF5RDtBQUd6RCxNQUFxQix3QkFBeUIsU0FBUSxrQkFBZ0I7SUFhbEUsWUFBb0IsU0FBaUIsRUFBRSxNQUFtQjtRQUN0RCxLQUFLLENBQUMsU0FBUyxFQUFFLE1BQU0sQ0FBQyxDQUFDO1FBRXpCLElBQUksQ0FBQyxjQUFjLEdBQWEsSUFBSSx5QkFBYSxDQUFDLFNBQVMsQ0FBQyxDQUFDO1FBQzdELElBQUksQ0FBQyxZQUFZLEdBQWUsSUFBSSxzQkFBMkIsQ0FBQyxJQUFJLENBQUMsY0FBYyxDQUFDLENBQUM7UUFDckYsSUFBSSxDQUFDLHFCQUFxQixHQUFNLElBQUksQ0FBQyx3QkFBd0IsRUFBRSxDQUFDO1FBQ2hFLElBQUksQ0FBQyx3QkFBd0IsR0FBRyxJQUFJLHdCQUFpQyxFQUFFLENBQUM7UUFDeEUsSUFBSSxDQUFDLGlCQUFpQixHQUFVLElBQUksMkJBQWdCLENBQUMsSUFBSSxDQUFDLGNBQWMsRUFBRSxJQUFJLENBQUMscUJBQXFCLENBQUMsQ0FBQztRQUN0RyxJQUFJLENBQUMsUUFBUSxHQUFtQiwrQkFBK0IsQ0FBQztRQUNoRSxJQUFJLENBQUMsUUFBUSxHQUFtQixLQUFLLENBQUM7UUFDdEMsSUFBSSxDQUFDLGlCQUFpQixHQUFVLElBQUksQ0FBQztRQUNyQyxJQUFJLENBQUMsaUJBQWlCLEdBQVUsRUFB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QUM7UUFFSCxJQUFJLENBQUMsT0FBTyxDQUFDLE9BQU8sQ0FBQyxFQUFFLENBQUMsZUFBZSxFQUFFLEtBQUssRUFBRSxLQUF5QixFQUFFLEVBQUU7WUFDekUsSUFBQSxxQ0FBcUIsRUFBQyxJQUFJLEVBQUUsS0FBSyxDQUFDLENBQUM7WUFFbkMsSUFBSSxDQUFDLGlCQUFpQixDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsU0FBUyxDQUFDLENBQUM7WUFFN0MsSUFBSSxLQUFLLENBQUMsU0FBUztnQkFDZixJQUFJLENBQUMsWUFBWSxDQUFDLE9BQU8sQ0FBQyxLQUFLLENBQUMsU0FBUyxDQUFDLENBQUM7UUFDbkQsQ0FBQyxDQUFDLENBQUM7UUFFSCxNQUFNLElBQUksQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLFlBQVksQ0FBQyxFQUFFLE9BQU8sRUFBRSxJQUFJLEVBQUUsQ0FBQyxDQUFDO0lBQzVELENBQUM7SUFFTSxJQUFJO1FBQ1AsSUFBSSxDQUFDLFFBQVEsR0FBRyxJQUFJLENBQUM7SUFDekIsQ0FBQztDQUNKO0FBcFNELDJDQW9TQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IHJlbW92ZSB9IGZyb20gJ2xvZGFzaCc7XG5pbXBvcnQgeyBQcm90b2NvbEFwaSB9IGZyb20gJ2Nocm9tZS1yZW1vdGUtaW50ZXJmYWNlJztcbmltcG9ydCBQcm90b2NvbCBmcm9tICdkZXZ0b29scy1wcm90b2NvbCc7XG5pbXBvcnQgUmVxdWVzdFBhdXNlZEV2ZW50ID0gUHJvdG9jb2wuRmV0Y2guUmVxdWVzdFBhdXNlZEV2ZW50O1xuaW1wb3J0IEZyYW1lTmF2aWdhdGVkRXZlbnQgPSBQcm90b2NvbC5QYWdlLkZyYW1lTmF2aWdhdGVkRXZlbnQ7XG5pbXBvcnQgTG9hZGluZ0ZhaWxlZEV2ZW50ID0gUHJvdG9jb2wuTmV0d29yay5Mb2FkaW5nRmFpbGVkRXZlbnQ7XG5pbXBvcnQgQ29udGludWVSZXNwb25zZVJlcXVlc3QgPSBQcm90b2NvbC5GZXRjaC5Db250aW51ZVJlc3BvbnNlUmVxdWVzdDtcbmltcG9ydCBGcmFtZVRyZWUgPSBQcm90b2NvbC5QYWdlLkZyYW1lVHJlZTtcbmltcG9ydCBGdWxmaWxsUmVxdWVzdFJlcXVlc3QgPSBQcm90b2NvbC5GZXRjaC5GdWxmaWxsUmVxdWVzdFJlcXVlc3Q7XG5pbXBvcnQgUHJveHlsZXNzUmVxdWVzdEhvb2tFdmVudFByb3ZpZGVyIGZyb20gJy4uL3JlcXVlc3QtaG9va3MvZXZlbnQtcHJvdmlkZXInO1xuaW1wb3J0IFJlc291cmNlSW5qZWN0b3IgZnJvbSAnLi4vcmVzb3VyY2UtaW5qZWN0b3InO1xuaW1wb3J0IHsgY29udmVydFRvSGVhZGVyRW50cmllcyB9IGZyb20gJy4uL3V0aWxzL2hlYWRlcnMnO1xuXG5pbXBvcnQge1xuICAgIGNyZWF0ZVJlcXVlc3RQYXVzZWRFdmVudEZvclJlc3BvbnNlLFxuICAgIGdldFJlcXVlc3RJZCxcbiAgICBpc1JlcXVlc3QsXG4gICAgaXNVbmF1dGhvcml6ZWQsXG59IGZyb20gJy4uL3V0aWxzL2NkcCc7XG5cbmltcG9ydCBFUlJPUl9ST1VURSBmcm9tICcuLi9lcnJvci1yb3V0ZSc7XG5pbXBvcnQgeyBTZXNzaW9uU3RvcmFnZUluZm8sIFNwZWNpYWxTZXJ2aWNlUm91dGVzIH0gZnJvbSAnLi4vdHlwZXMnO1xuaW1wb3J0IHtcbiAgICByZXF1ZXN0UGlwZWxpbmVMb2dnZXIsXG4gICAgcmVxdWVzdFBpcGVsaW5lTW9ja0xvZ2dlcixcbiAgICByZXF1ZXN0UGlwZWxpbmVPdGhlclJlcXVlc3RMb2dnZXIsXG59IGZyb20gJy4uLy4uL3V0aWxzL2RlYnVnLWxvZ2dlcnMnO1xuXG5pbXBvcnQge1xuICAgIEluY29taW5nTWVzc2FnZUxpa2UsXG4gICAgaXNSZWRpcmVjdFN0YXR1c0NvZGUsXG4gICAgU1BFQ0lBTF9CTEFOS19QQUdFLFxuICAgIFN0b3JhZ2VzU25hcHNob3QsXG59IGZyb20gJ3Rlc3RjYWZlLWhhbW1lcmhlYWQnO1xuXG5pbXBvcnQgUHJveHlsZXNzUGlwZWxpbmVDb250ZXh0IGZyb20gJy4uL3JlcXVlc3QtaG9va3MvcGlwZWxpbmUtY29udGV4dCc7XG5pbXBvcnQgeyBQcm94eWxlc3NTZXR1cE9wdGlvbnMgfSBmcm9tICcuLi8uLi9zaGFyZWQvdHlwZXMnO1xuaW1wb3J0IERFRkFVTFRfUFJPWFlMRVNTX1NFVFVQX09QVElPTlMgZnJvbSAnLi4vZGVmYXVsdC1zZXR1cC1vcHRpb25zJztcbmltcG9ydCBnZXRTcGVjaWFsUmVxdWVzdEhhbmRsZXIgZnJvbSAnLi9zcGVjaWFsLWhhbmRsZXJzJztcbmltcG9ydCB7IHNhZmVDb250aW51ZVJlcXVlc3QsIHNhZmVDb250aW51ZVJlc3BvbnNlIH0gZnJvbSAnLi9zYWZlLWFwaSc7XG5pbXBvcnQgUHJveHlsZXNzQXBpQmFzZSBmcm9tICcuLi9hcGktYmFzZSc7XG5pbXBvcnQgeyByZXNlbmRBdXRoUmVxdWVzdCB9IGZyb20gJy4vcmVzZW5kQXV0aFJlcXVlc3QnO1xuaW1wb3J0IFRlc3RSdW5CcmlkZ2UgZnJvbSAnLi90ZXN0LXJ1bi1icmlkZ2UnO1xuaW1wb3J0IFByb3h5bGVzc1JlcXVlc3RDb250ZXh0SW5mbyBmcm9tICcuL2NvbnRleHQtaW5mbyc7XG5cblxuZXhwb3J0IGRlZmF1bHQgY2xhc3MgUHJveHlsZXNzUmVxdWVzdFBpcGVsaW5lIGV4dGVuZHMgUHJveHlsZXNzQXBpQmFzZSB7XG4gICAgcHJpdmF0ZSByZWFkb25seSBfdGVzdFJ1bkJyaWRnZTogVGVzdFJ1bkJyaWRnZTtcbiAgICBwcml2YXRlIHJlYWRvbmx5IF9jb250ZXh0SW5mbzogUHJveHlsZXNzUmVxdWVzdENvbnRleHRJbmZvO1xuICAgIHB1YmxpYyByZWFkb25seSByZXF1ZXN0SG9va0V2ZW50UHJvdmlkZXI6IFByb3h5bGVzc1JlcXVlc3RIb29rRXZlbnRQcm92aWRlcjtcbiAgICBwdWJsaWMgcmVzdG9yaW5nU3RvcmFnZXM6IFN0b3JhZ2VzU25hcHNob3QgfCBudWxsO1xuICAgIHB1YmxpYyBjb250ZXh0U3RvcmFnZTogU2Vzc2lvblN0b3JhZ2VJbmZvIHwgbnVsbDtcbiAgICBwcml2YXRlIHJlYWRvbmx5IF9yZXNvdXJjZUluamVjdG9yOiBSZXNvdXJjZUluamVjdG9yO1xuICAgIHByaXZhdGUgX29wdGlvbnM6IFByb3h5bGVzc1NldHVwT3B0aW9ucztcbiAgICBwcml2YXRlIHJlYWRvbmx5IF9zcGVjaWFsU2VydmljZVJvdXRlczogU3BlY2lhbFNlcnZpY2VSb3V0ZXM7XG4gICAgcHJpdmF0ZSBfc3RvcHBlZDogYm9vbGVhbjtcbiAgICBwcml2YXRlIF9jdXJyZW50RnJhbWVUcmVlOiBGcmFtZVRyZWUgfCBudWxsO1xuICAgIHByaXZhdGUgcmVhZG9ubHkgX2ZhaWxlZFJlcXVlc3RJZHM6IHN0cmluZ1tdO1xuXG4gICAgcHVibGljIGNvbnN0cnVjdG9yIChicm93c2VySWQ6IHN0cmluZywgY2xpZW50OiBQcm90b2NvbEFwaSkge1xuICAgICAgICBzdXBlcihicm93c2VySWQsIGNsaWVudCk7XG5cbiAgICAgICAgdGhpcy5fdGVzdFJ1bkJyaWRnZSAgICAgICAgICAgPSBuZXcgVGVzdFJ1bkJyaWRnZShicm93c2VySWQpO1xuICAgICAgICB0aGlzLl9jb250ZXh0SW5mbyAgICAgICAgICAgICA9IG5ldyBQcm94eWxlc3NSZXF1ZXN0Q29udGV4dEluZm8odGhpcy5fdGVzdFJ1bkJyaWRnZSk7XG4gICAgICAgIHRoaXMuX3NwZWNpYWxTZXJ2aWNlUm91dGVzICAgID0gdGhpcy5fZ2V0U3BlY2lhbFNlcnZpY2VSb3V0ZXMoKTtcbiAgICAgICAgdGhpcy5yZXF1ZXN0SG9va0V2ZW50UHJvdmlkZXIgPSBuZXcgUHJveHlsZXNzUmVxdWVzdEhvb2tFdmVudFByb3ZpZGVyKCk7XG4gICAgICAgIHRoaXMuX3Jlc291cmNlSW5qZWN0b3IgICAgICAgID0gbmV3IFJlc291cmNlSW5qZWN0b3IodGhpcy5fdGVzdFJ1bkJyaWRnZSwgdGhpcy5fc3BlY2lhbFNlcnZpY2VSb3V0ZXMpO1xuICAgICAgICB0aGlzLl9vcHRpb25zICAgICAgICAgICAgICAgICA9IERFRkFVTFRfUFJPWFlMRVNTX1NFVFVQX09QVElPTlM7XG4gICAgICAgIHRoaXMuX3N0b3BwZWQgICAgICAgICAgICAgICAgID0gZmFsc2U7XG4gICAgICAgIHRoaXMuX2N1cnJlbnRGcmFtZVRyZWUgICAgICAgID0gbnVsbDtcbiAgICAgICAgdGhpcy5fZmFpbGVkUmVxdWVzdElkcyAgICAgICAgPSBbXTtcbiAgICAgICAgdGhpcy5yZXN0b3JpbmdTdG9yYWdlcyAgICAgICAgPSBudWxsO1xuICAgICAgICB0aGlzLmNvbnRleHRTdG9yYWdlICAgICAgICAgICA9IG51bGw7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBfZ2V0U3BlY2lhbFNlcnZpY2VSb3V0ZXMgKCk6IFNwZWNpYWxTZXJ2aWNlUm91dGVzIHtcbiAgICAgICAgY29uc3QgYnJvd3NlckNvbm5lY3Rpb24gPSB0aGlzLl90ZXN0UnVuQnJpZGdlLmdldEJyb3dzZXJDb25uZWN0aW9uKCk7XG4gICAgICAgIGNvbnN0IHByb3h5ICAgICAgICAgICAgID0gYnJvd3NlckNvbm5lY3Rpb24uYnJvd3NlckNvbm5lY3Rpb25HYXRld2F5LnByb3h5O1xuXG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICBlcnJvclBhZ2UxOiAgICAgICAgICBwcm94eS5yZXNvbHZlUmVsYXRpdmVTZXJ2aWNlVXJsKEVSUk9SX1JPVVRFLCBwcm94eS5zZXJ2ZXIxSW5mby5kb21haW4pLFxuICAgICAgICAgICAgZXJyb3JQYWdlMjogICAgICAgICAgcHJveHkucmVzb2x2ZVJlbGF0aXZlU2VydmljZVVybChFUlJPUl9ST1VURSwgcHJveHkuc2VydmVyMkluZm8uZG9tYWluKSxcbiAgICAgICAgICAgIGlkbGVQYWdlOiAgICAgICAgICAgIGJyb3dzZXJDb25uZWN0aW9uLmlkbGVVcmwsXG4gICAgICAgICAgICBvcGVuRmlsZVByb3RvY29sVXJsOiBicm93c2VyQ29ubmVjdGlvbi5vcGVuRmlsZVByb3RvY29sVXJsLFxuICAgICAgICB9O1xuICAgIH1cblxuICAgIHByaXZhdGUgYXN5bmMgX2hhbmRsZU1vY2tFcnJvcklmTmVjZXNzYXJ5IChwaXBlbGluZUNvbnRleHQ6IFByb3h5bGVzc1BpcGVsaW5lQ29udGV4dCwgZXZlbnQ6IFJlcXVlc3RQYXVzZWRFdmVudCk6IFByb21pc2U8dm9pZD4ge1xuICAgICAgICBpZiAoIXBpcGVsaW5lQ29udGV4dC5tb2NrLmhhc0Vycm9yKVxuICAgICAgICAgICAgcmV0dXJuO1xuXG4gICAgICAgIGF3YWl0IHBpcGVsaW5lQ29udGV4dC5oYW5kbGVNb2NrRXJyb3IodGhpcy5yZXF1ZXN0SG9va0V2ZW50UHJvdmlkZXIpO1xuXG4gICAgICAgIHJlcXVlc3RQaXBlbGluZU1vY2tMb2dnZXIoJyVzXFxuJXMnLCBldmVudC5uZXR3b3JrSWQsIHBpcGVsaW5lQ29udGV4dC5tb2NrLmVycm9yKTtcbiAgICB9XG5cbiAgICBwcml2YXRlIGFzeW5jIF9oYW5kbGVNb2NrUmVzcG9uc2UgKG1vY2tlZFJlc3BvbnNlOiBJbmNvbWluZ01lc3NhZ2VMaWtlLCBwaXBlbGluZUNvbnRleHQ6IFByb3h5bGVzc1BpcGVsaW5lQ29udGV4dCwgZXZlbnQ6IFJlcXVlc3RQYXVzZWRFdmVudCk6IFByb21pc2U8dm9pZD4ge1xuICAgICAgICBjb25zdCBtb2NrZWRSZXNwb25zZUJvZHlTdHIgPSAobW9ja2VkUmVzcG9uc2UuZ2V0Qm9keSgpIGFzIEJ1ZmZlcikudG9TdHJpbmcoKTtcblxuICAgICAgICBjb25zdCBmdWxmaWxsSW5mbyA9IHtcbiAgICAgICAgICAgIHJlcXVlc3RJZDogICAgICAgZXZlbnQucmVxdWVzdElkLFxuICAgICAgICAgICAgcmVzcG9uc2VDb2RlOiAgICBtb2NrZWRSZXNwb25zZS5zdGF0dXNDb2RlLFxuICAgICAgICAgICAgcmVzcG9uc2VIZWFkZXJzOiBjb252ZXJ0VG9IZWFkZXJFbnRyaWVzKG1vY2tlZFJlc3BvbnNlLmhlYWRlcnMpLFxuICAgICAgICAgICAgYm9keTogICAgICAgICAgICBtb2NrZWRSZXNwb25zZUJvZHlTdHIsXG4gICAgICAgIH07XG5cbiAgICAgICAgaWYgKHBpcGVsaW5lQ29udGV4dC5yZXFPcHRzLmlzQWpheClcbiAgICAgICAgICAgIGF3YWl0IHRoaXMuX3Jlc291cmNlSW5qZWN0b3IucHJvY2Vzc05vblByb3hpZWRDb250ZW50KGZ1bGZpbGxJbmZvLCB0aGlzLl9jbGllbnQpO1xuICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgIGF3YWl0IHRoaXMuX3Jlc291cmNlSW5qZWN0b3IucHJvY2Vzc0hUTUxQYWdlQ29udGVudChmdWxmaWxsSW5mbywge1xuICAgICAgICAgICAgICAgIGlzSWZyYW1lOiAgICAgICBmYWxzZSxcbiAgICAgICAgICAgICAgICBjb250ZXh0U3RvcmFnZTogdGhpcy5jb250ZXh0U3RvcmFnZSxcbiAgICAgICAgICAgIH0sIHRoaXMuX2NsaWVudCk7XG4gICAgICAgIH1cblxuICAgICAgICByZXF1ZXN0UGlwZWxpbmVNb2NrTG9nZ2VyKGBNb2NrIHJlcXVlc3QgJHtldmVudC5yZXF1ZXN0SWR9YCk7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBfY3JlYXRlQ29udGludWVSZXNwb25zZVJlcXVlc3QgKGV2ZW50OiBSZXF1ZXN0UGF1c2VkRXZlbnQsIG1vZGlmaWVkOiBib29sZWFuKTogQ29udGludWVSZXNwb25zZVJlcXVlc3Qge1xuICAgICAgICBjb25zdCBjb250aW51ZVJlc3BvbnNlUmVxdWVzdCA9IHtcbiAgICAgICAgICAgIHJlcXVlc3RJZDogZXZlbnQucmVxdWVzdElkLFxuICAgICAgICB9IGFzIENvbnRpbnVlUmVzcG9uc2VSZXF1ZXN0O1xuXG4gICAgICAgIGlmIChtb2RpZmllZCkge1xuICAgICAgICAgICAgY29udGludWVSZXNwb25zZVJlcXVlc3QucmVzcG9uc2VIZWFkZXJzID0gZXZlbnQucmVzcG9uc2VIZWFkZXJzO1xuICAgICAgICAgICAgY29udGludWVSZXNwb25zZVJlcXVlc3QucmVzcG9uc2VDb2RlICAgID0gZXZlbnQucmVzcG9uc2VTdGF0dXNDb2RlIGFzIG51bWJlcjtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiBjb250aW51ZVJlc3BvbnNlUmVxdWVzdDtcbiAgICB9XG5cbiAgICBwcml2YXRlIF9zaG91bGRSZWRpcmVjdFRvRXJyb3JQYWdlIChldmVudDogUmVxdWVzdFBhdXNlZEV2ZW50KTogYm9vbGVhbiB7XG4gICAgICAgIHJldHVybiBldmVudC5yZXNvdXJjZVR5cGUgPT09ICdEb2N1bWVudCdcbiAgICAgICAgICAgICYmICF0aGlzLl9pc0lmcmFtZShldmVudC5mcmFtZUlkKTtcbiAgICB9XG5cbiAgICBwcml2YXRlIGFzeW5jIF9nZXRVc2VyU2NyaXB0cyAoZXZlbnQ6IFJlcXVlc3RQYXVzZWRFdmVudCB8IEZyYW1lTmF2aWdhdGVkRXZlbnQpOiBQcm9taXNlPHN0cmluZ1tdPiB7XG4gICAgICAgIGNvbnN0IHsgcGlwZWxpbmVDb250ZXh0LCBldmVudEZhY3RvcnkgfSA9IHRoaXMuX2NvbnRleHRJbmZvLmdldENvbnRleHREYXRhKGV2ZW50KTtcblxuICAgICAgICBhd2FpdCBwaXBlbGluZUNvbnRleHQucHJlcGFyZUluamVjdGFibGVVc2VyU2NyaXB0cyhldmVudEZhY3RvcnksIHRoaXMuX3Rlc3RSdW5CcmlkZ2UuZ2V0VXNlclNjcmlwdHMoKSk7XG5cbiAgICAgICAgcmV0dXJuIHBpcGVsaW5lQ29udGV4dC5pbmplY3RhYmxlVXNlclNjcmlwdHM7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBhc3luYyBfcmVzcG9uZFRvT3RoZXJSZXF1ZXN0IChldmVudDogUmVxdWVzdFBhdXNlZEV2ZW50KTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICAgIGlmIChpc1JlZGlyZWN0U3RhdHVzQ29kZShldmVudC5yZXNwb25zZVN0YXR1c0NvZGUpKSB7XG4gICAgICAgICAgICBhd2FpdCBzYWZlQ29udGludWVSZXNwb25zZSh0aGlzLl9jbGllbnQsIHsgcmVxdWVzdElkOiBldmVudC5yZXF1ZXN0SWQgfSk7XG5cbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IHJlc291cmNlSW5mbyA9IGF3YWl0IHRoaXMuX3Jlc291cmNlSW5qZWN0b3IuZ2V0RG9jdW1lbnRSZXNvdXJjZUluZm8oZXZlbnQsIHRoaXMuX2NsaWVudCk7XG5cbiAgICAgICAgaWYgKHJlc291cmNlSW5mby5lcnJvcikge1xuICAgICAgICAgICAgaWYgKHRoaXMuX3Nob3VsZFJlZGlyZWN0VG9FcnJvclBhZ2UoZXZlbnQpKSB7XG4gICAgICAgICAgICAgICAgYXdhaXQgdGhpcy5fcmVzb3VyY2VJbmplY3Rvci5yZWRpcmVjdFRvRXJyb3JQYWdlKHRoaXMuX2NsaWVudCwgcmVzb3VyY2VJbmZvLmVycm9yLCBldmVudC5yZXF1ZXN0LnVybCk7XG5cbiAgICAgICAgICAgICAgICB0aGlzLl9jb250ZXh0SW5mby5kaXNwb3NlKGdldFJlcXVlc3RJZChldmVudCkpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICBjb25zdCBtb2RpZmllZCA9IGF3YWl0IHRoaXMucmVxdWVzdEhvb2tFdmVudFByb3ZpZGVyLm9uUmVzcG9uc2UoZXZlbnQsIHJlc291cmNlSW5mby5ib2R5LCB0aGlzLl9jb250ZXh0SW5mbywgdGhpcy5fY2xpZW50KTtcblxuICAgICAgICBpZiAoZXZlbnQucmVzb3VyY2VUeXBlICE9PSAnRG9jdW1lbnQnKSB7XG4gICAgICAgICAgICBjb25zdCBjb250aW51ZVJlc3BvbnNlUmVxdWVzdCA9IHRoaXMuX2NyZWF0ZUNvbnRpbnVlUmVzcG9uc2VSZXF1ZXN0KGV2ZW50LCBtb2RpZmllZCk7XG5cbiAgICAgICAgICAgIGF3YWl0IHNhZmVDb250aW51ZVJlc3BvbnNlKHRoaXMuX2NsaWVudCwgY29udGludWVSZXNwb25zZVJlcXVlc3QpO1xuXG4gICAgICAgICAgICB0aGlzLl9jb250ZXh0SW5mby5kaXNwb3NlKGdldFJlcXVlc3RJZChldmVudCkpO1xuICAgICAgICB9XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgY29uc3QgZnVsZmlsbEluZm8gPSB7XG4gICAgICAgICAgICAgICAgcmVxdWVzdElkOiAgICAgICBldmVudC5yZXF1ZXN0SWQsXG4gICAgICAgICAgICAgICAgcmVzcG9uc2VIZWFkZXJzOiBldmVudC5yZXNwb25zZUhlYWRlcnMsXG4gICAgICAgICAgICAgICAgcmVzcG9uc2VDb2RlOiAgICBldmVudC5yZXNwb25zZVN0YXR1c0NvZGUgYXMgbnVtYmVyLFxuICAgICAgICAgICAgICAgIGJvZHk6ICAgICAgICAgICAgKHJlc291cmNlSW5mby5ib2R5IGFzIEJ1ZmZlcikudG9TdHJpbmcoKSxcbiAgICAgICAgICAgIH0gYXMgRnVsZmlsbFJlcXVlc3RSZXF1ZXN0O1xuXG4gICAgICAgICAgICAvLyBOT1RFOiBTdHJhbmdlIGJlaGF2aW9yIG9mIHRoZSBDRFAgQVBJOlxuICAgICAgICAgICAgLy8gaWYgd2UgcGFzcyB0aGUgZW1wdHkgXCJyZXNwb25zZVN0YXR1c1RleHRcIiB2YWx1ZSwgd2UgZ2V0IGFuIGVycm9yICdJbnZhbGlkIHN0YXR1cyBjb2RlIG9yIHBocmFzZScuXG4gICAgICAgICAgICBpZiAoZXZlbnQucmVzcG9uc2VTdGF0dXNUZXh0ICE9PSAnJylcbiAgICAgICAgICAgICAgICBmdWxmaWxsSW5mby5yZXNwb25zZVBocmFzZSA9IGV2ZW50LnJlc3BvbnNlU3RhdHVzVGV4dDtcblxuICAgICAgICAgICAgaWYgKGlzVW5hdXRob3JpemVkKGV2ZW50LnJlc3BvbnNlU3RhdHVzQ29kZSBhcyBudW1iZXIpKVxuICAgICAgICAgICAgICAgIGF3YWl0IHRoaXMuX3RyeUF1dGhvcml6ZVdpdGhIdHRwQmFzaWNBdXRoQ3JlZGVudGlhbHMoZXZlbnQsIGZ1bGZpbGxJbmZvKTtcblxuICAgICAgICAgICAgY29uc3QgdXNlclNjcmlwdHMgPSBhd2FpdCB0aGlzLl9nZXRVc2VyU2NyaXB0cyhldmVudCk7XG5cbiAgICAgICAgICAgIGF3YWl0IHRoaXMuX3Jlc291cmNlSW5qZWN0b3IucHJvY2Vzc0hUTUxQYWdlQ29udGVudChcbiAgICAgICAgICAgICAgICBmdWxmaWxsSW5mbyxcbiAgICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgICAgIGlzSWZyYW1lOiAgICAgICAgICB0aGlzLl9pc0lmcmFtZShldmVudC5mcmFtZUlkKSxcbiAgICAgICAgICAgICAgICAgICAgdXJsOiAgICAgICAgICAgICAgIGV2ZW50LnJlcXVlc3QudXJsLFxuICAgICAgICAgICAgICAgICAgICByZXN0b3JpbmdTdG9yYWdlczogdGhpcy5yZXN0b3JpbmdTdG9yYWdlcyxcbiAgICAgICAgICAgICAgICAgICAgY29udGV4dFN0b3JhZ2U6ICAgIHRoaXMuY29udGV4dFN0b3JhZ2UsXG4gICAgICAgICAgICAgICAgICAgIHVzZXJTY3JpcHRzLFxuICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgdGhpcy5fY2xpZW50KTtcblxuICAgICAgICAgICAgdGhpcy5fY29udGV4dEluZm8uZGlzcG9zZShnZXRSZXF1ZXN0SWQoZXZlbnQpKTtcblxuICAgICAgICAgICAgdGhpcy5yZXN0b3JpbmdTdG9yYWdlcyA9IG51bGw7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBwcml2YXRlIGFzeW5jIF90cnlBdXRob3JpemVXaXRoSHR0cEJhc2ljQXV0aENyZWRlbnRpYWxzIChldmVudDogUmVxdWVzdFBhdXNlZEV2ZW50LCBmdWxmaWxsSW5mbzogRnVsZmlsbFJlcXVlc3RSZXF1ZXN0KTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICAgIGNvbnN0IGNyZWRlbnRpYWxzID0gdGhpcy5fdGVzdFJ1bi5nZXRBdXRoQ3JlZGVudGlhbHMoKTtcblxuICAgICAgICBpZiAoIWNyZWRlbnRpYWxzKVxuICAgICAgICAgICAgcmV0dXJuO1xuXG4gICAgICAgIGNvbnN0IGF1dGhSZXF1ZXN0ID0gYXdhaXQgcmVzZW5kQXV0aFJlcXVlc3QoZXZlbnQucmVxdWVzdCwgY3JlZGVudGlhbHMpO1xuXG4gICAgICAgIGlmICh0eXBlb2YgYXV0aFJlcXVlc3QgIT09ICdzdHJpbmcnICYmICFpc1VuYXV0aG9yaXplZChhdXRoUmVxdWVzdC5zdGF0dXMpKSB7XG4gICAgICAgICAgICBmdWxmaWxsSW5mby5yZXNwb25zZUNvZGUgPSBhdXRoUmVxdWVzdC5zdGF0dXM7XG4gICAgICAgICAgICBmdWxmaWxsSW5mby5ib2R5ID0gYXV0aFJlcXVlc3QuYm9keS50b1N0cmluZygpO1xuICAgICAgICAgICAgZnVsZmlsbEluZm8ucmVzcG9uc2VQaHJhc2UgPSBhdXRoUmVxdWVzdC5zdGF0dXNUZXh0O1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBhc3luYyBfdHJ5UmVzcG9uZFRvT3RoZXJSZXF1ZXN0IChldmVudDogUmVxdWVzdFBhdXNlZEV2ZW50KTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgICBhd2FpdCB0aGlzLl9yZXNwb25kVG9PdGhlclJlcXVlc3QoZXZlbnQpO1xuICAgICAgICB9XG4gICAgICAgIGNhdGNoIChlcnIpIHtcbiAgICAgICAgICAgIGlmIChldmVudC5uZXR3b3JrSWQgJiYgdGhpcy5fZmFpbGVkUmVxdWVzdElkcy5pbmNsdWRlcyhldmVudC5uZXR3b3JrSWQpKSB7XG4gICAgICAgICAgICAgICAgcmVtb3ZlKHRoaXMuX2ZhaWxlZFJlcXVlc3RJZHMsIGV2ZW50Lm5ldHdvcmtJZCk7XG5cbiAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHRocm93IGVycjtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHByaXZhdGUgYXN5bmMgX2hhbmRsZU90aGVyUmVxdWVzdHMgKGV2ZW50OiBSZXF1ZXN0UGF1c2VkRXZlbnQpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICAgICAgcmVxdWVzdFBpcGVsaW5lT3RoZXJSZXF1ZXN0TG9nZ2VyKCclcicsIGV2ZW50KTtcblxuICAgICAgICBpZiAoIWV2ZW50LnJlc3BvbnNlRXJyb3JSZWFzb24gJiYgKGlzUmVxdWVzdChldmVudCkgfHwgaXNSZWRpcmVjdFN0YXR1c0NvZGUoZXZlbnQucmVzcG9uc2VTdGF0dXNDb2RlKSkpIHtcbiAgICAgICAgICAgIHRoaXMuX2NvbnRleHRJbmZvLmluaXQoZXZlbnQpO1xuXG4gICAgICAgICAgICBhd2FpdCB0aGlzLnJlcXVlc3RIb29rRXZlbnRQcm92aWRlci5vblJlcXVlc3QoZXZlbnQsIHRoaXMuX2NvbnRleHRJbmZvKTtcblxuICAgICAgICAgICAgY29uc3QgcGlwZWxpbmVDb250ZXh0ID0gdGhpcy5fY29udGV4dEluZm8uZ2V0UGlwZWxpbmVDb250ZXh0KGV2ZW50Lm5ldHdvcmtJZCBhcyBzdHJpbmcpO1xuXG4gICAgICAgICAgICBpZiAoIXBpcGVsaW5lQ29udGV4dCB8fCAhcGlwZWxpbmVDb250ZXh0Lm1vY2spXG4gICAgICAgICAgICAgICAgYXdhaXQgc2FmZUNvbnRpbnVlUmVxdWVzdCh0aGlzLl9jbGllbnQsIGV2ZW50KTtcbiAgICAgICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgICAgIGNvbnN0IG1vY2tlZFJlc3BvbnNlID0gYXdhaXQgcGlwZWxpbmVDb250ZXh0LmdldE1vY2tSZXNwb25zZSgpO1xuXG4gICAgICAgICAgICAgICAgYXdhaXQgdGhpcy5faGFuZGxlTW9ja0Vycm9ySWZOZWNlc3NhcnkocGlwZWxpbmVDb250ZXh0LCBldmVudCk7XG5cbiAgICAgICAgICAgICAgICBjb25zdCBtb2NrZWRSZXNwb25zZUV2ZW50ID0gY3JlYXRlUmVxdWVzdFBhdXNlZEV2ZW50Rm9yUmVzcG9uc2UobW9ja2VkUmVzcG9uc2UsIGV2ZW50KTtcblxuICAgICAgICAgICAgICAgIGF3YWl0IHRoaXMucmVxdWVzdEhvb2tFdmVudFByb3ZpZGVyLm9uUmVzcG9uc2UobW9ja2VkUmVzcG9uc2VFdmVudCwgbW9ja2VkUmVzcG9uc2UuZ2V0Qm9keSgpLCB0aGlzLl9jb250ZXh0SW5mbywgdGhpcy5fY2xpZW50KTtcblxuICAgICAgICAgICAgICAgIGF3YWl0IHRoaXMuX2hhbmRsZU1vY2tSZXNwb25zZShtb2NrZWRSZXNwb25zZSwgcGlwZWxpbmVDb250ZXh0LCBldmVudCk7XG5cbiAgICAgICAgICAgICAgICB0aGlzLl9jb250ZXh0SW5mby5kaXNwb3NlKGdldFJlcXVlc3RJZChldmVudCkpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIGVsc2VcbiAgICAgICAgICAgIGF3YWl0IHRoaXMuX3RyeVJlc3BvbmRUb090aGVyUmVxdWVzdChldmVudCk7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBfdG9wRnJhbWVOYXZpZ2F0aW9uIChldmVudDogRnJhbWVOYXZpZ2F0ZWRFdmVudCk6IGJvb2xlYW4ge1xuICAgICAgICByZXR1cm4gZXZlbnQudHlwZSA9PT0gJ05hdmlnYXRpb24nXG4gICAgICAgICAgICAmJiAhZXZlbnQuZnJhbWUucGFyZW50SWQ7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBhc3luYyBfdXBkYXRlQ3VycmVudEZyYW1lVHJlZSAoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICAgIC8vIE5PVEU6IER1ZSB0byBDRFAgcmVzdHJpY3Rpb25zIChpdCBoYW5ncyksIHdlIGNhbid0IGdldCB0aGUgZnJhbWUgdHJlZVxuICAgICAgICAvLyByaWdodCBiZWZvcmUgaW5qZWN0aW5nIHNlcnZpY2Ugc2NyaXB0cy5cbiAgICAgICAgLy8gU28sIHdlIGFyZSBmb3JjZWQgdHJhY2tpbmcgZnJhbWVzIHRyZWUuXG4gICAgICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IHRoaXMuX2NsaWVudC5QYWdlLmdldEZyYW1lVHJlZSgpO1xuXG4gICAgICAgIHRoaXMuX2N1cnJlbnRGcmFtZVRyZWUgPSByZXN1bHQuZnJhbWVUcmVlO1xuICAgIH1cblxuICAgIHByaXZhdGUgX2lzSWZyYW1lIChmcmFtZUlkOiBzdHJpbmcpOiBib29sZWFuIHtcbiAgICAgICAgaWYgKCF0aGlzLl9jdXJyZW50RnJhbWVUcmVlKVxuICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuXG4gICAgICAgIHJldHVybiB0aGlzLl9jdXJyZW50RnJhbWVUcmVlLmZyYW1lLmlkICE9PSBmcmFtZUlkO1xuICAgIH1cblxuICAgIHB1YmxpYyBhc3luYyBpbml0IChvcHRpb25zPzogUHJveHlsZXNzU2V0dXBPcHRpb25zKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICAgIHRoaXMuX29wdGlvbnMgPSBvcHRpb25zIGFzIFByb3h5bGVzc1NldHVwT3B0aW9ucztcblxuICAgICAgICB0aGlzLl9jbGllbnQuRmV0Y2gub24oJ3JlcXVlc3RQYXVzZWQnLCBhc3luYyAoZXZlbnQ6IFJlcXVlc3RQYXVzZWRFdmVudCkgPT4ge1xuICAgICAgICAgICAgaWYgKHRoaXMuX3N0b3BwZWQpXG4gICAgICAgICAgICAgICAgcmV0dXJuO1xuXG4gICAgICAgICAgICBjb25zdCBzcGVjaWFsUmVxdWVzdEhhbmRsZXIgPSBnZXRTcGVjaWFsUmVxdWVzdEhhbmRsZXIoZXZlbnQsIHRoaXMuX29wdGlvbnMsIHRoaXMuX3NwZWNpYWxTZXJ2aWNlUm91dGVzKTtcblxuICAgICAgICAgICAgaWYgKHNwZWNpYWxSZXF1ZXN0SGFuZGxlcilcbiAgICAgICAgICAgICAgICBhd2FpdCBzcGVjaWFsUmVxdWVzdEhhbmRsZXIoZXZlbnQsIHRoaXMuX2NsaWVudCwgdGhpcy5fb3B0aW9ucyk7XG4gICAgICAgICAgICBlbHNlXG4gICAgICAgICAgICAgICAgYXdhaXQgdGhpcy5faGFuZGxlT3RoZXJSZXF1ZXN0cyhldmVudCk7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIHRoaXMuX2NsaWVudC5QYWdlLm9uKCdmcmFtZU5hdmlnYXRlZCcsIGFzeW5jIChldmVudDogRnJhbWVOYXZpZ2F0ZWRFdmVudCkgPT4ge1xuICAgICAgICAgICAgcmVxdWVzdFBpcGVsaW5lTG9nZ2VyKCclZicsIGV2ZW50KTtcblxuICAgICAgICAgICAgaWYgKCF0aGlzLl90b3BGcmFtZU5hdmlnYXRpb24oZXZlbnQpXG4gICAgICAgICAgICAgICAgfHwgZXZlbnQuZnJhbWUudXJsICE9PSBTUEVDSUFMX0JMQU5LX1BBR0UpXG4gICAgICAgICAgICAgICAgcmV0dXJuO1xuXG4gICAgICAgICAgICB0aGlzLl9jb250ZXh0SW5mby5pbml0KGV2ZW50KTtcblxuICAgICAgICAgICAgY29uc3QgdXNlclNjcmlwdHMgPSBhd2FpdCB0aGlzLl9nZXRVc2VyU2NyaXB0cyhldmVudCk7XG5cbiAgICAgICAgICAgIGF3YWl0IHRoaXMuX3Jlc291cmNlSW5qZWN0b3IucHJvY2Vzc0Fib3V0QmxhbmtQYWdlKGV2ZW50LCB1c2VyU2NyaXB0cywgdGhpcy5fY2xpZW50KTtcblxuICAgICAgICAgICAgdGhpcy5fY29udGV4dEluZm8uZGlzcG9zZShnZXRSZXF1ZXN0SWQoZXZlbnQpKTtcbiAgICAgICAgfSk7XG5cbiAgICAgICAgdGhpcy5fY2xpZW50LlBhZ2Uub24oJ2ZyYW1lU3RhcnRlZExvYWRpbmcnLCBhc3luYyAoKSA9PiB7XG4gICAgICAgICAgICBhd2FpdCB0aGlzLl91cGRhdGVDdXJyZW50RnJhbWVUcmVlKCk7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIHRoaXMuX2NsaWVudC5OZXR3b3JrLm9uKCdsb2FkaW5nRmFpbGVkJywgYXN5bmMgKGV2ZW50OiBMb2FkaW5nRmFpbGVkRXZlbnQpID0+IHtcbiAgICAgICAgICAgIHJlcXVlc3RQaXBlbGluZUxvZ2dlcignJWwnLCBldmVudCk7XG5cbiAgICAgICAgICAgIHRoaXMuX2ZhaWxlZFJlcXVlc3RJZHMucHVzaChldmVudC5yZXF1ZXN0SWQpO1xuXG4gICAgICAgICAgICBpZiAoZXZlbnQucmVxdWVzdElkKVxuICAgICAgICAgICAgICAgIHRoaXMuX2NvbnRleHRJbmZvLmRpc3Bvc2UoZXZlbnQucmVxdWVzdElkKTtcbiAgICAgICAgfSk7XG5cbiAgICAgICAgYXdhaXQgdGhpcy5fY2xpZW50LlBhZ2Uuc2V0QnlwYXNzQ1NQKHsgZW5hYmxlZDogdHJ1ZSB9KTtcbiAgICB9XG5cbiAgICBwdWJsaWMgc3RvcCAoKTogdm9pZCB7XG4gICAgICAgIHRoaXMuX3N0b3BwZWQgPSB0cnVlO1xuICAgIH1cbn1cbiJdfQ==
|