UNPKG

@synerty/vortexjs

Version:

Custom observable data serialisation and routing based on Angular 2+

265 lines 40.5 kB
import { VortexClientABC, VortexClientStateE } from "./VortexClientABC"; import { dateStr, getFiltStr } from "./UtilMisc"; import { PayloadEnvelope } from "./PayloadEnvelope"; export class VortexClientWebsocket extends VortexClientABC { Socket = WebSocket || MozWebSocket; socket = null; lastReconnectDate = Date.parse("01-Jan-2017"); unsentBuffer = []; // Make note of when we're reconnecting, // otherwise closing the last websocket causes a reconnection // call which then closes the current socket being open (in a loop) reconnectingInProgress = false; _data = ""; _vortexMsgsQueue = []; constructor(vortexStatusService, url, vortexClientName) { super(vortexStatusService, url, vortexClientName); } get isReady() { return (this.socket != null && this.socket.readyState === this.Socket.OPEN); } // OVERRIDE Send send(payloadEnvelope) { if (!this.isReady) { throw new Error("Websocked vortex is not online."); } return super.send(payloadEnvelope); } // OVERRIDE reconnect async reconnect() { this.vortexStatusService.logDebug("VortexClientWebsocket.reconnect called"); if (this.reconnectingInProgress === true) { this.vortexStatusService.logDebug("VortexClientWebsocket.reconnect returning #1"); return; } this.clearBeatTimer(); this._vortexState = VortexClientStateE.Idle; this.reconnectingInProgress = true; try { await this.createSocket(); } catch (e) { console.error(`${dateStr()} Failed to connect websocket ${e}`); } this.reconnectingInProgress = false; this.restartTimer(); this.vortexStatusService.logDebug("VortexClientWebsocket.reconnect returning #2"); } sendVortexMsg(vortexMsgs) { this.unsentBuffer.add(vortexMsgs); this.sendMessages(); } sendMessages() { while (this.unsentBuffer.length !== 0) { if (!this.isReady) return; let vortexMsg = this.unsentBuffer.shift(); this.socket.send(vortexMsg + "."); } } _processData() { if (this._data) { let indexOfDot = this._data.indexOf("."); while (indexOfDot !== -1) { const vortexMsg = this._data.slice(0, indexOfDot); this._data = this._data.slice(indexOfDot + 1); if (vortexMsg.length !== 0) { this._vortexMsgsQueue.push(vortexMsg); } indexOfDot = this._data.indexOf("."); } } while (this._vortexMsgsQueue.length !== 0) { this._processVortexMsgs() // .catch((e) => console.log(`ERROR VortexClientWebsocket: ${e}`)); } } async _processVortexMsgs() { while (this._vortexMsgsQueue.length !== 0) { const vortexMsg = this._vortexMsgsQueue.shift(); try { const payloadEnvelope = await PayloadEnvelope.fromVortexMsg(vortexMsg); this._deliverPayload(payloadEnvelope); } catch (e) { console.log(dateStr() + `ERROR: processing vortexMsg\n${e}\n${vortexMsg}`); } } } _deliverPayload(payloadEnvelope) { this.receive(payloadEnvelope); } async shutdown() { this.vortexStatusService.logDebug("VortexClientWebsocket.shutdown called"); await this.closeWebsocket(); this.vortexStatusService.logDebug("VortexClientWebsocket.shutdown" + " returned"); } async closeWebsocket() { this.vortexStatusService.logDebug("VortexClientWebsocket.closeWebsocket called"); // If we're open then close if (this.socket && this.socket.readyState === this.Socket.OPEN) { await new Promise((resolve, reject) => { this.vortexStatusService.logDebug("Websocket close starting"); this.setClosing(); this.socket.addEventListener("close", () => { this.vortexStatusService.logInfo("Websocket close complete"); this.setClosed(); resolve(); }); this.socket.close(); }); } this.socket = null; this.vortexStatusService.logDebug("VortexClientWebsocket.closeWebsocket returning"); } async createSocket() { this.vortexStatusService.logDebug("VortexClientWebsocket.createSocket called"); // If we're already connecting, then do nothing if (this.socket && this.socket.readyState === this.Socket.CONNECTING) { if (!this.isShutdown) { this.vortexStatusService.logDebug("VortexClientWebsocket.createSocket" + " returning #1"); return; } try { console.log("Aborting WebSocket connection attempt," + " this is probably because of Vortex reconnection"); this.socket.close(); } catch (e) { // pass } } this.vortexStatusService.logDebug("VortexClientWebsocket.createSocket Closing old websocket"); await this.closeWebsocket(); // Don't continually reconnect let reconnectDiffMs = Date.now() - this.lastReconnectDate; if (reconnectDiffMs < this.RECONNECT_BACKOFF_SECONDS * 1000) { this.vortexStatusService.logDebug("VortexClientWebsocket.createSocket returning #2 - backoff" + " timeout"); setTimeout(() => this.createSocket(), this.RECONNECT_BACKOFF_SECONDS * 1000 - reconnectDiffMs + 10); return; } this.lastReconnectDate = Date.now(); // Prepare the args to send const args = { vortexUuid: this.uuid, vortexName: this.name, }; this.vortexStatusService.logConnectionInfo(`${dateStr()} WebSocket, connecting to ${this.url}`); await new Promise((resolve, reject) => { // Construct + open the socket let promiseCalled = false; this.vortexStatusService.logDebug("VortexClientWebsocket.createSocket Creating socket"); this.socket = new this.Socket(this.url + getFiltStr(args), []); this.socket.binaryType = "arraybuffer"; this.socket.addEventListener("message", (event) => { this.onMessage(event, () => { this.vortexStatusService.logDebug("VortexClientWebsocket.createSocket calling resolve" + " from message"); resolve(); promiseCalled = true; }); }); this.socket.addEventListener("close", (event) => { this.vortexStatusService.logDebug("VortexClientWebsocket.createSocket addEventListener close"); this.onClose(event); if (!promiseCalled) { this.vortexStatusService.logDebug("VortexClientWebsocket.createSocket calling reject" + " from close"); promiseCalled = true; reject(); } }); this.socket.addEventListener("error", (event) => { this.vortexStatusService.logDebug(`VortexClientWebsocket.createSocket addEventListener error: ${event}`); this.onError(event, () => { this.vortexStatusService.logDebug("VortexClientWebsocket.createSocket calling reject" + " from error"); reject(); promiseCalled = true; }); }); this.socket.addEventListener("open", (event) => { this.vortexStatusService.logDebug("VortexClientWebsocket.createSocket addEventListener open"); this.onOpen(event); }); }); this.vortexStatusService.logDebug("VortexClientWebsocket.createSocket returning #3"); } onMessage(event, promiseResolver) { if (!this.isOnline) { this.setOnline(); promiseResolver(); } this.beat(); if (event.data.length == null) { this.vortexStatusService.logConnectionError("WebSocket, We've received a websocket binary message," + " we expect a unicode"); return; } // If the server sends us a '.', that's a heart beat, return it. if (event.data === ".") { this.socket != null && this.socket.send("."); return; } if (event.data[0] !== "{") { this._data += event.data; } else { // It starts with {, ensure it ends with } if (event.data[event.data.length - 1] !== "}") { console.log(dateStr() + " ERROR, Payload should end with }," + " but it doesn't: " + event.data); return; } this._vortexMsgsQueue.push(event.data); } this._processData(); } onOpen(event) { super .send(new PayloadEnvelope()) .catch((e) => console.log(`ERROR VortexClientWebsocket onOpen Send: ${e}`)); this.vortexStatusService.logConnectionInfo("WebSocket, connecting"); } onClose(event) { this.vortexStatusService.logConnectionInfo("WebSocket, closed"); if (!(this.socket && this.socket.readyState === this.Socket.OPEN)) { this.setClosed(); } // The base class will reconnect } onError(event, reject) { reject(event.error?.toString() || "Websocket failed to connect"); // onClose will get called as well // Check if the server is still up, if it is we've been logged out this.testIfOnlineAndLoggedOut() .then(() => console.log("Server is unreachable")) .catch(() => { this.vortexStatusService.logConnectionError("Vortex Websocket doesn't connect but server is online," + " Marking vortex as logged out"); this.vortexStatusService.setHttpSessionLoggedOut(); return; }); } testIfOnlineAndLoggedOut() { return new Promise((resolve, reject) => { const httpUrl = "http" + this._url.substring(2); let xmlHttp = new XMLHttpRequest(); xmlHttp.timeout = 2000; xmlHttp.responseType = "document"; xmlHttp.onload = function (event) { reject(); }; xmlHttp.onerror = function (event) { resolve(); }; xmlHttp.open("GET", httpUrl, true); // true for asynchronous xmlHttp.send(null); }); } } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiVm9ydGV4Q2xpZW50V2Vic29ja2V0LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vc3JjL3ZvcnRleC9Wb3J0ZXhDbGllbnRXZWJzb2NrZXQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLGVBQWUsRUFBRSxrQkFBa0IsRUFBRSxNQUFNLG1CQUFtQixDQUFDO0FBRXhFLE9BQU8sRUFBRSxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sWUFBWSxDQUFDO0FBQ2pELE9BQU8sRUFBRSxlQUFlLEVBQUUsTUFBTSxtQkFBbUIsQ0FBQztBQU9wRCxNQUFNLE9BQU8scUJBQXNCLFNBQVEsZUFBZTtJQUM5QyxNQUFNLEdBQUcsU0FBUyxJQUFJLFlBQVksQ0FBQztJQUNuQyxNQUFNLEdBQXFCLElBQUksQ0FBQztJQUVoQyxpQkFBaUIsR0FBVyxJQUFJLENBQUMsS0FBSyxDQUFDLGFBQWEsQ0FBQyxDQUFDO0lBRXRELFlBQVksR0FBYSxFQUFFLENBQUM7SUFFcEMsd0NBQXdDO0lBQ3hDLDZEQUE2RDtJQUM3RCxvRUFBb0U7SUFDNUQsc0JBQXNCLEdBQVksS0FBSyxDQUFDO0lBRXhDLEtBQUssR0FBVyxFQUFFLENBQUM7SUFDbkIsZ0JBQWdCLEdBQWEsRUFBRSxDQUFDO0lBRXhDLFlBQ0ksbUJBQXdDLEVBQ3hDLEdBQVcsRUFDWCxnQkFBd0I7UUFFeEIsS0FBSyxDQUFDLG1CQUFtQixFQUFFLEdBQUcsRUFBRSxnQkFBZ0IsQ0FBQyxDQUFDO0lBQ3RELENBQUM7SUFFRCxJQUFJLE9BQU87UUFDUCxPQUFPLENBQ0gsSUFBSSxDQUFDLE1BQU0sSUFBSSxJQUFJLElBQUksSUFBSSxDQUFDLE1BQU0sQ0FBQyxVQUFVLEtBQUssSUFBSSxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQ3JFLENBQUM7SUFDTixDQUFDO0lBRUQsZ0JBQWdCO0lBQ2hCLElBQUksQ0FBQyxlQUFvRDtRQUNyRCxJQUFJLENBQUMsSUFBSSxDQUFDLE9BQU8s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QUFDLHdCQUF3QixFQUFFO2FBQzFCLElBQUksQ0FBQyxHQUFHLEVBQUUsQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLHVCQUF1QixDQUFDLENBQUM7YUFDaEQsS0FBSyxDQUFDLEdBQUcsRUFBRTtZQUNSLElBQUksQ0FBQyxtQkFBbUIsQ0FBQyxrQkFBa0IsQ0FDdkMsd0RBQXdEO2dCQUNwRCwrQkFBK0IsQ0FDdEMsQ0FBQztZQUNGLElBQUksQ0FBQyxtQkFBbUIsQ0FBQyx1QkFBdUIsRUFBRSxDQUFDO1lBQ25ELE9BQU87UUFDWCxDQUFDLENBQUMsQ0FBQztJQUNYLENBQUM7SUFFTyx3QkFBd0I7UUFDNUIsT0FBTyxJQUFJLE9BQU8sQ0FBTyxDQUFDLE9BQU8sRUFBRSxNQUFNLEVBQUUsRUFBRTtZQUN6QyxNQUFNLE9BQU8sR0FBRyxNQUFNLEdBQUcsSUFBSSxDQUFDLElBQUksQ0FBQyxTQUFTLENBQUMsQ0FBQyxDQUFDLENBQUM7WUFDaEQsSUFBSSxPQUFPLEdBQUcsSUFBSSxjQUFjLEVBQUUsQ0FBQztZQUNuQyxPQUFPLENBQUMsT0FBTyxHQUFHLElBQUksQ0FBQztZQUN2QixPQUFPLENBQUMsWUFBWSxHQUFHLFVBQVUsQ0FBQztZQUNsQyxPQUFPLENBQUMsTUFBTSxHQUFHLFVBQVUsS0FBSztnQkFDNUIsTUFBTSxFQUFFLENBQUM7WUFDYixDQUFDLENBQUM7WUFDRixPQUFPLENBQUMsT0FBTyxHQUFHLFVBQVUsS0FBSztnQkFDN0IsT0FBTyxFQUFFLENBQUM7WUFDZCxDQUFDLENBQUM7WUFDRixPQUFPLENBQUMsSUFBSSxDQUFDLEtBQUssRUFBRSxPQUFPLEVBQUUsSUFBSSxDQUFDLENBQUMsQ0FBQyx3QkFBd0I7WUFDNUQsT0FBTyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQztRQUN2QixDQUFDLENBQUMsQ0FBQztJQUNQLENBQUM7Q0FDSiIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IFZvcnRleENsaWVudEFCQywgVm9ydGV4Q2xpZW50U3RhdGVFIH0gZnJvbSBcIi4vVm9ydGV4Q2xpZW50QUJDXCI7XG5pbXBvcnQgeyBWb3J0ZXhTdGF0dXNTZXJ2aWNlIH0gZnJvbSBcIi4vVm9ydGV4U3RhdHVzU2VydmljZVwiO1xuaW1wb3J0IHsgZGF0ZVN0ciwgZ2V0RmlsdFN0ciB9IGZyb20gXCIuL1V0aWxNaXNjXCI7XG5pbXBvcnQgeyBQYXlsb2FkRW52ZWxvcGUgfSBmcm9tIFwiLi9QYXlsb2FkRW52ZWxvcGVcIjtcblxuLy8gaHR0cHM6Ly9kZXZlbG9wZXIubW96aWxsYS5vcmcvZW4tVVMvZG9jcy9XZWIvQVBJL1dlYlNvY2tldFxuXG5kZWNsYXJlIGNvbnN0IFdlYlNvY2tldDogYW55O1xuZGVjbGFyZSBjb25zdCBNb3pXZWJTb2NrZXQ6IGFueTtcblxuZXhwb3J0IGNsYXNzIFZvcnRleENsaWVudFdlYnNvY2tldCBleHRlbmRzIFZvcnRleENsaWVudEFCQyB7XG4gICAgcHJpdmF0ZSBTb2NrZXQgPSBXZWJTb2NrZXQgfHwgTW96V2ViU29ja2V0O1xuICAgIHByaXZhdGUgc29ja2V0OiBXZWJTb2NrZXQgfCBudWxsID0gbnVsbDtcblxuICAgIHByaXZhdGUgbGFzdFJlY29ubmVjdERhdGU6IG51bWJlciA9IERhdGUucGFyc2UoXCIwMS1KYW4tMjAxN1wiKTtcblxuICAgIHByaXZhdGUgdW5zZW50QnVmZmVyOiBzdHJpbmdbXSA9IFtdO1xuXG4gICAgLy8gTWFrZSBub3RlIG9mIHdoZW4gd2UncmUgcmVjb25uZWN0aW5nLFxuICAgIC8vIG90aGVyd2lzZSBjbG9zaW5nIHRoZSBsYXN0IHdlYnNvY2tldCBjYXVzZXMgYSByZWNvbm5lY3Rpb25cbiAgICAvLyBjYWxsIHdoaWNoIHRoZW4gY2xvc2VzIHRoZSBjdXJyZW50IHNvY2tldCBiZWluZyBvcGVuIChpbiAgYSBsb29wKVxuICAgIHByaXZhdGUgcmVjb25uZWN0aW5nSW5Qcm9ncmVzczogYm9vbGVhbiA9IGZhbHNlO1xuXG4gICAgcHJpdmF0ZSBfZGF0YTogc3RyaW5nID0gXCJcIjtcbiAgICBwcml2YXRlIF92b3J0ZXhNc2dzUXVldWU6IHN0cmluZ1tdID0gW107XG5cbiAgICBjb25zdHJ1Y3RvcihcbiAgICAgICAgdm9ydGV4U3RhdHVzU2VydmljZTogVm9ydGV4U3RhdHVzU2VydmljZSxcbiAgICAgICAgdXJsOiBzdHJpbmcsXG4gICAgICAgIHZvcnRleENsaWVudE5hbWU6IHN0cmluZyxcbiAgICApIHtcbiAgICAgICAgc3VwZXIodm9ydGV4U3RhdHVzU2VydmljZSwgdXJsLCB2b3J0ZXhDbGllbnROYW1lKTtcbiAgICB9XG5cbiAgICBnZXQgaXNSZWFkeSgpOiBib29sZWFuIHtcbiAgICAgICAgcmV0dXJuIChcbiAgICAgICAgICAgIHRoaXMuc29ja2V0ICE9IG51bGwgJiYgdGhpcy5zb2NrZXQucmVhZHlTdGF0ZSA9PT0gdGhpcy5Tb2NrZXQuT1BFTlxuICAgICAgICApO1xuICAgIH1cblxuICAgIC8vIE9WRVJSSURFIFNlbmRcbiAgICBzZW5kKHBheWxvYWRFbnZlbG9wZTogUGF5bG9hZEVudmVsb3BlIHwgUGF5bG9hZEVudmVsb3BlW10pOiBQcm9taXNlPHZvaWQ+IHtcbiAgICAgICAgaWYgKCF0aGlzLmlzUmVhZHkpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcIldlYnNvY2tlZCB2b3J0ZXggaXMgbm90IG9ubGluZS5cIik7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gc3VwZXIuc2VuZChwYXlsb2FkRW52ZWxvcGUpO1xuICAgIH1cblxuICAgIC8vIE9WRVJSSURFIHJlY29ubmVjdFxuICAgIGFzeW5jIHJlY29ubmVjdCgpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICAgICAgdGhpcy52b3J0ZXhTdGF0dXNTZXJ2aWNlLmxvZ0RlYnVnKFxuICAgICAgICAgICAgXCJWb3J0ZXhDbGllbnRXZWJzb2NrZXQucmVjb25uZWN0IGNhbGxlZFwiLFxuICAgICAgICApO1xuXG4gICAgICAgIGlmICh0aGlzLnJlY29ubmVjdGluZ0luUHJvZ3Jlc3MgPT09IHRydWUpIHtcbiAgICAgICAgICAgIHRoaXMudm9ydGV4U3RhdHVzU2VydmljZS5sb2dEZWJ1ZyhcbiAgICAgICAgICAgICAgICBcIlZvcnRleENsaWVudFdlYnNvY2tldC5yZWNvbm5lY3QgcmV0dXJuaW5nICMxXCIsXG4gICAgICAgICAgICApO1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICAgIHRoaXMuY2xlYXJCZWF0VGltZXIoKTtcbiAgICAgICAgdGhpcy5fdm9ydGV4U3RhdGUgPSBWb3J0ZXhDbGllbnRTdGF0ZUUuSWRsZTtcbiAgICAgICAgdGhpcy5yZWNvbm5lY3RpbmdJblByb2dyZXNzID0gdHJ1ZTtcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIGF3YWl0IHRoaXMuY3JlYXRlU29ja2V0KCk7XG4gICAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IoYCR7ZGF0ZVN0cigpfSBGYWlsZWQgdG8gY29ubmVjdCB3ZWJzb2NrZXQgJHtlfWApO1xuICAgICAgICB9XG4gICAgICAgIHRoaXMucmVjb25uZWN0aW5nSW5Qcm9ncmVzcyA9IGZhbHNlO1xuICAgICAgICB0aGlzLnJlc3RhcnRUaW1lcigpO1xuXG4gICAgICAgIHRoaXMudm9ydGV4U3RhdHVzU2VydmljZS5sb2dEZWJ1ZyhcbiAgICAgICAgICAgIFwiVm9ydGV4Q2xpZW50V2Vic29ja2V0LnJlY29ubmVjdCByZXR1cm5pbmcgIzJcIixcbiAgICAgICAgKTtcbiAgICB9XG5cbiAgICBwcm90ZWN0ZWQgc2VuZFZvcnRleE1zZyh2b3J0ZXhNc2dzOiBzdHJpbmdbXSk6IHZvaWQge1xuICAgICAgICB0aGlzLnVuc2VudEJ1ZmZlci5hZGQodm9ydGV4TXNncyk7XG5cbiAgICAgICAgdGhpcy5zZW5kTWVzc2FnZXMoKTtcbiAgICB9XG5cbiAgICBwcml2YXRlIHNlbmRNZXNzYWdlcygpIHtcbiAgICAgICAgd2hpbGUgKHRoaXMudW5zZW50QnVmZmVyLmxlbmd0aCAhPT0gMCkge1xuICAgICAgICAgICAgaWYgKCF0aGlzLmlzUmVhZHkpIHJldHVybjtcblxuICAgICAgICAgICAgbGV0IHZvcnRleE1zZyA9IHRoaXMudW5zZW50QnVmZmVyLnNoaWZ0KCk7XG4gICAgICAgICAgICB0aGlzLnNvY2tldC5zZW5kKHZvcnRleE1zZyArIFwiLlwiKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHByaXZhdGUgX3Byb2Nlc3NEYXRhKCk6IHZvaWQge1xuICAgICAgICBpZiAodGhpcy5fZGF0YSkge1xuICAgICAgICAgICAgbGV0IGluZGV4T2ZEb3Q6IG51bWJlciA9IHRoaXMuX2RhdGEuaW5kZXhPZihcIi5cIik7XG4gICAgICAgICAgICB3aGlsZSAoaW5kZXhPZkRvdCAhPT0gLTEpIHtcbiAgICAgICAgICAgICAgICBjb25zdCB2b3J0ZXhNc2cgPSB0aGlzLl9kYXRhLnNsaWNlKDAsIGluZGV4T2ZEb3QpO1xuICAgICAgICAgICAgICAgIHRoaXMuX2RhdGEgPSB0aGlzLl9kYXRhLnNsaWNlKGluZGV4T2ZEb3QgKyAxKTtcblxuICAgICAgICAgICAgICAgIGlmICh2b3J0ZXhNc2cubGVuZ3RoICE9PSAwKSB7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuX3ZvcnRleE1zZ3NRdWV1ZS5wdXNoKHZvcnRleE1zZyk7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgaW5kZXhPZkRvdCA9IHRoaXMuX2RhdGEuaW5kZXhPZihcIi5cIik7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICB3aGlsZSAodGhpcy5fdm9ydGV4TXNnc1F1ZXVlLmxlbmd0aCAhPT0gMCkge1xuICAgICAgICAgICAgdGhpcy5fcHJvY2Vzc1ZvcnRleE1zZ3MoKSAvL1xuICAgICAgICAgICAgICAgIC5jYXRjaCgoZSkgPT4gY29uc29sZS5sb2coYEVSUk9SIFZvcnRleENsaWVudFdlYnNvY2tldDogJHtlfWApKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHByaXZhdGUgYXN5bmMgX3Byb2Nlc3NWb3J0ZXhNc2dzKCkge1xuICAgICAgICB3aGlsZSAodGhpcy5fdm9ydGV4TXNnc1F1ZXVlLmxlbmd0aCAhPT0gMCkge1xuICAgICAgICAgICAgY29uc3Qgdm9ydGV4TXNnID0gdGhpcy5fdm9ydGV4TXNnc1F1ZXVlLnNoaWZ0KCk7XG5cbiAgICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICAgICAgY29uc3QgcGF5bG9hZEVudmVsb3BlID1cbiAgICAgICAgICAgICAgICAgICAgYXdhaXQgUGF5bG9hZEVudmVsb3BlLmZyb21Wb3J0ZXhNc2codm9ydGV4TXNnKTtcblxuICAgICAgICAgICAgICAgIHRoaXMuX2RlbGl2ZXJQYXlsb2FkKHBheWxvYWRFbnZlbG9wZSk7XG4gICAgICAgICAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgICAgICAgICAgY29uc29sZS5sb2coXG4gICAgICAgICAgICAgICAgICAgIGRhdGVTdHIoKSArXG4gICAgICAgICAgICAgICAgICAgICAgICBgRVJST1I6IHByb2Nlc3Npbmcgdm9ydGV4TXNnXFxuJHtlfVxcbiR7dm9ydGV4TXNnfWAsXG4gICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH1cblxuICAgIHByaXZhdGUgX2RlbGl2ZXJQYXlsb2FkKHBheWxvYWRFbnZlbG9wZTogUGF5bG9hZEVudmVsb3BlKSB7XG4gICAgICAgIHRoaXMucmVjZWl2ZShwYXlsb2FkRW52ZWxvcGUpO1xuICAgIH1cblxuICAgIHByb3RlY3RlZCBhc3luYyBzaHV0ZG93bigpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICAgICAgdGhpcy52b3J0ZXhTdGF0dXNTZXJ2aWNlLmxvZ0RlYnVnKFxuICAgICAgICAgICAgXCJWb3J0ZXhDbGllbnRXZWJzb2NrZXQuc2h1dGRvd24gY2FsbGVkXCIsXG4gICAgICAgICk7XG4gICAgICAgIGF3YWl0IHRoaXMuY2xvc2VXZWJzb2NrZXQoKTtcbiAgICAgICAgdGhpcy52b3J0ZXhTdGF0dXNTZXJ2aWNlLmxvZ0RlYnVnKFxuICAgICAgICAgICAgXCJWb3J0ZXhDbGllbnRXZWJzb2NrZXQuc2h1dGRvd25cIiArIFwiIHJldHVybmVkXCIsXG4gICAgICAgICk7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBhc3luYyBjbG9zZVdlYnNvY2tldCgpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICAgICAgdGhpcy52b3J0ZXhTdGF0dXNTZXJ2aWNlLmxvZ0RlYnVnKFxuICAgICAgICAgICAgXCJWb3J0ZXhDbGllbnRXZWJzb2NrZXQuY2xvc2VXZWJzb2NrZXQgY2FsbGVkXCIsXG4gICAgICAgICk7XG4gICAgICAgIC8vIElmIHdlJ3JlIG9wZW4gdGhlbiBjbG9zZVxuICAgICAgICBpZiAodGhpcy5zb2NrZXQgJiYgdGhpcy5zb2NrZXQucmVhZHlTdGF0ZSA9PT0gdGhpcy5Tb2NrZXQuT1BFTikge1xuICAgICAgICAgICAgYXdhaXQgbmV3IFByb21pc2U8dm9pZD4oKHJlc29sdmUsIHJlamVjdCkgPT4ge1xuICAgICAgICAgICAgICAgIHRoaXMudm9ydGV4U3RhdHVzU2VydmljZS5sb2dEZWJ1ZyhcIldlYnNvY2tldCBjbG9zZSBzdGFydGluZ1wiKTtcbiAgICAgICAgICAgICAgICB0aGlzLnNldENsb3NpbmcoKTtcbiAgICAgICAgICAgICAgICB0aGlzLnNvY2tldC5hZGRFdmVudExpc3RlbmVyKFwiY2xvc2VcIiwgKCkgPT4ge1xuICAgICAgICAgICAgICAgICAgICB0aGlzLnZvcnRleFN0YXR1c1NlcnZpY2UubG9nSW5mbyhcbiAgICAgICAgICAgICAgICAgICAgICAgIFwiV2Vic29ja2V0IGNsb3NlIGNvbXBsZXRlXCIsXG4gICAgICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuc2V0Q2xvc2VkKCk7XG4gICAgICAgICAgICAgICAgICAgIHJlc29sdmUoKTtcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICB0aGlzLnNvY2tldC5jbG9zZSgpO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLnNvY2tldCA9IG51bGw7XG5cbiAgICAgICAgdGhpcy52b3J0ZXhTdGF0dXNTZXJ2aWNlLmxvZ0RlYnVnKFxuICAgICAgICAgICAgXCJWb3J0ZXhDbGllbnRXZWJzb2NrZXQuY2xvc2VXZWJzb2NrZXQgcmV0dXJuaW5nXCIsXG4gICAgICAgICk7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBhc3luYyBjcmVhdGVTb2NrZXQoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICAgIHRoaXMudm9ydGV4U3RhdHVzU2VydmljZS5sb2dEZWJ1ZyhcbiAgICAgICAgICAgIFwiVm9ydGV4Q2xpZW50V2Vic29ja2V0LmNyZWF0ZVNvY2tldCBjYWxsZWRcIixcbiAgICAgICAgKTtcbiAgICAgICAgLy8gSWYgd2UncmUgYWxyZWFkeSBjb25uZWN0aW5nLCB0aGVuIGRvIG5vdGhpbmdcbiAgICAgICAgaWYgKHRoaXMuc29ja2V0ICYmIHRoaXMuc29ja2V0LnJlYWR5U3RhdGUgPT09IHRoaXMuU29ja2V0LkNPTk5FQ1RJTkcpIHtcbiAgICAgICAgICAgIGlmICghdGhpcy5pc1NodXRkb3duKSB7XG4gICAgICAgICAgICAgICAgdGhpcy52b3J0ZXhTdGF0dXNTZXJ2aWNlLmxvZ0RlYnVnKFxuICAgICAgICAgICAgICAgICAgICBcIlZvcnRleENsaWVudFdlYnNvY2tldC5jcmVhdGVTb2NrZXRcIiArIFwiIHJldHVybmluZyAjMVwiLFxuICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgICAgICBjb25zb2xlLmxvZyhcbiAgICAgICAgICAgICAgICAgICAgXCJBYm9ydGluZyBXZWJTb2NrZXQgY29ubmVjdGlvbiBhdHRlbXB0LFwiICtcbiAgICAgICAgICAgICAgICAgICAgICAgIFwiIHRoaXMgaXMgcHJvYmFibHkgYmVjYXVzZSBvZiBWb3J0ZXggcmVjb25uZWN0aW9uXCIsXG4gICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICB0aGlzLnNvY2tldC5jbG9zZSgpO1xuICAgICAgICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICAgICAgICAgIC8vIHBhc3NcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIHRoaXMudm9ydGV4U3RhdHVzU2VydmljZS5sb2dEZWJ1ZyhcbiAgICAgICAgICAgIFwiVm9ydGV4Q2xpZW50V2Vic29ja2V0LmNyZWF0ZVNvY2tldCBDbG9zaW5nIG9sZCB3ZWJzb2NrZXRcIixcbiAgICAgICAgKTtcbiAgICAgICAgYXdhaXQgdGhpcy5jbG9zZVdlYnNvY2tldCgpO1xuXG4gICAgICAgIC8vIERvbid0IGNvbnRpbnVhbGx5IHJlY29ubmVjdFxuICAgICAgICBsZXQgcmVjb25uZWN0RGlmZk1zID0gRGF0ZS5ub3coKSAtIHRoaXMubGFzdFJlY29ubmVjdERhdGU7XG4gICAgICAgIGlmIChyZWNvbm5lY3REaWZmTXMgPCB0aGlzLlJFQ09OTkVDVF9CQUNLT0ZGX1NFQ09ORFMgKiAxMDAwKSB7XG4gICAgICAgICAgICB0aGlzLnZvcnRleFN0YXR1c1NlcnZpY2UubG9nRGVidWcoXG4gICAgICAgICAgICAgICAgXCJWb3J0ZXhDbGllbnRXZWJzb2NrZXQuY3JlYXRlU29ja2V0IHJldHVybmluZyAjMiAtIGJhY2tvZmZcIiArXG4gICAgICAgICAgICAgICAgICAgIFwiIHRpbWVvdXRcIixcbiAgICAgICAgICAgICk7XG4gICAgICAgICAgICBzZXRUaW1lb3V0KFxuICAgICAgICAgICAgICAgICgpID0+IHRoaXMuY3JlYXRlU29ja2V0KCksXG4gICAgICAgICAgICAgICAgdGhpcy5SRUNPTk5FQ1RfQkFDS09GRl9TRUNPTkRTICogMTAwMCAtIHJlY29ubmVjdERpZmZNcyArIDEwLFxuICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIHRoaXMubGFzdFJlY29ubmVjdERhdGUgPSBEYXRlLm5vdygpO1xuXG4gICAgICAgIC8vIFByZXBhcmUgdGhlIGFyZ3MgdG8gc2VuZFxuICAgICAgICBjb25zdCBhcmdzID0ge1xuICAgICAgICAgICAgdm9ydGV4VXVpZDogdGhpcy51dWlkLFxuICAgICAgICAgICAgdm9ydGV4TmFtZTogdGhpcy5uYW1lLFxuICAgICAgICB9O1xuXG4gICAgICAgIHRoaXMudm9ydGV4U3RhdHVzU2VydmljZS5sb2dDb25uZWN0aW9uSW5mbyhcbiAgICAgICAgICAgIGAke2RhdGVTdHIoKX0gV2ViU29ja2V0LCBjb25uZWN0aW5nIHRvICR7dGhpcy51cmx9YCxcbiAgICAgICAgKTtcblxuICAgICAgICBhd2FpdCBuZXcgUHJvbWlzZTx2b2lkPigocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XG4gICAgICAgICAgICAvLyBDb25zdHJ1Y3QgKyBvcGVuIHRoZSBzb2NrZXRcbiAgICAgICAgICAgIGxldCBwcm9taXNlQ2FsbGVkID0gZmFsc2U7XG5cbiAgICAgICAgICAgIHRoaXMudm9ydGV4U3RhdHVzU2VydmljZS5sb2dEZWJ1ZyhcbiAgICAgICAgICAgICAgICBcIlZvcnRleENsaWVudFdlYnNvY2tldC5jcmVhdGVTb2NrZXQgQ3JlYXRpbmcgc29ja2V0XCIsXG4gICAgICAgICAgICApO1xuICAgICAgICAgICAgdGhpcy5zb2NrZXQgPSBuZXcgdGhpcy5Tb2NrZXQodGhpcy51cmwgKyBnZXRGaWx0U3RyKGFyZ3MpLCBbXSk7XG5cbiAgICAgICAgICAgIHRoaXMuc29ja2V0LmJpbmFyeVR5cGUgPSBcImFycmF5YnVmZmVyXCI7XG5cbiAgICAgICAgICAgIHRoaXMuc29ja2V0LmFkZEV2ZW50TGlzdGVuZXIoXCJtZXNzYWdlXCIsIChldmVudCkgPT4ge1xuICAgICAgICAgICAgICAgIHRoaXMub25NZXNzYWdlKGV2ZW50LCAoKSA9PiB7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMudm9ydGV4U3RhdHVzU2VydmljZS5sb2dEZWJ1ZyhcbiAgICAgICAgICAgICAgICAgICAgICAgIFwiVm9ydGV4Q2xpZW50V2Vic29ja2V0LmNyZWF0ZVNvY2tldCBjYWxsaW5nIHJlc29sdmVcIiArXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgXCIgZnJvbSBtZXNzYWdlXCIsXG4gICAgICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgICAgIHJlc29sdmUoKTtcbiAgICAgICAgICAgICAgICAgICAgcHJvbWlzZUNhbGxlZCA9IHRydWU7XG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIHRoaXMuc29ja2V0LmFkZEV2ZW50TGlzdGVuZXIoXCJjbG9zZVwiLCAoZXZlbnQpID0+IHtcbiAgICAgICAgICAgICAgICB0aGlzLnZvcnRleFN0YXR1c1NlcnZpY2UubG9nRGVidWcoXG4gICAgICAgICAgICAgICAgICAgIFwiVm9ydGV4Q2xpZW50V2Vic29ja2V0LmNyZWF0ZVNvY2tldCBhZGRFdmVudExpc3RlbmVyIGNsb3NlXCIsXG4gICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICB0aGlzLm9uQ2xvc2UoZXZlbnQpO1xuICAgICAgICAgICAgICAgIGlmICghcHJvbWlzZUNhbGxlZCkge1xuICAgICAgICAgICAgICAgICAgICB0aGlzLnZvcnRleFN0YXR1c1NlcnZpY2UubG9nRGVidWcoXG4gICAgICAgICAgICAgICAgICAgICAgICBcIlZvcnRleENsaWVudFdlYnNvY2tldC5jcmVhdGVTb2NrZXQgY2FsbGluZyByZWplY3RcIiArXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgXCIgZnJvbSBjbG9zZVwiLFxuICAgICAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICAgICAgICBwcm9taXNlQ2FsbGVkID0gdHJ1ZTtcbiAgICAgICAgICAgICAgICAgICAgcmVqZWN0KCk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB0aGlzLnNvY2tldC5hZGRFdmVudExpc3RlbmVyKFwiZXJyb3JcIiwgKGV2ZW50KSA9PiB7XG4gICAgICAgICAgICAgICAgdGhpcy52b3J0ZXhTdGF0dXNTZXJ2aWNlLmxvZ0RlYnVnKFxuICAgICAgICAgICAgICAgICAgICBgVm9ydGV4Q2xpZW50V2Vic29ja2V0LmNyZWF0ZVNvY2tldCBhZGRFdmVudExpc3RlbmVyIGVycm9yOiAke2V2ZW50fWAsXG4gICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICB0aGlzLm9uRXJyb3IoZXZlbnQsICgpID0+IHtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy52b3J0ZXhTdGF0dXNTZXJ2aWNlLmxvZ0RlYnVnKFxuICAgICAgICAgICAgICAgICAgICAgICAgXCJWb3J0ZXhDbGllbnRXZWJzb2NrZXQuY3JlYXRlU29ja2V0IGNhbGxpbmcgcmVqZWN0XCIgK1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIFwiIGZyb20gZXJyb3JcIixcbiAgICAgICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICAgICAgcmVqZWN0KCk7XG4gICAgICAgICAgICAgICAgICAgIHByb21pc2VDYWxsZWQgPSB0cnVlO1xuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB0aGlzLnNvY2tldC5hZGRFdmVudExpc3RlbmVyKFwib3BlblwiLCAoZXZlbnQpID0+IHtcbiAgICAgICAgICAgICAgICB0aGlzLnZvcnRleFN0YXR1c1NlcnZpY2UubG9nRGVidWcoXG4gICAgICAgICAgICAgICAgICAgIFwiVm9ydGV4Q2xpZW50V2Vic29ja2V0LmNyZWF0ZVNvY2tldCBhZGRFdmVudExpc3RlbmVyIG9wZW5cIixcbiAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICAgIHRoaXMub25PcGVuKGV2ZW50KTtcbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9KTtcblxuICAgICAgICB0aGlzLnZvcnRleFN0YXR1c1NlcnZpY2UubG9nRGVidWcoXG4gICAgICAgICAgICBcIlZvcnRleENsaWVudFdlYnNvY2tldC5jcmVhdGVTb2NrZXQgcmV0dXJuaW5nICMzXCIsXG4gICAgICAgICk7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBvbk1lc3NhZ2UoZXZlbnQsIHByb21pc2VSZXNvbHZlcikge1xuICAgICAgICBpZiAoIXRoaXMuaXNPbmxpbmUpIHtcbiAgICAgICAgICAgIHRoaXMuc2V0T25saW5lKCk7XG4gICAgICAgICAgICBwcm9taXNlUmVzb2x2ZXIoKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHRoaXMuYmVhdCgpO1xuXG4gICAgICAgIGlmIChldmVudC5kYXRhLmxlbmd0aCA9PSBudWxsKSB7XG4gICAgICAgICAgICB0aGlzLnZvcnRleFN0YXR1c1NlcnZpY2UubG9nQ29ubmVjdGlvbkVycm9yKFxuICAgICAgICAgICAgICAgIFwiV2ViU29ja2V0LCBXZSd2ZSByZWNlaXZlZCBhIHdlYnNvY2tldCBiaW5hcnkgbWVzc2FnZSxcIiArXG4gICAgICAgICAgICAgICAgICAgIFwiIHdlIGV4cGVjdCBhIHVuaWNvZGVcIixcbiAgICAgICAgICAgICk7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICAvLyBJZiB0aGUgc2VydmVyIHNlbmRzIHVzIGEgJy4nLCB0aGF0J3MgYSBoZWFydCBiZWF0LCByZXR1cm4gaXQuXG4gICAgICAgIGlmIChldmVudC5kYXRhID09PSBcIi5cIikge1xuICAgICAgICAgICAgdGhpcy5zb2NrZXQgIT0gbnVsbCAmJiB0aGlzLnNvY2tldC5zZW5kKFwiLlwiKTtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChldmVudC5kYXRhWzBdICE9PSBcIntcIikge1xuICAgICAgICAgICAgdGhpcy5fZGF0YSArPSBldmVudC5kYXRhO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgLy8gSXQgc3RhcnRzIHdpdGggeywgZW5zdXJlIGl0IGVuZHMgd2l0aCB9XG4gICAgICAgICAgICBpZiAoZXZlbnQuZGF0YVtldmVudC5kYXRhLmxlbmd0aCAtIDFdICE9PSBcIn1cIikge1xuICAgICAgICAgICAgICAgIGNvbnNvbGUubG9nKFxuICAgICAgICAgICAgICAgICAgICBkYXRlU3RyKCkgK1xuICAgICAgICAgICAgICAgICAgICAgICAgXCIgRVJST1IsIFBheWxvYWQgc2hvdWxkIGVuZCB3aXRoIH0sXCIgK1xuICAgICAgICAgICAgICAgICAgICAgICAgXCIgYnV0IGl0IGRvZXNuJ3Q6IFwiICtcbiAgICAgICAgICAgICAgICAgICAgICAgIGV2ZW50LmRhdGEsXG4gICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICB0aGlzLl92b3J0ZXhNc2dzUXVldWUucHVzaChldmVudC5kYXRhKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHRoaXMuX3Byb2Nlc3NEYXRhKCk7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBvbk9wZW4oZXZlbnQpIHtcbiAgICAgICAgc3VwZXJcbiAgICAgICAgICAgIC5zZW5kKG5ldyBQYXlsb2FkRW52ZWxvcGUoKSlcbiAgICAgICAgICAgIC5jYXRjaCgoZSkgPT5cbiAgICAgICAgICAgICAgICBjb25zb2xlLmxvZyhgRVJST1IgVm9ydGV4Q2xpZW50V2Vic29ja2V0IG9uT3BlbiBTZW5kOiAke2V9YCksXG4gICAgICAgICAgICApO1xuICAgICAgICB0aGlzLnZvcnRleFN0YXR1c1NlcnZpY2UubG9nQ29ubmVjdGlvbkluZm8oXCJXZWJTb2NrZXQsIGNvbm5lY3RpbmdcIik7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBvbkNsb3NlKGV2ZW50KSB7XG4gICAgICAgIHRoaXMudm9ydGV4U3RhdHVzU2VydmljZS5sb2dDb25uZWN0aW9uSW5mbyhcIldlYlNvY2tldCwgY2xvc2VkXCIpO1xuICAgICAgICBpZiAoISh0aGlzLnNvY2tldCAmJiB0aGlzLnNvY2tldC5yZWFkeVN0YXRlID09PSB0aGlzLlNvY2tldC5PUEVOKSkge1xuICAgICAgICAgICAgdGhpcy5zZXRDbG9zZWQoKTtcbiAgICAgICAgfVxuICAgICAgICAvLyBUaGUgYmFzZSBjbGFzcyB3aWxsIHJlY29ubmVjdFxuICAgIH1cblxuICAgIHByaXZhdGUgb25FcnJvcihldmVudCwgcmVqZWN0KSB7XG4gICAgICAgIHJlamVjdChldmVudC5lcnJvcj8udG9TdHJpbmcoKSB8fCBcIldlYnNvY2tldCBmYWlsZWQgdG8gY29ubmVjdFwiKTtcbiAgICAgICAgLy8gb25DbG9zZSB3aWxsIGdldCBjYWxsZWQgYXMgd2VsbFxuXG4gICAgICAgIC8vIENoZWNrIGlmIHRoZSBzZXJ2ZXIgaXMgc3RpbGwgdXAsIGlmIGl0IGlzIHdlJ3ZlIGJlZW4gbG9nZ2VkIG91dFxuICAgICAgICB0aGlzLnRlc3RJZk9ubGluZUFuZExvZ2dlZE91dCgpXG4gICAgICAgICAgICAudGhlbigoKSA9PiBjb25zb2xlLmxvZyhcIlNlcnZlciBpcyB1bnJlYWNoYWJsZVwiKSlcbiAgICAgICAgICAgIC5jYXRjaCgoKSA9PiB7XG4gICAgICAgICAgICAgICAgdGhpcy52b3J0ZXhTdGF0dXNTZXJ2aWNlLmxvZ0Nvbm5lY3Rpb25FcnJvcihcbiAgICAgICAgICAgICAgICAgICAgXCJWb3J0ZXggV2Vic29ja2V0IGRvZXNuJ3QgY29ubmVjdCBidXQgc2VydmVyIGlzIG9ubGluZSxcIiArXG4gICAgICAgICAgICAgICAgICAgICAgICBcIiBNYXJraW5nIHZvcnRleCBhcyBsb2dnZWQgb3V0XCIsXG4gICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICB0aGlzLnZvcnRleFN0YXR1c1NlcnZpY2Uuc2V0SHR0cFNlc3Npb25Mb2dnZWRPdXQoKTtcbiAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICB9KTtcbiAgICB9XG5cbiAgICBwcml2YXRlIHRlc3RJZk9ubGluZUFuZExvZ2dlZE91dCgpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICAgICAgcmV0dXJuIG5ldyBQcm9taXNlPHZvaWQ+KChyZXNvbHZlLCByZWplY3QpID0+IHtcbiAgICAgICAgICAgIGNvbnN0IGh0dHBVcmwgPSBcImh0dHBcIiArIHRoaXMuX3VybC5zdWJzdHJpbmcoMik7XG4gICAgICAgICAgICBsZXQgeG1sSHR0cCA9IG5ldyBYTUxIdHRwUmVxdWVzdCgpO1xuICAgICAgICAgICAgeG1sSHR0cC50aW1lb3V0ID0gMjAwMDtcbiAgICAgICAgICAgIHhtbEh0dHAucmVzcG9uc2VUeXBlID0gXCJkb2N1bWVudFwiO1xuICAgICAgICAgICAgeG1sSHR0cC5vbmxvYWQgPSBmdW5jdGlvbiAoZXZlbnQpIHtcbiAgICAgICAgICAgICAgICByZWplY3QoKTtcbiAgICAgICAgICAgIH07XG4gICAgICAgICAgICB4bWxIdHRwLm9uZXJyb3IgPSBmdW5jdGlvbiAoZXZlbnQpIHtcbiAgICAgICAgICAgICAgICByZXNvbHZlKCk7XG4gICAgICAgICAgICB9O1xuICAgICAgICAgICAgeG1sSHR0cC5vcGVuKFwiR0VUXCIsIGh0dHBVcmwsIHRydWUpOyAvLyB0cnVlIGZvciBhc3luY2hyb25vdXNcbiAgICAgICAgICAgIHhtbEh0dHAuc2VuZChudWxsKTtcbiAgICAgICAgfSk7XG4gICAgfVxufVxuIl19