UNPKG

atom-languageclient

Version:
551 lines 73.8 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __exportStar = (this && this.__exportStar) || function(m, exports) { for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p); }; 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.LanguageClientConnection = void 0; const lsp = require("vscode-languageserver-protocol"); const events_1 = require("events"); const logger_1 = require("./logger"); __exportStar(require("vscode-languageserver-protocol"), exports); /** * TypeScript wrapper around JSONRPC to implement Microsoft Language Server Protocol v3 * https://github.com/Microsoft/language-server-protocol/blob/master/protocol.md */ class LanguageClientConnection extends events_1.EventEmitter { constructor(rpc, logger) { super(); this._rpc = rpc; this._log = logger || new logger_1.NullLogger(); this.setupLogging(); rpc.listen(); this.isConnected = true; this._rpc.onClose(() => { this.isConnected = false; this._log.warn("rpc.onClose", "The RPC connection closed unexpectedly"); this.emit("close"); }); } setupLogging() { this._rpc.onError((error) => this._log.error(["rpc.onError", error])); this._rpc.onUnhandledNotification((notification) => { if (notification.method != null && notification.params != null) { this._log.warn(`rpc.onUnhandledNotification ${notification.method}`, notification.params); } else { this._log.warn("rpc.onUnhandledNotification", notification); } }); this._rpc.onNotification((...args) => this._log.debug("rpc.onNotification", args)); } dispose() { this._rpc.dispose(); } /** * Public: Initialize the language server with necessary {InitializeParams}. * * @param params The {InitializeParams} containing processId, rootPath, options and server capabilities. * @returns A {Promise} containing the {InitializeResult} with details of the server's capabilities. */ initialize(params) { return this._sendRequest(lsp.InitializeRequest.type, params); } /** Public: Send an `initialized` notification to the language server. */ initialized() { this._sendNotification(lsp.InitializedNotification.type, {}); } /** Public: Send a `shutdown` request to the language server. */ shutdown() { return this._sendRequest(lsp.ShutdownRequest.type); } /** Public: Send an `exit` notification to the language server. */ exit() { this._sendNotification(lsp.ExitNotification.type); } /** * Public: Register a callback for a custom notification * * @param method A string containing the name of the message to listen for. * @param callback The function to be called when the message is received. The payload from the message is passed to * the function. */ onCustomNotification(method, callback) { this._onNotification({ method }, callback); } /** @deprecated Use `onCustomNotification` method instead */ onCustom(method, callback) { this.onCustomNotification(method, callback); } /** * Public: Register a callback for a custom request * * @param method A string containing the name of the message to listen for. * @param callback The function to be called when the message is received. The payload from the message is passed to * the function. */ onCustomRequest(method, callback) { this._onRequest({ method }, callback); } /** * Public: Send a custom request * * @param method A string containing the name of the request message. * @param params The method's parameters */ sendCustomRequest(method, params) { return this._sendRequest(new lsp.ProtocolRequestType(method), params); } /** * Public: Send a custom notification * * @param method A string containing the name of the notification message. * @param params The method's parameters */ sendCustomNotification(method, params) { this._sendNotification(new lsp.ProtocolNotificationType(method), params); } /** * Public: Register a callback for the `window/showMessage` message. * * @param callback The function to be called when the `window/showMessage` message is received with * {ShowMessageParams} being passed. */ onShowMessage(callback) { this._onNotification({ method: "window/showMessage" }, callback); } /** * Public: Register a callback for the `window/showMessageRequest` message. * * @param callback The function to be called when the `window/showMessageRequest` message is received with * {ShowMessageRequestParam}' being passed. * @returns A {Promise} containing the {MessageActionItem}. */ onShowMessageRequest(callback) { this._onRequest({ method: "window/showMessageRequest" }, callback); } /** * Public: Register a callback for the `window/showDocument` message. * * @param callback The function to be called when the `window/showDocument` message is received with * {ShowDocumentParams} being passed. */ onShowDocument(callback) { this._onRequest({ method: "window/showDocument" }, callback); } /** * Public: Register a callback for the `window/logMessage` message. * * @param callback The function to be called when the `window/logMessage` message is received with {LogMessageParams} * being passed. */ onLogMessage(callback) { this._onNotification({ method: "window/logMessage" }, callback); } /** * Public: Register a callback for the `telemetry/event` message. * * @param callback The function to be called when the `telemetry/event` message is received with any parameters * received being passed on. */ onTelemetryEvent(callback) { this._onNotification({ method: "telemetry/event" }, callback); } /** * Public: Register a callback for the `workspace/applyEdit` message. * * @param callback The function to be called when the `workspace/applyEdit` message is received with * {ApplyWorkspaceEditParams} being passed. * @returns A {Promise} containing the {ApplyWorkspaceEditResponse}. */ onApplyEdit(callback) { this._onRequest({ method: "workspace/applyEdit" }, callback); } /** * Public: Send a `workspace/didChangeConfiguration` notification. * * @param params The {DidChangeConfigurationParams} containing the new configuration. */ didChangeConfiguration(params) { this._sendNotification(lsp.DidChangeConfigurationNotification.type, params); } /** * Public: Send a `textDocument/didOpen` notification. * * @param params The {DidOpenTextDocumentParams} containing the opened text document details. */ didOpenTextDocument(params) { this._sendNotification(lsp.DidOpenTextDocumentNotification.type, params); } /** * Public: Send a `textDocument/didChange` notification. * * @param params The {DidChangeTextDocumentParams} containing the changed text document details including the version * number and actual text changes. */ didChangeTextDocument(params) { this._sendNotification(lsp.DidChangeTextDocumentNotification.type, params); } /** * Public: Send a `textDocument/didClose` notification. * * @param params The {DidCloseTextDocumentParams} containing the opened text document details. */ didCloseTextDocument(params) { this._sendNotification(lsp.DidCloseTextDocumentNotification.type, params); } /** * Public: Send a `textDocument/willSave` notification. * * @param params The {WillSaveTextDocumentParams} containing the to-be-saved text document details and the reason for the save. */ willSaveTextDocument(params) { this._sendNotification(lsp.WillSaveTextDocumentNotification.type, params); } /** * Public: Send a `textDocument/willSaveWaitUntil` notification. * * @param params The {WillSaveTextDocumentParams} containing the to-be-saved text document details and the reason for the save. * @returns A {Promise} containing an {Array} of {TextEdit}s to be applied to the text document before it is saved. */ willSaveWaitUntilTextDocument(params) { return this._sendRequest(lsp.WillSaveTextDocumentWaitUntilRequest.type, params); } /** * Public: Send a `textDocument/didSave` notification. * * @param params The {DidSaveTextDocumentParams} containing the saved text document details. */ didSaveTextDocument(params) { this._sendNotification(lsp.DidSaveTextDocumentNotification.type, params); } /** * Public: Send a `workspace/didChangeWatchedFiles` notification. * * @param params The {DidChangeWatchedFilesParams} containing the array of {FileEvent}s that have been observed upon * the watched files. */ didChangeWatchedFiles(params) { this._sendNotification(lsp.DidChangeWatchedFilesNotification.type, params); } /** * Public: Register a callback for the `workspace.workspaceFolders` request. This request is sent from the server to * Atom to fetch the current open list of workspace folders * * @param A Callback which returns a {Promise} containing an {Array} of {lsp.WorkspaceFolder[]} or {null} if only a * single file is open in the tool. */ onWorkspaceFolders(callback) { return this._onRequest(lsp.WorkspaceFoldersRequest.type, callback); } /** * Public: Send a `workspace/didChangeWorkspaceFolders` notification. * * @param {DidChangeWorkspaceFoldersParams} params An object that contains the actual workspace folder change event * ({WorkspaceFoldersChangeEvent}) in its {event} property */ didChangeWorkspaceFolders(params) { this._sendNotification(lsp.DidChangeWorkspaceFoldersNotification.type, params); } /** * Public: Register a callback for the `textDocument/publishDiagnostics` message. * * @param callback The function to be called when the `textDocument/publishDiagnostics` message is received a * {PublishDiagnosticsParams} containing new {Diagnostic} messages for a given uri. */ onPublishDiagnostics(callback) { this._onNotification({ method: "textDocument/publishDiagnostics" }, callback); } /** * Public: Send a `textDocument/completion` request. * * @param params The {TextDocumentPositionParams} or {CompletionParams} for which {CompletionItem}s are desired. * @param cancellationToken The {CancellationToken} that is used to cancel this request if necessary. * @returns A {Promise} containing either a {CompletionList} or an {Array} of {CompletionItem}s. */ completion(params, cancellationToken) { // Cancel prior request if necessary return this._sendRequest(lsp.CompletionRequest.type, params, cancellationToken); } /** * Public: Send a `completionItem/resolve` request. * * @param params The {CompletionItem} for which a fully resolved {CompletionItem} is desired. * @returns A {Promise} containing a fully resolved {CompletionItem}. */ completionItemResolve(params) { return this._sendRequest(lsp.CompletionResolveRequest.type, params); } /** * Public: Send a `textDocument/hover` request. * * @param params The {TextDocumentPositionParams} for which a {Hover} is desired. * @returns A {Promise} containing a {Hover}. */ hover(params) { return this._sendRequest(lsp.HoverRequest.type, params); } /** * Public: Send a `textDocument/signatureHelp` request. * * @param params The {TextDocumentPositionParams} for which a {SignatureHelp} is desired. * @returns A {Promise} containing a {SignatureHelp}. */ signatureHelp(params) { return this._sendRequest(lsp.SignatureHelpRequest.type, params); } /** * Public: Send a `textDocument/definition` request. * * @param params The {TextDocumentPositionParams} of a symbol for which one or more {Location}s that define that * symbol are required. * @returns A {Promise} containing either a single {Location} or an {Array} of many {Location}s. */ gotoDefinition(params) { return this._sendRequest(lsp.DefinitionRequest.type, params); } /** * Public: Send a `textDocument/references` request. * * @param params The {TextDocumentPositionParams} of a symbol for which all referring {Location}s are desired. * @returns A {Promise} containing an {Array} of {Location}s that reference this symbol. */ findReferences(params) { return this._sendRequest(lsp.ReferencesRequest.type, params); } /** * Public: Send a `textDocument/documentHighlight` request. * * @param params The {TextDocumentPositionParams} of a symbol for which all highlights are desired. * @returns A {Promise} containing an {Array} of {DocumentHighlight}s that can be used to highlight this symbol. */ documentHighlight(params) { return this._sendRequest(lsp.DocumentHighlightRequest.type, params); } /** * Public: Send a `textDocument/documentSymbol` request. * * @param params The {DocumentSymbolParams} that identifies the document for which symbols are desired. * @param cancellationToken The {CancellationToken} that is used to cancel this request if necessary. * @returns A {Promise} containing an {Array} of {SymbolInformation}s that can be used to navigate this document. */ documentSymbol(params, _cancellationToken) { return this._sendRequest(lsp.DocumentSymbolRequest.type, params); } /** * Public: Send a `workspace/symbol` request. * * @param params The {WorkspaceSymbolParams} containing the query string to search the workspace for. * @returns A {Promise} containing an {Array} of {SymbolInformation}s that identify where the query string occurs * within the workspace. */ workspaceSymbol(params) { return this._sendRequest(lsp.WorkspaceSymbolRequest.type, params); } /** * Public: Send a `textDocument/codeAction` request. * * @param params The {CodeActionParams} identifying the document, range and context for the code action. * @returns A {Promise} containing an {Array} of {Command}s or {CodeAction}s that can be performed against the given * documents range. */ codeAction(params) { return this._sendRequest(lsp.CodeActionRequest.type, params); } /** * Public: Send a `codeAction/resolve` request. * * @param params The {CodeAction} whose properties (e.g. `edit`) are to be resolved. * @returns A resolved {CodeAction} that can be applied immediately. */ codeActionResolve(params) { return this._sendRequest(lsp.CodeActionResolveRequest.type, params); } /** * Public: Send a `textDocument/codeLens` request. * * @param params The {CodeLensParams} identifying the document for which code lens commands are desired. * @returns A {Promise} containing an {Array} of {CodeLens}s that associate commands and data with specified ranges * within the document. */ codeLens(params) { return this._sendRequest(lsp.CodeLensRequest.type, params); } /** * Public: Send a `codeLens/resolve` request. * * @param params The {CodeLens} identifying the code lens to be resolved with full detail. * @returns A {Promise} containing the {CodeLens} fully resolved. */ codeLensResolve(params) { return this._sendRequest(lsp.CodeLensResolveRequest.type, params); } /** * Public: Send a `textDocument/documentLink` request. * * @param params The {DocumentLinkParams} identifying the document for which links should be identified. * @returns A {Promise} containing an {Array} of {DocumentLink}s relating uri's to specific ranges within the document. */ documentLink(params) { return this._sendRequest(lsp.DocumentLinkRequest.type, params); } /** * Public: Send a `documentLink/resolve` request. * * @param params The {DocumentLink} identifying the document link to be resolved with full detail. * @returns A {Promise} containing the {DocumentLink} fully resolved. */ documentLinkResolve(params) { return this._sendRequest(lsp.DocumentLinkResolveRequest.type, params); } /** * Public: Send a `textDocument/formatting` request. * * @param params The {DocumentFormattingParams} identifying the document to be formatted as well as additional * formatting preferences. * @returns A {Promise} containing an {Array} of {TextEdit}s to be applied to the document to correctly reformat it. */ documentFormatting(params) { return this._sendRequest(lsp.DocumentFormattingRequest.type, params); } /** * Public: Send a `textDocument/rangeFormatting` request. * * @param params The {DocumentRangeFormattingParams} identifying the document and range to be formatted as well as * additional formatting preferences. * @returns A {Promise} containing an {Array} of {TextEdit}s to be applied to the document to correctly reformat it. */ documentRangeFormatting(params) { return this._sendRequest(lsp.DocumentRangeFormattingRequest.type, params); } /** * Public: Send a `textDocument/onTypeFormatting` request. * * @param params The {DocumentOnTypeFormattingParams} identifying the document to be formatted, the character that was * typed and at what position as well as additional formatting preferences. * @returns A {Promise} containing an {Array} of {TextEdit}s to be applied to the document to correctly reformat it. */ documentOnTypeFormatting(params) { return this._sendRequest(lsp.DocumentOnTypeFormattingRequest.type, params); } /** * Public: Send a `textDocument/rename` request. * * @param params The {RenameParams} identifying the document containing the symbol to be renamed, as well as the * position and new name. * @returns A {Promise} containing an {WorkspaceEdit} that contains a list of {TextEdit}s either on the changes * property (keyed by uri) or the documentChanges property containing an {Array} of {TextDocumentEdit}s (preferred). */ rename(params) { return this._sendRequest(lsp.RenameRequest.type, params); } /** * Public: Send a `workspace/executeCommand` request. * * @param params The {ExecuteCommandParams} specifying the command and arguments the language server should execute * (these commands are usually from {CodeLens} or {CodeAction} responses). * @returns A {Promise} containing anything. */ executeCommand(params) { return this._sendRequest(lsp.ExecuteCommandRequest.type, params); } /** * Public: Send a `textDocument/prepareCallHierarchy` request. * * @param params The {CallHierarchyIncomingCallsParams} that containing {textDocument} and {position} associated with * the calling. * @param cancellationToken The {CancellationToken} that is used to cancel this request if necessary. * @returns A {Promise} containing an {Array} of {CallHierarchyItem}s that corresponding to the request. */ prepareCallHierarchy(params, _cancellationToken) { return this._sendRequest(lsp.CallHierarchyPrepareRequest.type, params); } /** * Public: Send a `callHierarchy/incomingCalls` request. * * @param params The {CallHierarchyIncomingCallsParams} that identifies {CallHierarchyItem} to get incoming calls. * @param cancellationToken The {CancellationToken} that is used to cancel this request if necessary. * @returns A {Promise} containing an {Array} of {CallHierarchyIncomingCall}s for the function that called by the * function given to the parameter. */ callHierarchyIncomingCalls(params, _cancellationToken) { return this._sendRequest(lsp.CallHierarchyIncomingCallsRequest.type, params); } /** * Public: Send a `callHierarchy/outgoingCalls` request. * * @param params The {CallHierarchyOutgoingCallsParams} that identifies {CallHierarchyItem} to get outgoing calls. * @param cancellationToken The {CancellationToken} that is used to cancel this request if necessary. * @returns A {Promise} containing an {Array} of {CallHierarchyIncomingCall}s for the function that calls the function * given to the parameter. */ callHierarchyOutgoingCalls(params, _cancellationToken) { return this._sendRequest(lsp.CallHierarchyOutgoingCallsRequest.type, params); } _onRequest(type, callback) { this._rpc.onRequest(type.method, (value) => { this._log.debug(`rpc.onRequest ${type.method}`, value); return callback(value); }); } _onNotification(type, callback) { this._rpc.onNotification(type.method, (value) => { this._log.debug(`rpc.onNotification ${type.method}`, value); callback(value); }); } _sendNotification(protocol, args) { const { method } = protocol; this._log.debug(`rpc.sendNotification ${method}`, args); this._rpc.sendNotification(method, args); } _sendRequest(protocol, args, cancellationToken) { return __awaiter(this, void 0, void 0, function* () { const { method } = protocol; this._log.debug(`rpc.sendRequest ${method} sending`, args); try { const start = performance.now(); let result; if (cancellationToken) { result = yield this._rpc.sendRequest(method, args, cancellationToken); } else { // If cancellationToken is null or undefined, don't add the third // argument otherwise vscode-jsonrpc will send an additional, null // message parameter to the request result = yield this._rpc.sendRequest(method, args); } const took = performance.now() - start; this._log.debug(`rpc.sendRequest ${method} received (${Math.floor(took)}ms)`, result); return result; } catch (e) { const responseError = e; if (cancellationToken && responseError.code === lsp.LSPErrorCodes.RequestCancelled) { this._log.debug(`rpc.sendRequest ${method} was cancelled`); } else { this._log.error(`rpc.sendRequest ${method} threw`, e); } throw e; } }); } } exports.LanguageClientConnection = LanguageClientConnection; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibGFuZ3VhZ2VjbGllbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9saWIvbGFuZ3VhZ2VjbGllbnQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQUNBLHNEQUFxRDtBQUNyRCxtQ0FBcUM7QUFDckMscUNBQTZDO0FBRTdDLGlFQUE4QztBQXNCOUM7OztHQUdHO0FBQ0gsTUFBYSx3QkFBeUIsU0FBUSxxQkFBWTtJQUt4RCxZQUFZLEdBQThCLEVBQUUsTUFBZTtRQUN6RCxLQUFLLEVBQUUsQ0FBQTtRQUNQLElBQUksQ0FBQyxJQUFJLEdBQUcsR0FBRyxDQUFBO1FBQ2YsSUFBSSxDQUFDLElBQUksR0FBRyxNQUFNLElBQUksSUFBSSxtQkFBVSxFQUFFLENBQUE7UUFDdEMsSUFBSSxDQUFDLFlBQVksRUFBRSxDQUFBO1FBQ25CLEdBQUcsQ0FBQyxNQUFNLEVBQUUsQ0FBQTtRQUVaLElBQUksQ0FBQyxXQUFXLEdBQUcsSUFBSSxDQUFBO1FBQ3ZCLElBQUksQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLEdBQUcsRUFBRTtZQUNyQixJQUFJLENBQUMsV0FBVyxHQUFHLEtBQUssQ0FBQTtZQUN4QixJQUFJLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxhQUFhLEVBQUUsd0NBQXdDLENBQUMsQ0FBQTtZQUN2RSxJQUFJLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxDQUFBO1FBQ3BCLENBQUMsQ0FBQyxDQUFBO0lBQ0osQ0FBQztJQUVPLFlBQVk7UUFDbEIsSUFBSSxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsQ0FBQyxLQUFLLEVBQUUsRUFBRSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUMsYUFBYSxFQUFFLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQTtRQUNyRSxJQUFJLENBQUMsSUFBSSxDQUFDLHVCQUF1QixDQUFDLENBQUMsWUFBWSxFQUFFLEVBQUU7WUFDakQsSUFBSSxZ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QUFhLENBQUMsZ0JBQWdCLEVBQUU7b0JBQ2xGLElBQUksQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLG1CQUFtQixNQUFNLGdCQUFnQixDQUFDLENBQUE7aUJBQzNEO3FCQUFNO29CQUNMLElBQUksQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLG1CQUFtQixNQUFNLFFBQVEsRUFBRSxDQUFDLENBQUMsQ0FBQTtpQkFDdEQ7Z0JBRUQsTUFBTSxDQUFDLENBQUE7YUFDUjtRQUNILENBQUM7S0FBQTtDQUNGO0FBbm1CRCw0REFtbUJDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0ICogYXMganNvbnJwYyBmcm9tIFwidnNjb2RlLWpzb25ycGNcIlxuaW1wb3J0ICogYXMgbHNwIGZyb20gXCJ2c2NvZGUtbGFuZ3VhZ2VzZXJ2ZXItcHJvdG9jb2xcIlxuaW1wb3J0IHsgRXZlbnRFbWl0dGVyIH0gZnJvbSBcImV2ZW50c1wiXG5pbXBvcnQgeyBOdWxsTG9nZ2VyLCBMb2dnZXIgfSBmcm9tIFwiLi9sb2dnZXJcIlxuXG5leHBvcnQgKiBmcm9tIFwidnNjb2RlLWxhbmd1YWdlc2VydmVyLXByb3RvY29sXCJcblxuZXhwb3J0IGludGVyZmFjZSBLbm93bk5vdGlmaWNhdGlvbnMge1xuICBcInRleHREb2N1bWVudC9wdWJsaXNoRGlhZ25vc3RpY3NcIjogbHNwLlB1Ymxpc2hEaWFnbm9zdGljc1BhcmFtc1xuICBcInRlbGVtZXRyeS9ldmVudFwiOiBhbnlcbiAgXCJ3aW5kb3cvbG9nTWVzc2FnZVwiOiBsc3AuTG9nTWVzc2FnZVBhcmFtc1xuICBcIndpbmRvdy9zaG93TWVzc2FnZVJlcXVlc3RcIjogbHNwLlNob3dNZXNzYWdlUmVxdWVzdFBhcmFtc1xuICBcIndpbmRvdy9zaG93TWVzc2FnZVwiOiBsc3AuU2hvd01lc3NhZ2VQYXJhbXNcbiAgW2N1c3RvbTogc3RyaW5nXTogb2JqZWN0XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgS25vd25SZXF1ZXN0cyB7XG4gIFwid2luZG93L3Nob3dEb2N1bWVudFwiOiBbbHNwLlNob3dEb2N1bWVudFBhcmFtcywgbHNwLlNob3dEb2N1bWVudFJlc3VsdF1cbiAgXCJ3aW5kb3cvc2hvd01lc3NhZ2VSZXF1ZXN0XCI6IFtsc3AuU2hvd01lc3NhZ2VSZXF1ZXN0UGFyYW1zLCBsc3AuTWVzc2FnZUFjdGlvbkl0ZW0gfCBudWxsXVxuICBcIndvcmtzcGFjZS9hcHBseUVkaXRcIjogW2xzcC5BcHBseVdvcmtzcGFjZUVkaXRQYXJhbXMsIGxzcC5BcHBseVdvcmtzcGFjZUVkaXRSZXNwb25zZV1cbiAgW2N1c3RvbTogc3RyaW5nXTogW1JlY29yZDxzdHJpbmcsIGFueT4sIFJlY29yZDxzdHJpbmcsIGFueT4gfCBudWxsXVxufVxuXG5leHBvcnQgdHlwZSBSZXF1ZXN0Q2FsbGJhY2s8VCBleHRlbmRzIGtleW9mIEtub3duUmVxdWVzdHM+ID0gS25vd25SZXF1ZXN0c1tUXSBleHRlbmRzIFtpbmZlciBVLCBpbmZlciBWXVxuICA/IChwYXJhbTogVSkgPT4gUHJvbWlzZTxWPlxuICA6IG5ldmVyXG5cbi8qKlxuICogVHlwZVNjcmlwdCB3cmFwcGVyIGFyb3VuZCBKU09OUlBDIHRvIGltcGxlbWVudCBNaWNyb3NvZnQgTGFuZ3VhZ2UgU2VydmVyIFByb3RvY29sIHYzXG4gKiBodHRwczovL2dpdGh1Yi5jb20vTWljcm9zb2Z0L2xhbmd1YWdlLXNlcnZlci1wcm90b2NvbC9ibG9iL21hc3Rlci9wcm90b2NvbC5tZFxuICovXG5leHBvcnQgY2xhc3MgTGFuZ3VhZ2VDbGllbnRDb25uZWN0aW9uIGV4dGVuZHMgRXZlbnRFbWl0dGVyIHtcbiAgcHJpdmF0ZSBfcnBjOiBqc29ucnBjLk1lc3NhZ2VDb25uZWN0aW9uXG4gIHByaXZhdGUgX2xvZzogTG9nZ2VyXG4gIHB1YmxpYyBpc0Nvbm5lY3RlZDogYm9vbGVhblxuXG4gIGNvbnN0cnVjdG9yKHJwYzoganNvbnJwYy5NZXNzYWdlQ29ubmVjdGlvbiwgbG9nZ2VyPzogTG9nZ2VyKSB7XG4gICAgc3VwZXIoKVxuICAgIHRoaXMuX3JwYyA9IHJwY1xuICAgIHRoaXMuX2xvZyA9IGxvZ2dlciB8fCBuZXcgTnVsbExvZ2dlcigpXG4gICAgdGhpcy5zZXR1cExvZ2dpbmcoKVxuICAgIHJwYy5saXN0ZW4oKVxuXG4gICAgdGhpcy5pc0Nvbm5lY3RlZCA9IHRydWVcbiAgICB0aGlzLl9ycGMub25DbG9zZSgoKSA9PiB7XG4gICAgICB0aGlzLmlzQ29ubmVjdGVkID0gZmFsc2VcbiAgICAgIHRoaXMuX2xvZy53YXJuKFwicnBjLm9uQ2xvc2VcIiwgXCJUaGUgUlBDIGNvbm5lY3Rpb24gY2xvc2VkIHVuZXhwZWN0ZWRseVwiKVxuICAgICAgdGhpcy5lbWl0KFwiY2xvc2VcIilcbiAgICB9KVxuICB9XG5cbiAgcHJpdmF0ZSBzZXR1cExvZ2dpbmcoKTogdm9pZCB7XG4gICAgdGhpcy5fcnBjLm9uRXJyb3IoKGVycm9yKSA9PiB0aGlzLl9sb2cuZXJyb3IoW1wicnBjLm9uRXJyb3JcIiwgZXJyb3JdKSlcbiAgICB0aGlzLl9ycGMub25VbmhhbmRsZWROb3RpZmljYXRpb24oKG5vdGlmaWNhdGlvbikgPT4ge1xuICAgICAgaWYgKG5vdGlmaWNhdGlvbi5tZXRob2QgIT0gbnVsbCAmJiBub3RpZmljYXRpb24ucGFyYW1zICE9IG51bGwpIHtcbiAgICAgICAgdGhpcy5fbG9nLndhcm4oYHJwYy5vblVuaGFuZGxlZE5vdGlmaWNhdGlvbiAke25vdGlmaWNhdGlvbi5tZXRob2R9YCwgbm90aWZpY2F0aW9uLnBhcmFtcylcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHRoaXMuX2xvZy53YXJuKFwicnBjLm9uVW5oYW5kbGVkTm90aWZpY2F0aW9uXCIsIG5vdGlmaWNhdGlvbilcbiAgICAgIH1cbiAgICB9KVxuICAgIHRoaXMuX3JwYy5vbk5vdGlmaWNhdGlvbigoLi4uYXJnczogYW55W10pID0+IHRoaXMuX2xvZy5kZWJ1ZyhcInJwYy5vbk5vdGlmaWNhdGlvblwiLCBhcmdzKSlcbiAgfVxuXG4gIHB1YmxpYyBkaXNwb3NlKCk6IHZvaWQge1xuICAgIHRoaXMuX3JwYy5kaXNwb3NlKClcbiAgfVxuXG4gIC8qKlxuICAgKiBQdWJsaWM6IEluaXRpYWxpemUgdGhlIGxhbmd1YWdlIHNlcnZlciB3aXRoIG5lY2Vzc2FyeSB7SW5pdGlhbGl6ZVBhcmFtc30uXG4gICAqXG4gICAqIEBwYXJhbSBwYXJhbXMgVGhlIHtJbml0aWFsaXplUGFyYW1zfSBjb250YWluaW5nIHByb2Nlc3NJZCwgcm9vdFBhdGgsIG9wdGlvbnMgYW5kIHNlcnZlciBjYXBhYmlsaXRpZXMuXG4gICAqIEByZXR1cm5zIEEge1Byb21pc2V9IGNvbnRhaW5pbmcgdGhlIHtJbml0aWFsaXplUmVzdWx0fSB3aXRoIGRldGFpbHMgb2YgdGhlIHNlcnZlcidzIGNhcGFiaWxpdGllcy5cbiAgICovXG4gIHB1YmxpYyBpbml0aWFsaXplKHBhcmFtczogbHNwLkluaXRpYWxpemVQYXJhbXMpOiBQcm9taXNlPGxzcC5Jbml0aWFsaXplUmVzdWx0PiB7XG4gICAgcmV0dXJuIHRoaXMuX3NlbmRSZXF1ZXN0KGxzcC5Jbml0aWFsaXplUmVxdWVzdC50eXBlLCBwYXJhbXMpXG4gIH1cblxuICAvKiogUHVibGljOiBTZW5kIGFuIGBpbml0aWFsaXplZGAgbm90aWZpY2F0aW9uIHRvIHRoZSBsYW5ndWFnZSBzZXJ2ZXIuICovXG4gIHB1YmxpYyBpbml0aWFsaXplZCgpOiB2b2lkIHtcbiAgICB0aGlzLl9zZW5kTm90aWZpY2F0aW9uKGxzcC5Jbml0aWFsaXplZE5vdGlmaWNhdGlvbi50eXBlLCB7fSlcbiAgfVxuXG4gIC8qKiBQdWJsaWM6IFNlbmQgYSBgc2h1dGRvd25gIHJlcXVlc3QgdG8gdGhlIGxhbmd1YWdlIHNlcnZlci4gKi9cbiAgcHVibGljIHNodXRkb3duKCk6IFByb21pc2U8dm9pZD4ge1xuICAgIHJldHVybiB0aGlzLl9zZW5kUmVxdWVzdChsc3AuU2h1dGRvd25SZXF1ZXN0LnR5cGUpXG4gIH1cblxuICAvKiogUHVibGljOiBTZW5kIGFuIGBleGl0YCBub3RpZmljYXRpb24gdG8gdGhlIGxhbmd1YWdlIHNlcnZlci4gKi9cbiAgcHVibGljIGV4aXQoKTogdm9pZCB7XG4gICAgdGhpcy5fc2VuZE5vdGlmaWNhdGlvbihsc3AuRXhpdE5vdGlmaWNhdGlvbi50eXBlKVxuICB9XG5cbiAgLyoqXG4gICAqIFB1YmxpYzogUmVnaXN0ZXIgYSBjYWxsYmFjayBmb3IgYSBjdXN0b20gbm90aWZpY2F0aW9uXG4gICAqXG4gICAqIEBwYXJhbSBtZXRob2QgQSBzdHJpbmcgY29udGFpbmluZyB0aGUgbmFtZSBvZiB0aGUgbWVzc2FnZSB0byBsaXN0ZW4gZm9yLlxuICAgKiBAcGFyYW0gY2FsbGJhY2sgVGhlIGZ1bmN0aW9uIHRvIGJlIGNhbGxlZCB3aGVuIHRoZSBtZXNzYWdlIGlzIHJlY2VpdmVkLiBUaGUgcGF5bG9hZCBmcm9tIHRoZSBtZXNzYWdlIGlzIHBhc3NlZCB0b1xuICAgKiAgIHRoZSBmdW5jdGlvbi5cbiAgICovXG4gIHB1YmxpYyBvbkN1c3RvbU5vdGlmaWNhdGlvbihtZXRob2Q6IHN0cmluZywgY2FsbGJhY2s6IChvYmo6IG9iamVjdCkgPT4gdm9pZCk6IHZvaWQge1xuICAgIHRoaXMuX29uTm90aWZpY2F0aW9uKHsgbWV0aG9kIH0sIGNhbGxiYWNrKVxuICB9XG5cbiAgLyoqIEBkZXByZWNhdGVkIFVzZSBgb25DdXN0b21Ob3RpZmljYXRpb25gIG1ldGhvZCBpbnN0ZWFkICovXG4gIHB1YmxpYyBvbkN1c3RvbShtZXRob2Q6IHN0cmluZywgY2FsbGJhY2s6IChvYmo6IG9iamVjdCkgPT4gdm9pZCk6IHZvaWQge1xuICAgIHRoaXMub25DdXN0b21Ob3RpZmljYXRpb24obWV0aG9kLCBjYWxsYmFjaylcbiAgfVxuXG4gIC8qKlxuICAgKiBQdWJsaWM6IFJlZ2lzdGVyIGEgY2FsbGJhY2sgZm9yIGEgY3VzdG9tIHJlcXVlc3RcbiAgICpcbiAgICogQHBhcmFtIG1ldGhvZCBBIHN0cmluZyBjb250YWluaW5nIHRoZSBuYW1lIG9mIHRoZSBtZXNzYWdlIHRvIGxpc3RlbiBmb3IuXG4gICAqIEBwYXJhbSBjYWxsYmFjayBUaGUgZnVuY3Rpb24gdG8gYmUgY2FsbGVkIHdoZW4gdGhlIG1lc3NhZ2UgaXMgcmVjZWl2ZWQuIFRoZSBwYXlsb2FkIGZyb20gdGhlIG1lc3NhZ2UgaXMgcGFzc2VkIHRvXG4gICAqICAgdGhlIGZ1bmN0aW9uLlxuICAgKi9cbiAgcHVibGljIG9uQ3VzdG9tUmVxdWVzdChcbiAgICBtZXRob2Q6IHN0cmluZyxcbiAgICBjYWxsYmFjazogKG9iajogUmVjb3JkPHN0cmluZywgYW55PikgPT4gUHJvbWlzZTxSZWNvcmQ8c3RyaW5nLCBhbnk+IHwgbnVsbD5cbiAgKTogdm9pZCB7XG4gICAgdGhpcy5fb25SZXF1ZXN0KHsgbWV0aG9kIH0sIGNhbGxiYWNrKVxuICB9XG5cbiAgLyoqXG4gICAqIFB1YmxpYzogU2VuZCBhIGN1c3RvbSByZXF1ZXN0XG4gICAqXG4gICAqIEBwYXJhbSBtZXRob2QgQSBzdHJpbmcgY29udGFpbmluZyB0aGUgbmFtZSBvZiB0aGUgcmVxdWVzdCBtZXNzYWdlLlxuICAgKiBAcGFyYW0gcGFyYW1zIFRoZSBtZXRob2QncyBwYXJhbWV0ZXJzXG4gICAqL1xuICBwdWJsaWMgc2VuZEN1c3RvbVJlcXVlc3QobWV0aG9kOiBzdHJpbmcsIHBhcmFtcz86IGFueVtdIHwgb2JqZWN0KTogUHJvbWlzZTxhbnk+IHtcbiAgICByZXR1cm4gdGhpcy5fc2VuZFJlcXVlc3QobmV3IGxzcC5Qcm90b2NvbFJlcXVlc3RUeXBlPHR5cGVvZiBwYXJhbXMsIGFueSwgYW55LCB2b2lkLCBhbnk+KG1ldGhvZCksIHBhcmFtcylcbiAgfVxuXG4gIC8qKlxuICAgKiBQdWJsaWM6IFNlbmQgYSBjdXN0b20gbm90aWZpY2F0aW9uXG4gICAqXG4gICAqIEBwYXJhbSBtZXRob2QgQSBzdHJpbmcgY29udGFpbmluZyB0aGUgbmFtZSBvZiB0aGUgbm90aWZpY2F0aW9uIG1lc3NhZ2UuXG4gICAqIEBwYXJhbSBwYXJhbXMgVGhlIG1ldGhvZCdzIHBhcmFtZXRlcnNcbiAgICovXG4gIHB1YmxpYyBzZW5kQ3VzdG9tTm90aWZpY2F0aW9uKG1ldGhvZDogc3RyaW5nLCBwYXJhbXM/OiBhbnlbXSB8IG9iamVjdCk6IHZvaWQge1xuICAgIHRoaXMuX3NlbmROb3RpZmljYXRpb24obmV3IGxzcC5Qcm90b2NvbE5vdGlmaWNhdGlvblR5cGU8dHlwZW9mIHBhcmFtcywgYW55PihtZXRob2QpLCBwYXJhbXMpXG4gIH1cblxuICAvKipcbiAgICogUHVibGljOiBSZWdpc3RlciBhIGNhbGxiYWNrIGZvciB0aGUgYHdpbmRvdy9zaG93TWVzc2FnZWAgbWVzc2FnZS5cbiAgICpcbiAgICogQHBhcmFtIGNhbGxiYWNrIFRoZSBmdW5jdGlvbiB0byBiZSBjYWxsZWQgd2hlbiB0aGUgYHdpbmRvdy9zaG93TWVzc2FnZWAgbWVzc2FnZSBpcyByZWNlaXZlZCB3aXRoXG4gICAqICAge1Nob3dNZXNzYWdlUGFyYW1zfSBiZWluZyBwYXNzZWQuXG4gICAqL1xuICBwdWJsaWMgb25TaG93TWVzc2FnZShjYWxsYmFjazogKHBhcmFtczogbHNwLlNob3dNZXNzYWdlUGFyYW1zKSA9PiB2b2lkKTogdm9pZCB7XG4gICAgdGhpcy5fb25Ob3RpZmljYXRpb24oeyBtZXRob2Q6IFwid2luZG93L3Nob3dNZXNzYWdlXCIgfSwgY2FsbGJhY2spXG4gIH1cblxuICAvKipcbiAgICogUHVibGljOiBSZWdpc3RlciBhIGNhbGxiYWNrIGZvciB0aGUgYHdpbmRvdy9zaG93TWVzc2FnZVJlcXVlc3RgIG1lc3NhZ2UuXG4gICAqXG4gICAqIEBwYXJhbSBjYWxsYmFjayBUaGUgZnVuY3Rpb24gdG8gYmUgY2FsbGVkIHdoZW4gdGhlIGB3aW5kb3cvc2hvd01lc3NhZ2VSZXF1ZXN0YCBtZXNzYWdlIGlzIHJlY2VpdmVkIHdpdGhcbiAgICogICB7U2hvd01lc3NhZ2VSZXF1ZXN0UGFyYW19JyBiZWluZyBwYXNzZWQuXG4gICAqIEByZXR1cm5zIEEge1Byb21pc2V9IGNvbnRhaW5pbmcgdGhlIHtNZXNzYWdlQWN0aW9uSXRlbX0uXG4gICAqL1xuICBwdWJsaWMgb25TaG93TWVzc2FnZVJlcXVlc3QoXG4gICAgY2FsbGJhY2s6IChwYXJhbXM6IGxzcC5TaG93TWVzc2FnZVJlcXVlc3RQYXJhbXMpID0+IFByb21pc2U8bHNwLk1lc3NhZ2VBY3Rpb25JdGVtIHwgbnVsbD5cbiAgKTogdm9pZCB7XG4gICAgdGhpcy5fb25SZXF1ZXN0KHsgbWV0aG9kOiBcIndpbmRvdy9zaG93TWVzc2FnZVJlcXVlc3RcIiB9LCBjYWxsYmFjaylcbiAgfVxuXG4gIC8qKlxuICAgKiBQdWJsaWM6IFJlZ2lzdGVyIGEgY2FsbGJhY2sgZm9yIHRoZSBgd2luZG93L3Nob3dEb2N1bWVudGAgbWVzc2FnZS5cbiAgICpcbiAgICogQHBhcmFtIGNhbGxiYWNrIFRoZSBmdW5jdGlvbiB0byBiZSBjYWxsZWQgd2hlbiB0aGUgYHdpbmRvdy9zaG93RG9jdW1lbnRgIG1lc3NhZ2UgaXMgcmVjZWl2ZWQgd2l0aFxuICAgKiAgIHtTaG93RG9jdW1lbnRQYXJhbXN9IGJlaW5nIHBhc3NlZC5cbiAgICovXG4gIHB1YmxpYyBvblNob3dEb2N1bWVudChjYWxsYmFjazogKHBhcmFtczogbHNwLlNob3dEb2N1bWVudFBhcmFtcykgPT4gUHJvbWlzZTxsc3AuU2hvd0RvY3VtZW50UmVzdWx0Pik6IHZvaWQge1xuICAgIHRoaXMuX29uUmVxdWVzdCh7IG1ldGhvZDogXCJ3aW5kb3cvc2hvd0RvY3VtZW50XCIgfSwgY2FsbGJhY2spXG4gIH1cblxuICAvKipcbiAgICogUHVibGljOiBSZWdpc3RlciBhIGNhbGxiYWNrIGZvciB0aGUgYHdpbmRvdy9sb2dNZXNzYWdlYCBtZXNzYWdlLlxuICAgKlxuICAgKiBAcGFyYW0gY2FsbGJhY2sgVGhlIGZ1bmN0aW9uIHRvIGJlIGNhbGxlZCB3aGVuIHRoZSBgd2luZG93L2xvZ01lc3NhZ2VgIG1lc3NhZ2UgaXMgcmVjZWl2ZWQgd2l0aCB7TG9nTWVzc2FnZVBhcmFtc31cbiAgICogICBiZWluZyBwYXNzZWQuXG4gICAqL1xuICBwdWJsaWMgb25Mb2dNZXNzYWdlKGNhbGxiYWNrOiAocGFyYW1zOiBsc3AuTG9nTWVzc2FnZVBhcmFtcykgPT4gdm9pZCk6IHZvaWQge1xuICAgIHRoaXMuX29uTm90aWZpY2F0aW9uKHsgbWV0aG9kOiBcIndpbmRvdy9sb2dNZXNzYWdlXCIgfSwgY2FsbGJhY2spXG4gIH1cblxuICAvKipcbiAgICogUHVibGljOiBSZWdpc3RlciBhIGNhbGxiYWNrIGZvciB0aGUgYHRlbGVtZXRyeS9ldmVudGAgbWVzc2FnZS5cbiAgICpcbiAgICogQHBhcmFtIGNhbGxiYWNrIFRoZSBmdW5jdGlvbiB0byBiZSBjYWxsZWQgd2hlbiB0aGUgYHRlbGVtZXRyeS9ldmVudGAgbWVzc2FnZSBpcyByZWNlaXZlZCB3aXRoIGFueSBwYXJhbWV0ZXJzXG4gICAqICAgcmVjZWl2ZWQgYmVpbmcgcGFzc2VkIG9uLlxuICAgKi9cbiAgcHVibGljIG9uVGVsZW1ldHJ5RXZlbnQoY2FsbGJhY2s6ICguLi5hcmdzOiBhbnlbXSkgPT4gdm9pZCk6IHZvaWQge1xuICAgIHRoaXMuX29uTm90aWZpY2F0aW9uKHsgbWV0aG9kOiBcInRlbGVtZXRyeS9ldmVudFwiIH0sIGNhbGxiYWNrKVxuICB9XG5cbiAgLyoqXG4gICAqIFB1YmxpYzogUmVnaXN0ZXIgYSBjYWxsYmFjayBmb3IgdGhlIGB3b3Jrc3BhY2UvYXBwbHlFZGl0YCBtZXNzYWdlLlxuICAgKlxuICAgKiBAcGFyYW0gY2FsbGJhY2sgVGhlIGZ1bmN0aW9uIHRvIGJlIGNhbGxlZCB3aGVuIHRoZSBgd29ya3NwYWNlL2FwcGx5RWRpdGAgbWVzc2FnZSBpcyByZWNlaXZlZCB3aXRoXG4gICAqICAge0FwcGx5V29ya3NwYWNlRWRpdFBhcmFtc30gYmVpbmcgcGFzc2VkLlxuICAgKiBAcmV0dXJucyBBIHtQcm9taXNlfSBjb250YWluaW5nIHRoZSB7QXBwbHlXb3Jrc3BhY2VFZGl0UmVzcG9uc2V9LlxuICAgKi9cbiAgcHVibGljIG9uQXBwbHlFZGl0KFxuICAgIGNhbGxiYWNrOiAocGFyYW1zOiBsc3AuQXBwbHlXb3Jrc3BhY2VFZGl0UGFyYW1zKSA9PiBQcm9taXNlPGxzcC5BcHBseVdvcmtzcGFjZUVkaXRSZXNwb25zZT5cbiAgKTogdm9pZCB7XG4gICAgdGhpcy5fb25SZXF1ZXN0KHsgbWV0aG9kOiBcIndvcmtzcGFjZS9hcHBseUVkaXRcIiB9LCBjYWxsYmFjaylcbiAgfVxuXG4gIC8qKlxuICAgKiBQdWJsaWM6IFNlbmQgYSBgd29ya3NwYWNlL2RpZENoYW5nZUNvbmZpZ3VyYXRpb25gIG5vdGlmaWNhdGlvbi5cbiAgICpcbiAgICogQHBhcmFtIHBhcmFtcyBUaGUge0RpZENoYW5nZUNvbmZpZ3VyYXRpb25QYXJhbXN9IGNvbnRhaW5pbmcgdGhlIG5ldyBjb25maWd1cmF0aW9uLlxuICAgKi9cbiAgcHVibGljIGRpZENoYW5nZUNvbmZpZ3VyYXRpb24ocGFyYW1zOiBsc3AuRGlkQ2hhbmdlQ29uZmlndXJhdGlvblBhcmFtcyk6IHZvaWQge1xuICAgIHRoaXMuX3NlbmROb3RpZmljYXRpb24obHNwLkRpZENoYW5nZUNvbmZpZ3VyYXRpb25Ob3RpZmljYXRpb24udHlwZSwgcGFyYW1zKVxuICB9XG5cbiAgLyoqXG4gICAqIFB1YmxpYzogU2VuZCBhIGB0ZXh0RG9jdW1lbnQvZGlkT3BlbmAgbm90aWZpY2F0aW9uLlxuICAgKlxuICAgKiBAcGFyYW0gcGFyYW1zIFRoZSB7RGlkT3BlblRleHREb2N1bWVudFBhcmFtc30gY29udGFpbmluZyB0aGUgb3BlbmVkIHRleHQgZG9jdW1lbnQgZGV0YWlscy5cbiAgICovXG4gIHB1YmxpYyBkaWRPcGVuVGV4dERvY3VtZW50KHBhcmFtczogbHNwLkRpZE9wZW5UZXh0RG9jdW1lbnRQYXJhbXMpOiB2b2lkIHtcbiAgICB0aGlzLl9zZW5kTm90aWZpY2F0aW9uKGxzcC5EaWRPcGVuVGV4dERvY3VtZW50Tm90aWZpY2F0aW9uLnR5cGUsIHBhcmFtcylcbiAgfVxuXG4gIC8qKlxuICAgKiBQdWJsaWM6IFNlbmQgYSBgdGV4dERvY3VtZW50L2RpZENoYW5nZWAgbm90aWZpY2F0aW9uLlxuICAgKlxuICAgKiBAcGFyYW0gcGFyYW1zIFRoZSB7RGlkQ2hhbmdlVGV4dERvY3VtZW50UGFyYW1zfSBjb250YWluaW5nIHRoZSBjaGFuZ2VkIHRleHQgZG9jdW1lbnQgZGV0YWlscyBpbmNsdWRpbmcgdGhlIHZlcnNpb25cbiAgICogICBudW1iZXIgYW5kIGFjdHVhbCB0ZXh0IGNoYW5nZXMuXG4gICAqL1xuICBwdWJsaWMgZGlkQ2hhbmdlVGV4dERvY3VtZW50KHBhcmFtczogbHNwLkRpZENoYW5nZVRleHREb2N1bWVudFBhcmFtcyk6IHZvaWQge1xuICAgIHRoaXMuX3NlbmROb3RpZmljYXRpb24obHNwLkRpZENoYW5nZVRleHREb2N1bWVudE5vdGlmaWNhdGlvbi50eXBlLCBwYXJhbXMpXG4gIH1cblxuICAvKipcbiAgICogUHVibGljOiBTZW5kIGEgYHRleHREb2N1bWVudC9kaWRDbG9zZWAgbm90aWZpY2F0aW9uLlxuICAgKlxuICAgKiBAcGFyYW0gcGFyYW1zIFRoZSB7RGlkQ2xvc2VUZXh0RG9jdW1lbnRQYXJhbXN9IGNvbnRhaW5pbmcgdGhlIG9wZW5lZCB0ZXh0IGRvY3VtZW50IGRldGFpbHMuXG4gICAqL1xuICBwdWJsaWMgZGlkQ2xvc2VUZXh0RG9jdW1lbnQocGFyYW1zOiBsc3AuRGlkQ2xvc2VUZXh0RG9jdW1lbnRQYXJhbXMpOiB2b2lkIHtcbiAgICB0aGlzLl9zZW5kTm90aWZpY2F0aW9uKGxzcC5EaWRDbG9zZVRleHREb2N1bWVudE5vdGlmaWNhdGlvbi50eXBlLCBwYXJhbXMpXG4gIH1cblxuICAvKipcbiAgICogUHVibGljOiBTZW5kIGEgYHRleHREb2N1bWVudC93aWxsU2F2ZWAgbm90aWZpY2F0aW9uLlxuICAgKlxuICAgKiBAcGFyYW0gcGFyYW1zIFRoZSB7V2lsbFNhdmVUZXh0RG9jdW1lbnRQYXJhbXN9IGNvbnRhaW5pbmcgdGhlIHRvLWJlLXNhdmVkIHRleHQgZG9jdW1lbnQgZGV0YWlscyBhbmQgdGhlIHJlYXNvbiBmb3IgdGhlIHNhdmUuXG4gICAqL1xuICBwdWJsaWMgd2lsbFNhdmVUZXh0RG9jdW1lbnQocGFyYW1zOiBsc3AuV2lsbFNhdmVUZXh0RG9jdW1lbnRQYXJhbXMpOiB2b2lkIHtcbiAgICB0aGlzLl9zZW5kTm90aWZpY2F0aW9uKGxzcC5XaWxsU2F2ZVRleHREb2N1bWVudE5vdGlmaWNhdGlvbi50eXBlLCBwYXJhbXMpXG4gIH1cblxuICAvKipcbiAgICogUHVibGljOiBTZW5kIGEgYHRleHREb2N1bWVudC93aWxsU2F2ZVdhaXRVbnRpbGAgbm90aWZpY2F0aW9uLlxuICAgKlxuICAgKiBAcGFyYW0gcGFyYW1zIFRoZSB7V2lsbFNhdmVUZXh0RG9jdW1lbnRQYXJh