UNPKG

atom-languageclient

Version:
313 lines 46.5 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.considerAdditionalPath = exports.normalizePath = exports.normalizedProjectPathToWorkspaceFolder = exports.projectPathToWorkspaceFolder = exports.ServerManager = void 0; const convert_1 = require("./convert"); const path = require("path"); const atom_1 = require("atom"); /** Manages the language server lifecycles and their associated objects necessary for adapting them to Atom IDE. */ class ServerManager { constructor(_startServer, _logger, _startForEditor, _changeWatchedFileFilter, _reportBusyWhile, _languageServerName, _determineProjectPath, shutdownGracefully) { this._startServer = _startServer; this._logger = _logger; this._startForEditor = _startForEditor; this._changeWatchedFileFilter = _changeWatchedFileFilter; this._reportBusyWhile = _reportBusyWhile; this._languageServerName = _languageServerName; this._determineProjectPath = _determineProjectPath; this.shutdownGracefully = shutdownGracefully; this._activeServers = []; this._startingServerPromises = new Map(); this._restartCounterPerProject = new Map(); this._stoppingServers = []; this._disposable = new atom_1.CompositeDisposable(); this._editorToServer = new Map(); this._normalizedProjectPaths = []; this._previousNormalizedProjectPaths = undefined; // TODO we should not hold a separate cache this._isStarted = false; /** @deprecated Use the exported `normalizePath` function */ this.normalizePath = normalizePath; this.updateNormalizedProjectPaths(); } startListening() { if (!this._isStarted) { this._disposable = new atom_1.CompositeDisposable(); this._disposable.add(atom.textEditors.observe(this.observeTextEditors.bind(this))); this._disposable.add(atom.project.onDidChangePaths(this.projectPathsChanged.bind(this))); if (atom.project.onDidChangeFiles) { this._disposable.add(atom.project.onDidChangeFiles(this.projectFilesChanged.bind(this))); } } this._isStarted = true; } stopListening() { if (this._isStarted) { this._disposable.dispose(); this._isStarted = false; } } observeTextEditors(editor) { // Track grammar changes for opened editors const listener = editor.observeGrammar((_grammar) => this._handleGrammarChange(editor)); this._disposable.add(editor.onDidDestroy(() => listener.dispose())); // Try to see if editor can have LS connected to it this._handleTextEditor(editor); } _handleTextEditor(editor) { return __awaiter(this, void 0, void 0, function* () { if (!this._editorToServer.has(editor)) { // editor hasn't been processed yet, so process it by allocating LS for it if necessary const server = yield this.getServer(editor, { shouldStart: true }); if (server != null) { // There LS for the editor (either started now and already running) this._editorToServer.set(editor, server); this._disposable.add(editor.onDidDestroy(() => { this._editorToServer.delete(editor); this.stopUnusedServers(); })); } } }); } _handleGrammarChange(editor) { if (this._startForEditor(editor)) { // If editor is interesting for LS process the editor further to attempt to start LS if needed this._handleTextEditor(editor); } else { // Editor is not supported by the LS const server = this._editorToServer.get(editor); // If LS is running for the unsupported editor then disconnect the editor from LS and shut down LS if necessary if (server) { // Remove editor from the cache this._editorToServer.delete(editor); // Shut down LS if it's used by any other editor this.stopUnusedServers(); } } } getActiveServers() { return this._activeServers; } getServer(textEditor, { shouldStart } = { shouldStart: false }) { return __awaiter(this, void 0, void 0, function* () { const finalProjectPath = this._determineProjectPath(textEditor); if (finalProjectPath == null) { // Files not yet saved have no path return null; } const foundActiveServer = this._activeServers.find((s) => finalProjectPath === s.projectPath); if (foundActiveServer) { return foundActiveServer; } const startingPromise = this._startingServerPromises.get(finalProjectPath); if (startingPromise) { return startingPromise; } // TODO remove eslint-disable // eslint-disable-next-line no-return-await return shouldStart && this._startForEditor(textEditor) ? yield this.startServer(finalProjectPath) : null; }); } startServer(projectPath) { return __awaiter(this, void 0, void 0, function* () { this._logger.debug(`Server starting "${projectPath}"`); const startingPromise = this._startServer(projectPath); this._startingServerPromises.set(projectPath, startingPromise); try { const startedActiveServer = yield startingPromise; this._activeServers.push(startedActiveServer); this._startingServerPromises.delete(projectPath); this._logger.debug(`Server started "${projectPath}" (pid ${startedActiveServer.process.pid})`); return startedActiveServer; } catch (e) { this._startingServerPromises.delete(projectPath); throw e; } }); } stopUnusedServers() { return __awaiter(this, void 0, void 0, function* () { const usedServers = new Set(this._editorToServer.values()); const unusedServers = this._activeServers.filter((s) => !usedServers.has(s)); if (unusedServers.length > 0) { this._logger.debug(`Stopping ${unusedServers.length} unused servers`); yield Promise.all(unusedServers.map((s) => this.stopServer(s))); } }); } stopAllServers() { return __awaiter(this, void 0, void 0, function* () { for (const [projectPath, restartCounter] of this._restartCounterPerProject) { clearTimeout(restartCounter.timerId); this._restartCounterPerProject.delete(projectPath); } yield Promise.all(this._activeServers.map((s) => this.stopServer(s))); }); } restartAllServers() { return __awaiter(this, void 0, void 0, function* () { this.stopListening(); yield this.stopAllServers(); this._editorToServer = new Map(); this.startListening(); }); } hasServerReachedRestartLimit(server) { let restartCounter = this._restartCounterPerProject.get(server.projectPath); if (!restartCounter) { restartCounter = { restarts: 0, timerId: setTimeout(() => { this._restartCounterPerProject.delete(server.projectPath); }, 3 * 60 * 1000 /* 3 minutes */), }; this._restartCounterPerProject.set(server.projectPath, restartCounter); } return ++restartCounter.restarts > 5; } stopServer(server) { return __awaiter(this, void 0, void 0, function* () { yield this._reportBusyWhile(`Stopping ${this._languageServerName} for ${path.basename(server.projectPath)}`, () => __awaiter(this, void 0, void 0, function* () { this._logger.debug(`Server stopping "${server.projectPath}"`); // Immediately remove the server to prevent further usage. // If we re-open the file after this point, we'll get a new server. this._activeServers.splice(this._activeServers.indexOf(server), 1); this._stoppingServers.push(server); server.disposable.dispose(); if (this.shutdownGracefully && server.connection.isConnected) { yield server.connection.shutdown(); } for (const [editor, mappedServer] of this._editorToServer) { if (mappedServer === server) { this._editorToServer.delete(editor); } } this.exitServer(server); this._stoppingServers.splice(this._stoppingServers.indexOf(server), 1); })); }); } exitServer(server) { const pid = server.process.pid; try { if (server.connection.isConnected) { server.connection.exit(); server.connection.dispose(); } } finally { server.process.kill(); } this._logger.debug(`Server stopped "${server.projectPath}" (pid ${pid})`); } terminate() { this._stoppingServers.forEach((server) => { this._logger.debug(`Server terminating "${server.projectPath}"`); this.exitServer(server); }); } updateNormalizedProjectPaths() { this._normalizedProjectPaths = atom.project.getPaths().map(normalizePath); } getNormalizedProjectPaths() { return this._normalizedProjectPaths; } /** * Public: fetch the current open list of workspace folders * * @returns A {Promise} containing an {Array} of {lsp.WorkspaceFolder[]} or {null} if only a single file is open in the tool. */ getWorkspaceFolders() { // NOTE the method must return a Promise based on the specification const projectPaths = this.getNormalizedProjectPaths(); if (projectPaths.length === 0) { // only a single file is open return Promise.resolve(null); } else { return Promise.resolve(projectPaths.map(normalizedProjectPathToWorkspaceFolder)); } } projectPathsChanged(projectPaths) { var _a; return __awaiter(this, void 0, void 0, function* () { const pathsAll = projectPaths.map(normalizePath); const previousPaths = (_a = this._previousNormalizedProjectPaths) !== null && _a !== void 0 ? _a : this.getNormalizedProjectPaths(); const pathsRemoved = previousPaths.filter((projectPath) => !pathsAll.includes(projectPath)); const pathsAdded = pathsAll.filter((projectPath) => !previousPaths.includes(projectPath)); // update cache this._previousNormalizedProjectPaths = pathsAll; // send didChangeWorkspaceFolders const didChangeWorkspaceFoldersParams = { event: { added: pathsAdded.map(normalizedProjectPathToWorkspaceFolder), removed: pathsRemoved.map(normalizedProjectPathToWorkspaceFolder), }, }; for (const activeServer of this._activeServers) { activeServer.connection.didChangeWorkspaceFolders(didChangeWorkspaceFoldersParams); } // stop the servers that don't have projectPath const serversToStop = this._activeServers.filter((server) => pathsRemoved.includes(server.projectPath)); yield Promise.all(serversToStop.map((s) => this.stopServer(s))); // update this._normalizedProjectPaths this.updateNormalizedProjectPaths(); }); } projectFilesChanged(fileEvents) { if (this._activeServers.length === 0) { return; } for (const activeServer of this._activeServers) { const changes = []; for (const fileEvent of fileEvents) { if (fileEvent.path.startsWith(activeServer.projectPath) && this._changeWatchedFileFilter(fileEvent.path)) { changes.push(convert_1.default.atomFileEventToLSFileEvents(fileEvent)[0]); } if (fileEvent.action === "renamed" && fileEvent.oldPath.startsWith(activeServer.projectPath) && this._changeWatchedFileFilter(fileEvent.oldPath)) { changes.push(convert_1.default.atomFileEventToLSFileEvents(fileEvent)[1]); } } if (changes.length > 0) { activeServer.connection.didChangeWatchedFiles({ changes }); } } } } exports.ServerManager = ServerManager; function projectPathToWorkspaceFolder(projectPath) { const normalizedProjectPath = normalizePath(projectPath); return normalizedProjectPathToWorkspaceFolder(normalizedProjectPath); } exports.projectPathToWorkspaceFolder = projectPathToWorkspaceFolder; function normalizedProjectPathToWorkspaceFolder(normalizedProjectPath) { return { uri: convert_1.default.pathToUri(normalizedProjectPath), name: path.basename(normalizedProjectPath), }; } exports.normalizedProjectPathToWorkspaceFolder = normalizedProjectPathToWorkspaceFolder; function normalizePath(projectPath) { return !projectPath.endsWith(path.sep) ? path.join(projectPath, path.sep) : projectPath; } exports.normalizePath = normalizePath; /** Considers a path for inclusion in `additionalPaths`. */ function considerAdditionalPath(server, additionalPath) { if (!additionalPath.startsWith(server.projectPath)) { server.additionalPaths.add(additionalPath); } } exports.considerAdditionalPath = considerAdditionalPath; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2VydmVyLW1hbmFnZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9saWIvc2VydmVyLW1hbmFnZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7O0FBQUEsdUNBQStCO0FBQy9CLDZCQUE0QjtBQUk1QiwrQkFBNkU7QUE0QjdFLG1IQUFtSDtBQUNuSCxNQUFhLGFBQWE7SUFXeEIsWUFDVSxZQUE0RCxFQUM1RCxPQUFlLEVBQ2YsZUFBZ0QsRUFDaEQsd0JBQXVELEVBQ3ZELGdCQUFpQyxFQUNqQyxtQkFBMkIsRUFDM0IscUJBQWdFLEVBQ2hFLGtCQUEyQjtRQVAzQixpQkFBWSxHQUFaLFlBQVksQ0FBZ0Q7UUFDNUQsWUFBTyxHQUFQLE9BQU8sQ0FBUTtRQUNmLG9CQUFlLEdBQWYsZUFBZSxDQUFpQztRQUNoRCw2QkFBd0IsR0FBeEIsd0JBQXdCLENBQStCO1FBQ3ZELHFCQUFnQixHQUFoQixnQkFBZ0IsQ0FBaUI7UUFDakMsd0JBQW1CLEdBQW5CLG1CQUFtQixDQUFRO1FBQzNCLDBCQUFxQixHQUFyQixxQkFBcUIsQ0FBMkM7UUFDaEUsdUJBQWtCLEdBQWxCLGtCQUFrQixDQUFTO1FBbEI3QixtQkFBYyxHQUFtQixFQUFFLENBQUE7UUFDbkMsNEJBQXVCLEdBQXVDLElBQUksR0FBRyxFQUFFLENBQUE7UUFDdkUsOEJBQXlCLEdBQWdDLElBQUksR0FBRyxFQUFFLENBQUE7UUFDbEUscUJBQWdCLEdBQW1CLEVBQUUsQ0FBQTtRQUNyQyxnQkFBVyxHQUF3QixJQUFJLDBCQUFtQixFQUFFLENBQUE7UUFDNUQsb0JBQWUsR0FBa0MsSUFBSSxHQUFHLEVBQUUsQ0FBQTtRQUMxRCw0QkFBdUIsR0FBYSxFQUFFLENBQUE7UUFDdEMsb0NBQStCLEdBQXlCLFNBQVMsQ0FBQSxDQUFDLDJDQUEyQztRQUM3RyxlQUFVLEdBQUcsS0FBSyxDQUFBO1FBOFIxQiw0REFBNEQ7UUFDckQsa0JBQWEsR0FBRyxhQUFhLENBQUE7UUFuUmxD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LENBQUMsY0FBYyxDQUFDLFVBQVUsQ0FBQyxNQUFNLENBQUMsV0FBVyxDQUFDLEVBQUU7UUFDbEQsTUFBTSxDQUFDLGVBQWUsQ0FBQyxHQUFHLENBQUMsY0FBYyxDQUFDLENBQUE7S0FDM0M7QUFDSCxDQUFDO0FBUEQsd0RBT0MiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgQ29udmVydCBmcm9tIFwiLi9jb252ZXJ0XCJcbmltcG9ydCAqIGFzIHBhdGggZnJvbSBcInBhdGhcIlxuaW1wb3J0ICogYXMgbHMgZnJvbSBcIi4vbGFuZ3VhZ2VjbGllbnRcIlxuaW1wb3J0IHsgQ2hpbGRQcm9jZXNzIH0gZnJvbSBcImNoaWxkX3Byb2Nlc3NcIlxuaW1wb3J0IHsgTG9nZ2VyIH0gZnJvbSBcIi4vbG9nZ2VyXCJcbmltcG9ydCB7IENvbXBvc2l0ZURpc3Bvc2FibGUsIEZpbGVzeXN0ZW1DaGFuZ2VFdmVudCwgVGV4dEVkaXRvciB9IGZyb20gXCJhdG9tXCJcbmltcG9ydCB7IFJlcG9ydEJ1c3lXaGlsZSB9IGZyb20gXCIuL3V0aWxzXCJcblxuZXhwb3J0IHR5cGUgTWluaW1hbExhbmd1YWdlU2VydmVyUHJvY2VzcyA9IFBpY2s8Q2hpbGRQcm9jZXNzLCBcInN0ZGluXCIgfCBcInN0ZG91dFwiIHwgXCJzdGRlcnJcIiB8IFwicGlkXCIgfCBcImtpbGxcIiB8IFwib25cIj5cblxuLyoqXG4gKiBQdWJsaWM6IERlZmluZXMgYSBsYW5ndWFnZSBzZXJ2ZXIgcHJvY2VzcyB3aGljaCBpcyBlaXRoZXIgYSBDaGlsZFByb2Nlc3MsIG9yIGl0IGlzIGEgbWluaW1hbCBvYmplY3QgdGhhdCByZXNlbWJsZXMgYVxuICogQ2hpbGRQcm9jZXNzLiBgTWluaW1hbExhbmd1YWdlU2VydmVyUHJvY2Vzc2AgaXMgdXNlZCBzbyB0aGF0IGxhbmd1YWdlIHBhY2thZ2VzIHdpdGggYWx0ZXJuYXRpdmUgbGFuZ3VhZ2Ugc2VydmVyXG4gKiBwcm9jZXNzIGhvc3Rpbmcgc3RyYXRlZ2llcyBjYW4gcmV0dXJuIHNvbWV0aGluZyBjb21wYXRpYmxlIHdpdGggYEF1dG9MYW5ndWFnZUNsaWVudC5zdGFydFNlcnZlclByb2Nlc3NgLlxuICovXG5leHBvcnQgdHlwZSBMYW5ndWFnZVNlcnZlclByb2Nlc3MgPSBDaGlsZFByb2Nlc3MgfCBNaW5pbWFsTGFuZ3VhZ2VTZXJ2ZXJQcm9jZXNzXG5cbi8qKiBUaGUgbmVjZXNzYXJ5IGVsZW1lbnRzIGZvciBhIHNlcnZlciB0aGF0IGhhcyBzdGFydGVkIG9yIGlzIHN0YXJ0aW5nLiAqL1xuZXhwb3J0IGludGVyZmFjZSBBY3RpdmVTZXJ2ZXIge1xuICBkaXNwb3NhYmxlOiBDb21wb3NpdGVEaXNwb3NhYmxlXG4gIHByb2plY3RQYXRoOiBzdHJpbmdcbiAgcHJvY2VzczogTGFuZ3VhZ2VTZXJ2ZXJQcm9jZXNzXG4gIGNvbm5lY3Rpb246IGxzLkxhbmd1YWdlQ2xpZW50Q29ubmVjdGlvblxuICBjYXBhYmlsaXRpZXM6IGxzLlNlcnZlckNhcGFiaWxpdGllc1xuICAvKiogT3V0IG9mIHByb2plY3QgZGlyZWN0b3JpZXMgdGhhdCB0aGlzIHNlcnZlciBjYW4gYWxzbyBzdXBwb3J0LiAqL1xuICBhZGRpdGlvbmFsUGF0aHM/OiBTZXQ8c3RyaW5nPlxufVxuXG5pbnRlcmZhY2UgUmVzdGFydENvdW50ZXIge1xuICByZXN0YXJ0czogbnVtYmVyXG4gIHRpbWVySWQ6IE5vZGVKUy5UaW1lclxufVxuXG4vKiogTWFuYWdlcyB0aGUgbGFuZ3VhZ2Ugc2VydmVyIGxpZmVjeWNsZXMgYW5kIHRoZWlyIGFzc29jaWF0ZWQgb2JqZWN0cyBuZWNlc3NhcnkgZm9yIGFkYXB0aW5nIHRoZW0gdG8gQXRvbSBJREUuICovXG5leHBvcnQgY2xhc3MgU2VydmVyTWFuYWdlciB7XG4gIHByaXZhdGUgX2FjdGl2ZVNlcnZlcnM6IEFjdGl2ZVNlcnZlcltdID0gW11cbiAgcHJpdmF0ZSBfc3RhcnRpbmdTZXJ2ZXJQcm9taXNlczogTWFwPHN0cmluZywgUHJvbWlzZTxBY3RpdmVTZXJ2ZXI+PiA9IG5ldyBNYXAoKVxuICBwcml2YXRlIF9yZXN0YXJ0Q291bnRlclBlclByb2plY3Q6IE1hcDxzdHJpbmcsIFJlc3RhcnRDb3VudGVyPiA9IG5ldyBNYXAoKVxuICBwcml2YXRlIF9zdG9wcGluZ1NlcnZlcnM6IEFjdGl2ZVNlcnZlcltdID0gW11cbiAgcHJpdmF0ZSBfZGlzcG9zYWJsZTogQ29tcG9zaXRlRGlzcG9zYWJsZSA9IG5ldyBDb21wb3NpdGVEaXNwb3NhYmxlKClcbiAgcHJpdmF0ZSBfZWRpdG9yVG9TZXJ2ZXI6IE1hcDxUZXh0RWRpdG9yLCBBY3RpdmVTZXJ2ZXI+ID0gbmV3IE1hcCgpXG4gIHByaXZhdGUgX25vcm1hbGl6ZWRQcm9qZWN0UGF0aHM6IHN0cmluZ1tdID0gW11cbiAgcHJpdmF0ZSBfcHJldmlvdXNOb3JtYWxpemVkUHJvamVjdFBhdGhzOiBzdHJpbmdbXSB8IHVuZGVmaW5lZCA9IHVuZGVmaW5lZCAvLyBUT0RPIHdlIHNob3VsZCBub3QgaG9sZCBhIHNlcGFyYXRlIGNhY2hlXG4gIHByaXZhdGUgX2lzU3RhcnRlZCA9IGZhbHNlXG5cbiAgY29uc3RydWN0b3IoXG4gICAgcHJpdmF0ZSBfc3RhcnRTZXJ2ZXI6IChwcm9qZWN0UGF0aDogc3RyaW5nKSA9PiBQcm9taXNlPEFjdGl2ZVNlcnZlcj4sXG4gICAgcHJpdmF0ZSBfbG9nZ2VyOiBMb2dnZXIsXG4gICAgcHJpdmF0ZSBfc3RhcnRGb3JFZGl0b3I6IChlZGl0b3I6IFRleHRFZGl0b3IpID0+IGJvb2xlYW4sXG4gICAgcHJpdmF0ZSBfY2hhbmdlV2F0Y2hlZEZpbGVGaWx0ZXI6IChmaWxlUGF0aDogc3RyaW5nKSA9PiBib29sZWFuLFxuICAgIHByaXZhdGUgX3JlcG9ydEJ1c3lXaGlsZTogUmVwb3J0QnVzeVdoaWxlLFxuICAgIHByaXZhdGUgX2xhbmd1YWdlU2VydmVyTmFtZTogc3RyaW5nLFxuICAgIHByaXZhdGUgX2RldGVybWluZVByb2plY3RQYXRoOiAodGV4dEVkaXRvcjogVGV4dEVkaXRvcikgPT4gc3RyaW5nIHwgbnVsbCxcbiAgICBwcml2YXRlIHNodXRkb3duR3JhY2VmdWxseTogYm9vbGVhblxuICApIHtcbiAgICB0aGlzLnVwZGF0ZU5vcm1hbGl6ZWRQcm9qZWN0UGF0aHMoKVxuICB9XG5cbiAgcHVibGljIHN0YXJ0TGlzdGVuaW5nKCk6IHZvaWQge1xuICAgIGlmICghdGhpcy5faXNTdGFydGVkKSB7XG4gICAgICB0aGlzLl9kaXNwb3NhYmxlID0gbmV3IENvbXBvc2l0ZURpc3Bvc2FibGUoKVxuICAgICAgdGhpcy5fZGlzcG9zYWJsZS5hZGQoYXRvbS50ZXh0RWRpdG9ycy5vYnNlcnZlKHRoaXMub2JzZXJ2ZVRleHRFZGl0b3JzLmJpbmQodGhpcykpKVxuICAgICAgdGhpcy5fZGlzcG9zYWJsZS5hZGQoYXRvbS5wcm9qZWN0Lm9uRGlkQ2hhbmdlUGF0aHModGhpcy5wcm9qZWN0UGF0aHNDaGFuZ2VkLmJpbmQodGhpcykpKVxuICAgICAgaWYgKGF0b20ucHJvamVjdC5vbkRpZENoYW5nZUZpbGVzKSB7XG4gICAgICAgIHRoaXMuX2Rpc3Bvc2FibGUuYWRkKGF0b20ucHJvamVjdC5vbkRpZENoYW5nZUZpbGVzKHRoaXMucHJvamVjdEZpbGVzQ2hhbmdlZC5iaW5kKHRoaXMpKSlcbiAgICAgIH1cbiAgICB9XG4gICAgdGhpcy5faXNTdGFydGVkID0gdHJ1ZVxuICB9XG5cbiAgcHVibGljIHN0b3BMaXN0ZW5pbmcoKTogdm9pZCB7XG4gICAgaWYgKHRoaXMuX2lzU3RhcnRlZCkge1xuICAgICAgdGhpcy5fZGlzcG9zYWJsZS5kaXNwb3NlKClcbiAgICAgIHRoaXMuX2lzU3RhcnRlZCA9IGZhbHNlXG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBvYnNlcnZlVGV4dEVkaXRvcnMoZWRpdG9yOiBUZXh0RWRpdG9yKTogdm9pZCB7XG4gICAgLy8gVHJhY2sgZ3JhbW1hciBjaGFuZ2VzIGZvciBvcGVuZWQgZWRpdG9yc1xuICAgIGNvbnN0IGxpc3RlbmVyID0gZWRpdG9yLm9ic2VydmVHcmFtbWFyKChfZ3JhbW1hcikgPT4gdGhpcy5faGFuZGxlR3JhbW1hckNoYW5nZShlZGl0b3IpKVxuICAgIHRoaXMuX2Rpc3Bvc2FibGUuYWRkKGVkaXRvci5vbkRpZERlc3Ryb3koKCkgPT4gbGlzdGVuZXIuZGlzcG9zZSgpKSlcbiAgICAvLyBUcnkgdG8gc2VlIGlmIGVkaXRvciBjYW4gaGF2ZSBMUyBjb25uZWN0ZWQgdG8gaXRcbiAgICB0aGlzLl9oYW5kbGVUZXh0RWRpdG9yKGVkaXRvcilcbiAgfVxuXG4gIHByaXZhdGUgYXN5bmMgX2hhbmRsZVRleHRFZGl0b3IoZWRpdG9yOiBUZXh0RWRpdG9yKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgaWYgKCF0aGlzLl9lZGl0b3JUb1NlcnZlci5oYXMoZWRpdG9yKSkge1xuICAgICAgLy8gZWRpdG9yIGhhc24ndCBiZWVuIHByb2Nlc3NlZCB5ZXQsIHNvIHByb2Nlc3MgaXQgYnkgYWxsb2NhdGluZyBMUyBmb3IgaXQgaWYgbmVjZXNzYXJ5XG4gICAgICBjb25zdCBzZXJ2ZXIgPSBhd2FpdCB0aGlzLmdldFNlcnZlcihlZGl0b3IsIHsgc2hvdWxkU3RhcnQ6IHRydWUgfSlcbiAgICAgIGlmIChzZXJ2ZXIgIT0gbnVsbCkge1xuICAgICAgICAvLyBUaGVyZSBMUyBmb3IgdGhlIGVkaXRvciAoZWl0aGVyIHN0YXJ0ZWQgbm93IGFuZCBhbHJlYWR5IHJ1bm5pbmcpXG4gICAgICAgIHRoaXMuX2VkaXRvclRvU2VydmVyLnNldChlZGl0b3IsIHNlcnZlcilcbiAgICAgICAgdGhpcy5fZGlzcG9zYWJsZS5hZGQoXG4gICAgICAgICAgZWRpdG9yLm9uRGlkRGVzdHJveSgoKSA9PiB7XG4gICAgICAgICAgICB0aGlzLl9lZGl0b3JUb1NlcnZlci5kZWxldGUoZWRpdG9yKVxuICAgICAgICAgICAgdGhpcy5zdG9wVW51c2VkU2VydmVycygpXG4gICAgICAgICAgfSlcbiAgICAgICAgKVxuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIHByaXZhdGUgX2hhbmRsZUdyYW1tYXJDaGFuZ2UoZWRpdG9yOiBUZXh0RWRpdG9yKSB7XG4gICAgaWYgKHRoaXMuX3N0YXJ0Rm9yRWRpdG9yKGVkaXRvcikpIHtcbiAgICAgIC8vIElmIGVkaXRvciBpcyBpbnRlcmVzdGluZyBmb3IgTFMgcHJvY2VzcyB0aGUgZWRpdG9yIGZ1cnRoZXIgdG8gYXR0ZW1wdCB0byBzdGFydCBMUyBpZiBuZWVkZWRcbiAgICAgIHRoaXMuX2hhbmRsZVRleHRFZGl0b3IoZWRpdG9yKVxuICAgIH0gZWxzZSB7XG4gICAgICAvLyBFZGl0b3IgaXMgbm90IHN1cHBvcnRlZCBieSB0aGUgTFNcbiAgICAgIGNvbnN0IHNlcnZlciA9IHRoaXMuX2VkaXRvclRvU2VydmVyLmdldChlZGl0b3IpXG4gICAgICAvLyBJZiBMUyBpcyBydW5uaW5nIGZvciB0aGUgdW5zdXBwb3J0ZWQgZWRpdG9yIHRoZW4gZGlzY29ubmVjdCB0aGUgZWRpdG9yIGZyb20gTFMgYW5kIHNodXQgZG93biBMUyBpZiBuZWNlc3NhcnlcbiAgICAgIGlmIChzZXJ2ZXIpIHtcbiAgICAgICAgLy8gUmVtb3ZlIGVkaXRvciBmcm9tIHRoZSBjYWNoZVxuICAgICAgICB0aGlzLl9lZGl0b3JUb1NlcnZlci5kZWxldGUoZWRpdG9yKVxuICAgICAgICAvLyBTaHV0IGRvd24gTFMgaWYgaXQncyB1c2VkIGJ5IGFueSBvdGhlciBlZGl0b3JcbiAgICAgICAgdGhpcy5zdG9wVW51c2VkU2VydmVycygpXG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgcHVibGljIGdldEFjdGl2ZVNlcnZlcnMoKTogUmVhZG9ubHk8QWN0aXZlU2VydmVyW10+IHtcbiAgICByZXR1cm4gdGhpcy5fYWN0aXZlU2VydmVyc1xuICB9XG5cbiAgcHVibGljIGFzeW5jIGdldFNlcnZlcihcbiAgICB0ZXh0RWRpdG9yOiBUZXh0RWRpdG9yLFxuICAgIHsgc2hvdWxkU3RhcnQgfTogeyBzaG91bGRTdGFydD86IGJvb2xlYW4gfSA9IHsgc2hvdWxkU3RhcnQ6IGZhbHNlIH1cbiAgKTogUHJvbWlzZTxBY3RpdmVTZXJ2ZXIgfCBudWxsPiB7XG4gICAgY29uc3QgZmluYWxQcm9qZWN0UGF0aCA9IHRoaXMuX2RldGVybWluZVByb2plY3RQYXRoKHRleHRFZGl0b3IpXG4gICAgaWYgKGZpbmFsUHJvamVjdFBhdGggPT0gbnVsbCkge1xuICAgICAgLy8gRmlsZXMgbm90IHlldCBzYXZlZCBoYXZlIG5vIHBhdGhcbiAgICAgIHJldHVybiBudWxsXG4gICAgfVxuXG4gICAgY29uc3QgZm91bmRBY3RpdmVTZXJ2ZXIgPSB0aGlzLl9hY3RpdmVTZXJ2ZXJzLmZpbmQoKHMpID0+IGZpbmFsUHJvamVjdFBhdGggPT09IHMucHJvamVjdFBhdGgpXG4gICAgaWYgKGZvdW5kQWN0aXZlU2VydmVyKSB7XG4gICAgICByZXR1cm4gZm91bmRBY3RpdmVTZXJ2ZXJcbiAgICB9XG5cbiAgICBjb25zdCBzdGFydGluZ1Byb21pc2UgPSB0aGlzLl9zdGFydGluZ1NlcnZlclByb21pc2VzLmdldChmaW5hbFByb2plY3RQYXRoKVxuICAgIGlmIChzdGFydGluZ1Byb21pc2UpIHtcbiAgICAgIHJldHVybiBzdGFydGluZ1Byb21pc2VcbiAgICB9XG4gICAgLy8gVE9ETyByZW1vdmUgZXNsaW50LWRpc2FibGVcbiAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tcmV0dXJuLWF3YWl0XG4gICAgcmV0dXJuIHNob3VsZFN0YXJ0ICYmIHRoaXMuX3N0YXJ0Rm9yRWRpdG9yKHRleHRFZGl0b3IpID8gYXdhaXQgdGhpcy5zdGFydFNlcnZlcihmaW5hbFByb2plY3RQYXRoKSA6IG51bGxcbiAgfVxuXG4gIHB1YmxpYyBhc3luYyBzdGFydFNlcnZlcihwcm9qZWN0UGF0aDogc3RyaW5nKTogUHJvbWlzZTxBY3RpdmVTZXJ2ZXI+IHtcbiAgICB0aGlzLl9sb2dnZXIuZGVidWcoYFNlcnZlciBzdGFydGluZyBcIiR7cHJvamVjdFBhdGh9XCJgKVxuICAgIGNvbnN0IHN0YXJ0aW5nUHJvbWlzZSA9IHRoaXMuX3N0YXJ0U2VydmVyKHByb2plY3RQYXRoKVxuICAgIHRoaXMuX3N0YXJ0aW5nU2VydmVyUHJvbWlzZXMuc2V0KHByb2plY3RQYXRoLCBzdGFydGluZ1Byb21pc2UpXG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IHN0YXJ0ZWRBY3RpdmVTZXJ2ZXIgPSBhd2FpdCBzdGFydGluZ1Byb21pc2VcbiAgICAgIHRoaXMuX2FjdGl2ZVNlcnZlcnMucHVzaChzdGFydGVkQWN0aXZlU2VydmVyKVxuICAgICAgdGhpcy5fc3RhcnRpbmdTZXJ2ZXJQcm9taXNlcy5kZWxldGUocHJvamVjdFBhdGgpXG4gICAgICB0aGlzLl9sb2dnZXIuZGVidWcoYFNlcnZlciBzdGFydGVkIFwiJHtwcm9qZWN0UGF0aH1cIiAocGlkICR7c3RhcnRlZEFjdGl2ZVNlcnZlci5wcm9jZXNzLnBpZH0pYClcbiAgICAgIHJldHVybiBzdGFydGVkQWN0aXZlU2VydmVyXG4gICAgfSBjYXRjaCAoZSkge1xuICAgICAgdGhpcy5fc3RhcnRpbmdTZXJ2ZXJQcm9taXNlcy5kZWxldGUocHJvamVjdFBhdGgpXG4gICAgICB0aHJvdyBlXG4gICAgfVxuICB9XG5cbiAgcHVibGljIGFzeW5jIHN0b3BVbnVzZWRTZXJ2ZXJzKCk6IFByb21pc2U8dm9pZD4ge1xuICAgIGNvbnN0IHVzZWRTZXJ2ZXJzID0gbmV3IFNldCh0aGlzLl9lZGl0b3JUb1NlcnZlci52YWx1ZXMoKSlcbiAgICBjb25zdCB1bnVzZWRTZXJ2ZXJzID0gdGhpcy5fYWN0aXZlU2VydmVycy5maWx0ZXIoKHMpID0+ICF1c2VkU2VydmVycy5oYXMocykpXG4gICAgaWYgKHVudXNlZFNlcnZlcnMubGVuZ3RoID4gMCkge1xuICAgICAgdGhpcy5fbG9nZ2VyLmRlYnVnKGBTdG9wcGluZyAke3VudXNlZFNlcnZlcnMubGVuZ3RofSB1bnVzZWQgc2VydmVyc2ApXG4gICAgICBhd2FpdCBQcm9taXNlLmFsbCh1bnVzZWRTZXJ2ZXJzLm1hcCgocykgPT4gdGhpcy5zdG9wU2VydmVyKHMpKSlcbiAgICB9XG4gIH1cblxuICBwdWJsaWMgYXN5bmMgc3RvcEFsbFNlcnZlcnMoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgZm9yIChjb25zdCBbcHJvamVjdFBhdGgsIHJlc3RhcnRDb3VudGVyXSBvZiB0aGlzLl9yZXN0YXJ0Q291bnRlclBlclByb2plY3QpIHtcbiAgICAgIGNsZWFyVGltZW91dChyZXN0YXJ0Q291bnRlci50aW1lcklkKVxuICAgICAgdGhpcy5fcmVzdGFydENvdW50ZXJQZXJQcm9qZWN0LmRlbGV0ZShwcm9qZWN0UGF0aClcbiAgICB9XG5cbiAgICBhd2FpdCBQcm9taXNlLmFsbCh0aGlzLl9hY3RpdmVTZXJ2ZXJzLm1hcCgocykgPT4gdGhpcy5zdG9wU2VydmVyKHMpKSlcbiAgfVxuXG4gIHB1YmxpYyBhc3luYyByZXN0YXJ0QWxsU2VydmVycygpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICB0aGlzLnN0b3BMaXN0ZW5pbmcoKVxuICAgIGF3YWl0IHRoaXMuc3RvcEFsbFNlcnZlcnMoKVxuICAgIHRoaXMuX2VkaXRvclRvU2VydmVyID0gbmV3IE1hcCgpXG4gICAgdGhpcy5zdGFydExpc3RlbmluZygpXG4gIH1cblxuICBwdWJsaWMgaGFzU2VydmVyUmVhY2hlZFJlc3RhcnRMaW1pdChzZXJ2ZXI6IEFjdGl2ZVNlcnZlcik6IGJvb2xlYW4ge1xuICAgIGxldCByZXN0YXJ0Q291bnRlciA9IHRoaXMuX3Jlc3RhcnRDb3VudGVyUGVyUHJvamVjdC5nZXQoc2VydmVyLnByb2plY3RQYXRoKVxuXG4gICAgaWYgKCFyZXN0YXJ0Q291bnRlcikge1xuICAgICAgcmVzdGFydENvdW50ZXIgPSB7XG4gICAgICAgIHJlc3RhcnRzOiAwLFxuICAgICAgICB0aW1lcklkOiBzZXRUaW1lb3V0KCgpID0+IHtcbiAgICAgICAgICB0aGlzLl9yZXN0YXJ0Q291bnRlclBlclByb2plY3QuZGVsZXRlKHNlcnZlci5wcm9qZWN0UGF0aClcbiAgICAgICAgfSwgMyAqIDYwICogMTAwMCAvKiAzIG1pbnV0ZXMgKi8pLFxuICAgICAgfVxuXG4gICAgICB0aGlzLl9yZXN0YXJ0Q291bnRlclBlclByb2plY3Quc2V0KHNlcnZlci5wcm9qZWN0UGF0aCwgcmVzdGFydENvdW50ZXIpXG4gICAgfVxuXG4gICAgcmV0dXJuICsrcmVzdGFydENvdW50ZXIucmVzdGFydHMgPiA1XG4gIH1cblxuICBwdWJsaWMgYXN5bmMgc3RvcFNlcnZlcihzZXJ2ZXI6IEFjdGl2ZVNlcnZlcik6IFByb21pc2U8dm9pZD4ge1xuICAgIGF3YWl0IHRoaXMuX3JlcG9ydEJ1c3lXaGlsZShcbiAgICAgIGBTdG9wcGluZyAke3RoaXMuX2xhbmd1YWdlU2VydmVyTmFtZX0gZm9yICR7cGF0aC5iYXNlbmFtZShzZXJ2ZXIucHJvamVjdFBhdGgpfWAsXG4gICAgICBhc3luYyAoKSA9PiB7XG4gICAgICAgIHRoaXMuX2xvZ2dlci5kZWJ1ZyhgU2VydmVyIHN0b3BwaW5nIFwiJHtzZXJ2ZXIucHJvamVjdFBhdGh9XCJgKVxuICAgICAgICAvLyBJbW1lZGlhdGVseSByZW1vdmUgdGhlIHNlcnZlciB0byBwcmV2ZW50IGZ1cnRoZXIgdXNhZ2UuXG4gICAgICAgIC8vIElmIHdlIHJlLW9wZW4gdGhlIGZpbGUgYWZ0ZXIgdGhpcyBwb2ludCwgd2UnbGwgZ2V0IGEgbmV3IHNlcnZlci5cbiAgICAgICAgdGhpcy5fYWN0aXZlU2VydmVycy5zcGxpY2UodGhpcy5fYWN0aXZlU2VydmVycy5pbmRleE9mKHNlcnZlciksIDEpXG4gICAgICAgIHRoaXMuX3N0b3BwaW5nU2VydmVycy5wdXNoKHNlcnZlcilcbiAgICAgICAgc2VydmVyLmRpc3Bvc2FibGUuZGlzcG9zZSgpXG4gICAgICAgIGlmICh0aGlzLnNodXRkb3duR3JhY2VmdWxseSAmJiBzZXJ2ZXIuY29ubmVjdGlvbi5pc0Nvbm5lY3RlZCkge1xuICAgICAgICAgIGF3YWl0IHNlcnZlci5jb25uZWN0aW9uLnNodXRkb3duKClcbiAgICAgICAgfVxuXG4gICAgICAgIGZvciAoY29uc3QgW2VkaXRvciwgbWFwcGVkU2VydmVyXSBvZiB0aGlzLl9lZGl0b3JUb1NlcnZlcikge1xuICAgICAgICAgIGlmIChtYXBwZWRTZXJ2ZXIgPT09IHNlcnZlcikge1xuICAgICAgICAgICAgdGhpcy5fZWRpdG9yVG9TZXJ2ZXIuZGVsZXRlKGVkaXRvcilcbiAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLmV4aXRTZXJ2ZXIoc2VydmVyKVxuICAgICAgICB0aGlzLl9zdG9wcGluZ1NlcnZlcnMuc3BsaWNlKHRoaXMuX3N0b3BwaW5nU2VydmVycy5pbmRleE9mKHNlcnZlciksIDEpXG4gICAgICB9XG4gICAgKVxuICB9XG5cbiAgcHVibGljIGV4aXRTZXJ2ZXIoc2VydmVyOiBBY3RpdmVTZXJ2ZXIpOiB2b2lkIHtcbiAgICBjb25zdCBwaWQgPSBzZXJ2ZXIucHJvY2Vzcy5waWRcbiAgICB0cnkge1xuICAgICAgaWYgKHNlcnZlci5jb25uZWN0aW9uLmlzQ29ubmVjdGVkKSB7XG4gICAgICAgIHNlcnZlci5jb25uZWN0aW9uLmV4aXQoKVxuICAgICAgICBzZXJ2ZXIuY29ubmVjdGlvbi5kaXNwb3NlKClcbiAgICAgIH1cbiAgICB9IGZpbmFsbHkge1xuICAgICAgc2VydmVyLnByb2Nlc3Mua2lsbCgpXG4gICAgfVxuICAgIHRoaXMuX2xvZ2dlci5kZWJ1ZyhgU2VydmVyIHN0b3BwZWQgXCIke3NlcnZlci5wcm9qZWN0UGF0aH1cIiAocGlkICR7cGlkfSlgKVxuICB9XG5cbiAgcHVibGljIHRlcm1pbmF0ZSgpOiB2b2lkIHtcbiAgICB0aGlzLl9zdG9wcGluZ1NlcnZlcnMuZm9yRWFjaCgoc2VydmVyKSA9PiB7XG4gICAgICB0aGlzLl9sb2dnZXIuZGVidWcoYFNlcnZlciB0ZXJtaW5hdGluZyBcIiR7c2VydmVyLnByb2plY3RQYXRofVwiYClcbiAgICAgIHRoaXMuZXhpdFNlcnZlcihzZXJ2ZXIpXG4gICAgfSlcbiAgfVxuXG4gIHB1YmxpYyB1cGRhdGVOb3JtYWxpemVkUHJvamVjdFBhdGhzKCk6IHZvaWQge1xuICAgIHRoaXMuX25vcm1hbGl6ZWRQcm9qZWN0UGF0aHMgPSBhdG9tLnByb2plY3QuZ2V0UGF0aHMoKS5tYXAobm9ybWFsaXplUGF0aClcbiAgfVxuXG4gIHB1YmxpYyBnZXROb3JtYWxpemVkUHJvamVjdFBhdGhzKCk6IFJlYWRvbmx5PHN0cmluZ1tdPiB7XG4gICAgcmV0dXJuIHRoaXMuX25vcm1hbGl6ZWRQcm9qZWN0UGF0aHNcbiAgfVxuXG4gIC8qKlxuICAgKiBQdWJsaWM6IGZldGNoIHRoZSBjdXJyZW50IG9wZW4gbGlzdCBvZiB3b3Jrc3BhY2UgZm9sZGVyc1xuICAgKlxuICAgKiBAcmV0dXJucyBBIHtQcm9taXNlfSBjb250YWluaW5nIGFuIHtBcnJheX0gb2Yge2xzcC5Xb3Jrc3BhY2VGb2xkZXJbXX0gb3Ige251bGx9IGlmIG9ubHkgYSBzaW5nbGUgZmlsZSBpcyBvcGVuIGluIHRoZSB0b29sLlxuICAgKi9cbiAgcHVibGljIGdldFdvcmtzcGFjZUZvbGRlcnMoKTogUHJvbWlzZTxscy5Xb3Jrc3BhY2VGb2xkZXJbXSB8IG51bGw+IHtcbiAgICAvLyBOT1RFIHRoZSBtZXRob2QgbXVzdCByZXR1cm4gYSBQcm9taXNlIGJhc2VkIG9uIHRoZSBzcGVjaWZpY2F0aW9uXG4gICAgY29uc3QgcHJvamVjdFBhdGhzID0gdGhpcy5nZXROb3JtYWxpemVkUHJvamVjdFBhdGhzKClcbiAgICBpZiAocHJvamVjdFBhdGhzLmxlbmd0aCA9PT0gMCkge1xuICAgICAgLy8gb25seSBhIHNpbmdsZSBmaWxlIGlzIG9wZW5cbiAgICAgIHJldHVybiBQcm9taXNlLnJlc29sdmUobnVsbClcbiAgICB9IGVsc2Uge1xuICAgICAgcmV0dXJuIFByb21pc2UucmVzb2x2ZShwcm9qZWN0UGF0aHMubWFwKG5vcm1hbGl6ZWRQcm9qZWN0UGF0aFRvV29ya3NwYWNlRm9sZGVyKSlcbiAgICB9XG4gIH1cblxuICBwdWJsaWMgYXN5bmMgcHJvamVjdFBhdGhzQ2hhbmdlZChwcm9qZWN0UGF0aHM6IHN0cmluZ1tdKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgY29uc3QgcGF0aHNBbGwgPSBwcm9qZWN0UGF0aHMubWFwKG5vcm1hbGl6ZVBhdGgpXG5cbiAgICBjb25zdCBwcmV2aW91c1BhdGhzID0gdGhpcy5fcHJldmlvdXNOb3JtYWxpemVkUHJvamVjdFBhdGhzID8/IHRoaXMuZ2V0Tm9ybWFsaXplZFByb2plY3RQYXRocygpXG4gICAgY29uc3QgcGF0aHNSZW1vdmVkID0gcHJldmlvdXNQYXRocy5maWx0ZXIoKHByb2plY3RQYXRoKSA9PiAhcGF0aHNBbGwuaW5jbHVkZXMocHJvamVjdFBhdGgpKVxuICAgIGNvbnN0IHBhdGhzQWRkZWQgPSBwYXRoc0FsbC5maWx0ZXIoKHByb2plY3RQYXRoKSA9PiAhcHJldmlvdXNQYXRocy5pbmNsdWRlcyhwcm9qZWN0UGF0aCkpXG5cbiAgICAvLyB1cGRhdGUgY2FjaGVcbiAgICB0aGlzLl9wcmV2aW91c05vcm1hbGl6ZWRQcm9qZWN0UGF0aHMgPSBwYXRoc0FsbFxuXG4gICAgLy8gc2VuZCBkaWRDaGFuZ2VXb3Jrc3BhY2VGb2xkZXJzXG4gICAgY29uc3QgZGlkQ2hhbmdlV29ya3NwYWNlRm9sZGVyc1BhcmFtcyA9IHtcbiAgICAgIGV2ZW50OiB7XG4gICAgICAgIGFkZGVkOiBwYXRoc0FkZGVkLm1hcChub3JtYWxpemVkUHJvamVjdFBhdGhUb1dvcmtzcGFjZUZvbGRlciksXG4gICAgICAgIHJlbW92ZWQ6IHBhdGhzUmVtb3ZlZC5tYXAobm9ybWFsaXplZFByb2plY3RQYXRoVG9Xb3Jrc3BhY2VGb2xkZXIpLFxuICAgICAgfSxcbiAgICB9XG4gICAgZm9yIChjb25zdCBhY3RpdmVTZXJ2ZXIgb2YgdGhpcy5fYWN0aXZlU2VydmVycykge1xuICAgICAgYWN0aXZlU2VydmVyLmNvbm5lY3Rpb24uZGlkQ2hhbmdlV29ya3NwYWNlRm9sZGVycyhkaWRDaGFuZ2VXb3Jrc3BhY2VGb2xkZXJzUGFyYW1zKVxuICAgIH1cblxuICAgIC8vIHN0b3AgdGhlIHNlcnZlcnMgdGhhdCBkb24ndCBoYXZlIHByb2plY3RQYXRoXG4gICAgY29uc3Qgc2VydmVyc1RvU3RvcCA9IHRoaXMuX2FjdGl2ZVNlcnZlcnMuZmlsdGVyKChzZXJ2ZXIpID0+IHBhdGhzUmVtb3ZlZC5pbmNsdWRlcyhzZXJ2ZXIucHJvamVjdFBhdGgpKVxuICAgIGF3YWl0IFByb21pc2UuYWxsKHNlcnZlcnNUb1N0b3AubWFwKChzKSA9PiB0aGlzLnN0b3BTZXJ2ZXIocykpKVxuXG4gICAgLy8gdXBkYXRlIHRoaXMuX25vcm1hbGl6ZWRQcm9qZWN0UGF0aHNcbiAgICB0aGlzLnVwZGF0ZU5vcm1hbGl6ZWRQcm9qZWN0UGF0aHMoKVxuICB9XG5cbiAgcHVibGljIHByb2plY3RGaWxlc0NoYW5nZWQoZmlsZUV2ZW50czogRmlsZXN5c3RlbUNoYW5nZUV2ZW50KTogdm9pZCB7XG4gICAgaWYgKHRoaXMuX2FjdGl2ZVNlcnZlcnMubGVuZ3RoID09PSAwKSB7XG4gICAgICByZXR1cm5cbiAgICB9XG5cbiAgICBmb3IgKGNvbnN0IGFjdGl2ZVNlcnZlciBvZiB0aGlzLl9hY3RpdmVTZXJ2ZXJzKSB7XG4gICAgICBjb25zdCBjaGFuZ2VzOiBscy5GaWxlRXZlbnRbXSA9IFtdXG4gICAgICBmb3IgKGNvbnN0IGZpbGVFdmVudCBvZiBmaWxlRXZlbnRzKSB7XG4gICAgICAgIGlmIChmaWxlRXZlbnQucGF0aC5zdGFydHNXaXRoKGFjdGl2ZVNlcnZlci5wcm9qZWN0UGF0aCkgJiYgdGhpcy5fY2hhbmdlV2F0Y2hlZEZpbGVGaWx0ZXIoZmlsZUV2ZW50LnBhdGgpKSB7XG4gICAgICAgICAgY2hhbmdlcy5wdXNoKENvbnZlcnQuYXRvbUZpbGVFdmVudFRvTFNGaWxlRXZlbnRzKGZpbGVFdmVudClbMF0pXG4gICAgICAgIH1cbiAgICAgICAgaWYgKFxuICAgICAgICAgIGZpbGVFdmVudC5hY3Rpb24gPT09IFwicmVuYW1lZFwiICYmXG4gICAgICAgICAgZmlsZUV2ZW50Lm9sZFBhdGguc3RhcnRzV2l0aChhY3RpdmVTZXJ2ZXIucHJvamVjdFBhdGgpICYmXG4gICAgICAgICAgdGhpcy5fY2hhbmdlV2F0Y2hlZEZpbGVGaWx0ZXIoZmlsZUV2ZW50Lm9sZFBhdGgpXG4gICAgICAgICkge1xuICAgICAgICAgIGNoYW5nZXMucHVzaChDb252ZXJ0LmF0b21GaWxlRXZlbnRUb0xTRmlsZUV2ZW50cyhmaWxlRXZlbnQpWzFdKVxuICAgICAgICB9XG4gICAgICB9XG4gICAgICBpZiAoY2hhbmdlcy5sZW5ndGggPiAwKSB7XG4gICAgICAgIGFjdGl2ZVNlcnZlci5jb25uZWN0aW9uLmRpZENoYW5nZVdhdGNoZWRGaWxlcyh7IGNoYW5nZXMgfSlcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICAvKiogQGRlcHJlY2F0ZWQgVXNlIHRoZSBleHBvcnRlZCBgbm9ybWFsaXplUGF0aGAgZnVuY3Rpb24gKi9cbiAgcHVibGljIG5vcm1hbGl6ZVBhdGggPSBub3JtYWxpemVQYXRoXG59XG5cbmV4cG9ydCBmdW5jdGlvbiBwcm9qZWN0UGF0aFRvV29ya3NwYWNlRm9sZGVyKHByb2plY3RQYXRoOiBzdHJpbmcpOiBscy5Xb3Jrc3BhY2VGb2xkZXIge1xuICBjb25zdCBub3JtYWxpemVkUHJvamVjdFBhdGggPSBub3JtYWxpemVQYXRoKHByb2plY3RQYXRoKVxuICByZXR1cm4gbm9ybWFsaXplZFByb2plY3RQYXRoVG9Xb3Jrc3BhY2VGb2xkZXIobm9ybWFsaXplZFByb2plY3RQYXRoKVxufVxuXG5leHBvcnQgZnVuY3Rpb24gbm9ybWFsaXplZFByb2plY3RQYXRoVG9Xb3Jrc3BhY2VGb2xkZXIobm9ybWFsaXplZFByb2plY3RQYXRoOiBzdHJpbmcpOiBscy5Xb3Jrc3BhY2VGb2xkZXIge1xuICByZXR1cm4ge1xuICAgIHVyaTogQ29udmVydC5wYXRoVG9Vcmkobm9ybWFsaXplZFByb2plY3RQYXRoKSxcbiAgICBuYW1lOiBwYXRoLmJhc2VuYW1lKG5vcm1hbGl6ZWRQcm9qZWN0UGF0aCksXG4gIH1cbn1cblxuZXhwb3J0IGZ1bmN0aW9uIG5vcm1hbGl6ZVBhdGgocHJvamVjdFBhdGg6IHN0cmluZyk6IHN0cmluZyB7XG4gIHJldHVybiAhcHJvamVjdFBhdGguZW5kc1dpdGgocGF0aC5zZXApID8gcGF0aC5qb2luKHByb2plY3RQYXRoLCBwYXRoLnNlcCkgOiBwcm9qZWN0UGF0aFxufVxuXG4vKiogQ29uc2lkZXJzIGEgcGF0aCBmb3IgaW5jbHVzaW9uIGluIGBhZGRpdGlvbmFsUGF0aHNgLiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGNvbnNpZGVyQWRkaXRpb25hbFBhdGgoXG4gIHNlcnZlcjogQWN0aXZlU2VydmVyICYgeyBhZGRpdGlvbmFsUGF0aHM6IFNldDxzdHJpbmc+IH0sXG4gIGFkZGl0aW9uYWxQYXRoOiBzdHJpbmdcbik6IHZvaWQge1xuICBpZiAoIWFkZGl0aW9uYWxQYXRoLnN0YXJ0c1dpdGgoc2VydmVyLnByb2plY3RQYXRoKSkge1xuICAgIHNlcnZlci5hZGRpdGlvbmFsUGF0aHMuYWRkKGFkZGl0aW9uYWxQYXRoKVxuICB9XG59XG4iXX0=