atom-languageclient
Version:
Integrate Language Servers with Atom
304 lines • 40 kB
JavaScript
"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 });
const convert_1 = require("../convert");
const Utils = require("../utils");
const languageclient_1 = require("../languageclient");
const atom_1 = require("atom");
/** Public: Adapts the documentSymbolProvider of the language server to the Outline View supplied by Atom IDE UI. */
class OutlineViewAdapter {
constructor() {
this._cancellationTokens = new WeakMap();
}
/**
* Public: Determine whether this adapter can be used to adapt a language server based on the serverCapabilities
* matrix containing a documentSymbolProvider.
*
* @param serverCapabilities The {ServerCapabilities} of the language server to consider.
* @returns A {Boolean} indicating adapter can adapt the server based on the given serverCapabilities.
*/
static canAdapt(serverCapabilities) {
return serverCapabilities.documentSymbolProvider === true;
}
/**
* Public: Obtain the Outline for document via the {LanguageClientConnection} as identified by the {TextEditor}.
*
* @param connection A {LanguageClientConnection} to the language server that will be queried for the outline.
* @param editor The Atom {TextEditor} containing the text the Outline should represent.
* @returns A {Promise} containing the {Outline} of this document.
*/
getOutline(connection, editor) {
return __awaiter(this, void 0, void 0, function* () {
const results = yield Utils.doWithCancellationToken(connection, this._cancellationTokens, (cancellationToken) => connection.documentSymbol({ textDocument: convert_1.default.editorToTextDocumentIdentifier(editor) }, cancellationToken));
if (results === null || results.length === 0) {
return {
outlineTrees: [],
};
}
if (results[0].selectionRange !== undefined) {
// If the server is giving back the newer DocumentSymbol format.
return {
outlineTrees: OutlineViewAdapter.createHierarchicalOutlineTrees(results),
};
}
else {
// If the server is giving back the original SymbolInformation format.
return {
outlineTrees: OutlineViewAdapter.createOutlineTrees(results),
};
}
});
}
/**
* Public: Create an {Array} of {OutlineTree}s from the Array of {DocumentSymbol} recieved from the language server.
* This includes converting all the children nodes in the entire hierarchy.
*
* @param symbols An {Array} of {DocumentSymbol}s received from the language server that should be converted to an
* {Array} of {OutlineTree}.
* @returns An {Array} of {OutlineTree} containing the given symbols that the Outline View can display.
*/
static createHierarchicalOutlineTrees(symbols) {
// Sort all the incoming symbols
symbols.sort((a, b) => {
if (a.range.start.line !== b.range.start.line) {
return a.range.start.line - b.range.start.line;
}
if (a.range.start.character !== b.range.start.character) {
return a.range.start.character - b.range.start.character;
}
if (a.range.end.line !== b.range.end.line) {
return a.range.end.line - b.range.end.line;
}
return a.range.end.character - b.range.end.character;
});
return symbols.map((symbol) => {
const tree = OutlineViewAdapter.hierarchicalSymbolToOutline(symbol);
if (symbol.children != null) {
tree.children = OutlineViewAdapter.createHierarchicalOutlineTrees(symbol.children);
}
return tree;
});
}
/**
* Public: Create an {Array} of {OutlineTree}s from the Array of {SymbolInformation} recieved from the language
* server. This includes determining the appropriate child and parent relationships for the hierarchy.
*
* @param symbols An {Array} of {SymbolInformation}s received from the language server that should be converted to an
* {OutlineTree}.
* @returns An {OutlineTree} containing the given symbols that the Outline View can display.
*/
static createOutlineTrees(symbols) {
symbols.sort((a, b) => {
if (a.location.range.start.line === b.location.range.start.line) {
return a.location.range.start.character - b.location.range.start.character;
}
else {
return a.location.range.start.line - b.location.range.start.line;
}
});
// Temporarily keep containerName through the conversion process
// Also filter out symbols without a name - it's part of the spec but some don't include it
const allItems = symbols
.filter((symbol) => symbol.name)
.map((symbol) => ({
containerName: symbol.containerName,
outline: OutlineViewAdapter.symbolToOutline(symbol),
}));
// Create a map of containers by name with all items that have that name
const containers = allItems.reduce((map, item) => {
const name = item.outline.representativeName;
if (name != null) {
const container = map.get(name);
if (container == null) {
map.set(name, [item.outline]);
}
else {
container.push(item.outline);
}
}
return map;
}, new Map());
const roots = [];
// Put each item within its parent and extract out the roots
for (const item of allItems) {
const containerName = item.containerName;
const child = item.outline;
if (containerName == null || containerName === "") {
roots.push(item.outline);
}
else {
const possibleParents = containers.get(containerName);
let closestParent = OutlineViewAdapter._getClosestParent(possibleParents, child);
if (closestParent == null) {
closestParent = {
plainText: containerName,
representativeName: containerName,
startPosition: new atom_1.Point(0, 0),
children: [child],
};
roots.push(closestParent);
if (possibleParents == null) {
containers.set(containerName, [closestParent]);
}
else {
possibleParents.push(closestParent);
}
}
else {
closestParent.children.push(child);
}
}
}
return roots;
}
static _getClosestParent(candidates, child) {
if (candidates == null || candidates.length === 0) {
return null;
}
let parent;
for (const candidate of candidates) {
if (candidate !== child &&
candidate.startPosition.isLessThanOrEqual(child.startPosition) &&
(candidate.endPosition === undefined ||
(child.endPosition && candidate.endPosition.isGreaterThanOrEqual(child.endPosition)))) {
if (parent === undefined ||
parent.startPosition.isLessThanOrEqual(candidate.startPosition) ||
(parent.endPosition != null &&
candidate.endPosition &&
parent.endPosition.isGreaterThanOrEqual(candidate.endPosition))) {
parent = candidate;
}
}
}
return parent || null;
}
/**
* Public: Convert an individual {DocumentSymbol} from the language server to an {OutlineTree} for use by the Outline
* View. It does NOT recursively process the given symbol's children (if any).
*
* @param symbol The {DocumentSymbol} to convert to an {OutlineTree}.
* @returns The {OutlineTree} corresponding to the given {DocumentSymbol}.
*/
static hierarchicalSymbolToOutline(symbol) {
const icon = OutlineViewAdapter.symbolKindToEntityKind(symbol.kind);
return {
tokenizedText: [
{
kind: OutlineViewAdapter.symbolKindToTokenKind(symbol.kind),
value: symbol.name,
},
],
icon: icon != null ? icon : undefined,
representativeName: symbol.name,
startPosition: convert_1.default.positionToPoint(symbol.selectionRange.start),
endPosition: convert_1.default.positionToPoint(symbol.selectionRange.end),
children: [],
};
}
/**
* Public: Convert an individual {SymbolInformation} from the language server to an {OutlineTree} for use by the Outline View.
*
* @param symbol The {SymbolInformation} to convert to an {OutlineTree}.
* @returns The {OutlineTree} equivalent to the given {SymbolInformation}.
*/
static symbolToOutline(symbol) {
const icon = OutlineViewAdapter.symbolKindToEntityKind(symbol.kind);
return {
tokenizedText: [
{
kind: OutlineViewAdapter.symbolKindToTokenKind(symbol.kind),
value: symbol.name,
},
],
icon: icon != null ? icon : undefined,
representativeName: symbol.name,
startPosition: convert_1.default.positionToPoint(symbol.location.range.start),
endPosition: convert_1.default.positionToPoint(symbol.location.range.end),
children: [],
};
}
/**
* Public: Convert a symbol kind into an outline entity kind used to determine the styling such as the appropriate
* icon in the Outline View.
*
* @param symbol The numeric symbol kind received from the language server.
* @returns A string representing the equivalent OutlineView entity kind.
*/
static symbolKindToEntityKind(symbol) {
switch (symbol) {
case languageclient_1.SymbolKind.Array:
return "type-array";
case languageclient_1.SymbolKind.Boolean:
return "type-boolean";
case languageclient_1.SymbolKind.Class:
return "type-class";
case languageclient_1.SymbolKind.Constant:
return "type-constant";
case languageclient_1.SymbolKind.Constructor:
return "type-constructor";
case languageclient_1.SymbolKind.Enum:
return "type-enum";
case languageclient_1.SymbolKind.Field:
return "type-field";
case languageclient_1.SymbolKind.File:
return "type-file";
case languageclient_1.SymbolKind.Function:
return "type-function";
case languageclient_1.SymbolKind.Interface:
return "type-interface";
case languageclient_1.SymbolKind.Method:
return "type-method";
case languageclient_1.SymbolKind.Module:
return "type-module";
case languageclient_1.SymbolKind.Namespace:
return "type-namespace";
case languageclient_1.SymbolKind.Number:
return "type-number";
case languageclient_1.SymbolKind.Package:
return "type-package";
case languageclient_1.SymbolKind.Property:
return "type-property";
case languageclient_1.SymbolKind.String:
return "type-string";
case languageclient_1.SymbolKind.Variable:
return "type-variable";
case languageclient_1.SymbolKind.Struct:
return "type-class";
case languageclient_1.SymbolKind.EnumMember:
return "type-constant";
default:
return null;
}
}
/**
* Public: Convert a symbol kind to the appropriate token kind used to syntax highlight the symbol name in the Outline View.
*
* @param symbol The numeric symbol kind received from the language server.
* @returns A string representing the equivalent syntax token kind.
*/
static symbolKindToTokenKind(symbol) {
switch (symbol) {
case languageclient_1.SymbolKind.Class:
return "type";
case languageclient_1.SymbolKind.Constructor:
return "constructor";
case languageclient_1.SymbolKind.Method:
case languageclient_1.SymbolKind.Function:
return "method";
case languageclient_1.SymbolKind.String:
return "string";
default:
return "plain";
}
}
}
exports.default = OutlineViewAdapter;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoib3V0bGluZS12aWV3LWFkYXB0ZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9saWIvYWRhcHRlcnMvb3V0bGluZS12aWV3LWFkYXB0ZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7QUFDQSx3Q0FBZ0M7QUFDaEMsa0NBQWlDO0FBRWpDLHNEQU0wQjtBQUMxQiwrQkFBd0M7QUFFeEMsb0hBQW9IO0FBQ3BILE1BQXFCLGtCQUFrQjtJQUF2QztRQUNVLHdCQUFtQixHQUErRCxJQUFJLE9BQU8sRUFBRSxDQUFBO0lBb1R6RyxDQUFDO0lBbFRDOzs7Ozs7T0FNRztJQUNJLE1BQU0sQ0FBQyxRQUFRLENBQUMsa0JBQXNDO1FBQzNELE9BQU8sa0JBQWtCLENBQUMsc0JBQXNCLEtBQUssSUFBSSxDQUFBO0lBQzNELENBQUM7SUFFRDs7Ozs7O09BTUc7SUFDVSxVQUFVLENBQUMsVUFBb0MsRUFBRSxNQUFrQjs7WUFDOUUsTUFBTSxPQUFPLEdBQUcsTUFBTSxLQUFLLENBQUMsdUJBQXVCLENBQUMsVUFBVSxFQUFFLElBQUksQ0FBQyxtQkFBbUIsRUFBRSxDQUFDLGlCQUFpQixFQUFFLEVBQUUsQ0FDOUcsVUFBVSxDQUFDLGNBQWMsQ0FBQyxFQUFFLFlBQVksRUFBRSxpQkFBTyxDQUFDLDhCQUE4QixDQUFDLE1BQU0sQ0FBQyxFQUFFLEVBQUUsaUJBQWlCLENBQUMsQ0FDL0csQ0FBQTtZQUVELElBQUksT0FBTyxLQUFLLElBQUksSUFBSSxPQUFPLENBQUMsTUFBTSxLQUFLLENBQUMsRUFBRTtnQkFDNUMsT0FBTztvQkFDTCxZQUFZLEVBQUUsRUFBRTtpQkFDakIsQ0FBQTthQUNGO1lBRUQsSUFBSyxPQUFPLENBQUMsQ0FBQyxDQUFvQixDQUFDLGNBQWMsS0FBSyxTQUFTLEVBQUU7Z0JBQy9ELGdFQUFnRTtnQkFDaEUsT0FBTztvQkFDTCxZQUFZLEVBQUUsa0JBQWtCLENBQUMsOEJBQThCLENBQUMsT0FBMkIsQ0FBQztp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TSxDQUFBO1lBQ2YsS0FBSywyQkFBVSxDQUFDLFdBQVc7Z0JBQ3pCLE9BQU8sYUFBYSxDQUFBO1lBQ3RCLEtBQUssMkJBQVUsQ0FBQyxNQUFNLENBQUM7WUFDdkIsS0FBSywyQkFBVSxDQUFDLFFBQVE7Z0JBQ3RCLE9BQU8sUUFBUSxDQUFBO1lBQ2pCLEtBQUssMkJBQVUsQ0FBQyxNQUFNO2dCQUNwQixPQUFPLFFBQVEsQ0FBQTtZQUNqQjtnQkFDRSxPQUFPLE9BQU8sQ0FBQTtTQUNqQjtJQUNILENBQUM7Q0FDRjtBQXJURCxxQ0FxVEMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgdHlwZSAqIGFzIGF0b21JZGUgZnJvbSBcImF0b20taWRlLWJhc2VcIlxuaW1wb3J0IENvbnZlcnQgZnJvbSBcIi4uL2NvbnZlcnRcIlxuaW1wb3J0ICogYXMgVXRpbHMgZnJvbSBcIi4uL3V0aWxzXCJcbmltcG9ydCB7IENhbmNlbGxhdGlvblRva2VuU291cmNlIH0gZnJvbSBcInZzY29kZS1qc29ucnBjXCJcbmltcG9ydCB7XG4gIExhbmd1YWdlQ2xpZW50Q29ubmVjdGlvbixcbiAgU3ltYm9sS2luZCxcbiAgU2VydmVyQ2FwYWJpbGl0aWVzLFxuICBTeW1ib2xJbmZvcm1hdGlvbixcbiAgRG9jdW1lbnRTeW1ib2wsXG59IGZyb20gXCIuLi9sYW5ndWFnZWNsaWVudFwiXG5pbXBvcnQgeyBQb2ludCwgVGV4dEVkaXRvciB9IGZyb20gXCJhdG9tXCJcblxuLyoqIFB1YmxpYzogQWRhcHRzIHRoZSBkb2N1bWVudFN5bWJvbFByb3ZpZGVyIG9mIHRoZSBsYW5ndWFnZSBzZXJ2ZXIgdG8gdGhlIE91dGxpbmUgVmlldyBzdXBwbGllZCBieSBBdG9tIElERSBVSS4gKi9cbmV4cG9ydCBkZWZhdWx0IGNsYXNzIE91dGxpbmVWaWV3QWRhcHRlciB7XG4gIHByaXZhdGUgX2NhbmNlbGxhdGlvblRva2VuczogV2Vha01hcDxMYW5ndWFnZUNsaWVudENvbm5lY3Rpb24sIENhbmNlbGxhdGlvblRva2VuU291cmNlPiA9IG5ldyBXZWFrTWFwKClcblxuICAvKipcbiAgICogUHVibGljOiBEZXRlcm1pbmUgd2hldGhlciB0aGlzIGFkYXB0ZXIgY2FuIGJlIHVzZWQgdG8gYWRhcHQgYSBsYW5ndWFnZSBzZXJ2ZXIgYmFzZWQgb24gdGhlIHNlcnZlckNhcGFiaWxpdGllc1xuICAgKiBtYXRyaXggY29udGFpbmluZyBhIGRvY3VtZW50U3ltYm9sUHJvdmlkZXIuXG4gICAqXG4gICAqIEBwYXJhbSBzZXJ2ZXJDYXBhYmlsaXRpZXMgVGhlIHtTZXJ2ZXJDYXBhYmlsaXRpZXN9IG9mIHRoZSBsYW5ndWFnZSBzZXJ2ZXIgdG8gY29uc2lkZXIuXG4gICAqIEByZXR1cm5zIEEge0Jvb2xlYW59IGluZGljYXRpbmcgYWRhcHRlciBjYW4gYWRhcHQgdGhlIHNlcnZlciBiYXNlZCBvbiB0aGUgZ2l2ZW4gc2VydmVyQ2FwYWJpbGl0aWVzLlxuICAgKi9cbiAgcHVibGljIHN0YXRpYyBjYW5BZGFwdChzZXJ2ZXJDYXBhYmlsaXRpZXM6IFNlcnZlckNhcGFiaWxpdGllcyk6IGJvb2xlYW4ge1xuICAgIHJldHVybiBzZXJ2ZXJDYXBhYmlsaXRpZXMuZG9jdW1lbnRTeW1ib2xQcm92aWRlciA9PT0gdHJ1ZVxuICB9XG5cbiAgLyoqXG4gICAqIFB1YmxpYzogT2J0YWluIHRoZSBPdXRsaW5lIGZvciBkb2N1bWVudCB2aWEgdGhlIHtMYW5ndWFnZUNsaWVudENvbm5lY3Rpb259IGFzIGlkZW50aWZpZWQgYnkgdGhlIHtUZXh0RWRpdG9yfS5cbiAgICpcbiAgICogQHBhcmFtIGNvbm5lY3Rpb24gQSB7TGFuZ3VhZ2VDbGllbnRDb25uZWN0aW9ufSB0byB0aGUgbGFuZ3VhZ2Ugc2VydmVyIHRoYXQgd2lsbCBiZSBxdWVyaWVkIGZvciB0aGUgb3V0bGluZS5cbiAgICogQHBhcmFtIGVkaXRvciBUaGUgQXRvbSB7VGV4dEVkaXRvcn0gY29udGFpbmluZyB0aGUgdGV4dCB0aGUgT3V0bGluZSBzaG91bGQgcmVwcmVzZW50LlxuICAgKiBAcmV0dXJucyBBIHtQcm9taXNlfSBjb250YWluaW5nIHRoZSB7T3V0bGluZX0gb2YgdGhpcyBkb2N1bWVudC5cbiAgICovXG4gIHB1YmxpYyBhc3luYyBnZXRPdXRsaW5lKGNvbm5lY3Rpb246IExhbmd1YWdlQ2xpZW50Q29ubmVjdGlvbiwgZWRpdG9yOiBUZXh0RWRpdG9yKTogUHJvbWlzZTxhdG9tSWRlLk91dGxpbmUgfCBudWxsPiB7XG4gICAgY29uc3QgcmVzdWx0cyA9IGF3YWl0IFV0aWxzLmRvV2l0aENhbmNlbGxhdGlvblRva2VuKGNvbm5lY3Rpb24sIHRoaXMuX2NhbmNlbGxhdGlvblRva2VucywgKGNhbmNlbGxhdGlvblRva2VuKSA9PlxuICAgICAgY29ubmVjdGlvbi5kb2N1bWVudFN5bWJvbCh7IHRleHREb2N1bWVudDogQ29udmVydC5lZGl0b3JUb1RleHREb2N1bWVudElkZW50aWZpZXIoZWRpdG9yKSB9LCBjYW5jZWxsYXRpb25Ub2tlbilcbiAgICApXG5cbiAgICBpZiAocmVzdWx0cyA9PT0gbnVsbCB8fCByZXN1bHRzLmxlbmd0aCA9PT0gMCkge1xuICAgICAgcmV0dXJuIHtcbiAgICAgICAgb3V0bGluZVRyZWVzOiBbXSxcbiAgICAgIH1cbiAgICB9XG5cbiAgICBpZiAoKHJlc3VsdHNbMF0gYXMgRG9jdW1lbnRTeW1ib2wpLnNlbGVjdGlvblJhbmdlICE9PSB1bmRlZmluZWQpIHtcbiAgICAgIC8vIElmIHRoZSBzZXJ2ZXIgaXMgZ2l2aW5nIGJhY2sgdGhlIG5ld2VyIERvY3VtZW50U3ltYm9sIGZvcm1hdC5cbiAgICAgIHJldHVybiB7XG4gICAgICAgIG91dGxpbmVUcmVlczogT3V0bGluZVZpZXdBZGFwdGVyLmNyZWF0ZUhpZXJhcmNoaWNhbE91dGxpbmVUcmVlcyhyZXN1bHRzIGFzIERvY3VtZW50U3ltYm9sW10pLFxuICAgICAgfVxuICAgIH0gZWxzZSB7XG4gICAgICAvLyBJZiB0aGUgc2VydmVyIGlzIGdpdmluZyBiYWNrIHRoZSBvcmlnaW5hbCBTeW1ib2xJbmZvcm1hdGlvbiBmb3JtYXQuXG4gICAgICByZXR1cm4ge1xuICAgICAgICBvdXRsaW5lVHJlZXM6IE91dGxpbmVWaWV3QWRhcHRlci5jcmVhdGVPdXRsaW5lVHJlZXMocmVzdWx0cyBhcyBTeW1ib2xJbmZvcm1hdGlvbltdKSxcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogUHVibGljOiBDcmVhdGUgYW4ge0FycmF5fSBvZiB7T3V0bGluZVRyZWV9cyBmcm9tIHRoZSBBcnJheSBvZiB7RG9jdW1lbnRTeW1ib2x9IHJlY2lldmVkIGZyb20gdGhlIGxhbmd1YWdlIHNlcnZlci5cbiAgICogVGhpcyBpbmNsdWRlcyBjb252ZXJ0aW5nIGFsbCB0aGUgY2hpbGRyZW4gbm9kZXMgaW4gdGhlIGVudGlyZSBoaWVyYXJjaHkuXG4gICAqXG4gICAqIEBwYXJhbSBzeW1ib2xzIEFuIHtBcnJheX0gb2Yge0RvY3VtZW50U3ltYm9sfXMgcmVjZWl2ZWQgZnJvbSB0aGUgbGFuZ3VhZ2Ugc2VydmVyIHRoYXQgc2hvdWxkIGJlIGNvbnZlcnRlZCB0byBhblxuICAgKiAgIHtBcnJheX0gb2Yge091dGxpbmVUcmVlfS5cbiAgICogQHJldHVybnMgQW4ge0FycmF5fSBvZiB7T3V0bGluZVRyZWV9IGNvbnRhaW5pbmcgdGhlIGdpdmVuIHN5bWJvbHMgdGhhdCB0aGUgT3V0bGluZSBWaWV3IGNhbiBkaXNwbGF5LlxuICAgKi9cbiAgcHVibGljIHN0YXRpYyBjcmVhdGVIaWVyYXJjaGljYWxPdXRsaW5lVHJlZXMoc3ltYm9sczogRG9jdW1lbnRTeW1ib2xbXSk6IGF0b21JZGUuT3V0bGluZVRyZWVbXSB7XG4gICAgLy8gU29ydCBhbGwgdGhlIGluY29taW5nIHN5bWJvbHNcbiAgICBzeW1ib2xzLnNvcnQoKGEsIGIpID0+IHtcbiAgICAgIGlmIChhLnJhbmdlLnN0YXJ0LmxpbmUgIT09IGIucmFuZ2Uuc3RhcnQubGluZSkge1xuICAgICAgICByZXR1cm4gYS5yYW5nZS5zdGFydC5saW5lIC0gYi5yYW5nZS5zdGFydC5saW5lXG4gICAgICB9XG5cbiAgICAgIGlmIChhLnJhbmdlLnN0YXJ0LmNoYXJhY3RlciAhPT0gYi5yYW5nZS5zdGFydC5jaGFyYWN0ZXIpIHtcbiAgICAgICAgcmV0dXJuIGEucmFuZ2Uuc3RhcnQuY2hhcmFjdGVyIC0gYi5yYW5nZS5zdGFydC5jaGFyYWN0ZXJcbiAgICAgIH1cblxuICAgICAgaWYgKGEucmFuZ2UuZW5kLmxpbmUgIT09IGIucmFuZ2UuZW5kLmxpbmUpIHtcbiAgICAgICAgcmV0dXJuIGEucmFuZ2UuZW5kLmxpbmUgLSBiLnJhbmdlLmVuZC5saW5lXG4gICAgICB9XG5cbiAgICAgIHJldHVybiBhLnJhbmdlLmVuZC5jaGFyYWN0ZXIgLSBiLnJhbmdlLmVuZC5jaGFyYWN0ZXJcbiAgICB9KVxuXG4gICAgcmV0dXJuIHN5bWJvbHMubWFwKChzeW1ib2wpID0+IHtcbiAgICAgIGNvbnN0IHRyZWUgPSBPdXRsaW5lVmlld0FkYXB0ZXIuaGllcmFyY2hpY2FsU3ltYm9sVG9PdXRsaW5lKHN5bWJvbClcblxuICAgICAgaWYgKHN5bWJvbC5jaGlsZHJlbiAhPSBudWxsKSB7XG4gICAgICAgIHRyZWUuY2hpbGRyZW4gPSBPdXRsaW5lVmlld0FkYXB0ZXIuY3JlYXRlSGllcmFyY2hpY2FsT3V0bGluZVRyZWVzKHN5bWJvbC5jaGlsZHJlbilcbiAgICAgIH1cblxuICAgICAgcmV0dXJuIHRyZWVcbiAgICB9KVxuICB9XG5cbiAgLyoqXG4gICAqIFB1YmxpYzogQ3JlYXRlIGFuIHtBcnJheX0gb2Yge091dGxpbmVUcmVlfXMgZnJvbSB0aGUgQXJyYXkgb2Yge1N5bWJvbEluZm9ybWF0aW9ufSByZWNpZXZlZCBmcm9tIHRoZSBsYW5ndWFnZVxuICAgKiBzZXJ2ZXIuIFRoaXMgaW5jbHVkZXMgZGV0ZXJtaW5pbmcgdGhlIGFwcHJvcHJpYXRlIGNoaWxkIGFuZCBwYXJlbnQgcmVsYXRpb25zaGlwcyBmb3IgdGhlIGhpZXJhcmNoeS5cbiAgICpcbiAgICogQHBhcmFtIHN5bWJvbHMgQW4ge0FycmF5fSBvZiB7U3ltYm9sSW5mb3JtYXRpb259cyByZWNlaXZlZCBmcm9tIHRoZSBsYW5ndWFnZSBzZXJ2ZXIgdGhhdCBzaG91bGQgYmUgY29udmVydGVkIHRvIGFuXG4gICAqICAge091dGxpbmVUcmVlfS5cbiAgICogQHJldHVybnMgQW4ge091dGxpbmVUcmVlfSBjb250YWluaW5nIHRoZSBnaXZlbiBzeW1ib2xzIHRoYXQgdGhlIE91dGxpbmUgVmlldyBjYW4gZGlzcGxheS5cbiAgICovXG4gIHB1YmxpYyBzdGF0aWMgY3JlYXRlT3V0bGluZVRyZWVzKHN5bWJvbHM6IFN5bWJvbEluZm9ybWF0aW9uW10pOiBhdG9tSWRlLk91dGxpbmVUcmVlW10ge1xuICAgIHN5bWJvbHMuc29ydCgoYSwgYikgPT4ge1xuICAgICAgaWYgKGEubG9jYXRpb24ucmFuZ2Uuc3RhcnQubGluZSA9PT0gYi5sb2NhdGlvbi5yYW5nZS5zdGFydC5saW5lKSB7XG4gICAgICAgIHJldHVybiBhLmxvY2F0aW9uLnJhbmdlLnN0YXJ0LmNoYXJhY3RlciAtIGIubG9jYXRpb24ucmFuZ2Uuc3RhcnQuY2hhcmFjdGVyXG4gICAgICB9IGVsc2Uge1xuICAgICAgICByZXR1cm4gYS5sb2NhdGlvbi5yYW5nZS5zdGFydC5saW5lIC0gYi5sb2NhdGlvbi5yYW5nZS5zdGFydC5saW5lXG4gICAgICB9XG4gICAgfSlcblxuICAgIC8vIFRlbXBvcmFyaWx5IGtlZXAgY29udGFpbmVyTmFtZSB0aHJvdWdoIHRoZSBjb252ZXJzaW9uIHByb2Nlc3NcbiAgICAvLyBBbHNvIGZpbHRlciBvdXQgc3ltYm9scyB3aXRob3V0IGEgbmFtZSAtIGl0J3MgcGFydCBvZiB0aGUgc3BlYyBidXQgc29tZSBkb24ndCBpbmNsdWRlIGl0XG4gICAgY29uc3QgYWxsSXRlbXMgPSBzeW1ib2xzXG4gICAgICAuZmlsdGVyKChzeW1ib2wpID0+IHN5bWJvbC5uYW1lKVxuICAgICAgLm1hcCgoc3ltYm9sKSA9PiAoe1xuICAgICAgICBjb250YWluZXJOYW1lOiBzeW1ib2wuY29udGFpbmVyTmFtZSxcbiAgICAgICAgb3V0bGluZTogT3V0bGluZVZpZXdBZGFwdGVyLnN5bWJvbFRvT3V0bGluZShzeW1ib2wpLFxuICAgICAgfSkpXG5cbiAgICAvLyBDcmVhdGUgYSBtYXAgb2YgY29udGFpbmVycyBieSBuYW1lIHdpdGggYWxsIGl0ZW1zIHRoYXQgaGF2ZSB0aGF0IG5hbWVcbiAgICBjb25zdCBjb250YWluZXJzID0gYWxsSXRlbXMucmVkdWNlKChtYXAsIGl0ZW0pID0+IHtcbiAgICAgIGNvbnN0IG5hbWUgPSBpdGVtLm91dGxpbmUucmVwcmVzZW50YXRpdmVOYW1lXG4gICAgICBpZiAobmFtZSAhPSBudWxsKSB7XG4gICAgICAgIGNvbnN0IGNvbnRhaW5lciA9IG1hcC5nZXQobmFtZSlcbiAgICAgICAgaWYgKGNvbnRhaW5lciA9PSBudWxsKSB7XG4gICAgICAgICAgbWFwLnNldChuYW1lLCBbaXRlbS5vdXRsaW5lXSlcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBjb250YWluZXIucHVzaChpdGVtLm91dGxpbmUpXG4gICAgICAgIH1cbiAgICAgIH1cbiAgICAgIHJldHVybiBtYXBcbiAgICB9LCBuZXcgTWFwKCkpXG5cbiAgICBjb25zdCByb290czogYXRvbUlkZS5PdXRsaW5lVHJlZVtdID0gW11cblxuICAgIC8vIFB1dCBlYWNoIGl0ZW0gd2l0aGluIGl0cyBwYXJlbnQgYW5kIGV4dHJhY3Qgb3V0IHRoZSByb290c1xuICAgIGZvciAoY29uc3QgaXRlbSBvZiBhbGxJdGVtcykge1xuICAgICAgY29uc3QgY29udGFpbmVyTmFtZSA9IGl0ZW0uY29udGFpbmVyTmFtZVxuICAgICAgY29uc3QgY2hpbGQgPSBpdGVtLm91dGxpbmVcbiAgICAgIGlmIChjb250YWluZXJOYW1lID09IG51bGwgfHwgY29udGFpbmVyTmFtZSA9PT0gXCJcIikge1xuICAgICAgICByb290cy5wdXNoKGl0ZW0ub3V0bGluZSlcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGNvbnN0IHBvc3NpYmxlUGFyZW50cyA9IGNvbnRhaW5lcnMuZ2V0KGNvbnRhaW5lck5hbWUpXG4gICAgICAgIGxldCBjbG9zZXN0UGFyZW50ID0gT3V0bGluZVZpZXdBZGFwdGVyLl9nZXRDbG9zZXN0UGFyZW50KHBvc3NpYmxlUGFyZW50cywgY2hpbGQpXG4gICAgICAgIGlmIChjbG9zZXN0UGFyZW50ID09IG51bGwpIHtcbiAgICAgICAgICBjbG9zZXN0UGFyZW50ID0ge1xuICAgICAgICAgICAgcGxhaW5UZXh0OiBjb250YWluZXJOYW1lLFxuICAgICAgICAgICAgcmVwcmVzZW50YXRpdmVOYW1lOiBjb250YWluZXJOYW1lLFxuICAgICAgICAgICAgc3RhcnRQb3NpdGlvbjogbmV3IFBvaW50KDAsIDApLFxuICAgICAgICAgICAgY2hpbGRyZW46IFtjaGlsZF0sXG4gICAgICAgICAgfVxuICAgICAgICAgIHJvb3RzLnB1c2goY2xvc2VzdFBhcmVudClcbiAgICAgICAgICBpZiAocG9zc2libGVQYXJlbnRzID09IG51bGwpIHtcbiAgICAgICAgICAgIGNvbnRhaW5lcnMuc2V0KGNvbnRhaW5lck5hbWUsIFtjbG9zZXN0UGFyZW50XSlcbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgcG9zc2libGVQYXJlbnRzLnB1c2goY2xvc2VzdFBhcmVudClcbiAgICAgICAgICB9XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgY2xvc2VzdFBhcmVudC5jaGlsZHJlbi5wdXNoKGNoaWxkKVxuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuXG4gICAgcmV0dXJuIHJvb3RzXG4gIH1cblxuICBwcml2YXRlIHN0YXRpYyBfZ2V0Q2xvc2VzdFBhcmVudChcbiAgICBjYW5kaWRhdGVzOiBhdG9tSWRlLk91dGxpbmVUcmVlW10gfCBudWxsLFxuICAgIGNoaWxkOiBhdG9tSWRlLk91dGxpbmVUcmVlXG4gICk6IGF0b21JZGUuT3V0bGluZVRyZWUgfCBudWxsIHtcbiAgICBpZiAoY2FuZGlkYXRlcyA9PSBudWxsIHx8IGNhbmRpZGF0ZXMubGVuZ3RoID09PSAwKSB7XG4gICAgICByZXR1cm4gbnVsbFxuICAgIH1cblxuICAgIGxldCBwYXJlbnQ6IGF0b21JZGUuT3V0bGluZVRyZWUgfCB1bmRlZmluZWRcbiAgICBmb3IgKGNvbnN0IGNhbmRpZGF0ZSBvZiBjYW5kaWRhdGVzKSB7XG4gICAgICBpZiAoXG4gICAgICAgIGNhbmRpZGF0ZSAhPT0gY2hpbGQgJiZcbiAgICAgICAgY2FuZGlkYXRlLnN0YXJ0UG9zaXRpb24uaXNMZXNzVGhhbk9yRXF1YWwoY2hpbGQuc3RhcnRQb3NpdGlvbikgJiZcbiAgICAgICAgKGNhbmRpZGF0ZS5lbmRQb3NpdGlvbiA9PT0gdW5kZWZpbmVkIHx8XG4gICAgICAgICAgKGNoaWxkLmVuZFBvc2l0aW9uICYmIGNhbmRpZGF0ZS5lbmRQb3NpdGlvbi5pc0dyZWF0ZXJUaGFuT3JFcXVhbChjaGlsZC5lbmRQb3NpdGlvbikpKVxuICAgICAgKSB7XG4gICAgICAgIGlmIChcbiAgICAgICAgICBwYXJlbnQgPT09IHVuZGVmaW5lZCB8fFxuICAgICAgICAgIHBhcmVudC5zdGFydFBvc2l0aW9uLmlzTGVzc1RoYW5PckVxdWFsKGNhbmRpZGF0ZS5zdGFydFBvc2l0aW9uKSB8fFxuICAgICAgICAgIChwYXJlbnQuZW5kUG9zaXRpb24gIT0gbnVsbCAmJlxuICAgICAgICAgICAgY2FuZGlkYXRlLmVuZFBvc2l0aW9uICYmXG4gICAgICAgICAgICBwYXJlbnQuZW5kUG9zaXRpb24uaXNHcmVhdGVyVGhhbk9yRXF1YWwoY2FuZGlkYXRlLmVuZFBvc2l0aW9uKSlcbiAgICAgICAgKSB7XG4gICAgICAgICAgcGFyZW50ID0gY2FuZGlkYXRlXG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG5cbiAgICByZXR1cm4gcGFyZW50IHx8IG51bGxcbiAgfVxuXG4gIC8qKlxuICAgKiBQdWJsaWM6IENvbnZlcnQgYW4gaW5kaXZpZHVhbCB7RG9jdW1lbnRTeW1ib2x9IGZyb20gdGhlIGxhbmd1YWdlIHNlcnZlciB0byBhbiB7T3V0bGluZVRyZWV9IGZvciB1c2UgYnkgdGhlIE91dGxpbmVcbiAgICogVmlldy4gSXQgZG9lcyBOT1QgcmVjdXJzaXZlbHkgcHJvY2VzcyB0aGUgZ2l2ZW4gc3ltYm9sJ3MgY2hpbGRyZW4gKGlmIGFueSkuXG4gICAqXG4gICAqIEBwYXJhbSBzeW1ib2wgVGhlIHtEb2N1bWVudFN5bWJvbH0gdG8gY29udmVydCB0byBhbiB7T3V0bGluZVRyZWV9LlxuICAgKiBAcmV0dXJucyBUaGUge091dGxpbmVUcmVlfSBjb3JyZXNwb25kaW5nIHRvIHRoZSBnaXZlbiB7RG9jdW1lbnRTeW1ib2x9LlxuICAgKi9cbiAgcHVibGljIHN0YXRpYyBoaWVyYXJjaGljYWxTeW1ib2xUb091dGxpbmUoc3ltYm9sOiBEb2N1bWVudFN5bWJvbCk6IGF0b21JZGUuT3V0bGluZVRyZWUge1xuICAgIGNvbnN0IGljb24gPSBPdXRsaW5lVmlld0FkYXB0ZXIuc3ltYm9sS2luZFRvRW50aXR5S2luZChzeW1ib2wua2luZClcblxuICAgIHJldHVybiB7XG4gICAgICB0b2tlbml6ZWRUZXh0OiBbXG4gICAgICAgIHtcbiAgICAgICAgICBraW5kOiBPdXRsaW5lVmlld0FkYXB0ZXIuc3ltYm9sS2luZFRvVG9rZW5LaW5kKHN5bWJvbC5raW5kKSxcbiAgICAgICAgICB2YWx1ZTogc3ltYm9sLm5hbWUsXG4gICAgICAgIH0sXG4gICAgICBdLFxuICAgICAgaWNvbjogaWNvbiAhPSBudWxsID8gaWNvbiA6IHVuZGVmaW5lZCxcbiAgICAgIHJlcHJlc2VudGF0aXZlTmFtZTogc3ltYm9sLm5hbWUsXG4gICAgICBzdGFydFBvc2l0aW9uOiBDb252ZXJ0LnBvc2l0aW9uVG9Qb2ludChzeW1ib2wuc2VsZWN0aW9uUmFuZ2Uuc3RhcnQpLFxuICAgICAgZW5kUG9zaXRpb246IENvbnZlcnQucG9zaXRpb25Ub1BvaW50KHN5bWJvbC5zZWxlY3Rpb25SYW5nZS5lbmQpLFxuICAgICAgY2hpbGRyZW46IFtdLFxuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBQdWJsaWM6IENvbnZlcnQgYW4gaW5kaXZpZHVhbCB7U3ltYm9sSW5mb3JtYXRpb259IGZyb20gdGhlIGxhbmd1YWdlIHNlcnZlciB0byBhbiB7T3V0bGluZVRyZWV9IGZvciB1c2UgYnkgdGhlIE91dGxpbmUgVmlldy5cbiAgICpcbiAgICogQHBhcmFtIHN5bWJvbCBUaGUge1N5bWJvbEluZm9ybWF0aW9ufSB0byBjb252ZXJ0IHRvIGFuIHtPdXRsaW5lVHJlZX0uXG4gICAqIEByZXR1cm5zIFRoZSB7T3V0bGluZVRyZWV9IGVxdWl2YWxlbnQgdG8gdGhlIGdpdmVuIHtTeW1ib2xJbmZvcm1hdGlvbn0uXG4gICAqL1xuICBwdWJsaWMgc3RhdGljIHN5bWJvbFRvT3V0bGluZShzeW1ib2w6IFN5bWJvbEluZm9ybWF0aW9uKTogYXRvbUlkZS5PdXRsaW5lVHJlZSB7XG4gICAgY29uc3QgaWNvbiA9IE91dGxpbmVWaWV3QWRhcHRlci5zeW1ib2xLaW5kVG9FbnRpdHlLaW5kKHN5bWJvbC5raW5kKVxuICAgIHJldHVybiB7XG4gICAgICB0b2tlbml6ZWRUZXh0OiBbXG4gICAgICAgIHtcbiAgICAgICAgICBraW5kOiBPdXRsaW5lVmlld0FkYXB0ZXIuc3ltYm9sS2luZFRvVG9rZW5LaW5kKHN5bWJvbC5raW5kKSxcbiAgICAgICAgICB2YWx1ZTogc3ltYm9sLm5hbWUsXG4gICAgICAgIH0sXG4gICAgICBdLFxuICAgICAgaWNvbjogaWNvbiAhPSBudWxsID8gaWNvbiA6IHVuZGVmaW5lZCxcbiAgICAgIHJlcHJlc2VudGF0aXZlTmFtZTogc3ltYm9sLm5hbWUsXG4gICAgICBzdGFydFBvc2l0aW9uOiBDb252ZXJ0LnBvc2l0aW9uVG9Qb2ludChzeW1ib2wubG9jYXRpb24ucmFuZ2Uuc3RhcnQpLFxuICAgICAgZW5kUG9zaXRpb246IENvbnZlcnQucG9zaXRpb25Ub1BvaW50KHN5bWJvbC5sb2NhdGlvbi5yYW5nZS5lbmQpLFxuICAgICAgY2hpbGRyZW46IFtdLFxuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBQdWJsaWM6IENvbnZlcnQgYSBzeW1ib2wga2luZCBpbnRvIGFuIG91dGxpbmUgZW50aXR5IGtpbmQgdXNlZCB0byBkZXRlcm1pbmUgdGhlIHN0eWxpbmcgc3VjaCBhcyB0aGUgYXBwcm9wcmlhdGVcbiAgICogaWNvbiBpbiB0aGUgT3V0bGluZSBWaWV3LlxuICAgKlxuICAgKiBAcGFyYW0gc3ltYm9sIFRoZSBudW1lcmljIHN5bWJvbCBraW5kIHJlY2VpdmVkIGZyb20gdGhlIGxhbmd1YWdlIHNlcnZlci5cbiAgICogQHJldHVybnMgQSBzdHJpbmcgcmVwcmVzZW50aW5nIHRoZSBlcXVpdmFsZW50IE91dGxpbmVWaWV3IGVudGl0eSBraW5kLlxuICAgKi9cbiAgcHVibGljIHN0YXRpYyBzeW1ib2xLaW5kVG9FbnRpdHlLaW5kKHN5bWJvbDogbnVtYmVyKTogc3RyaW5nIHwgbnVsbCB7XG4gICAgc3dpdGNoIChzeW1ib2wpIHtcbiAgICAgIGNhc2UgU3ltYm9sS2luZC5BcnJheTpcbiAgICAgICAgcmV0dXJuIFwidHlwZS1hcnJheVwiXG4gICAgICBjYXNlIFN5bWJvbEtpbmQuQm9vbGVhbjpcbiAgICAgICAgcmV0dXJuIFwidHlwZS1ib29sZWFuXCJcbiAgICAgIGNhc2UgU3ltYm9sS2luZC5DbGFzczpcbiAgICAgICAgcmV0dXJuIFwidHlwZS1jbGFzc1wiXG4gICAgICBjYXNlIFN5bWJvbEtpbmQuQ29uc3RhbnQ6XG4gICAgICAgIHJldHVybiBcInR5cGUtY29uc3RhbnRcIlxuICAgICAgY2FzZSBTeW1ib2xLaW5kLkNvbnN0cnVjdG9yOlxuICAgICAgICByZXR1cm4gXCJ0eXBlLWNvbnN0cnVjdG9yXCJcbiAgICAgIGNhc2UgU3ltYm9sS2luZC5FbnVtOlxuICAgICAgICByZXR1cm4gXCJ0eXBlLWVudW1cIlxuICAgICAgY2FzZSBTeW1ib2xLaW5kLkZpZWxkOlxuICAgICAgICByZXR1cm4gXCJ0eXBlLWZpZWxkXCJcbiAgICAgIGNhc2UgU3ltYm9sS2luZC5GaWxlOlxuICAgICAgICByZXR1cm4gXCJ0eXBlLWZpbGVcIlxuICAgICAgY2FzZSBTeW1ib2xLaW5kLkZ1bmN0aW9uOlxuICAgICAgICByZXR1cm4gXCJ0eXBlLWZ1bmN0aW9uXCJcbiAgICAgIGNhc2UgU3ltYm9sS2luZC5JbnRlcmZhY2U6XG4gICAgICAgIHJldHVybiBcInR5cGUtaW50ZXJmYWNlXCJcbiAgICAgIGNhc2UgU3ltYm9sS2luZC5NZXRob2Q6XG4gICAgICAgIHJldHVybiBcInR5cGUtbWV0aG9kXCJcbiAgICAgIGNhc2UgU3ltYm9sS2luZC5Nb2R1bGU6XG4gICAgICAgIHJldHVybiBcInR5cGUtbW9kdWxlXCJcbiAgICAgIGNhc2UgU3ltYm9sS2luZC5OYW1lc3BhY2U6XG4gICAgICAgIHJldHVybiBcInR5cGUtbmFtZXNwYWNlXCJcbiAgICAgIGNhc2UgU3ltYm9sS2luZC5OdW1iZXI6XG4gICAgICAgIHJldHVybiBcInR5cGUtbnVtYmVyXCJcbiAgICAgIGNhc2UgU3ltYm9sS2luZC5QYWNrYWdlOlxuICAgICAgICByZXR1cm4gXCJ0eXBlLXBhY2thZ2VcIlxuICAgICAgY2FzZSBTeW1ib2xLaW5kLlByb3BlcnR5OlxuICAgICAgICByZXR1cm4gXCJ0eXBlLXByb3BlcnR5XCJcbiAgICAgIGNhc2UgU3ltYm9sS2luZC5TdHJpbmc6XG4gICAgICAgIHJldHVybiBcInR5cGUtc3RyaW5nXCJcbiAgICAgIGNhc2UgU3ltYm9sS2luZC5WYXJpYWJsZTpcbiAgICAgICAgcmV0dXJuIFwidHlwZS12YXJpYWJsZVwiXG4gICAgICBjYXNlIFN5bWJvbEtpbmQuU3RydWN0OlxuICAgICAgICByZXR1cm4gXCJ0eXBlLWNsYXNzXCJcbiAgICAgIGNhc2UgU3ltYm9sS2luZC5FbnVtTWVtYmVyOlxuICAgICAgICByZXR1cm4gXCJ0eXBlLWNvbnN0YW50XCJcbiAgICAgIGRlZmF1bHQ6XG4gICAgICAgIHJldHVybiBudWxsXG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIFB1YmxpYzogQ29udmVydCBhIHN5bWJvbCBraW5kIHRvIHRoZSBhcHByb3ByaWF0ZSB0b2tlbiBraW5kIHVzZWQgdG8gc3ludGF4IGhpZ2hsaWdodCB0aGUgc3ltYm9sIG5hbWUgaW4gdGhlIE91dGxpbmUgVmlldy5cbiAgICpcbiAgICogQHBhcmFtIHN5bWJvbCBUaGUgbnVtZXJpYyBzeW1ib2wga2luZCByZWNlaXZlZCBmcm9tIHRoZSBsYW5ndWFnZSBzZXJ2ZXIuXG4gICAqIEByZXR1cm5zIEEgc3RyaW5nIHJlcHJlc2VudGluZyB0aGUgZXF1aXZhbGVudCBzeW50YXggdG9rZW4ga2luZC5cbiAgICovXG4gIHB1YmxpYyBzdGF0aWMgc3ltYm9sS2luZFRvVG9rZW5LaW5kKHN5bWJvbDogbnVtYmVyKTogYXRvbUlkZS5Ub2tlbktpbmQge1xuICAgIHN3aXRjaCAoc3ltYm9sKSB7XG4gICAgICBjYXNlIFN5bWJvbEtpbmQuQ2xhc3M6XG4gICAgICAgIHJldHVybiBcInR5cGVcIlxuICAgICAgY2FzZSBTeW1ib2xLaW5kLkNvbnN0cnVjdG9yOlxuICAgICAgICByZXR1cm4gXCJjb25zdHJ1Y3RvclwiXG4gICAgICBjYXNlIFN5bWJvbEtpbmQuTWV0aG9kOlxuICAgICAgY2FzZSBTeW1ib2xLaW5kLkZ1bmN0aW9uOlxuICAgICAgICByZXR1cm4gXCJtZXRob2RcIlxuICAgICAgY2FzZSBTeW1ib2xLaW5kLlN0cmluZzpcbiAgICAgICAgcmV0dXJuIFwic3RyaW5nXCJcbiAgICAgIGRlZmF1bHQ6XG4gICAgICAgIHJldHVybiBcInBsYWluXCJcbiAgICB9XG4gIH1cbn1cbiJdfQ==