UNPKG

serverless-spy

Version:

CDK-based library for writing elegant integration tests on AWS serverless architecture and an additional web console to monitor events in real time.

232 lines 35.3 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.WsListener = void 0; const iot_connection_1 = require("./iot-connection"); const topic_1 = require("./topic"); class WsListener { constructor() { this.messages = []; this.trackers = []; this.closed = true; this.functionPrefix = 'waitFor'; this.debugMode = false; this.fragments = new Map(); } async start(params) { this.debugMode = !!params.debugMode; try { this.connection = await (0, iot_connection_1.getConnection)(this.debugMode, params.serverlessSpyWsUrl); this.closed = false; const topic = (0, topic_1.getTopic)(params.scope || '#'); this.log(`Subscribing to topic ${topic}`); const connectionOpenResolve = this.connectionOpenResolve || params.connectionOpenResolve; const localConnection = this.connection; this.connection.on('connect', () => { this.closed = false; this.log('Connection opened'); localConnection.subscribe(topic); if (connectionOpenResolve) { connectionOpenResolve(); } }); this.connection.on('message', (_topic, data) => { if (this.closed) return; this.log('Message received', data.toString()); const fragment = JSON.parse(data.toString()); let message = undefined; if (!fragment.id) { message = JSON.parse(fragment.data); } let pending = this.fragments.get(fragment.id); if (!pending) { pending = new Map(); this.fragments.set(fragment.id, pending); } pending.set(fragment.index, fragment); if (pending.size === fragment.count) { const data = [...pending.values()] .sort((a, b) => a.index - b.index) .map((item) => item.data) .join(''); this.fragments.delete(fragment.id); message = JSON.parse(data); } if (message) { message.serviceKeyForFunction = message.serviceKey.replace(/#/g, ''); if (message.serviceKey.startsWith('Function')) { message.functionContextAwsRequestId = message.data.context.awsRequestId; } this.messages.push(message); this.resolveOldTrackerWithNewMessage(message); } }); this.connection.on('close', () => { this.log('Connection closed'); this.closed = true; }); const connectionOpenReject = this.connectionOpenReject || params.connectionOpenReject; this.connection.on('error', (error) => { this.log('Connection error:', error); connectionOpenReject?.(error); }); } catch (e) { console.error('Failed to get connection', e); throw e; } } async stop() { this.closed = true; this.connection.end(true); } trackerMatchMessage(tracker, message) { if (tracker.finished) return; if ((tracker.serviceKey && tracker.serviceKey === message.serviceKey) || (tracker.serviceKeyForFunction && tracker.serviceKeyForFunction === message.serviceKeyForFunction)) { if (this.trackerMatchCondition(tracker, message)) { tracker.finished = true; const spyAndJestMatchers = { getData: () => message.data, }; const serviceKeyForFunction = tracker.serviceKeyForFunction; if (serviceKeyForFunction && serviceKeyForFunction.startsWith('Function') && (serviceKeyForFunction.endsWith('Request') || serviceKeyForFunction.endsWith('Console'))) { let serviceKeyForFunctionChain = serviceKeyForFunction; if (serviceKeyForFunctionChain.endsWith('Request')) { serviceKeyForFunctionChain = serviceKeyForFunctionChain.substring(0, serviceKeyForFunctionChain.length - 'Request'.length); } else if (serviceKeyForFunctionChain.endsWith('Console')) { serviceKeyForFunctionChain = serviceKeyForFunctionChain.substring(0, serviceKeyForFunctionChain.length - 'Console'.length); } spyAndJestMatchers.followedByConsole = (paramsW) => { return this.createWaitForXXXFunc(`${serviceKeyForFunctionChain}Console`, message.data.context.awsRequestId)(paramsW); }; spyAndJestMatchers.followedByResponse = (paramsW) => { return this.createWaitForXXXFunc(`${serviceKeyForFunctionChain}Response`, message.data.context.awsRequestId)(paramsW); }; } const proxy = new Proxy(spyAndJestMatchers, { get: function (target, objectKey) { if (target.hasOwnProperty(objectKey)) { return target[objectKey]; } else if (objectKey !== 'then') { return function () { const jestFunctionToExecute = expect(message.data)[objectKey]; jestFunctionToExecute.apply(undefined, arguments); return proxy; }; } }, }); tracker.promiseResolve(proxy); return true; } } return false; } resolveTrackerInOldMessages(tracker) { for (const message of this.messages) { if (this.trackerMatchMessage(tracker, message)) { return true; } } return false; } resolveOldTrackerWithNewMessage(message) { for (let index = 0; index < this.trackers.length; index++) { const tracker = this.trackers[index]; if (this.trackerMatchMessage(tracker, message)) { this.trackers = this.trackers.splice(index, 1); return true; } } return false; } trackerMatchCondition(tracker, message) { const matchCondition = (tracker.condition && tracker.condition(message.data)) || !tracker.condition; const matchRequestId = (tracker.functionContextAwsRequestId && tracker.functionContextAwsRequestId === message.functionContextAwsRequestId) || !tracker.functionContextAwsRequestId; if (matchCondition && matchRequestId) { return true; } else { if (!matchCondition && matchRequestId && !tracker.possibleSpyMessageDataForDebugging) { tracker.possibleSpyMessageDataForDebugging = message.data; } return false; } } createWaitForXXXFunc(serviceKeyForFunction, functionContextAwsRequestId) { return (paramsW) => { let resolve; const promise = new Promise((res) => { resolve = res; }); const tracker = { finished: false, // @ts-ignore promiseResolve: resolve, serviceKeyForFunction, functionContextAwsRequestId, }; tracker.condition = paramsW?.condition; let timeoutPid; const timer = new Promise((_, reject) => { timeoutPid = setTimeout(() => { if (tracker.finished) return; tracker.finished = true; let message = `Timeout waiting for Serverless Spy message ${serviceKeyForFunction}.`; if (tracker.possibleSpyMessageDataForDebugging) { message += ` Similar matching spy event data: ${JSON.stringify(tracker.possibleSpyMessageDataForDebugging, null, 2)}`; } reject(new Error(message)); }, paramsW?.timoutMs || 10000); }); if (!this.resolveTrackerInOldMessages(tracker)) { this.trackers.push(tracker); } return Promise.race([promise, timer]).finally(() => { if (!!timeoutPid) { clearTimeout(timeoutPid); } }); }; } createProxy() { const spyListener = {}; spyListener.stop = async () => { await this.stop(); }; return new Proxy(spyListener, { get: (target, objectKey) => { if (target.hasOwnProperty(objectKey)) { return target[objectKey].bind(target); } else if (typeof objectKey === 'string' && objectKey.startsWith(this.functionPrefix)) { const serviceKeyForFunction = objectKey.substring(this.functionPrefix.length); return this.createWaitForXXXFunc(serviceKeyForFunction); } }, }); } log(message, ...optionalParams) { if (this.debugMode && !this.closed) { console.debug('SSPY', message, new Date().toISOString(), ...optionalParams); } } } exports.WsListener = WsListener; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiV3NMaXN0ZW5lci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL2xpc3RlbmVyL1dzTGlzdGVuZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBQ0EscURBQTJEO0FBRzNELG1DQUFtQztBQUtuQyxNQUFhLFVBQVU7SUFBdkI7UUFDVSxhQUFRLEdBQXdCLEVBQUUsQ0FBQztRQUNuQyxhQUFRLEdBQWMsRUFBRSxDQUFDO1FBSXpCLFdBQU0sR0FBRyxJQUFJLENBQUM7UUFDZCxtQkFBYyxHQUFHLFNBQVMsQ0FBQztRQUMzQixjQUFTLEdBQUcsS0FBSyxDQUFDO1FBR2xCLGNBQVMsR0FBRyxJQUFJLEdBQUcsRUFBaUMsQ0FBQztJQW1TL0QsQ0FBQztJQWpTUSxLQUFLLENBQUMsS0FBSyxDQUFDLE1BQW1DO1FBQ3BELElBQUksQ0FBQyxTQUFTLEdBQUcsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxTQUFTLENBQUM7UUFDcEMsSUFBSSxDQUFDO1lBQ0gsSUFBSSxDQUFDLFVBQVUsR0FBRyxNQUFNLElBQUEsOEJBQWEsRUFDbkMsSUFBSSxDQUFDLFNBQVMsRUFDZCxNQUFNLENBQUMsa0JBQWtCLENBQzFCLENBQUM7WUFDRixJQUFJLENBQUMsTUFBTSxHQUFHLEtBQUssQ0FBQztZQUNwQixNQUFNLEtBQUssR0FBRyxJQUFBLGdCQUFRLEVBQUMsTUFBTSxDQUFDLEtBQUssSUFBSSxHQUFHLENBQUMsQ0FBQztZQUM1QyxJQUFJLENBQUMsR0FBRyxDQUFDLHdCQUF3QixLQUFLLEVBQUUsQ0FBQyxDQUFDO1lBQzFDLE1BQU0scUJBQXFCLEdBQ3pCLElBQUksQ0FBQyxxQkFBcUIsSUFBSSxNQUFNLENBQUMscUJBQXFCLENBQUM7WUFDN0QsTUFBTSxlQUFlLEdBQUcsSUFBSSxDQUFDLFVBQVUsQ0FBQztZQUN4QyxJQUFJLENBQUMsVUFBVSxDQUFDLEVBQUUsQ0FBQyxTQUFTLEVBQUUsR0FBRyxFQUFFO2dCQUNqQyxJQUFJLENBQUMsTUFBTSxHQUFHLEtB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QUcsQ0FBQyxPQUFlLEVBQUUsR0FBRyxjQUFxQjtRQUNuRCxJQUFJLElBQUksQ0FBQyxTQUFTLElBQUksQ0FBQyxJQUFJLENBQUMsTUFBTSxFQUFFLENBQUM7WUFDbkMsT0FBTyxDQUFDLEtBQUssQ0FDWCxNQUFNLEVBQ04sT0FBTyxFQUNQLElBQUksSUFBSSxFQUFFLENBQUMsV0FBVyxFQUFFLEVBQ3hCLEdBQUcsY0FBYyxDQUNsQixDQUFDO1FBQ0osQ0FBQztJQUNILENBQUM7Q0FDRjtBQTlTRCxnQ0E4U0MiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBkZXZpY2UgfSBmcm9tICdhd3MtaW90LWRldmljZS1zZGsnO1xuaW1wb3J0IHsgZnJhZ21lbnQsIGdldENvbm5lY3Rpb24gfSBmcm9tICcuL2lvdC1jb25uZWN0aW9uJztcbmltcG9ydCB7IFNlcnZlcmxlc3NTcHlMaXN0ZW5lciB9IGZyb20gJy4vU2VydmVybGVzc1NweUxpc3RlbmVyJztcbmltcG9ydCB7IFNlcnZlcmxlc3NTcHlMaXN0ZW5lclBhcmFtcyB9IGZyb20gJy4vU2VydmVybGVzc1NweUxpc3RlbmVyUGFyYW1zJztcbmltcG9ydCB7IGdldFRvcGljIH0gZnJvbSAnLi90b3BpYyc7XG5pbXBvcnQgeyBXYWl0Rm9yUGFyYW1zIH0gZnJvbSAnLi9XYWl0Rm9yUGFyYW1zJztcbmltcG9ydCB7IEZ1bmN0aW9uUmVxdWVzdFNweUV2ZW50IH0gZnJvbSAnLi4vY29tbW9uL3NweUV2ZW50cy9GdW5jdGlvblJlcXVlc3RTcHlFdmVudCc7XG5pbXBvcnQgeyBTcHlNZXNzYWdlIH0gZnJvbSAnLi4vY29tbW9uL3NweUV2ZW50cy9TcHlNZXNzYWdlJztcblxuZXhwb3J0IGNsYXNzIFdzTGlzdGVuZXI8VFNweUV2ZW50cz4ge1xuICBwcml2YXRlIG1lc3NhZ2VzOiBTcHlNZXNzYWdlU3RvcmFnZVtdID0gW107XG4gIHByaXZhdGUgdHJhY2tlcnM6IFRyYWNrZXJbXSA9IFtdO1xuXG4gIHByaXZhdGUgY29ubmVjdGlvbk9wZW5SZXNvbHZlPzogKCkgPT4gdm9pZDtcbiAgcHJpdmF0ZSBjb25uZWN0aW9uT3BlblJlamVjdD86IChyZWFzb24/OiBhbnkpID0+IHZvaWQ7XG4gIHByaXZhdGUgY2xvc2VkID0gdHJ1ZTtcbiAgcHJpdmF0ZSBmdW5jdGlvblByZWZpeCA9ICd3YWl0Rm9yJztcbiAgcHJpdmF0ZSBkZWJ1Z01vZGUgPSBmYWxzZTtcbiAgcHJpdmF0ZSBjb25uZWN0aW9uOiBkZXZpY2UgfCB1bmRlZmluZWQ7XG5cbiAgcHJpdmF0ZSBmcmFnbWVudHMgPSBuZXcgTWFwPHN0cmluZywgTWFwPG51bWJlciwgZnJhZ21lbnQ+PigpO1xuXG4gIHB1YmxpYyBhc3luYyBzdGFydChwYXJhbXM6IFNlcnZlcmxlc3NTcHlMaXN0ZW5lclBhcmFtcykge1xuICAgIHRoaXMuZGVidWdNb2RlID0gISFwYXJhbXMuZGVidWdNb2RlO1xuICAgIHRyeSB7XG4gICAgICB0aGlzLmNvbm5lY3Rpb24gPSBhd2FpdCBnZXRDb25uZWN0aW9uKFxuICAgICAgICB0aGlzLmRlYnVnTW9kZSxcbiAgICAgICAgcGFyYW1zLnNlcnZlcmxlc3NTcHlXc1VybFxuICAgICAgKTtcbiAgICAgIHRoaXMuY2xvc2VkID0gZmFsc2U7XG4gICAgICBjb25zdCB0b3BpYyA9IGdldFRvcGljKHBhcmFtcy5zY29wZSB8fCAnIycpO1xuICAgICAgdGhpcy5sb2coYFN1YnNjcmliaW5nIHRvIHRvcGljICR7dG9waWN9YCk7XG4gICAgICBjb25zdCBjb25uZWN0aW9uT3BlblJlc29sdmUgPVxuICAgICAgICB0aGlzLmNvbm5lY3Rpb25PcGVuUmVzb2x2ZSB8fCBwYXJhbXMuY29ubmVjdGlvbk9wZW5SZXNvbHZlO1xuICAgICAgY29uc3QgbG9jYWxDb25uZWN0aW9uID0gdGhpcy5jb25uZWN0aW9uO1xuICAgICAgdGhpcy5jb25uZWN0aW9uLm9uKCdjb25uZWN0JywgKCkgPT4ge1xuICAgICAgICB0aGlzLmNsb3NlZCA9IGZhbHNlO1xuICAgICAgICB0aGlzLmxvZygnQ29ubmVjdGlvbiBvcGVuZWQnKTtcbiAgICAgICAgbG9jYWxDb25uZWN0aW9uLnN1YnNjcmliZSh0b3BpYyk7XG4gICAgICAgIGlmIChjb25uZWN0aW9uT3BlblJlc29sdmUpIHtcbiAgICAgICAgICBjb25uZWN0aW9uT3BlblJlc29sdmUoKTtcbiAgICAgICAgfVxuICAgICAgfSk7XG4gICAgICB0aGlzLmNvbm5lY3Rpb24ub24oJ21lc3NhZ2UnLCAoX3RvcGljOiBzdHJpbmcsIGRhdGE6IEJ1ZmZlcikgPT4ge1xuICAgICAgICBpZiAodGhpcy5jbG9zZWQpIHJldHVybjtcblxuICAgICAgICB0aGlzLmxvZygnTWVzc2FnZSByZWNlaXZlZCcsIGRhdGEudG9TdHJpbmcoKSk7XG4gICAgICAgIGNvbnN0IGZyYWdtZW50ID0gSlNPTi5wYXJzZShkYXRhLnRvU3RyaW5nKCkpO1xuICAgICAgICBsZXQgbWVzc2FnZTogU3B5TWVzc2FnZVN0b3JhZ2UgfCB1bmRlZmluZWQgPSB1bmRlZmluZWQ7XG4gICAgICAgIGlmICghZnJhZ21lbnQuaWQpIHtcbiAgICAgICAgICBtZXNzYWdlID0gSlNPTi5wYXJzZShmcmFnbWVudC5kYXRhKSBhcyBTcHlNZXNzYWdlU3RvcmFnZTtcbiAgICAgICAgfVxuXG4gICAgICAgIGxldCBwZW5kaW5nID0gdGhpcy5mcmFnbWVudHMuZ2V0KGZyYWdtZW50LmlkKTtcbiAgICAgICAgaWYgKCFwZW5kaW5nKSB7XG4gICAgICAgICAgcGVuZGluZyA9IG5ldyBNYXAoKTtcbiAgICAgICAgICB0aGlzLmZyYWdtZW50cy5zZXQoZnJhZ21lbnQuaWQsIHBlbmRpbmcpO1xuICAgICAgICB9XG4gICAgICAgIHBlbmRpbmcuc2V0KGZyYWdtZW50LmluZGV4LCBmcmFnbWVudCk7XG5cbiAgICAgICAgaWYgKHBlbmRpbmcuc2l6ZSA9PT0gZnJhZ21lbnQuY291bnQpIHtcbiAgICAgICAgICBjb25zdCBkYXRhID0gWy4uLnBlbmRpbmcudmFsdWVzKCldXG4gICAgICAgICAgICAuc29ydCgoYSwgYikgPT4gYS5pbmRleCAtIGIuaW5kZXgpXG4gICAgICAgICAgICAubWFwKChpdGVtKSA9PiBpdGVtLmRhdGEpXG4gICAgICAgICAgICAuam9pbignJyk7XG4gICAgICAgICAgdGhpcy5mcmFnbWVudHMuZGVsZXRlKGZyYWdtZW50LmlkKTtcbiAgICAgICAgICBtZXNzYWdlID0gSlNPTi5wYXJzZShkYXRhKSBhcyBTcHlNZXNzYWdlU3RvcmFnZTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChtZXNzYWdlKSB7XG4gICAgICAgICAgbWVzc2FnZS5zZXJ2aWNlS2V5Rm9yRnVuY3Rpb24gPSBtZXNzYWdlLnNlcnZpY2VLZXkucmVwbGFjZSgvIy9nLCAnJyk7XG5cbiAgICAgICAgICBpZiAobWVzc2FnZS5zZXJ2aWNlS2V5LnN0YXJ0c1dpdGgoJ0Z1bmN0aW9uJykpIHtcbiAgICAgICAgICAgIG1lc3NhZ2UuZnVuY3Rpb25Db250ZXh0QXdzUmVxdWVzdElkID0gKFxuICAgICAgICAgICAgICBtZXNzYWdlLmRhdGEgYXMgRnVuY3Rpb25SZXF1ZXN0U3B5RXZlbnRcbiAgICAgICAgICAgICkuY29udGV4dC5hd3NSZXF1ZXN0SWQ7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgdGhpcy5tZXNzYWdlcy5wdXNoKG1lc3NhZ2UpO1xuICAgICAgICAgIHRoaXMucmVzb2x2ZU9sZFRyYWNrZXJXaXRoTmV3TWVzc2FnZShtZXNzYWdlKTtcbiAgICAgICAgfVxuICAgICAgfSk7XG4gICAgICB0aGlzLmNvbm5lY3Rpb24ub24oJ2Nsb3NlJywgKCkgPT4ge1xuICAgICAgICB0aGlzLmxvZygnQ29ubmVjdGlvbiBjbG9zZWQnKTtcblxuICAgICAgICB0aGlzLmNsb3NlZCA9IHRydWU7XG4gICAgICB9KTtcblxuICAgICAgY29uc3QgY29ubmVjdGlvbk9wZW5SZWplY3QgPVxuICAgICAgICB0aGlzLmNvbm5lY3Rpb25PcGVuUmVqZWN0IHx8IHBhcmFtcy5jb25uZWN0aW9uT3BlblJlamVjdDtcbiAgICAgIHRoaXMuY29ubmVjdGlvbi5vbignZXJyb3InLCAoZXJyb3IpID0+IHtcbiAgICAgICAgdGhpcy5sb2coJ0Nvbm5lY3Rpb24gZXJyb3I6JywgZXJyb3IpO1xuICAgICAgICBjb25uZWN0aW9uT3BlblJlamVjdD8uKGVycm9yKTtcbiAgICAgIH0pO1xuICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgIGNvbnNvbGUuZXJyb3IoJ0ZhaWxlZCB0byBnZXQgY29ubmVjdGlvbicsIGUpO1xuICAgICAgdGhyb3cgZTtcbiAgICB9XG4gIH1cblxuICBwdWJsaWMgYXN5bmMgc3RvcCgpIHtcbiAgICB0aGlzLmNsb3NlZCA9IHRydWU7XG4gICAgdGhpcy5jb25uZWN0aW9uIS5lbmQodHJ1ZSk7XG4gIH1cblxuICBwcml2YXRlIHRyYWNrZXJNYXRjaE1lc3NhZ2UodHJhY2tlcjogVHJhY2tlciwgbWVzc2FnZTogU3B5TWVzc2FnZVN0b3JhZ2UpIHtcbiAgICBpZiAodHJhY2tlci5maW5pc2hlZCkgcmV0dXJuO1xuXG4gICAgaWYgKFxuICAgICAgKHRyYWNrZXIuc2VydmljZUtleSAmJiB0cmFja2VyLnNlcnZpY2VLZXkgPT09IG1lc3NhZ2Uuc2VydmljZUtleSkgfHxcbiAgICAgICh0cmFja2VyLnNlcnZpY2VLZXlGb3JGdW5jdGlvbiAmJlxuICAgICAgICB0cmFja2VyLnNlcnZpY2VLZXlGb3JGdW5jdGlvbiA9PT0gbWVzc2FnZS5zZXJ2aWNlS2V5Rm9yRnVuY3Rpb24pXG4gICAgKSB7XG4gICAgICBpZiAodGhpcy50cmFja2VyTWF0Y2hDb25kaXRpb24odHJhY2tlciwgbWVzc2FnZSkpIHtcbiAgICAgICAgdHJhY2tlci5maW5pc2hlZCA9IHRydWU7XG5cbiAgICAgICAgY29uc3Qgc3B5QW5kSmVzdE1hdGNoZXJzOiBhbnkgPSB7XG4gICAgICAgICAgZ2V0RGF0YTogKCkgPT4gbWVzc2FnZS5kYXRhLFxuICAgICAgICB9O1xuXG4gICAgICAgIGNvbnN0IHNlcnZpY2VLZXlGb3JGdW5jdGlvbiA9IHRyYWNrZXIuc2VydmljZUtleUZvckZ1bmN0aW9uO1xuICAgICAgICBpZiAoXG4gICAgICAgICAgc2VydmljZUtleUZvckZ1bmN0aW9uICYmXG4gICAgICAgICAgc2VydmljZUtleUZvckZ1bmN0aW9uLnN0YXJ0c1dpdGgoJ0Z1bmN0aW9uJykgJiZcbiAgICAgICAgICAoc2VydmljZUtleUZvckZ1bmN0aW9uLmVuZHNXaXRoKCdSZXF1ZXN0JykgfHxcbiAgICAgICAgICAgIHNlcnZpY2VLZXlGb3JGdW5jdGlvbi5lbmRzV2l0aCgnQ29uc29sZScpKVxuICAgICAgICApIHtcbiAgICAgICAgICBsZXQgc2VydmljZUtleUZvckZ1bmN0aW9uQ2hhaW4gPSBzZXJ2aWNlS2V5Rm9yRnVuY3Rpb247XG5cbiAgICAgICAgICBpZiAoc2VydmljZUtleUZvckZ1bmN0aW9uQ2hhaW4uZW5kc1dpdGgoJ1JlcXVlc3QnKSkge1xuICAgICAgICAgICAgc2VydmljZUtleUZvckZ1bmN0aW9uQ2hhaW4gPSBzZXJ2aWNlS2V5Rm9yRnVuY3Rpb25DaGFpbi5zdWJzdHJpbmcoXG4gICAgICAgICAgICAgIDAsXG4gICAgICAgICAgICAgIHNlcnZpY2VLZXlGb3JGdW5jdGlvbkNoYWluLmxlbmd0aCAtICdSZXF1ZXN0Jy5sZW5ndGhcbiAgICAgICAgICAgICk7XG4gICAgICAgICAgfSBlbHNlIGlmIChzZXJ2aWNlS2V5Rm9yRnVuY3Rpb25DaGFpbi5lbmRzV2l0aCgnQ29uc29sZScpKSB7XG4gICAgICAgICAgICBzZXJ2aWNlS2V5Rm9yRnVuY3Rpb25DaGFpbiA9IHNlcnZpY2VLZXlGb3JGdW5jdGlvbkNoYWluLnN1YnN0cmluZyhcbiAgICAgICAgICAgICAgMCxcbiAgICAgICAgICAgICAgc2VydmljZUtleUZvckZ1bmN0aW9uQ2hhaW4ubGVuZ3RoIC0gJ0NvbnNvbGUnLmxlbmd0aFxuICAgICAgICAgICAgKTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICBzcHlBbmRKZXN0TWF0Y2hlcnMuZm9sbG93ZWRCeUNvbnNvbGUgPSAocGFyYW1zVzogV2FpdEZvclBhcmFtcykgPT4ge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMuY3JlYXRlV2FpdEZvclhYWEZ1bmMoXG4gICAgICAgICAgICAgIGAke3NlcnZpY2VLZXlGb3JGdW5jdGlvbkNoYWlufUNvbnNvbGVgLFxuICAgICAgICAgICAgICAobWVzc2FnZS5kYXRhIGFzIEZ1bmN0aW9uUmVxdWVzdFNweUV2ZW50KS5jb250ZXh0LmF3c1JlcXVlc3RJZFxuICAgICAgICAgICAgKShwYXJhbXNXKTtcbiAgICAgICAgICB9O1xuXG4gICAgICAgICAgc3B5QW5kSmVzdE1hdGNoZXJzLmZvbGxvd2VkQnlSZXNwb25zZSA9IChwYXJhbXNXOiBXYWl0Rm9yUGFyYW1zKSA9PiB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5jcmVhdGVXYWl0Rm9yWFhYRnVuYyhcbiAgICAgICAgICAgICAgYCR7c2VydmljZUtleUZvckZ1bmN0aW9uQ2hhaW59UmVzcG9uc2VgLFxuICAgICAgICAgICAgICAobWVzc2FnZS5kYXRhIGFzIEZ1bmN0aW9uUmVxdWVzdFNweUV2ZW50KS5jb250ZXh0LmF3c1JlcXVlc3RJZFxuICAgICAgICAgICAgKShwYXJhbXNXKTtcbiAgICAgICAgICB9O1xuICAgICAgICB9XG5cbiAgICAgICAgY29uc3QgcHJveHkgPSBuZXcgUHJveHkoc3B5QW5kSmVzdE1hdGNoZXJzLCB7XG4gICAgICAgICAgZ2V0OiBmdW5jdGlvbiAodGFyZ2V0OiBhbnksIG9iamVjdEtleTogc3RyaW5nKSB7XG4gICAgICAgICAgICBpZiAodGFyZ2V0Lmhhc093blByb3BlcnR5KG9iamVjdEtleSkpIHtcbiAgICAgICAgICAgICAgcmV0dXJuIHRhcmdldFtvYmplY3RLZXldO1xuICAgICAgICAgICAgfSBlbHNlIGlmIChvYmplY3RLZXkgIT09ICd0aGVuJykge1xuICAgICAgICAgICAgICByZXR1cm4gZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgIGNvbnN0IGplc3RGdW5jdGlvblRvRXhlY3V0ZSA9IChleHBlY3QobWVzc2FnZS5kYXRhKSBhcyBhbnkpW1xuICAgICAgICAgICAgICAgICAgb2JqZWN0S2V5XG4gICAgICAgICAgICAgICAgXTtcbiAgICAgICAgICAgICAgICBqZXN0RnVuY3Rpb25Ub0V4ZWN1dGUuYXBwbHkodW5kZWZpbmVkLCBhcmd1bWVudHMpO1xuICAgICAgICAgICAgICAgIHJldHVybiBwcm94eTtcbiAgICAgICAgICAgICAgfTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9LFxuICAgICAgICB9KTtcblxuICAgICAgICB0cmFja2VyLnByb21pc2VSZXNvbHZlKHByb3h5KTtcbiAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICB9XG4gICAgfVxuICAgIHJldHVybiBmYWxzZTtcbiAgfVxuXG4gIHByaXZhdGUgcmVzb2x2ZVRyYWNrZXJJbk9sZE1lc3NhZ2VzKHRyYWNrZXI6IFRyYWNrZXIpIHtcbiAgICBmb3IgKGNvbnN0IG1lc3NhZ2Ugb2YgdGhpcy5tZXNzYWdlcykge1xuICAgICAgaWYgKHRoaXMudHJhY2tlck1hdGNoTWVzc2FnZSh0cmFja2VyLCBtZXNzYWdlKSkge1xuICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICByZXR1cm4gZmFsc2U7XG4gIH1cblxuICBwcml2YXRlIHJlc29sdmVPbGRUcmFja2VyV2l0aE5ld01lc3NhZ2UobWVzc2FnZTogU3B5TWVzc2FnZVN0b3JhZ2UpIHtcbiAgICBmb3IgKGxldCBpbmRleCA9IDA7IGluZGV4IDwgdGhpcy50cmFja2Vycy5sZW5ndGg7IGluZGV4KyspIHtcbiAgICAgIGNvbnN0IHRyYWNrZXIgPSB0aGlzLnRyYWNrZXJzW2luZGV4XTtcbiAgICAgIGlmICh0aGlzLnRyYWNrZXJNYXRjaE1lc3NhZ2UodHJhY2tlciwgbWVzc2FnZSkpIHtcbiAgICAgICAgdGhpcy50cmFja2VycyA9IHRoaXMudHJhY2tlcnMuc3BsaWNlKGluZGV4LCAxKTtcbiAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICB9XG4gICAgfVxuXG4gICAgcmV0dXJuIGZhbHNlO1xuICB9XG5cbiAgcHJpdmF0ZSB0cmFja2VyTWF0Y2hDb25kaXRpb24odHJhY2tlcjogVHJhY2tlciwgbWVzc2FnZTogU3B5TWVzc2FnZVN0b3JhZ2UpIHtcbiAgICBjb25zdCBtYXRjaENvbmRpdGlvbiA9XG4gICAgICAodHJhY2tlci5jb25kaXRpb24gJiYgdHJhY2tlci5jb25kaXRpb24obWVzc2FnZS5kYXRhKSkgfHxcbiAgICAgICF0cmFja2VyLmNvbmRpdGlvbjtcblxuICAgIGNvbnN0IG1hdGNoUmVxdWVzdElkID1cbiAgICAgICh0cmFja2VyLmZ1bmN0aW9uQ29udGV4dEF3c1JlcXVlc3RJZCAmJlxuICAgICAgICB0cmFja2VyLmZ1bmN0aW9uQ29udGV4dEF3c1JlcXVlc3RJZCA9PT1cbiAgICAgICAgICBtZXNzYWdlLmZ1bmN0aW9uQ29udGV4dEF3c1JlcXVlc3RJZCkgfHxcbiAgICAgICF0cmFja2VyLmZ1bmN0aW9uQ29udGV4dEF3c1JlcXVlc3RJZDtcblxuICAgIGlmIChtYXRjaENvbmRpdGlvbiAmJiBtYXRjaFJlcXVlc3RJZCkge1xuICAgICAgcmV0dXJuIHRydWU7XG4gICAgfSBlbHNlIHtcbiAgICAgIGlmIChcbiAgICAgICAgIW1hdGNoQ29uZGl0aW9uICYmXG4gICAgICAgIG1hdGNoUmVxdWVzdElkICYmXG4gICAgICAgICF0cmFja2VyLnBvc3NpYmxlU3B5TWVzc2FnZURhdGFGb3JEZWJ1Z2dpbmdcbiAgICAgICkge1xuICAgICAgICB0cmFja2VyLnBvc3NpYmxlU3B5TWVzc2FnZURhdGFGb3JEZWJ1Z2dpbmcgPSBtZXNzYWdlLmRhdGE7XG4gICAgICB9XG4gICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBjcmVhdGVXYWl0Rm9yWFhYRnVuYyhcbiAgICBzZXJ2aWNlS2V5Rm9yRnVuY3Rpb246IHN0cmluZyxcbiAgICBmdW5jdGlvbkNvbnRleHRBd3NSZXF1ZXN0SWQ/OiBzdHJpbmdcbiAgKSB7XG4gICAgcmV0dXJuIChwYXJhbXNXPzogV2FpdEZvclBhcmFtcykgPT4ge1xuICAgICAgbGV0IHJlc29sdmU6ICh2YWx1ZTogdm9pZCB8IFByb21pc2VMaWtlPGFueT4pID0+IHZvaWQ7XG4gICAgICBjb25zdCBwcm9taXNlID0gbmV3IFByb21pc2UoKHJlcykgPT4ge1xuICAgICAgICByZXNvbHZlID0gcmVzO1xuICAgICAgfSk7XG4gICAgICBjb25zdCB0cmFja2VyOiBUcmFja2VyID0ge1xuICAgICAgICBmaW5pc2hlZDogZmFsc2UsXG4gICAgICAgIC8vIEB0cy1pZ25vcmVcbiAgICAgICAgcHJvbWlzZVJlc29sdmU6IHJlc29sdmUsXG4gICAgICAgIHNlcnZpY2VLZXlGb3JGdW5jdGlvbixcbiAgICAgICAgZnVuY3Rpb25Db250ZXh0QXdzUmVxdWVzdElkLFxuICAgICAgfTtcblxuICAgICAgdHJhY2tlci5jb25kaXRpb24gPSBwYXJhbXNXPy5jb25kaXRpb247XG5cbiAgICAgIGxldCB0aW1lb3V0UGlkOiBOb2RlSlMuVGltZW91dCB8IHVuZGVmaW5lZDtcbiAgICAgIGNvbnN0IHRpbWVyID0gbmV3IFByb21pc2UoKF8sIHJlamVjdCkgPT4ge1xuICAgICAgICB0aW1lb3V0UGlkID0gc2V0VGltZW91dCgoKSA9PiB7XG4gICAgICAgICAgaWYgKHRyYWNrZXIuZmluaXNoZWQpIHJldHVybjtcbiAgICAgICAgICB0cmFja2VyLmZpbmlzaGVkID0gdHJ1ZTtcbiAgICAgICAgICBsZXQgbWVzc2FnZSA9IGBUaW1lb3V0IHdhaXRpbmcgZm9yIFNlcnZlcmxlc3MgU3B5IG1lc3NhZ2UgJHtzZXJ2aWNlS2V5Rm9yRnVuY3Rpb259LmA7XG5cbiAgICAgICAgICBpZiAodHJhY2tlci5wb3NzaWJsZVNweU1lc3NhZ2VEYXRhRm9yRGVidWdnaW5nKSB7XG4gICAgICAgICAgICBtZXNzYWdlICs9IGAgU2ltaWxhciBtYXRjaGluZyBzcHkgZXZlbnQgZGF0YTogJHtKU09OLnN0cmluZ2lmeShcbiAgICAgICAgICAgICAgdHJhY2tlci5wb3NzaWJsZVNweU1lc3NhZ2VEYXRhRm9yRGVidWdnaW5nLFxuICAgICAgICAgICAgICBudWxsLFxuICAgICAgICAgICAgICAyXG4gICAgICAgICAgICApfWA7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgcmVqZWN0KG5ldyBFcnJvcihtZXNzYWdlKSk7XG4gICAgICAgIH0sIHBhcmFtc1c/LnRpbW91dE1zIHx8IDEwMDAwKTtcbiAgICAgIH0pO1xuXG4gICAgICBpZiAoIXRoaXMucmVzb2x2ZVRyYWNrZXJJbk9sZE1lc3NhZ2VzKHRyYWNrZXIpKSB7XG4gICAgICAgIHRoaXMudHJhY2tlcnMucHVzaCh0cmFja2VyKTtcbiAgICAgIH1cblxuICAgICAgcmV0dXJuIFByb21pc2UucmFjZShbcHJvbWlzZSwgdGltZXJdKS5maW5hbGx5KCgpID0+IHtcbiAgICAgICAgaWYgKCEhdGltZW91dFBpZCkge1xuICAgICAgICAgIGNsZWFyVGltZW91dCh0aW1lb3V0UGlkKTtcbiAgICAgICAgfVxuICAgICAgfSk7XG4gICAgfTtcbiAgfVxuXG4gIHB1YmxpYyBjcmVhdGVQcm94eSgpIHtcbiAgICBjb25zdCBzcHlMaXN0ZW5lciA9IHt9IGFzIFNlcnZlcmxlc3NTcHlMaXN0ZW5lcjxUU3B5RXZlbnRzPjtcblxuICAgIHNweUxpc3RlbmVyLnN0b3AgPSBhc3luYyAoKSA9PiB7XG4gICAgICBhd2FpdCB0aGlzLnN0b3AoKTtcbiAgICB9O1xuXG4gICAgcmV0dXJuIG5ldyBQcm94eTxTZXJ2ZXJsZXNzU3B5TGlzdGVuZXI8VFNweUV2ZW50cz4+KHNweUxpc3RlbmVyLCB7XG4gICAgICBnZXQ6ICh0YXJnZXQ6IGFueSwgb2JqZWN0S2V5OiBzdHJpbmcpID0+IHtcbiAgICAgICAgaWYgKHRhcmdldC5oYXNPd25Qcm9wZXJ0eShvYmplY3RLZXkpKSB7XG4gICAgICAgICAgcmV0dXJuIHRhcmdldFtvYmplY3RLZXldLmJpbmQodGFyZ2V0KTtcbiAgICAgICAgfSBlbHNlIGlmIChcbiAgICAgICAgICB0eXBlb2Ygb2JqZWN0S2V5ID09PSAnc3RyaW5nJyAmJlxuICAgICAgICAgIG9iamVjdEtleS5zdGFydHNXaXRoKHRoaXMuZnVuY3Rpb25QcmVmaXgpXG4gICAgICAgICkge1xuICAgICAgICAgIGNvbnN0IHNlcnZpY2VLZXlGb3JGdW5jdGlvbiA9IG9iamVjdEtleS5zdWJzdHJpbmcoXG4gICAgICAgICAgICB0aGlzLmZ1bmN0aW9uUHJlZml4Lmxlbmd0aFxuICAgICAgICAgICk7XG5cbiAgICAgICAgICByZXR1cm4gdGhpcy5jcmVhdGVXYWl0Rm9yWFhYRnVuYyhzZXJ2aWNlS2V5Rm9yRnVuY3Rpb24pO1xuICAgICAgICB9XG4gICAgICB9LFxuICAgIH0pO1xuICB9XG5cbiAgcHJpdmF0ZSBsb2cobWVzc2FnZTogc3RyaW5nLCAuLi5vcHRpb25hbFBhcmFtczogYW55W10pIHtcbiAgICBpZiAodGhpcy5kZWJ1Z01vZGUgJiYgIXRoaXMuY2xvc2VkKSB7XG4gICAgICBjb25zb2xlLmRlYnVnKFxuICAgICAgICAnU1NQWScsXG4gICAgICAgIG1lc3NhZ2UsXG4gICAgICAgIG5ldyBEYXRlKCkudG9JU09TdHJpbmcoKSxcbiAgICAgICAgLi4ub3B0aW9uYWxQYXJhbXNcbiAgICAgICk7XG4gICAgfVxuICB9XG59XG5cbnR5cGUgVHJhY2tlciA9IHtcbiAgcHJvbWlzZVJlc29sdmU6IChkYXRhOiBhbnkpID0+IHZvaWQ7XG4gIGZpbmlzaGVkOiBib29sZWFuO1xuICBzZXJ2aWNlS2V5Pzogc3RyaW5nO1xuICBzZXJ2aWNlS2V5Rm9yRnVuY3Rpb24/OiBzdHJpbmc7XG4gIGNvbmRpdGlvbj86IChkYXRhOiBhbnkpID0+IGJvb2xlYW47XG4gIHRpbW91dE1zPzogbnVtYmVyO1xuICBmdW5jdGlvbkNvbnRleHRBd3NSZXF1ZXN0SWQ/OiBzdHJpbmc7XG4gIHBvc3NpYmxlU3B5TWVzc2FnZURhdGFGb3JEZWJ1Z2dpbmc/OiBhbnk7XG59O1xuXG50eXBlIFNweU1lc3NhZ2VTdG9yYWdlID0gU3B5TWVzc2FnZSAmIHtcbiAgc2VydmljZUtleUZvckZ1bmN0aW9uOiBzdHJpbmc7XG4gIGZ1bmN0aW9uQ29udGV4dEF3c1JlcXVlc3RJZD86IHN0cmluZztcbn07XG4iXX0=