UNPKG

40 kBJavaScriptView Raw
1"use strict";
2var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3 function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4 return new (P || (P = Promise))(function (resolve, reject) {
5 function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6 function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7 function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8 step((generator = generator.apply(thisArg, _arguments || [])).next());
9 });
10};
11Object.defineProperty(exports, "__esModule", { value: true });
12const convert_1 = require("../convert");
13const Utils = require("../utils");
14const languageclient_1 = require("../languageclient");
15const atom_1 = require("atom");
16/** Public: Adapts the documentSymbolProvider of the language server to the Outline View supplied by Atom IDE UI. */
17class OutlineViewAdapter {
18 constructor() {
19 this._cancellationTokens = new WeakMap();
20 }
21 /**
22 * Public: Determine whether this adapter can be used to adapt a language server based on the serverCapabilities
23 * matrix containing a documentSymbolProvider.
24 *
25 * @param serverCapabilities The {ServerCapabilities} of the language server to consider.
26 * @returns A {Boolean} indicating adapter can adapt the server based on the given serverCapabilities.
27 */
28 static canAdapt(serverCapabilities) {
29 return serverCapabilities.documentSymbolProvider === true;
30 }
31 /**
32 * Public: Obtain the Outline for document via the {LanguageClientConnection} as identified by the {TextEditor}.
33 *
34 * @param connection A {LanguageClientConnection} to the language server that will be queried for the outline.
35 * @param editor The Atom {TextEditor} containing the text the Outline should represent.
36 * @returns A {Promise} containing the {Outline} of this document.
37 */
38 getOutline(connection, editor) {
39 return __awaiter(this, void 0, void 0, function* () {
40 const results = yield Utils.doWithCancellationToken(connection, this._cancellationTokens, (cancellationToken) => connection.documentSymbol({ textDocument: convert_1.default.editorToTextDocumentIdentifier(editor) }, cancellationToken));
41 if (results === null || results.length === 0) {
42 return {
43 outlineTrees: [],
44 };
45 }
46 if (results[0].selectionRange !== undefined) {
47 // If the server is giving back the newer DocumentSymbol format.
48 return {
49 outlineTrees: OutlineViewAdapter.createHierarchicalOutlineTrees(results),
50 };
51 }
52 else {
53 // If the server is giving back the original SymbolInformation format.
54 return {
55 outlineTrees: OutlineViewAdapter.createOutlineTrees(results),
56 };
57 }
58 });
59 }
60 /**
61 * Public: Create an {Array} of {OutlineTree}s from the Array of {DocumentSymbol} recieved from the language server.
62 * This includes converting all the children nodes in the entire hierarchy.
63 *
64 * @param symbols An {Array} of {DocumentSymbol}s received from the language server that should be converted to an
65 * {Array} of {OutlineTree}.
66 * @returns An {Array} of {OutlineTree} containing the given symbols that the Outline View can display.
67 */
68 static createHierarchicalOutlineTrees(symbols) {
69 // Sort all the incoming symbols
70 symbols.sort((a, b) => {
71 if (a.range.start.line !== b.range.start.line) {
72 return a.range.start.line - b.range.start.line;
73 }
74 if (a.range.start.character !== b.range.start.character) {
75 return a.range.start.character - b.range.start.character;
76 }
77 if (a.range.end.line !== b.range.end.line) {
78 return a.range.end.line - b.range.end.line;
79 }
80 return a.range.end.character - b.range.end.character;
81 });
82 return symbols.map((symbol) => {
83 const tree = OutlineViewAdapter.hierarchicalSymbolToOutline(symbol);
84 if (symbol.children != null) {
85 tree.children = OutlineViewAdapter.createHierarchicalOutlineTrees(symbol.children);
86 }
87 return tree;
88 });
89 }
90 /**
91 * Public: Create an {Array} of {OutlineTree}s from the Array of {SymbolInformation} recieved from the language
92 * server. This includes determining the appropriate child and parent relationships for the hierarchy.
93 *
94 * @param symbols An {Array} of {SymbolInformation}s received from the language server that should be converted to an
95 * {OutlineTree}.
96 * @returns An {OutlineTree} containing the given symbols that the Outline View can display.
97 */
98 static createOutlineTrees(symbols) {
99 symbols.sort((a, b) => {
100 if (a.location.range.start.line === b.location.range.start.line) {
101 return a.location.range.start.character - b.location.range.start.character;
102 }
103 else {
104 return a.location.range.start.line - b.location.range.start.line;
105 }
106 });
107 // Temporarily keep containerName through the conversion process
108 // Also filter out symbols without a name - it's part of the spec but some don't include it
109 const allItems = symbols
110 .filter((symbol) => symbol.name)
111 .map((symbol) => ({
112 containerName: symbol.containerName,
113 outline: OutlineViewAdapter.symbolToOutline(symbol),
114 }));
115 // Create a map of containers by name with all items that have that name
116 const containers = allItems.reduce((map, item) => {
117 const name = item.outline.representativeName;
118 if (name != null) {
119 const container = map.get(name);
120 if (container == null) {
121 map.set(name, [item.outline]);
122 }
123 else {
124 container.push(item.outline);
125 }
126 }
127 return map;
128 }, new Map());
129 const roots = [];
130 // Put each item within its parent and extract out the roots
131 for (const item of allItems) {
132 const containerName = item.containerName;
133 const child = item.outline;
134 if (containerName == null || containerName === "") {
135 roots.push(item.outline);
136 }
137 else {
138 const possibleParents = containers.get(containerName);
139 let closestParent = OutlineViewAdapter._getClosestParent(possibleParents, child);
140 if (closestParent == null) {
141 closestParent = {
142 plainText: containerName,
143 representativeName: containerName,
144 startPosition: new atom_1.Point(0, 0),
145 children: [child],
146 };
147 roots.push(closestParent);
148 if (possibleParents == null) {
149 containers.set(containerName, [closestParent]);
150 }
151 else {
152 possibleParents.push(closestParent);
153 }
154 }
155 else {
156 closestParent.children.push(child);
157 }
158 }
159 }
160 return roots;
161 }
162 static _getClosestParent(candidates, child) {
163 if (candidates == null || candidates.length === 0) {
164 return null;
165 }
166 let parent;
167 for (const candidate of candidates) {
168 if (candidate !== child &&
169 candidate.startPosition.isLessThanOrEqual(child.startPosition) &&
170 (candidate.endPosition === undefined ||
171 (child.endPosition && candidate.endPosition.isGreaterThanOrEqual(child.endPosition)))) {
172 if (parent === undefined ||
173 parent.startPosition.isLessThanOrEqual(candidate.startPosition) ||
174 (parent.endPosition != null &&
175 candidate.endPosition &&
176 parent.endPosition.isGreaterThanOrEqual(candidate.endPosition))) {
177 parent = candidate;
178 }
179 }
180 }
181 return parent || null;
182 }
183 /**
184 * Public: Convert an individual {DocumentSymbol} from the language server to an {OutlineTree} for use by the Outline
185 * View. It does NOT recursively process the given symbol's children (if any).
186 *
187 * @param symbol The {DocumentSymbol} to convert to an {OutlineTree}.
188 * @returns The {OutlineTree} corresponding to the given {DocumentSymbol}.
189 */
190 static hierarchicalSymbolToOutline(symbol) {
191 const icon = OutlineViewAdapter.symbolKindToEntityKind(symbol.kind);
192 return {
193 tokenizedText: [
194 {
195 kind: OutlineViewAdapter.symbolKindToTokenKind(symbol.kind),
196 value: symbol.name,
197 },
198 ],
199 icon: icon != null ? icon : undefined,
200 representativeName: symbol.name,
201 startPosition: convert_1.default.positionToPoint(symbol.selectionRange.start),
202 endPosition: convert_1.default.positionToPoint(symbol.selectionRange.end),
203 children: [],
204 };
205 }
206 /**
207 * Public: Convert an individual {SymbolInformation} from the language server to an {OutlineTree} for use by the Outline View.
208 *
209 * @param symbol The {SymbolInformation} to convert to an {OutlineTree}.
210 * @returns The {OutlineTree} equivalent to the given {SymbolInformation}.
211 */
212 static symbolToOutline(symbol) {
213 const icon = OutlineViewAdapter.symbolKindToEntityKind(symbol.kind);
214 return {
215 tokenizedText: [
216 {
217 kind: OutlineViewAdapter.symbolKindToTokenKind(symbol.kind),
218 value: symbol.name,
219 },
220 ],
221 icon: icon != null ? icon : undefined,
222 representativeName: symbol.name,
223 startPosition: convert_1.default.positionToPoint(symbol.location.range.start),
224 endPosition: convert_1.default.positionToPoint(symbol.location.range.end),
225 children: [],
226 };
227 }
228 /**
229 * Public: Convert a symbol kind into an outline entity kind used to determine the styling such as the appropriate
230 * icon in the Outline View.
231 *
232 * @param symbol The numeric symbol kind received from the language server.
233 * @returns A string representing the equivalent OutlineView entity kind.
234 */
235 static symbolKindToEntityKind(symbol) {
236 switch (symbol) {
237 case languageclient_1.SymbolKind.Array:
238 return "type-array";
239 case languageclient_1.SymbolKind.Boolean:
240 return "type-boolean";
241 case languageclient_1.SymbolKind.Class:
242 return "type-class";
243 case languageclient_1.SymbolKind.Constant:
244 return "type-constant";
245 case languageclient_1.SymbolKind.Constructor:
246 return "type-constructor";
247 case languageclient_1.SymbolKind.Enum:
248 return "type-enum";
249 case languageclient_1.SymbolKind.Field:
250 return "type-field";
251 case languageclient_1.SymbolKind.File:
252 return "type-file";
253 case languageclient_1.SymbolKind.Function:
254 return "type-function";
255 case languageclient_1.SymbolKind.Interface:
256 return "type-interface";
257 case languageclient_1.SymbolKind.Method:
258 return "type-method";
259 case languageclient_1.SymbolKind.Module:
260 return "type-module";
261 case languageclient_1.SymbolKind.Namespace:
262 return "type-namespace";
263 case languageclient_1.SymbolKind.Number:
264 return "type-number";
265 case languageclient_1.SymbolKind.Package:
266 return "type-package";
267 case languageclient_1.SymbolKind.Property:
268 return "type-property";
269 case languageclient_1.SymbolKind.String:
270 return "type-string";
271 case languageclient_1.SymbolKind.Variable:
272 return "type-variable";
273 case languageclient_1.SymbolKind.Struct:
274 return "type-class";
275 case languageclient_1.SymbolKind.EnumMember:
276 return "type-constant";
277 default:
278 return null;
279 }
280 }
281 /**
282 * Public: Convert a symbol kind to the appropriate token kind used to syntax highlight the symbol name in the Outline View.
283 *
284 * @param symbol The numeric symbol kind received from the language server.
285 * @returns A string representing the equivalent syntax token kind.
286 */
287 static symbolKindToTokenKind(symbol) {
288 switch (symbol) {
289 case languageclient_1.SymbolKind.Class:
290 return "type";
291 case languageclient_1.SymbolKind.Constructor:
292 return "constructor";
293 case languageclient_1.SymbolKind.Method:
294 case languageclient_1.SymbolKind.Function:
295 return "method";
296 case languageclient_1.SymbolKind.String:
297 return "string";
298 default:
299 return "plain";
300 }
301 }
302}
303exports.default = OutlineViewAdapter;
304//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoib3V0bGluZS12aWV3LWFkYXB0ZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9saWIvYWRhcHRlcnMvb3V0bGluZS12aWV3LWFkYXB0ZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7QUFDQSx3Q0FBZ0M7QUFDaEMsa0NBQWlDO0FBRWpDLHNEQU0wQjtBQUMxQiwrQkFBd0M7QUFFeEMsb0hBQW9IO0FBQ3BILE1BQXFCLGtCQUFrQjtJQUF2QztRQUNVLHdCQUFtQixHQUErRCxJQUFJLE9BQU8sRUFBRSxDQUFBO0lBb1R6RyxDQUFDO0lBbFRDOzs7Ozs7T0FNRztJQUNJLE1BQU0sQ0FBQyxRQUFRLENBQUMsa0JBQXNDO1FBQzNELE9BQU8sa0JBQWtCLENBQUMsc0JBQXNCLEtBQUssSUFBSSxDQUFBO0lBQzNELENBQUM7SUFFRDs7Ozs7O09BTUc7SUFDVSxVQUFVLENBQUMsVUFBb0MsRUFBRSxNQUFrQjs7WUFDOUUsTUFBTSxPQUFPLEdBQUcsTUFBTSxLQUFLLENBQUMsdUJBQXVCLENBQUMsVUFBVSxFQUFFLElBQUksQ0FBQyxtQkFBbUIsRUFBRSxDQUFDLGlCQUFpQixFQUFFLEVBQUUsQ0FDOUcsVUFBVSxDQUFDLGNBQWMsQ0FBQyxFQUFFLFlBQVksRUFBRSxpQkFBTyxDQUFDLDhCQUE4QixDQUFDLE1BQU0sQ0FBQyxFQUFFLEVBQUUsaUJBQWlCLENBQUMsQ0FDL0csQ0FBQTtZQUVELElBQUksT0FBTyxLQUFLLElBQUksSUFBSSxPQUFPLENBQUMsTUFBTSxLQUFLLENBQUMsRUFBRTtnQkFDNUMsT0FBTztvQkFDTCxZQUFZLEVBQUUsRUFBRTtpQkFDakIsQ0FBQTthQUNGO1lBRUQsSUFBSyxPQUFPLENBQUMsQ0FBQyxDQUFvQixDQUFDLGNBQWMsS0FBSyxTQUFTLEVBQUU7Z0JBQy9ELGdFQUFnRTtnQkFDaEUsT0FBTztvQkFDTCxZQUFZLEVBQUUsa0JBQWtCLENBQUMsOEJBQThCLENBQUMsT0FBMkIsQ0FBQztp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TSxDQUFBO1lBQ2YsS0FBSywyQkFBVSxDQUFDLFdBQVc7Z0JBQ3pCLE9BQU8sYUFBYSxDQUFBO1lBQ3RCLEtBQUssMkJBQVUsQ0FBQyxNQUFNLENBQUM7WUFDdkIsS0FBSywyQkFBVSxDQUFDLFFBQVE7Z0JBQ3RCLE9BQU8sUUFBUSxDQUFBO1lBQ2pCLEtBQUssMkJBQVUsQ0FBQyxNQUFNO2dCQUNwQixPQUFPLFFBQVEsQ0FBQTtZQUNqQjtnQkFDRSxPQUFPLE9BQU8sQ0FBQTtTQUNqQjtJQUNILENBQUM7Q0FDRjtBQXJURCxxQ0FxVEMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgdHlwZSAqIGFzIGF0b21JZGUgZnJvbSBcImF0b20taWRlLWJhc2VcIlxuaW1wb3J0IENvbnZlcnQgZnJvbSBcIi4uL2NvbnZlcnRcIlxuaW1wb3J0ICogYXMgVXRpbHMgZnJvbSBcIi4uL3V0aWxzXCJcbmltcG9ydCB7IENhbmNlbGxhdGlvblRva2VuU291cmNlIH0gZnJvbSBcInZzY29kZS1qc29ucnBjXCJcbmltcG9ydCB7XG4gIExhbmd1YWdlQ2xpZW50Q29ubmVjdGlvbixcbiAgU3ltYm9sS2luZCxcbiAgU2VydmVyQ2FwYWJpbGl0aWVzLFxuICBTeW1ib2xJbmZvcm1hdGlvbixcbiAgRG9jdW1lbnRTeW1ib2wsXG59IGZyb20gXCIuLi9sYW5ndWFnZWNsaWVudFwiXG5pbXBvcnQgeyBQb2ludCwgVGV4dEVkaXRvciB9IGZyb20gXCJhdG9tXCJcblxuLyoqIFB1YmxpYzogQWRhcHRzIHRoZSBkb2N1bWVudFN5bWJvbFByb3ZpZGVyIG9mIHRoZSBsYW5ndWFnZSBzZXJ2ZXIgdG8gdGhlIE91dGxpbmUgVmlldyBzdXBwbGllZCBieSBBdG9tIElERSBVSS4gKi9cbmV4cG9ydCBkZWZhdWx0IGNsYXNzIE91dGxpbmVWaWV3QWRhcHRlciB7XG4gIHByaXZhdGUgX2NhbmNlbGxhdGlvblRva2VuczogV2Vha01hcDxMYW5ndWFnZUNsaWVudENvbm5lY3Rpb24sIENhbmNlbGxhdGlvblRva2VuU291cmNlPiA9IG5ldyBXZWFrTWFwKClcblxuICAvKipcbiAgICogUHVibGljOiBEZXRlcm1pbmUgd2hldGhlciB0aGlzIGFkYXB0ZXIgY2FuIGJlIHVzZWQgdG8gYWRhcHQgYSBsYW5ndWFnZSBzZXJ2ZXIgYmFzZWQgb24gdGhlIHNlcnZlckNhcGFiaWxpdGllc1xuICAgKiBtYXRyaXggY29udGFpbmluZyBhIGRvY3VtZW50U3ltYm9sUHJvdmlkZXIuXG4gICAqXG4gICAqIEBwYXJhbSBzZXJ2ZXJDYXBhYmlsaXRpZXMgVGhlIHtTZXJ2ZXJDYXBhYmlsaXRpZXN9IG9mIHRoZSBsYW5ndWFnZSBzZXJ2ZXIgdG8gY29uc2lkZXIuXG4gICAqIEByZXR1cm5zIEEge0Jvb2xlYW59IGluZGljYXRpbmcgYWRhcHRlciBjYW4gYWRhcHQgdGhlIHNlcnZlciBiYXNlZCBvbiB0aGUgZ2l2ZW4gc2VydmVyQ2FwYWJpbGl0aWVzLlxuICAgKi9cbiAgcHVibGljIHN0YXRpYyBjYW5BZGFwdChzZXJ2ZXJDYXBhYmlsaXRpZXM6IFNlcnZlckNhcGFiaWxpdGllcyk6IGJvb2xlYW4ge1xuICAgIHJldHVybiBzZXJ2ZXJDYXBhYmlsaXRpZXMuZG9jdW1lbnRTeW1ib2xQcm92aWRlciA9PT0gdHJ1ZVxuICB9XG5cbiAgLyoqXG4gICAqIFB1YmxpYzogT2J0YWluIHRoZSBPdXRsaW5lIGZvciBkb2N1bWVudCB2aWEgdGhlIHtMYW5ndWFnZUNsaWVudENvbm5lY3Rpb259IGFzIGlkZW50aWZpZWQgYnkgdGhlIHtUZXh0RWRpdG9yfS5cbiAgICpcbiAgICogQHBhcmFtIGNvbm5lY3Rpb24gQSB7TGFuZ3VhZ2VDbGllbnRDb25uZWN0aW9ufSB0byB0aGUgbGFuZ3VhZ2Ugc2VydmVyIHRoYXQgd2lsbCBiZSBxdWVyaWVkIGZvciB0aGUgb3V0bGluZS5cbiAgICogQHBhcmFtIGVkaXRvciBUaGUgQXRvbSB7VGV4dEVkaXRvcn0gY29udGFpbmluZyB0aGUgdGV4dCB0aGUgT3V0bGluZSBzaG91bGQgcmVwcmVzZW50LlxuICAgKiBAcmV0dXJucyBBIHtQcm9taXNlfSBjb250YWluaW5nIHRoZSB7T3V0bGluZX0gb2YgdGhpcyBkb2N1bWVudC5cbiAgICovXG4gIHB1YmxpYyBhc3luYyBnZXRPdXRsaW5lKGNvbm5lY3Rpb246IExhbmd1YWdlQ2xpZW50Q29ubmVjdGlvbiwgZWRpdG9yOiBUZXh0RWRpdG9yKTogUHJvbWlzZTxhdG9tSWRlLk91dGxpbmUgfCBudWxsPiB7XG4gICAgY29uc3QgcmVzdWx0cyA9IGF3YWl0IFV0aWxzLmRvV2l0aENhbmNlbGxhdGlvblRva2VuKGNvbm5lY3Rpb24sIHRoaXMuX2NhbmNlbGxhdGlvblRva2VucywgKGNhbmNlbGxhdGlvblRva2VuKSA9PlxuICAgICAgY29ubmVjdGlvbi5kb2N1bWVudFN5bWJvbCh7IHRleHREb2N1bWVudDogQ29udmVydC5lZGl0b3JUb1RleHREb2N1bWVudElkZW50aWZpZXIoZWRpdG9yKSB9LCBjYW5jZWxsYXRpb25Ub2tlbilcbiAgICApXG5cbiAgICBpZiAocmVzdWx0cyA9PT0gbnVsbCB8fCByZXN1bHRzLmxlbmd0aCA9PT0gMCkge1xuICAgICAgcmV0dXJuIHtcbiAgICAgICAgb3V0bGluZVRyZWVzOiBbXSxcbiAgICAgIH1cbiAgICB9XG5cbiAgICBpZiAoKHJlc3VsdHNbMF0gYXMgRG9jdW1lbnRTeW1ib2wpLnNlbGVjdGlvblJhbmdlICE9PSB1bmRlZmluZWQpIHtcbiAgICAgIC8vIElmIHRoZSBzZXJ2ZXIgaXMgZ2l2aW5nIGJhY2sgdGhlIG5ld2VyIERvY3VtZW50U3ltYm9sIGZvcm1hdC5cbiAgICAgIHJldHVybiB7XG4gICAgICAgIG91dGxpbmVUcmVlczogT3V0bGluZVZpZXdBZGFwdGVyLmNyZWF0ZUhpZXJhcmNoaWNhbE91dGxpbmVUcmVlcyhyZXN1bHRzIGFzIERvY3VtZW50U3ltYm9sW10pLFxuICAgICAgfVxuICAgIH0gZWxzZSB7XG4gICAgICAvLyBJZiB0aGUgc2VydmVyIGlzIGdpdmluZyBiYWNrIHRoZSBvcmlnaW5hbCBTeW1ib2xJbmZvcm1hdGlvbiBmb3JtYXQuXG4gICAgICByZXR1cm4ge1xuICAgICAgICBvdXRsaW5lVHJlZXM6IE91dGxpbmVWaWV3QWRhcHRlci5jcmVhdGVPdXRsaW5lVHJlZXMocmVzdWx0cyBhcyBTeW1ib2xJbmZvcm1hdGlvbltdKSxcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogUHVibGljOiBDcmVhdGUgYW4ge0FycmF5fSBvZiB7T3V0bGluZVRyZWV9cyBmcm9tIHRoZSBBcnJheSBvZiB7RG9jdW1lbnRTeW1ib2x9IHJlY2lldmVkIGZyb20gdGhlIGxhbmd1YWdlIHNlcnZlci5cbiAgICogVGhpcyBpbmNsdWRlcyBjb252ZXJ0aW5nIGFsbCB0aGUgY2hpbGRyZW4gbm9kZXMgaW4gdGhlIGVudGlyZSBoaWVyYXJjaHkuXG4gICAqXG4gICAqIEBwYXJhbSBzeW1ib2xzIEFuIHtBcnJheX0gb2Yge0RvY3VtZW50U3ltYm9sfXMgcmVjZWl2ZWQgZnJvbSB0aGUgbGFuZ3VhZ2Ugc2VydmVyIHRoYXQgc2hvdWxkIGJlIGNvbnZlcnRlZCB0byBhblxuICAgKiAgIHtBcnJheX0gb2Yge091dGxpbmVUcmVlfS5cbiAgICogQHJldHVybnMgQW4ge0FycmF5fSBvZiB7T3V0bGluZVRyZWV9IGNvbnRhaW5pbmcgdGhlIGdpdmVuIHN5bWJvbHMgdGhhdCB0aGUgT3V0bGluZSBWaWV3IGNhbiBkaXNwbGF5LlxuICAgKi9cbiAgcHVibGljIHN0YXRpYyBjcmVhdGVIaWVyYXJjaGljYWxPdXRsaW5lVHJlZXMoc3ltYm9sczogRG9jdW1lbnRTeW1ib2xbXSk6IGF0b21JZGUuT3V0bGluZVRyZWVbXSB7XG4gICAgLy8gU29ydCBhbGwgdGhlIGluY29taW5nIHN5bWJvbHNcbiAgICBzeW1ib2xzLnNvcnQoKGEsIGIpID0+IHtcbiAgICAgIGlmIChhLnJhbmdlLnN0YXJ0LmxpbmUgIT09IGIucmFuZ2Uuc3RhcnQubGluZSkge1xuICAgICAgICByZXR1cm4gYS5yYW5nZS5zdGFydC5saW5lIC0gYi5yYW5nZS5zdGFydC5saW5lXG4gICAgICB9XG5cbiAgICAgIGlmIChhLnJhbmdlLnN0YXJ0LmNoYXJhY3RlciAhPT0gYi5yYW5nZS5zdGFydC5jaGFyYWN0ZXIpIHtcbiAgICAgICAgcmV0dXJuIGEucmFuZ2Uuc3RhcnQuY2hhcmFjdGVyIC0gYi5yYW5nZS5zdGFydC5jaGFyYWN0ZXJcbiAgICAgIH1cblxuICAgICAgaWYgKGEucmFuZ2UuZW5kLmxpbmUgIT09IGIucmFuZ2UuZW5kLmxpbmUpIHtcbiAgICAgICAgcmV0dXJuIGEucmFuZ2UuZW5kLmxpbmUgLSBiLnJhbmdlLmVuZC5saW5lXG4gICAgICB9XG5cbiAgICAgIHJldHVybiBhLnJhbmdlLmVuZC5jaGFyYWN0ZXIgLSBiLnJhbmdlLmVuZC5jaGFyYWN0ZXJcbiAgICB9KVxuXG4gICAgcmV0dXJuIHN5bWJvbHMubWFwKChzeW1ib2wpID0+IHtcbiAgICAgIGNvbnN0IHRyZWUgPSBPdXRsaW5lVmlld0FkYXB0ZXIuaGllcmFyY2hpY2FsU3ltYm9sVG9PdXRsaW5lKHN5bWJvbClcblxuICAgICAgaWYgKHN5bWJvbC5jaGlsZHJlbiAhPSBudWxsKSB7XG4gICAgICAgIHRyZWUuY2hpbGRyZW4gPSBPdXRsaW5lVmlld0FkYXB0ZXIuY3JlYXRlSGllcmFyY2hpY2FsT3V0bGluZVRyZWVzKHN5bWJvbC5jaGlsZHJlbilcbiAgICAgIH1cblxuICAgICAgcmV0dXJuIHRyZWVcbiAgICB9KVxuICB9XG5cbiAgLyoqXG4gICAqIFB1YmxpYzogQ3JlYXRlIGFuIHtBcnJheX0gb2Yge091dGxpbmVUcmVlfXMgZnJvbSB0aGUgQXJyYXkgb2Yge1N5bWJvbEluZm9ybWF0aW9ufSByZWNpZXZlZCBmcm9tIHRoZSBsYW5ndWFnZVxuICAgKiBzZXJ2ZXIuIFRoaXMgaW5jbHVkZXMgZGV0ZXJtaW5pbmcgdGhlIGFwcHJvcHJpYXRlIGNoaWxkIGFuZCBwYXJlbnQgcmVsYXRpb25zaGlwcyBmb3IgdGhlIGhpZXJhcmNoeS5cbiAgICpcbiAgICogQHBhcmFtIHN5bWJvbHMgQW4ge0FycmF5fSBvZiB7U3ltYm9sSW5mb3JtYXRpb259cyByZWNlaXZlZCBmcm9tIHRoZSBsYW5ndWFnZSBzZXJ2ZXIgdGhhdCBzaG91bGQgYmUgY29udmVydGVkIHRvIGFuXG4gICAqICAge091dGxpbmVUcmVlfS5cbiAgICogQHJldHVybnMgQW4ge091dGxpbmVUcmVlfSBjb250YWluaW5nIHRoZSBnaXZlbiBzeW1ib2xzIHRoYXQgdGhlIE91dGxpbmUgVmlldyBjYW4gZGlzcGxheS5cbiAgICovXG4gIHB1YmxpYyBzdGF0aWMgY3JlYXRlT3V0bGluZVRyZWVzKHN5bWJvbHM6IFN5bWJvbEluZm9ybWF0aW9uW10pOiBhdG9tSWRlLk91dGxpbmVUcmVlW10ge1xuICAgIHN5bWJvbHMuc29ydCgoYSwgYikgPT4ge1xuICAgICAgaWYgKGEubG9jYXRpb24ucmFuZ2Uuc3RhcnQubGluZSA9PT0gYi5sb2NhdGlvbi5yYW5nZS5zdGFydC5saW5lKSB7XG4gICAgICAgIHJldHVybiBhLmxvY2F0aW9uLnJhbmdlLnN0YXJ0LmNoYXJhY3RlciAtIGIubG9jYXRpb24ucmFuZ2Uuc3RhcnQuY2hhcmFjdGVyXG4gICAgICB9IGVsc2Uge1xuICAgICAgICByZXR1cm4gYS5sb2NhdGlvbi5yYW5nZS5zdGFydC5saW5lIC0gYi5sb2NhdGlvbi5yYW5nZS5zdGFydC5saW5lXG4gICAgICB9XG4gICAgfSlcblxuICAgIC8vIFRlbXBvcmFyaWx5IGtlZXAgY29udGFpbmVyTmFtZSB0aHJvdWdoIHRoZSBjb252ZXJzaW9uIHByb2Nlc3NcbiAgICAvLyBBbHNvIGZpbHRlciBvdXQgc3ltYm9scyB3aXRob3V0IGEgbmFtZSAtIGl0J3MgcGFydCBvZiB0aGUgc3BlYyBidXQgc29tZSBkb24ndCBpbmNsdWRlIGl0XG4gICAgY29uc3QgYWxsSXRlbXMgPSBzeW1ib2xzXG4gICAgICAuZmlsdGVyKChzeW1ib2wpID0+IHN5bWJvbC5uYW1lKVxuICAgICAgLm1hcCgoc3ltYm9sKSA9PiAoe1xuICAgICAgICBjb250YWluZXJOYW1lOiBzeW1ib2wuY29udGFpbmVyTmFtZSxcbiAgICAgICAgb3V0bGluZTogT3V0bGluZVZpZXdBZGFwdGVyLnN5bWJvbFRvT3V0bGluZShzeW1ib2wpLFxuICAgICAgfSkpXG5cbiAgICAvLyBDcmVhdGUgYSBtYXAgb2YgY29udGFpbmVycyBieSBuYW1lIHdpdGggYWxsIGl0ZW1zIHRoYXQgaGF2ZSB0aGF0IG5hbWVcbiAgICBjb25zdCBjb250YWluZXJzID0gYWxsSXRlbXMucmVkdWNlKChtYXAsIGl0ZW0pID0+IHtcbiAgICAgIGNvbnN0IG5hbWUgPSBpdGVtLm91dGxpbmUucmVwcmVzZW50YXRpdmVOYW1lXG4gICAgICBpZiAobmFtZSAhPSBudWxsKSB7XG4gICAgICAgIGNvbnN0IGNvbnRhaW5lciA9IG1hcC5nZXQobmFtZSlcbiAgICAgICAgaWYgKGNvbnRhaW5lciA9PSBudWxsKSB7XG4gICAgICAgICAgbWFwLnNldChuYW1lLCBbaXRlbS5vdXRsaW5lXSlcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBjb250YWluZXIucHVzaChpdGVtLm91dGxpbmUpXG4gICAgICAgIH1cbiAgICAgIH1cbiAgICAgIHJldHVybiBtYXBcbiAgICB9LCBuZXcgTWFwKCkpXG5cbiAgICBjb25zdCByb290czogYXRvbUlkZS5PdXRsaW5lVHJlZVtdID0gW11cblxuICAgIC8vIFB1dCBlYWNoIGl0ZW0gd2l0aGluIGl0cyBwYXJlbnQgYW5kIGV4dHJhY3Qgb3V0IHRoZSByb290c1xuICAgIGZvciAoY29uc3QgaXRlbSBvZiBhbGxJdGVtcykge1xuICAgICAgY29uc3QgY29udGFpbmVyTmFtZSA9IGl0ZW0uY29udGFpbmVyTmFtZVxuICAgICAgY29uc3QgY2hpbGQgPSBpdGVtLm91dGxpbmVcbiAgICAgIGlmIChjb250YWluZXJOYW1lID09IG51bGwgfHwgY29udGFpbmVyTmFtZSA9PT0gXCJcIikge1xuICAgICAgICByb290cy5wdXNoKGl0ZW0ub3V0bGluZSlcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGNvbnN0IHBvc3NpYmxlUGFyZW50cyA9IGNvbnRhaW5lcnMuZ2V0KGNvbnRhaW5lck5hbWUpXG4gICAgICAgIGxldCBjbG9zZXN0UGFyZW50ID0gT3V0bGluZVZpZXdBZGFwdGVyLl9nZXRDbG9zZXN0UGFyZW50KHBvc3NpYmxlUGFyZW50cywgY2hpbGQpXG4gICAgICAgIGlmIChjbG9zZXN0UGFyZW50ID09IG51bGwpIHtcbiAgICAgICAgICBjbG9zZXN0UGFyZW50ID0ge1xuICAgICAgICAgICAgcGxhaW5UZXh0OiBjb250YWluZXJOYW1lLFxuICAgICAgICAgICAgcmVwcmVzZW50YXRpdmVOYW1lOiBjb250YWluZXJOYW1lLFxuICAgICAgICAgICAgc3RhcnRQb3NpdGlvbjogbmV3IFBvaW50KDAsIDApLFxuICAgICAgICAgICAgY2hpbGRyZW46IFtjaGlsZF0sXG4gICAgICAgICAgfVxuICAgICAgICAgIHJvb3RzLnB1c2goY2xvc2VzdFBhcmVudClcbiAgICAgICAgICBpZiAocG9zc2libGVQYXJlbnRzID09IG51bGwpIHtcbiAgICAgICAgICAgIGNvbnRhaW5lcnMuc2V0KGNvbnRhaW5lck5hbWUsIFtjbG9zZXN0UGFyZW50XSlcbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgcG9zc2libGVQYXJlbnRzLnB1c2goY2xvc2VzdFBhcmVudClcbiAgICAgICAgICB9XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgY2xvc2VzdFBhcmVudC5jaGlsZHJlbi5wdXNoKGNoaWxkKVxuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuXG4gICAgcmV0dXJuIHJvb3RzXG4gIH1cblxuICBwcml2YXRlIHN0YXRpYyBfZ2V0Q2xvc2VzdFBhcmVudChcbiAgICBjYW5kaWRhdGVzOiBhdG9tSWRlLk91dGxpbmVUcmVlW10gfCBudWxsLFxuICAgIGNoaWxkOiBhdG9tSWRlLk91dGxpbmVUcmVlXG4gICk6IGF0b21JZGUuT3V0bGluZVRyZWUgfCBudWxsIHtcbiAgICBpZiAoY2FuZGlkYXRlcyA9PSBudWxsIHx8IGNhbmRpZGF0ZXMubGVuZ3RoID09PSAwKSB7XG4gICAgICByZXR1cm4gbnVsbFxuICAgIH1cblxuICAgIGxldCBwYXJlbnQ6IGF0b21JZGUuT3V0bGluZVRyZWUgfCB1bmRlZmluZWRcbiAgICBmb3IgKGNvbnN0IGNhbmRpZGF0ZSBvZiBjYW5kaWRhdGVzKSB7XG4gICAgICBpZiAoXG4gICAgICAgIGNhbmRpZGF0ZSAhPT0gY2hpbGQgJiZcbiAgICAgICAgY2FuZGlkYXRlLnN0YXJ0UG9zaXRpb24uaXNMZXNzVGhhbk9yRXF1YWwoY2hpbGQuc3RhcnRQb3NpdGlvbikgJiZcbiAgICAgICAgKGNhbmRpZGF0ZS5lbmRQb3NpdGlvbiA9PT0gdW5kZWZpbmVkIHx8XG4gICAgICAgICAgKGNoaWxkLmVuZFBvc2l0aW9uICYmIGNhbmRpZGF0ZS5lbmRQb3NpdGlvbi5pc0dyZWF0ZXJUaGFuT3JFcXVhbChjaGlsZC5lbmRQb3NpdGlvbikpKVxuICAgICAgKSB7XG4gICAgICAgIGlmIChcbiAgICAgICAgICBwYXJlbnQgPT09IHVuZGVmaW5lZCB8fFxuICAgICAgICAgIHBhcmVudC5zdGFydFBvc2l0aW9uLmlzTGVzc1RoYW5PckVxdWFsKGNhbmRpZGF0ZS5zdGFydFBvc2l0aW9uKSB8fFxuICAgICAgICAgIChwYXJlbnQuZW5kUG9zaXRpb24gIT0gbnVsbCAmJlxuICAgICAgICAgICAgY2FuZGlkYXRlLmVuZFBvc2l0aW9uICYmXG4gICAgICAgICAgICBwYXJlbnQuZW5kUG9zaXRpb24uaXNHcmVhdGVyVGhhbk9yRXF1YWwoY2FuZGlkYXRlLmVuZFBvc2l0aW9uKSlcbiAgICAgICAgKSB7XG4gICAgICAgICAgcGFyZW50ID0gY2FuZGlkYXRlXG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG5cbiAgICByZXR1cm4gcGFyZW50IHx8IG51bGxcbiAgfVxuXG4gIC8qKlxuICAgKiBQdWJsaWM6IENvbnZlcnQgYW4gaW5kaXZpZHVhbCB7RG9jdW1lbnRTeW1ib2x9IGZyb20gdGhlIGxhbmd1YWdlIHNlcnZlciB0byBhbiB7T3V0bGluZVRyZWV9IGZvciB1c2UgYnkgdGhlIE91dGxpbmVcbiAgICogVmlldy4gSXQgZG9lcyBOT1QgcmVjdXJzaXZlbHkgcHJvY2VzcyB0aGUgZ2l2ZW4gc3ltYm9sJ3MgY2hpbGRyZW4gKGlmIGFueSkuXG4gICAqXG4gICAqIEBwYXJhbSBzeW1ib2wgVGhlIHtEb2N1bWVudFN5bWJvbH0gdG8gY29udmVydCB0byBhbiB7T3V0bGluZVRyZWV9LlxuICAgKiBAcmV0dXJucyBUaGUge091dGxpbmVUcmVlfSBjb3JyZXNwb25kaW5nIHRvIHRoZSBnaXZlbiB7RG9jdW1lbnRTeW1ib2x9LlxuICAgKi9cbiAgcHVibGljIHN0YXRpYyBoaWVyYXJjaGljYWxTeW1ib2xUb091dGxpbmUoc3ltYm9sOiBEb2N1bWVudFN5bWJvbCk6IGF0b21JZGUuT3V0bGluZVRyZWUge1xuICAgIGNvbnN0IGljb24gPSBPdXRsaW5lVmlld0FkYXB0ZXIuc3ltYm9sS2luZFRvRW50aXR5S2luZChzeW1ib2wua2luZClcblxuICAgIHJldHVybiB7XG4gICAgICB0b2tlbml6ZWRUZXh0OiBbXG4gICAgICAgIHtcbiAgICAgICAgICBraW5kOiBPdXRsaW5lVmlld0FkYXB0ZXIuc3ltYm9sS2luZFRvVG9rZW5LaW5kKHN5bWJvbC5raW5kKSxcbiAgICAgICAgICB2YWx1ZTogc3ltYm9sLm5hbWUsXG4gICAgICAgIH0sXG4gICAgICBdLFxuICAgICAgaWNvbjogaWNvbiAhPSBudWxsID8gaWNvbiA6IHVuZGVmaW5lZCxcbiAgICAgIHJlcHJlc2VudGF0aXZlTmFtZTogc3ltYm9sLm5hbWUsXG4gICAgICBzdGFydFBvc2l0aW9uOiBDb252ZXJ0LnBvc2l0aW9uVG9Qb2ludChzeW1ib2wuc2VsZWN0aW9uUmFuZ2Uuc3RhcnQpLFxuICAgICAgZW5kUG9zaXRpb246IENvbnZlcnQucG9zaXRpb25Ub1BvaW50KHN5bWJvbC5zZWxlY3Rpb25SYW5nZS5lbmQpLFxuICAgICAgY2hpbGRyZW46IFtdLFxuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBQdWJsaWM6IENvbnZlcnQgYW4gaW5kaXZpZHVhbCB7U3ltYm9sSW5mb3JtYXRpb259IGZyb20gdGhlIGxhbmd1YWdlIHNlcnZlciB0byBhbiB7T3V0bGluZVRyZWV9IGZvciB1c2UgYnkgdGhlIE91dGxpbmUgVmlldy5cbiAgICpcbiAgICogQHBhcmFtIHN5bWJvbCBUaGUge1N5bWJvbEluZm9ybWF0aW9ufSB0byBjb252ZXJ0IHRvIGFuIHtPdXRsaW5lVHJlZX0uXG4gICAqIEByZXR1cm5zIFRoZSB7T3V0bGluZVRyZWV9IGVxdWl2YWxlbnQgdG8gdGhlIGdpdmVuIHtTeW1ib2xJbmZvcm1hdGlvbn0uXG4gICAqL1xuICBwdWJsaWMgc3RhdGljIHN5bWJvbFRvT3V0bGluZShzeW1ib2w6IFN5bWJvbEluZm9ybWF0aW9uKTogYXRvbUlkZS5PdXRsaW5lVHJlZSB7XG4gICAgY29uc3QgaWNvbiA9IE91dGxpbmVWaWV3QWRhcHRlci5zeW1ib2xLaW5kVG9FbnRpdHlLaW5kKHN5bWJvbC5raW5kKVxuICAgIHJldHVybiB7XG4gICAgICB0b2tlbml6ZWRUZXh0OiBbXG4gICAgICAgIHtcbiAgICAgICAgICBraW5kOiBPdXRsaW5lVmlld0FkYXB0ZXIuc3ltYm9sS2luZFRvVG9rZW5LaW5kKHN5bWJvbC5raW5kKSxcbiAgICAgICAgICB2YWx1ZTogc3ltYm9sLm5hbWUsXG4gICAgICAgIH0sXG4gICAgICBdLFxuICAgICAgaWNvbjogaWNvbiAhPSBudWxsID8gaWNvbiA6IHVuZGVmaW5lZCxcbiAgICAgIHJlcHJlc2VudGF0aXZlTmFtZTogc3ltYm9sLm5hbWUsXG4gICAgICBzdGFydFBvc2l0aW9uOiBDb252ZXJ0LnBvc2l0aW9uVG9Qb2ludChzeW1ib2wubG9jYXRpb24ucmFuZ2Uuc3RhcnQpLFxuICAgICAgZW5kUG9zaXRpb246IENvbnZlcnQucG9zaXRpb25Ub1BvaW50KHN5bWJvbC5sb2NhdGlvbi5yYW5nZS5lbmQpLFxuICAgICAgY2hpbGRyZW46IFtdLFxuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBQdWJsaWM6IENvbnZlcnQgYSBzeW1ib2wga2luZCBpbnRvIGFuIG91dGxpbmUgZW50aXR5IGtpbmQgdXNlZCB0byBkZXRlcm1pbmUgdGhlIHN0eWxpbmcgc3VjaCBhcyB0aGUgYXBwcm9wcmlhdGVcbiAgICogaWNvbiBpbiB0aGUgT3V0bGluZSBWaWV3LlxuICAgKlxuICAgKiBAcGFyYW0gc3ltYm9sIFRoZSBudW1lcmljIHN5bWJvbCBraW5kIHJlY2VpdmVkIGZyb20gdGhlIGxhbmd1YWdlIHNlcnZlci5cbiAgICogQHJldHVybnMgQSBzdHJpbmcgcmVwcmVzZW50aW5nIHRoZSBlcXVpdmFsZW50IE91dGxpbmVWaWV3IGVudGl0eSBraW5kLlxuICAgKi9cbiAgcHVibGljIHN0YXRpYyBzeW1ib2xLaW5kVG9FbnRpdHlLaW5kKHN5bWJvbDogbnVtYmVyKTogc3RyaW5nIHwgbnVsbCB7XG4gICAgc3dpdGNoIChzeW1ib2wpIHtcbiAgICAgIGNhc2UgU3ltYm9sS2luZC5BcnJheTpcbiAgICAgICAgcmV0dXJuIFwidHlwZS1hcnJheVwiXG4gICAgICBjYXNlIFN5bWJvbEtpbmQuQm9vbGVhbjpcbiAgICAgICAgcmV0dXJuIFwidHlwZS1ib29sZWFuXCJcbiAgICAgIGNhc2UgU3ltYm9sS2luZC5DbGFzczpcbiAgICAgICAgcmV0dXJuIFwidHlwZS1jbGFzc1wiXG4gICAgICBjYXNlIFN5bWJvbEtpbmQuQ29uc3RhbnQ6XG4gICAgICAgIHJldHVybiBcInR5cGUtY29uc3RhbnRcIlxuICAgICAgY2FzZSBTeW1ib2xLaW5kLkNvbnN0cnVjdG9yOlxuICAgICAgICByZXR1cm4gXCJ0eXBlLWNvbnN0cnVjdG9yXCJcbiAgICAgIGNhc2UgU3ltYm9sS2luZC5FbnVtOlxuICAgICAgICByZXR1cm4gXCJ0eXBlLWVudW1cIlxuICAgICAgY2FzZSBTeW1ib2xLaW5kLkZpZWxkOlxuICAgICAgICByZXR1cm4gXCJ0eXBlLWZpZWxkXCJcbiAgICAgIGNhc2UgU3ltYm9sS2luZC5GaWxlOlxuICAgICAgICByZXR1cm4gXCJ0eXBlLWZpbGVcIlxuICAgICAgY2FzZSBTeW1ib2xLaW5kLkZ1bmN0aW9uOlxuICAgICAgICByZXR1cm4gXCJ0eXBlLWZ1bmN0aW9uXCJcbiAgICAgIGNhc2UgU3ltYm9sS2luZC5JbnRlcmZhY2U6XG4gICAgICAgIHJldHVybiBcInR5cGUtaW50ZXJmYWNlXCJcbiAgICAgIGNhc2UgU3ltYm9sS2luZC5NZXRob2Q6XG4gICAgICAgIHJldHVybiBcInR5cGUtbWV0aG9kXCJcbiAgICAgIGNhc2UgU3ltYm9sS2luZC5Nb2R1bGU6XG4gICAgICAgIHJldHVybiBcInR5cGUtbW9kdWxlXCJcbiAgICAgIGNhc2UgU3ltYm9sS2luZC5OYW1lc3BhY2U6XG4gICAgICAgIHJldHVybiBcInR5cGUtbmFtZXNwYWNlXCJcbiAgICAgIGNhc2UgU3ltYm9sS2luZC5OdW1iZXI6XG4gICAgICAgIHJldHVybiBcInR5cGUtbnVtYmVyXCJcbiAgICAgIGNhc2UgU3ltYm9sS2luZC5QYWNrYWdlOlxuICAgICAgICByZXR1cm4gXCJ0eXBlLXBhY2thZ2VcIlxuICAgICAgY2FzZSBTeW1ib2xLaW5kLlByb3BlcnR5OlxuICAgICAgICByZXR1cm4gXCJ0eXBlLXByb3BlcnR5XCJcbiAgICAgIGNhc2UgU3ltYm9sS2luZC5TdHJpbmc6XG4gICAgICAgIHJldHVybiBcInR5cGUtc3RyaW5nXCJcbiAgICAgIGNhc2UgU3ltYm9sS2luZC5WYXJpYWJsZTpcbiAgICAgICAgcmV0dXJuIFwidHlwZS12YXJpYWJsZVwiXG4gICAgICBjYXNlIFN5bWJvbEtpbmQuU3RydWN0OlxuICAgICAgICByZXR1cm4gXCJ0eXBlLWNsYXNzXCJcbiAgICAgIGNhc2UgU3ltYm9sS2luZC5FbnVtTWVtYmVyOlxuICAgICAgICByZXR1cm4gXCJ0eXBlLWNvbnN0YW50XCJcbiAgICAgIGRlZmF1bHQ6XG4gICAgICAgIHJldHVybiBudWxsXG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIFB1YmxpYzogQ29udmVydCBhIHN5bWJvbCBraW5kIHRvIHRoZSBhcHByb3ByaWF0ZSB0b2tlbiBraW5kIHVzZWQgdG8gc3ludGF4IGhpZ2hsaWdodCB0aGUgc3ltYm9sIG5hbWUgaW4gdGhlIE91dGxpbmUgVmlldy5cbiAgICpcbiAgICogQHBhcmFtIHN5bWJvbCBUaGUgbnVtZXJpYyBzeW1ib2wga2luZCByZWNlaXZlZCBmcm9tIHRoZSBsYW5ndWFnZSBzZXJ2ZXIuXG4gICAqIEByZXR1cm5zIEEgc3RyaW5nIHJlcHJlc2VudGluZyB0aGUgZXF1aXZhbGVudCBzeW50YXggdG9rZW4ga2luZC5cbiAgICovXG4gIHB1YmxpYyBzdGF0aWMgc3ltYm9sS2luZFRvVG9rZW5LaW5kKHN5bWJvbDogbnVtYmVyKTogYXRvbUlkZS5Ub2tlbktpbmQge1xuICAgIHN3aXRjaCAoc3ltYm9sKSB7XG4gICAgICBjYXNlIFN5bWJvbEtpbmQuQ2xhc3M6XG4gICAgICAgIHJldHVybiBcInR5cGVcIlxuICAgICAgY2FzZSBTeW1ib2xLaW5kLkNvbnN0cnVjdG9yOlxuICAgICAgICByZXR1cm4gXCJjb25zdHJ1Y3RvclwiXG4gICAgICBjYXNlIFN5bWJvbEtpbmQuTWV0aG9kOlxuICAgICAgY2FzZSBTeW1ib2xLaW5kLkZ1bmN0aW9uOlxuICAgICAgICByZXR1cm4gXCJtZXRob2RcIlxuICAgICAgY2FzZSBTeW1ib2xLaW5kLlN0cmluZzpcbiAgICAgICAgcmV0dXJuIFwic3RyaW5nXCJcbiAgICAgIGRlZmF1bHQ6XG4gICAgICAgIHJldHVybiBcInBsYWluXCJcbiAgICB9XG4gIH1cbn1cbiJdfQ==
\No newline at end of file