UNPKG

89.2 kBJavaScriptView Raw
1/**
2 * @license
3 * Copyright Google LLC All Rights Reserved.
4 *
5 * Use of this source code is governed by an MIT-style license that can be
6 * found in the LICENSE file at https://angular.io/license
7 */
8(function (factory) {
9 if (typeof module === "object" && typeof module.exports === "object") {
10 var v = factory(require, exports);
11 if (v !== undefined) module.exports = v;
12 }
13 else if (typeof define === "function" && define.amd) {
14 define("@angular/language-service/src/completions", ["require", "exports", "tslib", "@angular/compiler", "@angular/compiler/src/chars", "@angular/language-service/src/binding_utils", "@angular/language-service/src/expression_diagnostics", "@angular/language-service/src/expressions", "@angular/language-service/src/html_info", "@angular/language-service/src/template", "@angular/language-service/src/types", "@angular/language-service/src/utils"], factory);
15 }
16})(function (require, exports) {
17 "use strict";
18 Object.defineProperty(exports, "__esModule", { value: true });
19 exports.getTemplateCompletions = void 0;
20 var tslib_1 = require("tslib");
21 var compiler_1 = require("@angular/compiler");
22 var chars_1 = require("@angular/compiler/src/chars");
23 var binding_utils_1 = require("@angular/language-service/src/binding_utils");
24 var expression_diagnostics_1 = require("@angular/language-service/src/expression_diagnostics");
25 var expressions_1 = require("@angular/language-service/src/expressions");
26 var html_info_1 = require("@angular/language-service/src/html_info");
27 var template_1 = require("@angular/language-service/src/template");
28 var ng = require("@angular/language-service/src/types");
29 var utils_1 = require("@angular/language-service/src/utils");
30 var HIDDEN_HTML_ELEMENTS = new Set(['html', 'script', 'noscript', 'base', 'body', 'title', 'head', 'link']);
31 var HTML_ELEMENTS = html_info_1.elementNames().filter(function (name) { return !HIDDEN_HTML_ELEMENTS.has(name); }).map(function (name) {
32 return {
33 name: name,
34 kind: ng.CompletionKind.HTML_ELEMENT,
35 sortText: name,
36 };
37 });
38 var ANGULAR_ELEMENTS = [
39 {
40 name: 'ng-container',
41 kind: ng.CompletionKind.ANGULAR_ELEMENT,
42 sortText: 'ng-container',
43 },
44 {
45 name: 'ng-content',
46 kind: ng.CompletionKind.ANGULAR_ELEMENT,
47 sortText: 'ng-content',
48 },
49 {
50 name: 'ng-template',
51 kind: ng.CompletionKind.ANGULAR_ELEMENT,
52 sortText: 'ng-template',
53 },
54 ];
55 function isIdentifierPart(code) {
56 // Identifiers consist of alphanumeric characters, '_', or '$'.
57 return chars_1.isAsciiLetter(code) || chars_1.isDigit(code) || code == chars_1.$$ || code == chars_1.$_;
58 }
59 /**
60 * Gets the span of word in a template that surrounds `position`. If there is no word around
61 * `position`, nothing is returned.
62 */
63 function getBoundedWordSpan(templateInfo, position, ast) {
64 var template = templateInfo.template;
65 var templateSrc = template.source;
66 if (!templateSrc)
67 return;
68 if (ast instanceof compiler_1.Element) {
69 // The HTML tag may include `-` (e.g. `app-root`),
70 // so use the HtmlAst to get the span before ayazhafiz refactor the code.
71 return {
72 start: templateInfo.template.span.start + ast.startSourceSpan.start.offset + 1,
73 length: ast.name.length
74 };
75 }
76 // TODO(ayazhafiz): A solution based on word expansion will always be expensive compared to one
77 // based on ASTs. Whatever penalty we incur is probably manageable for small-length (i.e. the
78 // majority of) identifiers, but the current solution involes a number of branchings and we can't
79 // control potentially very long identifiers. Consider moving to an AST-based solution once
80 // existing difficulties with AST spans are more clearly resolved (see #31898 for discussion of
81 // known problems, and #33091 for how they affect text replacement).
82 //
83 // `templatePosition` represents the right-bound location of a cursor in the template.
84 // key.ent|ry
85 // ^---- cursor, at position `r` is at.
86 // A cursor is not itself a character in the template; it has a left (lower) and right (upper)
87 // index bound that hugs the cursor itself.
88 var templatePosition = position - template.span.start;
89 // To perform word expansion, we want to determine the left and right indices that hug the cursor.
90 // There are three cases here.
91 var left, right;
92 if (templatePosition === 0) {
93 // 1. Case like
94 // |rest of template
95 // the cursor is at the start of the template, hugged only by the right side (0-index).
96 left = right = 0;
97 }
98 else if (templatePosition === templateSrc.length) {
99 // 2. Case like
100 // rest of template|
101 // the cursor is at the end of the template, hugged only by the left side (last-index).
102 left = right = templateSrc.length - 1;
103 }
104 else {
105 // 3. Case like
106 // wo|rd
107 // there is a clear left and right index.
108 left = templatePosition - 1;
109 right = templatePosition;
110 }
111 if (!isIdentifierPart(templateSrc.charCodeAt(left)) &&
112 !isIdentifierPart(templateSrc.charCodeAt(right))) {
113 // Case like
114 // .|.
115 // left ---^ ^--- right
116 // There is no word here.
117 return;
118 }
119 // Expand on the left and right side until a word boundary is hit. Back up one expansion on both
120 // side to stay inside the word.
121 while (left >= 0 && isIdentifierPart(templateSrc.charCodeAt(left)))
122 --left;
123 ++left;
124 while (right < templateSrc.length && isIdentifierPart(templateSrc.charCodeAt(right)))
125 ++right;
126 --right;
127 var absoluteStartPosition = position - (templatePosition - left);
128 var length = right - left + 1;
129 return { start: absoluteStartPosition, length: length };
130 }
131 function getTemplateCompletions(templateInfo, position) {
132 var htmlAst = templateInfo.htmlAst, template = templateInfo.template;
133 // Calculate the position relative to the start of the template. This is needed
134 // because spans in HTML AST are relative. Inline template has non-zero start position.
135 var templatePosition = position - template.span.start;
136 var htmlPath = utils_1.getPathToNodeAtPosition(htmlAst, templatePosition);
137 var mostSpecific = htmlPath.tail;
138 var visitor = new HtmlVisitor(templateInfo, htmlPath);
139 var results = mostSpecific ?
140 mostSpecific.visit(visitor, null /* context */) :
141 elementCompletions(templateInfo);
142 var replacementSpan = getBoundedWordSpan(templateInfo, position, mostSpecific);
143 return results.map(function (entry) {
144 return tslib_1.__assign(tslib_1.__assign({}, entry), { replacementSpan: replacementSpan });
145 });
146 }
147 exports.getTemplateCompletions = getTemplateCompletions;
148 var HtmlVisitor = /** @class */ (function () {
149 function HtmlVisitor(templateInfo, htmlPath) {
150 this.templateInfo = templateInfo;
151 this.htmlPath = htmlPath;
152 this.relativePosition = htmlPath.position;
153 }
154 // Note that every visitor method must explicitly specify return type because
155 // Visitor returns `any` for all methods.
156 HtmlVisitor.prototype.visitElement = function (ast) {
157 var startTagSpan = utils_1.spanOf(ast.sourceSpan);
158 var tagLen = ast.name.length;
159 // + 1 for the opening angle bracket
160 if (this.relativePosition <= startTagSpan.start + tagLen + 1) {
161 // If we are in the tag then return the element completions.
162 return elementCompletions(this.templateInfo);
163 }
164 if (this.relativePosition < startTagSpan.end) {
165 // We are in the attribute section of the element (but not in an attribute).
166 // Return the attribute completions.
167 return attributeCompletionsForElement(this.templateInfo, ast.name);
168 }
169 return [];
170 };
171 HtmlVisitor.prototype.visitAttribute = function (ast) {
172 // An attribute consists of two parts, LHS="RHS".
173 // Determine if completions are requested for LHS or RHS
174 if (ast.valueSpan && utils_1.inSpan(this.relativePosition, utils_1.spanOf(ast.valueSpan))) {
175 // RHS completion
176 return attributeValueCompletions(this.templateInfo, this.htmlPath);
177 }
178 // LHS completion
179 return attributeCompletions(this.templateInfo, this.htmlPath);
180 };
181 HtmlVisitor.prototype.visitText = function () {
182 var _this = this;
183 var _a;
184 var templatePath = utils_1.findTemplateAstAt(this.templateInfo.templateAst, this.relativePosition);
185 if (templatePath.tail instanceof compiler_1.BoundTextAst) {
186 // If we know that this is an interpolation then do not try other scenarios.
187 var visitor = new ExpressionVisitor(this.templateInfo, this.relativePosition, function () {
188 return expression_diagnostics_1.getExpressionScope(utils_1.diagnosticInfoFromTemplateInfo(_this.templateInfo), templatePath);
189 });
190 (_a = templatePath.tail) === null || _a === void 0 ? void 0 : _a.visit(visitor, null);
191 return visitor.results;
192 }
193 // TODO(kyliau): Not sure if this check is really needed since we don't have
194 // any test cases for it.
195 var element = this.htmlPath.first(compiler_1.Element);
196 if (element &&
197 compiler_1.getHtmlTagDefinition(element.name).contentType !== compiler_1.TagContentType.PARSABLE_DATA) {
198 return [];
199 }
200 // This is to account for cases like <h1> <a> text | </h1> where the
201 // closest element has no closing tag and thus is considered plain text.
202 var results = voidElementAttributeCompletions(this.templateInfo, this.htmlPath);
203 if (results.length) {
204 return results;
205 }
206 return elementCompletions(this.templateInfo);
207 };
208 HtmlVisitor.prototype.visitComment = function () {
209 return [];
210 };
211 HtmlVisitor.prototype.visitExpansion = function () {
212 return [];
213 };
214 HtmlVisitor.prototype.visitExpansionCase = function () {
215 return [];
216 };
217 return HtmlVisitor;
218 }());
219 function attributeCompletions(info, path) {
220 var attr = path.tail;
221 var elem = path.parentOf(attr);
222 if (!(attr instanceof compiler_1.Attribute) || !(elem instanceof compiler_1.Element)) {
223 return [];
224 }
225 // TODO: Consider parsing the attrinute name to a proper AST instead of
226 // matching using regex. This is because the regexp would incorrectly identify
227 // bind parts for cases like [()|]
228 // ^ cursor is here
229 var binding = binding_utils_1.getBindingDescriptor(attr.name);
230 if (!binding) {
231 // This is a normal HTML attribute, not an Angular attribute.
232 return attributeCompletionsForElement(info, elem.name);
233 }
234 var results = [];
235 var ngAttrs = angularAttributes(info, elem.name);
236 switch (binding.kind) {
237 case binding_utils_1.ATTR.KW_MICROSYNTAX:
238 // template reference attribute: *attrName
239 results.push.apply(results, tslib_1.__spread(ngAttrs.templateRefs));
240 break;
241 case binding_utils_1.ATTR.KW_BIND:
242 case binding_utils_1.ATTR.IDENT_PROPERTY:
243 // property binding via bind- or []
244 results.push.apply(results, tslib_1.__spread(html_info_1.propertyNames(elem.name), ngAttrs.inputs));
245 break;
246 case binding_utils_1.ATTR.KW_ON:
247 case binding_utils_1.ATTR.IDENT_EVENT:
248 // event binding via on- or ()
249 results.push.apply(results, tslib_1.__spread(html_info_1.eventNames(elem.name), ngAttrs.outputs));
250 break;
251 case binding_utils_1.ATTR.KW_BINDON:
252 case binding_utils_1.ATTR.IDENT_BANANA_BOX:
253 // banana-in-a-box binding via bindon- or [()]
254 results.push.apply(results, tslib_1.__spread(ngAttrs.bananas));
255 break;
256 }
257 return results.map(function (name) {
258 return {
259 name: name,
260 kind: ng.CompletionKind.ATTRIBUTE,
261 sortText: name,
262 };
263 });
264 }
265 function attributeCompletionsForElement(info, elementName) {
266 var e_1, _a, e_2, _b;
267 var results = [];
268 if (info.template instanceof template_1.InlineTemplate) {
269 try {
270 // Provide HTML attributes completion only for inline templates
271 for (var _c = tslib_1.__values(html_info_1.attributeNames(elementName)), _d = _c.next(); !_d.done; _d = _c.next()) {
272 var name_1 = _d.value;
273 results.push({
274 name: name_1,
275 kind: ng.CompletionKind.HTML_ATTRIBUTE,
276 sortText: name_1,
277 });
278 }
279 }
280 catch (e_1_1) { e_1 = { error: e_1_1 }; }
281 finally {
282 try {
283 if (_d && !_d.done && (_a = _c.return)) _a.call(_c);
284 }
285 finally { if (e_1) throw e_1.error; }
286 }
287 }
288 // Add Angular attributes
289 var ngAttrs = angularAttributes(info, elementName);
290 try {
291 for (var _e = tslib_1.__values(ngAttrs.others), _f = _e.next(); !_f.done; _f = _e.next()) {
292 var name_2 = _f.value;
293 results.push({
294 name: name_2,
295 kind: ng.CompletionKind.ATTRIBUTE,
296 sortText: name_2,
297 });
298 }
299 }
300 catch (e_2_1) { e_2 = { error: e_2_1 }; }
301 finally {
302 try {
303 if (_f && !_f.done && (_b = _e.return)) _b.call(_e);
304 }
305 finally { if (e_2) throw e_2.error; }
306 }
307 return results;
308 }
309 /**
310 * Provide completions to the RHS of an attribute, which is of the form
311 * LHS="RHS". The template path is computed from the specified `info` whereas
312 * the context is determined from the specified `htmlPath`.
313 * @param info Object that contains the template AST
314 * @param htmlPath Path to the HTML node
315 */
316 function attributeValueCompletions(info, htmlPath) {
317 // Find the corresponding Template AST path.
318 var templatePath = utils_1.findTemplateAstAt(info.templateAst, htmlPath.position);
319 var visitor = new ExpressionVisitor(info, htmlPath.position, function () {
320 var dinfo = utils_1.diagnosticInfoFromTemplateInfo(info);
321 return expression_diagnostics_1.getExpressionScope(dinfo, templatePath);
322 });
323 if (templatePath.tail instanceof compiler_1.AttrAst ||
324 templatePath.tail instanceof compiler_1.BoundElementPropertyAst ||
325 templatePath.tail instanceof compiler_1.BoundEventAst) {
326 templatePath.tail.visit(visitor, null);
327 return visitor.results;
328 }
329 // In order to provide accurate attribute value completion, we need to know
330 // what the LHS is, and construct the proper AST if it is missing.
331 var htmlAttr = htmlPath.tail;
332 var binding = binding_utils_1.getBindingDescriptor(htmlAttr.name);
333 if (binding && binding.kind === binding_utils_1.ATTR.KW_REF) {
334 var refAst = void 0;
335 var elemAst = void 0;
336 if (templatePath.tail instanceof compiler_1.ReferenceAst) {
337 refAst = templatePath.tail;
338 var parent_1 = templatePath.parentOf(refAst);
339 if (parent_1 instanceof compiler_1.ElementAst) {
340 elemAst = parent_1;
341 }
342 }
343 else if (templatePath.tail instanceof compiler_1.ElementAst) {
344 refAst = new compiler_1.ReferenceAst(htmlAttr.name, null, htmlAttr.value, htmlAttr.valueSpan);
345 elemAst = templatePath.tail;
346 }
347 if (refAst && elemAst) {
348 refAst.visit(visitor, elemAst);
349 }
350 }
351 else {
352 // HtmlAst contains the `Attribute` node, however the corresponding `AttrAst`
353 // node is missing from the TemplateAst.
354 var attrAst = new compiler_1.AttrAst(htmlAttr.name, htmlAttr.value, htmlAttr.valueSpan);
355 attrAst.visit(visitor, null);
356 }
357 return visitor.results;
358 }
359 function elementCompletions(info) {
360 var e_3, _a;
361 var results = tslib_1.__spread(ANGULAR_ELEMENTS);
362 if (info.template instanceof template_1.InlineTemplate) {
363 // Provide HTML elements completion only for inline templates
364 results.push.apply(results, tslib_1.__spread(HTML_ELEMENTS));
365 }
366 // Collect the elements referenced by the selectors
367 var components = new Set();
368 try {
369 for (var _b = tslib_1.__values(utils_1.getSelectors(info).selectors), _c = _b.next(); !_c.done; _c = _b.next()) {
370 var selector = _c.value;
371 var name_3 = selector.element;
372 if (name_3 && !components.has(name_3)) {
373 components.add(name_3);
374 results.push({
375 name: name_3,
376 kind: ng.CompletionKind.COMPONENT,
377 sortText: name_3,
378 });
379 }
380 }
381 }
382 catch (e_3_1) { e_3 = { error: e_3_1 }; }
383 finally {
384 try {
385 if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
386 }
387 finally { if (e_3) throw e_3.error; }
388 }
389 return results;
390 }
391 // There is a special case of HTML where text that contains a unclosed tag is treated as
392 // text. For exaple '<h1> Some <a text </h1>' produces a text nodes inside of the H1
393 // element "Some <a text". We, however, want to treat this as if the user was requesting
394 // the attributes of an "a" element, not requesting completion in the a text element. This
395 // code checks for this case and returns element completions if it is detected or undefined
396 // if it is not.
397 function voidElementAttributeCompletions(info, path) {
398 var tail = path.tail;
399 if (tail instanceof compiler_1.Text) {
400 var match = tail.value.match(/<(\w(\w|\d|-)*:)?(\w(\w|\d|-)*)\s/);
401 // The position must be after the match, otherwise we are still in a place where elements
402 // are expected (such as `<|a` or `<a|`; we only want attributes for `<a |` or after).
403 if (match &&
404 path.position >= (match.index || 0) + match[0].length + tail.sourceSpan.start.offset) {
405 return attributeCompletionsForElement(info, match[3]);
406 }
407 }
408 return [];
409 }
410 var ExpressionVisitor = /** @class */ (function (_super) {
411 tslib_1.__extends(ExpressionVisitor, _super);
412 function ExpressionVisitor(info, position, getExpressionScope) {
413 var _this = _super.call(this) || this;
414 _this.info = info;
415 _this.position = position;
416 _this.getExpressionScope = getExpressionScope;
417 _this.completions = new Map();
418 return _this;
419 }
420 Object.defineProperty(ExpressionVisitor.prototype, "results", {
421 get: function () {
422 return Array.from(this.completions.values());
423 },
424 enumerable: false,
425 configurable: true
426 });
427 ExpressionVisitor.prototype.visitDirectiveProperty = function (ast) {
428 this.processExpressionCompletions(ast.value);
429 };
430 ExpressionVisitor.prototype.visitElementProperty = function (ast) {
431 this.processExpressionCompletions(ast.value);
432 };
433 ExpressionVisitor.prototype.visitEvent = function (ast) {
434 this.processExpressionCompletions(ast.handler);
435 };
436 ExpressionVisitor.prototype.visitElement = function () {
437 // no-op for now
438 };
439 ExpressionVisitor.prototype.visitAttr = function (ast) {
440 var binding = binding_utils_1.getBindingDescriptor(ast.name);
441 if (binding && binding.kind === binding_utils_1.ATTR.KW_MICROSYNTAX) {
442 // This a template binding given by micro syntax expression.
443 // First, verify the attribute consists of some binding we can give completions for.
444 // The sourceSpan of AttrAst points to the RHS of the attribute
445 var templateKey = binding.name;
446 var templateValue = ast.sourceSpan.toString();
447 var templateUrl = ast.sourceSpan.start.file.url;
448 // TODO(kyliau): We are unable to determine the absolute offset of the key
449 // but it is okay here, because we are only looking at the RHS of the attr
450 var absKeyOffset = 0;
451 var absValueOffset = ast.sourceSpan.start.offset;
452 var templateBindings = this.info.expressionParser.parseTemplateBindings(templateKey, templateValue, templateUrl, absKeyOffset, absValueOffset).templateBindings;
453 // Find the nearest template binding to the position.
454 var lastBindingEnd = templateBindings.length > 0 &&
455 templateBindings[templateBindings.length - 1].sourceSpan.end;
456 var normalizedPositionToBinding_1 = lastBindingEnd && this.position > lastBindingEnd ? lastBindingEnd : this.position;
457 var templateBinding = templateBindings.find(function (b) { return utils_1.inSpan(normalizedPositionToBinding_1, b.sourceSpan); });
458 if (!templateBinding) {
459 return;
460 }
461 this.microSyntaxInAttributeValue(ast, templateBinding);
462 }
463 else {
464 var expressionAst = this.info.expressionParser.parseBinding(ast.value, ast.sourceSpan.toString(), ast.sourceSpan.start.offset);
465 this.processExpressionCompletions(expressionAst);
466 }
467 };
468 ExpressionVisitor.prototype.visitReference = function (_ast, context) {
469 var _this = this;
470 context.directives.forEach(function (dir) {
471 var exportAs = dir.directive.exportAs;
472 if (exportAs) {
473 _this.completions.set(exportAs, { name: exportAs, kind: ng.CompletionKind.REFERENCE, sortText: exportAs });
474 }
475 });
476 };
477 ExpressionVisitor.prototype.visitBoundText = function (ast) {
478 if (utils_1.inSpan(this.position, ast.value.sourceSpan)) {
479 var completions = expressions_1.getExpressionCompletions(this.getExpressionScope(), ast.value, this.position, this.info.template);
480 if (completions) {
481 this.addSymbolsToCompletions(completions);
482 }
483 }
484 };
485 ExpressionVisitor.prototype.processExpressionCompletions = function (value) {
486 var symbols = expressions_1.getExpressionCompletions(this.getExpressionScope(), value, this.position, this.info.template);
487 if (symbols) {
488 this.addSymbolsToCompletions(symbols);
489 }
490 };
491 ExpressionVisitor.prototype.addSymbolsToCompletions = function (symbols) {
492 var e_4, _a;
493 try {
494 for (var symbols_1 = tslib_1.__values(symbols), symbols_1_1 = symbols_1.next(); !symbols_1_1.done; symbols_1_1 = symbols_1.next()) {
495 var s = symbols_1_1.value;
496 if (s.name.startsWith('__') || !s.public || this.completions.has(s.name)) {
497 continue;
498 }
499 // The pipe method should not include parentheses.
500 // e.g. {{ value_expression | slice : start [ : end ] }}
501 var shouldInsertParentheses = s.callable && s.kind !== ng.CompletionKind.PIPE;
502 this.completions.set(s.name, {
503 name: s.name,
504 kind: s.kind,
505 sortText: s.name,
506 insertText: shouldInsertParentheses ? s.name + "()" : s.name,
507 });
508 }
509 }
510 catch (e_4_1) { e_4 = { error: e_4_1 }; }
511 finally {
512 try {
513 if (symbols_1_1 && !symbols_1_1.done && (_a = symbols_1.return)) _a.call(symbols_1);
514 }
515 finally { if (e_4) throw e_4.error; }
516 }
517 };
518 /**
519 * This method handles the completions of attribute values for directives that
520 * support the microsyntax format. Examples are *ngFor and *ngIf.
521 * These directives allows declaration of "let" variables, adds context-specific
522 * symbols like $implicit, index, count, among other behaviors.
523 * For a complete description of such format, see
524 * https://angular.io/guide/structural-directives#the-asterisk--prefix
525 *
526 * @param attr descriptor for attribute name and value pair
527 * @param binding template binding for the expression in the attribute
528 */
529 ExpressionVisitor.prototype.microSyntaxInAttributeValue = function (attr, binding) {
530 var _a;
531 var key = attr.name.substring(1); // remove leading asterisk
532 // Find the selector - eg ngFor, ngIf, etc
533 var selectorInfo = utils_1.getSelectors(this.info);
534 var selector = selectorInfo.selectors.find(function (s) {
535 // attributes are listed in (attribute, value) pairs
536 for (var i = 0; i < s.attrs.length; i += 2) {
537 if (s.attrs[i] === key) {
538 return true;
539 }
540 }
541 });
542 if (!selector) {
543 return;
544 }
545 var valueRelativePosition = this.position - attr.sourceSpan.start.offset;
546 if (binding instanceof compiler_1.VariableBinding) {
547 // TODO(kyliau): With expression sourceSpan we shouldn't have to search
548 // the attribute value string anymore. Just check if position is in the
549 // expression source span.
550 var equalLocation = attr.value.indexOf('=');
551 if (equalLocation > 0 && valueRelativePosition > equalLocation) {
552 // We are after the '=' in a let clause. The valid values here are the members of the
553 // template reference's type parameter.
554 var directiveMetadata = selectorInfo.map.get(selector);
555 if (directiveMetadata) {
556 var contextTable = this.info.template.query.getTemplateContext(directiveMetadata.type.reference);
557 if (contextTable) {
558 // This adds symbols like $implicit, index, count, etc.
559 this.addSymbolsToCompletions(contextTable.values());
560 return;
561 }
562 }
563 }
564 }
565 else if (binding instanceof compiler_1.ExpressionBinding) {
566 if (utils_1.inSpan(this.position, (_a = binding.value) === null || _a === void 0 ? void 0 : _a.ast.sourceSpan)) {
567 this.processExpressionCompletions(binding.value.ast);
568 return;
569 }
570 else if (!binding.value && this.position > binding.key.span.end) {
571 // No expression is defined for the value of the key expression binding, but the cursor is
572 // in a location where the expression would be defined. This can happen in a case like
573 // let i of |
574 // ^-- cursor
575 // In this case, backfill the value to be an empty expression and retrieve completions.
576 this.processExpressionCompletions(new compiler_1.EmptyExpr(new compiler_1.ParseSpan(valueRelativePosition, valueRelativePosition), new compiler_1.AbsoluteSourceSpan(this.position, this.position)));
577 return;
578 }
579 }
580 };
581 return ExpressionVisitor;
582 }(compiler_1.NullTemplateVisitor));
583 /**
584 * Return all Angular-specific attributes for the element with `elementName`.
585 * @param info
586 * @param elementName
587 */
588 function angularAttributes(info, elementName) {
589 var e_5, _a, e_6, _b, e_7, _c, e_8, _d;
590 var _e = utils_1.getSelectors(info), selectors = _e.selectors, selectorMap = _e.map;
591 var templateRefs = new Set();
592 var inputs = new Set();
593 var outputs = new Set();
594 var bananas = new Set();
595 var others = new Set();
596 try {
597 for (var selectors_1 = tslib_1.__values(selectors), selectors_1_1 = selectors_1.next(); !selectors_1_1.done; selectors_1_1 = selectors_1.next()) {
598 var selector = selectors_1_1.value;
599 if (selector.element && selector.element !== elementName) {
600 continue;
601 }
602 var summary = selectorMap.get(selector);
603 var hasTemplateRef = utils_1.isStructuralDirective(summary.type);
604 // attributes are listed in (attribute, value) pairs
605 for (var i = 0; i < selector.attrs.length; i += 2) {
606 var attr = selector.attrs[i];
607 if (hasTemplateRef) {
608 templateRefs.add(attr);
609 }
610 else {
611 others.add(attr);
612 }
613 }
614 try {
615 for (var _f = (e_6 = void 0, tslib_1.__values(Object.values(summary.inputs))), _g = _f.next(); !_g.done; _g = _f.next()) {
616 var input = _g.value;
617 inputs.add(input);
618 }
619 }
620 catch (e_6_1) { e_6 = { error: e_6_1 }; }
621 finally {
622 try {
623 if (_g && !_g.done && (_b = _f.return)) _b.call(_f);
624 }
625 finally { if (e_6) throw e_6.error; }
626 }
627 try {
628 for (var _h = (e_7 = void 0, tslib_1.__values(Object.values(summary.outputs))), _j = _h.next(); !_j.done; _j = _h.next()) {
629 var output = _j.value;
630 outputs.add(output);
631 }
632 }
633 catch (e_7_1) { e_7 = { error: e_7_1 }; }
634 finally {
635 try {
636 if (_j && !_j.done && (_c = _h.return)) _c.call(_h);
637 }
638 finally { if (e_7) throw e_7.error; }
639 }
640 }
641 }
642 catch (e_5_1) { e_5 = { error: e_5_1 }; }
643 finally {
644 try {
645 if (selectors_1_1 && !selectors_1_1.done && (_a = selectors_1.return)) _a.call(selectors_1);
646 }
647 finally { if (e_5) throw e_5.error; }
648 }
649 try {
650 for (var inputs_1 = tslib_1.__values(inputs), inputs_1_1 = inputs_1.next(); !inputs_1_1.done; inputs_1_1 = inputs_1.next()) {
651 var name_4 = inputs_1_1.value;
652 // Add banana-in-a-box syntax
653 // https://angular.io/guide/template-syntax#two-way-binding-
654 if (outputs.has(name_4 + "Change")) {
655 bananas.add(name_4);
656 }
657 }
658 }
659 catch (e_8_1) { e_8 = { error: e_8_1 }; }
660 finally {
661 try {
662 if (inputs_1_1 && !inputs_1_1.done && (_d = inputs_1.return)) _d.call(inputs_1);
663 }
664 finally { if (e_8) throw e_8.error; }
665 }
666 return { templateRefs: templateRefs, inputs: inputs, outputs: outputs, bananas: bananas, others: others };
667 }
668});
669//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29tcGxldGlvbnMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi9wYWNrYWdlcy9sYW5ndWFnZS1zZXJ2aWNlL3NyYy9jb21wbGV0aW9ucy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7O0dBTUc7Ozs7Ozs7Ozs7Ozs7O0lBRUgsOENBQThYO0lBQzlYLHFEQUEyRTtJQUUzRSw2RUFBMkQ7SUFDM0QsK0ZBQTREO0lBQzVELHlFQUF1RDtJQUN2RCxxRUFBb0Y7SUFDcEYsbUVBQTBDO0lBQzFDLHdEQUE4QjtJQUM5Qiw2REFBd0o7SUFFeEosSUFBTSxvQkFBb0IsR0FDdEIsSUFBSSxHQUFHLENBQUMsQ0FBQyxNQUFNLEVBQUUsUUFBUSxFQUFFLFVBQVUsRUFBRSxNQUFNLEVBQUUsTUFBTSxFQUFFLE9BQU8sRUFBRSxNQUFNLEVBQUUsTUFBTSxDQUFDLENBQUMsQ0FBQztJQUNyRixJQUFNLGFBQWEsR0FDZix3QkFBWSxFQUFFLENBQUMsTUFBTSxDQUFDLFVBQUEsSUFBSSxJQUFJLE9BQUEsQ0FBQyxvQkFBb0IsQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLEVBQS9CLENBQStCLENBQUMsQ0FBQyxHQUFHLENBQUMsVUFBQSxJQUFJO1FBQ3JFLE9BQU87WUFDTCxJQUFJLE1BQUE7WUFDSixJQUFJLEVBQUUsRUFBRSxDQUFDLGNBQWMsQ0FBQyxZQUFZO1lBQ3BDLFFBQVEsRUFBRSxJQUFJO1NBQ2YsQ0FBQztJQUNKLENBQUMsQ0FBQyxDQUFDO0lBQ1AsSUFBTSxnQkFBZ0IsR0FBc0M7UUFDMUQ7WUFDRSxJQUFJLEVBQUUsY0FBYztZQUNwQixJQUFJLEVBQUUsRUFBRSxDQUFDLGNBQWMsQ0FBQyxlQUFlO1lBQ3ZDLFFBQVEsRUFBRSxjQUFjO1NBQ3pCO1FBQ0Q7WUFDRSxJQUFJLEVBQUUsWUFBWTtZQUNsQixJQUFJLEVBQUUsRUFBRSxDQUFDLGNBQWMsQ0FBQyxlQUFlO1lBQ3ZDLFFBQVEsRUFBRSxZQUFZO1NBQ3ZCO1FBQ0Q7WUFDRSxJQUFJLEVBQUUsYUFBYTtZQUNuQixJQUFJLEVBQUUsRUFBRSxDQUFDLGNBQWMsQ0FBQyxlQUFlO1lBQ3ZDLFFBQVEsRUFBRSxhQUFhO1NBQ3hCO0tBQ0YsQ0FBQztJQUVGLFNBQVMsZ0JBQWdCLENBQUMsSUFBWTtRQUNwQywrREFBK0Q7UUFDL0QsT0FBTyxxQkFBYSxDQUFDLElBQUksQ0FBQyxJQUFJLGVBQU8sQ0FBQyxJQUFJLENBQUMsSUFBSSxJQUFJLElBQUksVUFBRSxJQUFJLElBQUksSUFBSSxVQUFFLENBQUM7SUFDMUUsQ0FBQztJQUVEOzs7T0FHRztJQUNILFNBQVMsa0JBQWtCLENBQ3ZCLFlBQTBCLEVBQUUsUUFBZ0IsRUFBRSxHQUFzQjtRQUMvRCxJQUFBLFFBQVEsR0FBSSxZQUFZLFNBQWhCLENBQWlCO1FBQ2hDLElBQU0sV0FBVyxHQUFHLFFBQVEsQ0FBQyxNQUFNLENBQUM7UUFFcEMsSUFBSSxDQUFDLFdBQVc7WUFBRSxPQUFPO1FBRXpCLElBQUksR0FBRyxZQUFZLGtCQUFPLEVBQUU7WUFDMUIsa0RBQWtEO1lBQ2xELHlFQUF5RTtZQUN6RSxPQUFPO2dCQUNMLEtBQUssRUFBRSxZQUFZLENBQUMsUUFBUSxDQUFDLElBQUksQ0FBQyxLQUFLLEdBQUcsR0FBRyxDQUFDLGVBQWUsQ0FBQyxLQUFLLENBQUMsTUFBTSxHQUFHLENBQUM7Z0JBQzlFLE1BQU0sRUFBRSxHQUFHLENBQUMsSUFBSSxDQUFDLE1BQU07YUFDeEIsQ0FBQztTQUNIO1FBRUQsK0ZBQStGO1FBQy9GLDZGQUE2RjtRQUM3RixpR0FBaUc7UUFDakcsMkZBQTJGO1FBQzNGLCtGQUErRjtRQUMvRixvRUFBb0U7UUFDcEUsRUFBRTtRQUNGLHNGQUFzRjtRQUN0RixnQkFBZ0I7UUFDaEIsaURBQWlEO1FBQ2pELDhGQUE4RjtRQUM5RiwyQ0FBMkM7UUFDM0MsSUFBSSxnQkFBZ0IsR0FBRyxRQUFRLEdBQUcsUUFBUSxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUM7UUFDdEQsa0dBQWtHO1FBQ2xHLDhCQUE4QjtRQUM5QixJQUFJLElBQUksRUFBRSxLQUFLLENBQUM7UUFDaEIsSUFBSSxnQkFBZ0IsS0FBSyxDQUFDLEVBQUU7WUFDMUIsZUFBZTtZQUNmLHlCQUF5QjtZQUN6QiwwRkFBMEY7WUFDMUYsSUFBSSxHQUFHLEtBQUssR0FBRyxDQUFDLENBQUM7U0FDbEI7YUFBTSxJQUFJLGdCQUFnQixLQUFLLFdBQVcsQ0FBQyxNQUFNLEVBQUU7WUFDbEQsZUFBZTtZQUNmLHlCQUF5QjtZQUN6QiwwRkFBMEY7WUFDMUYsSUFBSSxHQUFHLEtBQUssR0FBRyxXQUFXLENBQUMsTUFBTSxHQUFHLENBQUMsQ0FBQztTQUN2QzthQUFNO1lBQ0wsZUFBZTtZQUNmLGFBQWE7WUFDYiw0Q0FBNEM7WUFDNUMsSUFBSSxHQUFHLGdCQUFnQixHQUFHLENBQUMsQ0FBQztZQUM1QixLQUFLLEdBQUcsZ0JBQWdCLENBQUM7U0FDMUI7UUFFRCxJQUFJLENBQUMsZ0JBQWdCLENBQUMsV0FBVyxDQUFDLFVBQVUsQ0FBQyxJQUFJLENBQUMsQ0FBQztZQUMvQyxDQUFDLGdCQUFnQixDQUFDLFdBQVcsQ0FBQyxVQUFVLENBQUMsS0FBSyxDQUFDLENBQUMsRUFBRTtZQUNwRCxZQUFZO1lBQ1osY0FBYztZQUNkLHVCQUF1QjtZQUN2Qix5QkFBeUI7WUFDekIsT0FBTztTQUNSO1FBRUQsZ0dBQWdHO1FBQ2hHLGdDQUFnQztRQUNoQyxPQUFPLElBQUksSUFBSSxDQUFDLElBQUksZ0JBQWdCLENBQUMsV0FBVyxDQUFDLFVBQVUsQ0FBQyxJQUFJLENBQUMsQ0FBQztZQUFFLEVBQUUsSUFBSSxDQUFDO1FBQzNFLEVBQUUsSUFBSSxDQUFDO1FBQ1AsT0FBTyxLQUFLLEdBQUcsV0FBVyxDQUFDLE1BQU0sSUFBSSxnQkFBZ0IsQ0FBQyxXQUFXLENBQUMsVUFBVSxDQUFDLEtBQUssQ0FBQyxDQUFDO1lBQUUsRUFBRSxLQUFLLENBQUM7UUFDOUYsRUFBRSxLQUFLLENBQUM7UUFFUixJQUFNLHFCQUFxQixHQUFHLFFBQVEsR0FBRyxDQUFDLGdCQUFnQixHQUFHLElBQUksQ0FBQyxDQUFDO1FBQ25FLElBQU0sTUFBTSxHQUFHLEtBQUssR0FBRyxJQUFJLEdBQUcsQ0FBQyxDQUFDO1FBQ2hDLE9BQU8sRUFBQyxLQUFLLEVBQUUscUJBQXFCLEVBQUUsTUFBTSxRQUFBLEVBQUMsQ0FBQztJQUNoRCxDQUFDO0lBRUQsU0FBZ0Isc0JBQXNCLENBQ2xDLFlBQTBCLEVBQUUsUUFBZ0I7UUFDdkMsSUFBQSxPQUFPLEdBQWMsWUFBWSxRQUExQixFQUFFLFFBQVEsR0FBSSxZQUFZLFNBQWhCLENBQWlCO1FBQ3pDLCtFQUErRTtRQUMvRSx1RkFBdUY7UUFDdkYsSUFBTSxnQkFBZ0IsR0FBRyxRQUFRLEdBQUcsUUFBUSxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUM7UUFDeEQsSUFBTSxRQUFRLEdBQWdCLCtCQUF1QixDQUFDLE9BQU8sRUFBRSxnQkFBZ0IsQ0FBQyxDQUFDO1FBQ2pGLElBQU0sWUFBWSxHQUFHLFFBQVEsQ0FBQyxJQUFJLENBQUM7UUFDbkMsSUFBTSxPQUFPLEdBQUcsSUFBSSxXQUFXLENBQUMsWUFBWSxFQUFFLFFBQVEsQ0FBQyxDQUFDO1FBQ3hELElBQU0sT0FBTyxHQUF5QixZQUFZLENBQUMsQ0FBQztZQUNoRCxZQUFZLENBQUMsS0FBSyxDQUFDLE9BQU8sRUFBRSxJQUFJLENBQUMsYUFBYSxDQUFDLENBQUMsQ0FBQztZQUNqRCxrQkFBa0IsQ0FBQyxZQUFZLENBQUMsQ0FBQztRQUNyQyxJQUFNLGVBQWUsR0FBRyxrQkFBa0IsQ0FBQyxZQUFZLEVBQUUsUUFBUSxFQUFFLFlBQVksQ0FBQyxDQUFDO1FBQ2pGLE9BQU8sT0FBTyxDQUFDLEdBQUcsQ0FBQyxVQUFBLEtBQUs7WUFDdEIsNkNBQ0ssS0FBSyxLQUNSLGVBQWUsaUJBQUEsSUFDZjtRQUNKLENBQUMsQ0FBQyxDQUFDO0lBQ0wsQ0FBQztJQW5CRCx3REFtQkM7SUFFRDtRQUtFLHFCQUE2QixZQUEwQixFQUFtQixRQUFxQjtZQUFsRSxpQkFBWSxHQUFaLFlBQVksQ0FBYztZQUFtQixhQUFRLEdBQVIsUUFBUSxDQUFhO1lBQzdGLElBQUksQ0FBQyxnQkFBZ0IsR0FBRyxRQUFRLENBQUMsUUFBUSxDQUFDO1FBQzVDLENBQUM7UUFDRCw2RUFBNkU7UUFDN0UseUNBQXlDO1FBQ3pDLGtDQUFZLEdBQVosVUFBYSxHQUFZO1lBQ3ZCLElBQU0sWUFBWSxHQUFHLGNBQU0sQ0FBQyxHQUFHLENBQUMsVUFBVSxDQUFDLENBQUM7WUFDNUMsSUFBTSxNQUFNLEdBQUcsR0FBRyxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUM7WUFDL0Isb0NBQW9DO1lBQ3BDLElBQUksSUFBSSxDQUFDLGdCQUFnQixJQUFJLFlBQVksQ0FBQyxLQUFLLEdBQUcsTUFBTSxHQUFHLENBQUMsRUFBRTtnQkFDNUQsNERBQTREO2dCQUM1RCxPQUFPLGtCQUFrQixDQUFDLElBQUksQ0FBQyxZQUFZLENBQUMsQ0FBQzthQUM5QztZQUNELElBQUksSUFBSSxDQUFDLGdCQUFnQixHQUFHLFlBQVksQ0FBQyxHQUFHLEVBQUU7Z0JBQzVDLDRFQUE0RTtnQkFDNUUsb0NBQW9DO2dCQUNwQyxPQUFPLDhCQUE4QixDQUFDLElBQUksQ0FBQyxZQUFZLEVBQUUsR0FBRyxDQUFDLElBQUksQ0FBQyxDQUFDO2FBQ3BFO1lBQ0QsT0FBTyxFQUFFLENBQUM7UUFDWixDQUFDO1FBQ0Qsb0NBQWMsR0FBZCxVQUFlLEdBQWM7WUFDM0IsaURBQWlEO1lBQ2pELHdEQUF3RDtZQUN4RCxJQUFJLEdBQUcsQ0FBQyxTQUFTLElBQUksY0FBTSxDQUFDLElBQUksQ0FBQyxnQkFBZ0IsRUFBRSxjQUFNLENBQUMsR0FBRyxDQUFDLFNBQVMsQ0FBQyxDQUFDLEVBQUU7Z0JBQ3pFLGlCQUFpQjtnQkFDakIsT0FBTyx5QkFBeUIsQ0FBQyxJQUFJLENBQUMsWUFBWSxFQUFFLElBQUksQ0FBQyxRQUFRLENBQUMsQ0FBQzthQUNwRTtZQUNELGlCQUFpQjtZQUNqQixPQUFPLG9CQUFvQixDQUFDLElBQUksQ0FBQyxZQUFZLEVBQUUsSUFBSSxDQUFDLFFBQVEsQ0FBQyxDQUFDO1FBQ2hFLENBQUM7UUFDRCwrQkFBUyxHQUFUO1lBQUEsaUJBeUJDOztZQXhCQyxJQUFNLFlBQVksR0FBRyx5QkFBaUIsQ0FBQyxJQUFJLENBQUMsWUFBWSxDQUFDLFdBQVcsRUFBRSxJQUFJLENBQUMsZ0JBQWdCLENBQUMsQ0FBQztZQUM3RixJQUFJLFlBQVksQ0FBQyxJQUFJLFlBQVksdUJBQVksRUFBRTtnQkFDN0MsNEVBQTRFO2dCQUM1RSxJQUFNLE9BQU8sR0FBRyxJQUFJLGlCQUFpQixDQUNqQyxJQUFJLENBQUMsWUFBWSxFQUFFLElBQUksQ0FBQyxnQkFBZ0IsRUFDeEM7b0JBQ0ksT0FBQSwyQ0FBa0IsQ0FBQyxzQ0FBOEIsQ0FBQyxLQUFJLENBQUMsWUFBWSxDQUFDLEVBQUUsWUFBWSxDQUFDO2dCQUFuRixDQUFtRixDQUFDLENBQUM7Z0JBQzdGLE1BQUEsWUFBWSxDQUFDLElBQUksMENBQUUsS0FBSyxDQUFDLE9BQU8sRUFBRSxJQUFJLEVBQUU7Z0JBQ3hDLE9BQU8sT0FBTyxDQUFDLE9BQU8sQ0FBQzthQUN4QjtZQUNELDRFQUE0RTtZQUM1RSx5QkFBeUI7WUFDekIsSUFBTSxPQUFPLEdBQUcsSUFBSSxDQUFDLFFBQVEsQ0FBQyxLQUFLLENBQUMsa0JBQU8sQ0FBQyxDQUFDO1lBQzdDLElBQUksT0FBTztnQkFDUCwrQkFBb0IsQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLENBQUMsV0FBVyxLQUFLLHlCQUFjLENBQUMsYUFBYSxFQUFFO2dCQUNuRixPQUFPLEVBQUUsQ0FBQzthQUNYO1lBQ0Qsb0VBQW9FO1lBQ3BFLHdFQUF3RTtZQUN4RSxJQUFNLE9BQU8sR0FBRywrQkFBK0IsQ0FBQyxJQUFJLENBQUMsWUFBWSxFQUFFLElBQUksQ0FBQyxRQUFRLENBQUMsQ0FBQztZQUNsRixJQUFJLE9BQU8sQ0FBQyxNQUFNLEVBQUU7Z0JBQ2xCLE9BQU8sT0FBTyxDQUFDO2FBQ2hCO1lBQ0QsT0FBTyxrQkFBa0IsQ0FBQyxJQUFJLENBQUMsWUFBWSxDQUFDLENBQUM7UUFDL0MsQ0FBQztRQUNELGtDQUFZLEdBQVo7WUFDRSxPQUFPLEVBQUUsQ0FBQztRQUNaLENBQUM7UUFDRCxvQ0FBYyxHQUFkO1lBQ0UsT0FBTyxFQUFFLENBQUM7UUFDWixDQUFDO1FBQ0Qsd0NBQWtCLEdBQWxCO1lBQ0UsT0FBTyxFQUFFLENBQUM7UUFDWixDQUFDO1FBQ0gsa0JBQUM7SUFBRCxDQUFDLEFBdEVELElBc0VDO0lBRUQsU0FBUyxvQkFBb0IsQ0FBQyxJQUFrQixFQUFFLElBQXNCO1FBQ3RFLElBQU0sSUFBSSxHQUFHLElBQUksQ0FBQyxJQUFJLENBQUM7UUFDdkIsSUFBTSxJQUFJLEdBQUcsSUFBSSxDQUFDLFFBQVEsQ0FBQyxJQUFJLENBQUMsQ0FBQztRQUNqQyxJQUFJLENBQUMsQ0FBQyxJQUFJLFlBQVksb0JBQVMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxJQUFJLFlBQVksa0JBQU8sQ0FBQyxFQUFFO1lBQzlELE9BQU8sRUFBRSxDQUFDO1NBQ1g7UUFFRCx1RUFBdUU7UUFDdkUsOEVBQThFO1FBQzlFLGtDQUFrQztRQUNsQyxnREFBZ0Q7UUFDaEQsSUFBTSxPQUFPLEdBQUcsb0NBQW9CLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDO1FBQ2hELElBQUksQ0FBQyxPQUFPLEVBQUU7WUFDWiw2REFBNkQ7WUFDN0QsT0FBTyw4QkFBOEIsQ0FBQyxJQUFJLEVBQUUsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDO1NBQ3hEO1FBRUQsSUFBTSxPQUFPLEdBQWEsRUFBRSxDQUFDO1FBQzdCLElBQU0sT0FBTyxHQUFHLGlCQUFpQixDQUFDLElBQUksRUFBRSxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUM7UUFDbkQsUUFBUSxPQUFPLENBQUMsSUFBSSxFQUFFO1lBQ3BCLEtBQUssb0JBQUksQ0FBQyxjQUFjO2dCQUN0QiwwQ0FBMEM7Z0JBQzFDLE9BQU8sQ0FBQyxJQUFJLE9BQVosT0FBTyxtQkFBUyxPQUFPLENBQUMsWUFBWSxHQUFFO2dCQUN0QyxNQUFNO1lBRVIsS0FBSyxvQkFBSSxDQUFDLE9BQU8sQ0FBQztZQUNsQixLQUFLLG9CQUFJLENBQUMsY0FBYztnQkFDdEIsbUNBQW1DO2dCQUNuQyxPQUFPLENBQUMsSUFBSSxPQUFaLE9BQU8sbUJBQVMseUJBQWEsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLEVBQUssT0FBTyxDQUFDLE1BQU0sR0FBRTtnQkFDN0QsTUFBTTtZQUVSLEtBQUssb0JBQUksQ0FBQyxLQUFLLENBQUM7WUFDaEIsS0FBSyxvQkFBSSxDQUFDLFdBQVc7Z0JBQ25CLDhCQUE4QjtnQkFDOUIsT0FBTyxDQUFDLElBQUksT0FBWixPQUFPLG1CQUFTLHNCQUFVLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxFQUFLLE9BQU8sQ0FBQyxPQUFPLEdBQUU7Z0JBQzNELE1BQU07WUFFUixLQUFLLG9CQUFJLENBQUMsU0FBUyxDQUFDO1lBQ3BCLEtBQUssb0JBQUksQ0FBQyxnQkFBZ0I7Z0JBQ3hCLDhDQUE4QztnQkFDOUMsT0FBTyxDQUFDLElBQUksT0FBWixPQUFPLG1CQUFTLE9BQU8sQ0FBQyxPQUFPLEdBQUU7Z0JBQ2pDLE1BQU07U0FDVDtRQUVELE9BQU8sT0FBTyxDQUFDLEdBQUcsQ0FBQyxVQUFBLElBQUk7WUFDckIsT0FBTztnQkFDTCxJQUFJLE1BQUE7Z0JBQ0osSUFBSSxFQUFFLEVBQUUsQ0FBQyxjQUFjLENBQUMsU0FBUztnQkFDakMsUUFBUSxFQUFFLElBQUk7YUFDZixDQUFDO1FBQ0osQ0FBQyxDQUFDLENBQUM7SUFDTCxDQUFDO0lBRUQsU0FBUyw4QkFBOEIsQ0FDbkMsSUFBa0IsRUFBRSxXQUFtQjs7UUFDekMsSUFBTSxPQUFPLEdBQXlCLEVBQUUsQ0FBQztRQUV6QyxJQUFJLElBQUksQ0FBQyxRQUFRLFlBQVkseUJBQWMsRUFBRTs7Z0JBQzNDLCtEQUErRDtnQkFDL0QsS0FBbUIsSUFBQSxLQUFBLGlCQUFBLDBCQUFjLENBQUMsV0FBVyxDQUFDLENBQUEsZ0JBQUEsNEJBQUU7b0JBQTNDLElBQU0sTUFBSSxXQUFBO29CQUNiLE9BQU8sQ0FBQyxJQUFJLENBQUM7d0JBQ1gsSUFBSSxRQUFBO3dCQUNKLElBQUksRUFBRSxFQUFFLENBQUMsY0FBYyxDQUFDLGNBQWM7d0JBQ3RDLFFBQVEsRUFBRSxNQUFJO3FCQUNmLENBQUMsQ0FBQztpQkFDSjs7Ozs7Ozs7O1NBQ0Y7UUFFRCx5QkFBeUI7UUFDekIsSUFBTSxPQUFPLEdBQUcsaUJBQWlCLENBQUMsSUFBSSxFQUFFLFdBQVcsQ0FBQyxDQUFDOztZQUNyRCxLQUFtQixJQUFBLEtBQUEsaUJBQUEsT0FBTyxDQUFDLE1BQU0sQ0FBQSxnQkFBQSw0QkFBRTtnQkFBOUIsSUFBTSxNQUFJLFdBQUE7Z0JBQ2IsT0FBTyxDQUFDLElBQUksQ0FBQztvQkFDWCxJQUFJLFFBQUE7b0JBQ0osSUFBSSxFQUFFLEVBQUUsQ0FBQyxjQUFjLENBQUMsU0FBUztvQkFDakMsUUFBUSxFQUFFLE1BQUk7aUJBQ2YsQ0FBQyxDQUFDO2FBQ0o7Ozs7Ozs7OztRQUVELE9BQU8sT0FBTyxDQUFDO0lBQ2pCLENBQUM7SUFFRDs7Ozs7O09BTUc7SUFDSCxTQUFTLHlCQUF5QixDQUM5QixJQUFrQixFQUFFLFFBQXFCO1FBQzNDLDRDQUE0QztRQUM1QyxJQUFNLFlBQVksR0FBRyx5QkFBaUIsQ0FBQyxJQUFJLENBQUMsV0FBVyxFQUFFLFFBQVEsQ0FBQyxRQUFRLENBQUMsQ0FBQztRQUM1RSxJQUFNLE9BQU8sR0FBRyxJQUFJLGlCQUFpQixDQUFDLElBQUksRUFBRSxRQUFRLENBQUMsUUFBUSxFQUFFO1lBQzdELElBQU0sS0FBSyxHQUFHLHNDQUE4QixDQUFDLElBQUksQ0FBQyxDQUFDO1lBQ25ELE9BQU8sMkNBQWtCLENBQUMsS0FBSyxFQUFFLFlBQVksQ0FBQyxDQUFDO1FBQ2pELENBQUMsQ0FBQyxDQUFDO1FBQ0gsSUFBSSxZQUFZLENBQUMsSUFBSSxZQUFZLGtCQUFPO1lBQ3BDLFlBQVksQ0FBQyxJQUFJLFlBQVksa0NBQXVCO1lBQ3BELFlBQVksQ0FBQyxJQUFJLFlBQVksd0JBQWEsRUFBRTtZQUM5QyxZQUFZLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxPQUFPLEVBQUUsSUFBSSxDQUFDLENBQUM7WUFDdkMsT0FBTyxPQUFPLENBQUMsT0FBTyxDQUFDO1NBQ3hCO1FBQ0QsMkVBQTJFO1FBQzNFLGtFQUFrRTtRQUNsRSxJQUFNLFFBQVEsR0FBRyxRQUFRLENBQUMsSUFBaUIsQ0FBQztRQUM1QyxJQUFNLE9BQU8sR0FBRyxvQ0FBb0IsQ0FBQyxRQUFRLENBQUMsSUFBSSxDQUFDLENBQUM7UUFDcEQsSUFBSSxPQUFPLElBQUksT0FBTyxDQUFDLElBQUksS0FBSyxvQkFBSSxDQUFDLE1BQU0sRUFBRTtZQUMzQyxJQUFJLE1BQU0sU0FBd0IsQ0FBQztZQUNuQyxJQUFJLE9BQU8sU0FBc0IsQ0FBQztZQUNsQyxJQUFJLFlBQVksQ0FBQyxJQUFJLFlBQVksdUJBQVksRUFBRTtnQkFDN0MsTUFBTSxHQUFHLFlBQVksQ0FBQyxJQUFJLENBQUM7Z0JBQzNCLElBQU0sUUFBTSxHQUFHLFlBQVksQ0FBQyxRQUFRLENBQUMsTUFBTSxDQUFDLENBQUM7Z0JBQzdDLElBQUksUUFBTSxZQUFZLHFCQUFVLEVBQUU7b0JBQ2hDLE9BQU8sR0FBRyxRQUFNLENBQUM7aUJBQ2xCO2FBQ0Y7aUJBQU0sSUFBSSxZQUFZLENBQUMsSUFBSSxZQUFZLHFCQUFVLEVBQUU7Z0JBQ2xELE1BQU0sR0FBRyxJQUFJLHVCQUFZLENBQUMsUUFBUSxDQUFDLElBQUksRUFBRSxJQUFLLEVBQUUsUUFBUSxDQUFDLEtBQUssRUFBRSxRQUFRLENBQUMsU0FBVSxDQUFDLENBQUM7Z0JBQ3JGLE9BQU8sR0FBRyxZQUFZLENBQUMsSUFBSSxDQUFDO2FBQzdCO1lBQ0QsSUFBSSxNQUFNLElBQUksT0FBTyxFQUFFO2dCQUNyQixNQUFNLENBQUMsS0FBSyxDQUFDLE9BQU8sRUFBRSxPQUFPLENBQUMsQ0FBQzthQUNoQztTQUNGO2FBQU07WUFDTCw2RUFBNkU7WUFDN0Usd0NBQXdDO1lBQ3hDLElBQU0sT0FBTyxHQUFHLElBQUksa0JBQU8sQ0FBQyxRQUFRLENBQUMsSUFBSSxFQUFFLFFBQVEsQ0FBQyxLQUFLLEVBQUUsUUFBUSxDQUFDLFNBQVUsQ0FBQyxDQUFDO1lBQ2hGLE9BQU8sQ0FBQyxLQUFLLENBQUMsT0FBTyxFQUFFLElBQUksQ0FBQyxDQUFDO1NBQzlCO1FBQ0QsT0FBTyxPQUFPLENBQUMsT0FBTyxDQUFDO0lBQ3pCLENBQUM7SUFFRCxTQUFTLGtCQUFrQixDQUFDLElBQWtCOztRQUM1QyxJQUFNLE9BQU8sb0JBQTZCLGdCQUFnQixDQUFDLENBQUM7UUFFNUQsSUFBSSxJQUFJLENBQUMsUUFBUSxZQUFZLHlCQUFjLEVBQUU7WUFDM0MsNkRBQTZEO1lBQzdELE9BQU8sQ0FBQyxJQUFJLE9BQVosT0FBTyxtQkFBUyxhQUFhLEdBQUU7U0FDaEM7UUFFRCxtREFBbUQ7UUFDbkQsSUFBTSxVQUFVLEdBQUcsSUFBSSxHQUFHLEVBQVUsQ0FBQzs7WUFDckMsS0FBdUIsSUFBQSxLQUFBLGlCQUFBLG9CQUFZLENBQUMsSUFBSSxDQUFDLENBQUMsU0FBUyxDQUFBLGdCQUFBLDRCQUFFO2dCQUFoRCxJQUFNLFFBQVEsV0FBQTtnQkFDakIsSUFBTSxNQUFJLEdBQUcsUUFBUSxDQUFDLE9BQU8sQ0FBQztnQkFDOUIsSUFBSSxNQUFJLElBQUksQ0FBQyxVQUFVLENBQUMsR0FBRyxDQUFDLE1BQUksQ0FBQyxFQUFFO29CQUNqQyxVQUFVLENBQUMsR0FBRyxDQUFDLE1BQUksQ0FBQyxDQUFDO29CQUNyQixPQUFPLENBQUMsSUFBSSxDQUFDO3dCQUNYLElBQUksUUFBQTt3QkFDSixJQUFJLEVBQUUsRUFBRSxDQUFDLGNBQWMsQ0FBQyxTQUFTO3dCQUNqQyxRQUFRLEVBQUUsTUFBSTtxQkFDZixDQUFDLENBQUM7aUJBQ0o7YUFDRjs7Ozs7Ozs7O1FBRUQsT0FBTyxPQUFPLENBQUM7SUFDakIsQ0FBQztJQUVELHdGQUF3RjtJQUN4RixvRkFBb0Y7SUFDcEYsd0ZBQXdGO0lBQ3hGLDBGQUEwRjtJQUMxRiwyRkFBMkY7SUFDM0YsZ0JBQWdCO0lBQ2hCLFNBQVMsK0JBQStCLENBQ3BDLElBQWtCLEVBQUUsSUFBc0I7UUFDNUMsSUFBTSxJQUFJLEdBQUcsSUFBSSxDQUFDLElBQUksQ0FBQztRQUN2QixJQUFJLElBQUksWUFBWSxlQUFJLEVBQUU7WUFDeEIsSUFBTSxLQUFLLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxLQUFLLENBQUMsbUNBQW1DLENBQUMsQ0FBQztZQUNwRSx5RkFBeUY7WUFDekYsc0ZBQXNGO1lBQ3RGLElBQUksS0FBSztnQkFDTCxJQUFJLENBQUMsUUFBUSxJQUFJLENBQUMsS0FBSyxDQUFDLEtBQUssSUFBSSxDQUFDLENBQUMsR0FBRyxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUMsTUFBTSxHQUFHLElBQUksQ0FBQyxVQUFVLENBQUMsS0FBSyxDQUFDLE1BQU0sRUFBRTtnQkFDeEYsT0FBTyw4QkFBOEIsQ0FBQyxJQUFJLEVBQUUsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7YUFDdkQ7U0FDRjtRQUNELE9BQU8sRUFBRSxDQUFDO0lBQ1osQ0FBQztJQUVEO1FBQWdDLDZDQUFtQjtRQUdqRCwyQkFDcUIsSUFBa0IsRUFBbUIsUUFBZ0IsRUFDckQsa0JBQXdDO1lBRjdELFlBR0UsaUJBQU8sU0FDUjtZQUhvQixVQUFJLEdBQUosSUFBSSxDQUFjO1lBQW1CLGNBQVEsR0FBUixRQUFRLENBQVE7WUFDckQsd0JBQWtCLEdBQWxCLGtCQUFrQixDQUFzQjtZQUo1QyxpQkFBVyxHQUFHLElBQUksR0FBRyxFQUE4QixDQUFDOztRQU1yRSxDQUFDO1FBRUQsc0JBQUksc0NBQU87aUJBQVg7Z0JBQ0UsT0FBTyxLQUFLLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxXQUFXLENBQUMsTUFBTSxFQUFFLENBQUMsQ0FBQztZQUMvQyxDQUFDOzs7V0FBQTtRQUVELGtEQUFzQixHQUF0QixVQUF1QixHQUE4QjtZQUNuRCxJQUFJLENBQUMsNEJBQTRCLENBQUMsR0FBRyxDQUFDLEtBQUssQ0FBQyxDQUFDO1FBQy9DLENBQUM7UUFFRCxnREFBb0IsR0FBcEIsVUFBcUIsR0FBNEI7WUFDL0MsSUFBSSxDQUFDLDRCQUE0QixDQUFDLEdBQUcsQ0FBQyxLQUFLLENBQUMsQ0FBQztRQUMvQyxDQUFDO1FBRUQsc0NBQVUsR0FBVixVQUFXLEdBQWtCO1lBQzNCLElBQUksQ0FBQyw0QkFBNEIsQ0FBQyxHQUFHLENBQUMsT0FBTyxDQUFDLENBQUM7UUFDakQsQ0FBQztRQUVELHdDQUFZLEdBQVo7WUFDRSxnQkFBZ0I7UUFDbEIsQ0FBQztRQUVELHFDQUFTLEdBQVQsVUFBVSxHQUFZO1lBQ3BCLElBQU0sT0FBTyxHQUFHLG9DQUFvQixDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsQ0FBQztZQUMvQyxJQUFJLE9BQU8sSUFBSSxPQUFPLENBQUMsSUFBSSxLQUFLLG9CQUFJLENBQUMsY0FBYyxFQUFFO2dCQUNuRCw0REFBNEQ7Z0JBQzVELG9GQUFvRjtnQkFDcEYsK0RBQStEO2dCQUMvRCxJQUFNLFdBQVcsR0FBRyxPQUFPLENBQUMsSUFBSSxDQUFDO2dCQUNqQyxJQUFNLGFBQWEsR0FBRyxHQUFHLENBQUMsVUFBVSxDQUFDLFFBQVEsRUFBRSxDQUFDO2dCQUNoRCxJQUFNLFdBQVcsR0FBRyxHQUFHLENBQUMsVUFBVSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDO2dCQUNsRCwwRUFBMEU7Z0JBQzFFLDBFQUEwRTtnQkFDMUUsSUFBTSxZQUFZLEdBQUcsQ0FBQyxDQUFDO2dCQUN2QixJQUFNLGNBQWMsR0FBRyxHQUFHLENBQUMsVUFBVSxDQUFDLEtBQUssQ0FBQyxNQUFNLENBQUM7Z0JBQzVDLElBQUEsZ0JBQWdCLEdBQUksSUFBSSxDQUFDLElBQUksQ0FBQyxnQkFBZ0IsQ0FBQyxxQkFBcUIsQ0FDdkUsV0FBVyxFQUFFLGFBQWEsRUFBRSxXQUFXLEVBQUUsWUFBWSxFQUFFLGNBQWMsQ0FBQyxpQkFEbkQsQ0FDb0Q7Z0JBQzNFLHFEQUFxRDtnQkFDckQsSUFBTSxjQUFjLEdBQUcsZ0JBQWdCLENBQUMsTUFBTSxHQUFHLENBQUM7b0JBQzlDLGdCQUFnQixDQUFDLGdCQUFnQixDQUFDLE1BQU0sR0FBRyxDQUFDLENBQUMsQ0FBQyxVQUFVLENBQUMsR0FBRyxDQUFDO2dCQUNqRSxJQUFNLDZCQUEyQixHQUM3QixjQUFjLElBQUksSUFBSSxDQUFDLFFBQVEsR0FBRyxjQUFjLENBQUMsQ0FBQyxDQUFDLGNBQWMsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQztnQkFDdEYsSUFBTSxlQUFlLEdBQ2pCLGdCQUFnQixDQUFDLElBQUksQ0FBQyxVQUFBLENBQUMsSUFBSSxPQUFBLGNBQU0sQ0FBQyw2QkFBMkIsRUFBRSxDQUFDLENBQUMsVUFBVSxDQUFDLEVBQWpELENBQWlELENBQUMsQ0FBQztnQkFFbEYsSUFBSSxDQUFDLGVBQWUsRUFBRTtvQkFDcEIsT0FBTztpQkFDUjtnQkFFRCxJQUFJLENBQUMsMkJBQTJCLENBQUMsR0FBRyxFQUFFLGVBQWUsQ0FBQyxDQUFDO2FBQ3hEO2lCQUFNO2dCQUNMLElBQU0sYUFBYSxHQUFHLElBQUksQ0FBQyxJQUFJLENBQUMsZ0JBQWdCLENBQUMsWUFBWSxDQUN6RCxHQUFHLENBQUMsS0FBSyxFQUFFLEdBQUcsQ0FBQyxVQUFVLENBQUMsUUFBUSxFQUFFLEVBQUUsR0FBRyxDQUFDLFVBQVUsQ0FBQyxLQUFLLENBQUMsTUFBTSxDQUFDLENBQUM7Z0JBQ3ZFLElBQUksQ0FBQyw0QkFBNEIsQ0FBQyxhQUFhLENBQUMsQ0FBQzthQUNsRDtRQUNILENBQUM7UUFFRCwwQ0FBYyxHQUFkLFVBQWUsSUFBa0IsRUFBRSxPQUFtQjtZQUF0RCxpQkFRQztZQVBDLE9BQU8sQ0FBQyxVQUFVLENBQUMsT0FBTyxDQUFDLFVBQUEsR0FBRztnQkFDckIsSUFBQSxRQUFRLEdBQUksR0FBRyxDQUFDLFNBQVMsU0FBakIsQ0FBa0I7Z0JBQ2pDLElBQUksUUFBUSxFQUFFO29CQUNaLEtBQUksQ0FBQyxXQUFXLENBQUMsR0FBRyxDQUNoQixRQUFRLEVBQUUsRUFBQyxJQUFJLEVBQUUsUUFBUSxFQUFFLElBQUksRUFBRSxFQUFFLENBQUMsY0FBYyxDQUFDLFNBQVMsRUFBRSxRQUFRLEVBQUUsUUFBUSxFQUFDLENBQUMsQ0FBQztpQkFDeEY7WUFDSCxDQUFDLENBQUMsQ0FBQztRQUNMLENBQUM7UUFFRCwwQ0FBYyxHQUFkLFVBQWUsR0FBaUI7WUFDOUIsSUFBSSxjQUFNLENBQUMsSUFBSSxDQUFDLFFBQVEsRUFBRSxHQUFHLENBQUMsS0FBSyxDQUFDLFVBQVUsQ0FBQyxFQUFFO2dCQUMvQyxJQUFNLFdBQVcsR0FBRyxzQ0FBd0IsQ0FDeEMsSUFBSSxDQUFDLGtCQUFrQixFQUFFLEVBQUUsR0FBRyxDQUFDLEtBQUssRUFBRSxJQUFJLENBQUMsUUFBUSxFQUFFLElBQUksQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLENBQUM7Z0JBQzdFLElBQUksV0FBVyxFQUFFO29CQUNmLElBQUksQ0FBQyx1QkFBdUIsQ0FBQyxXQUFXLENBQUMsQ0FBQztpQkFDM0M7YUFDRjtRQUNILENBQUM7UUFFTyx3REFBNEIsR0FBcEMsVUFBcUMsS0FBVTtZQUM3QyxJQUFNLE9BQU8sR0FBRyxzQ0FBd0IsQ0FDcEMsSUFBSSxDQUFDLGtCQUFrQixFQUFFLEVBQUUsS0FBSyxFQUFFLElBQUksQ0FBQyxRQUFRLEVBQUUsSUFBSSxDQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsQ0FBQztZQUN6RSxJQUFJLE9BQU8sRUFBRTtnQkFDWCxJQUFJLENBQUMsdUJBQXVCLENBQUMsT0FBTyxDQUFDLENBQUM7YUFDdkM7UUFDSCxDQUFDO1FBRU8sbURBQXVCLEdBQS9CLFVBQWdDLE9BQW9COzs7Z0JBQ2xELEtBQWdCLElBQUEsWUFBQSxpQkFBQSxPQUFPLENBQUEsZ0NBQUEscURBQUU7b0JBQXBCLElBQU0sQ0FBQyxvQkFBQTtvQkFDVixJQUFJLENBQUMsQ0FBQyxJQUFJLENBQUMsVUFBVSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLE1BQU0sSUFBSSxJQUFJLENBQUMsV0FBVyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLEVBQUU7d0JBQ3hFLFNBQVM7cUJBQ1Y7b0JBRUQsa0RBQWtEO29CQUNsRCx3REFBd0Q7b0JBQ3hELElBQU0sdUJBQXVCLEdBQUcsQ0FBQyxDQUFDLFFBQVEsSUFBSSxDQUFDLENBQUMsSUFBSSxLQUFLLEVBQUUsQ0FBQyxjQUFjLENBQUMsSUFBSSxDQUFDO29CQUNoRixJQUFJLENBQUMsV0FBVyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsSUFBSSxFQUFFO3dCQUMzQixJQUFJLEVBQUUsQ0FBQyxDQUFDLElBQUk7d0JBQ1osSUFBSSxFQUFFLENBQUMsQ0FBQyxJQUF5Qjt3QkFDakMsUUFBUSxFQUFFLENBQUMsQ0FBQyxJQUFJO3dCQUNoQixVQUFVLEVBQUUsdUJBQXVCLENBQUMsQ0FBQyxDQUFJLENBQUMsQ0FBQyxJQUFJLE9BQUksQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUk7cUJBQzdELENBQUMsQ0FBQztpQkFDSjs7Ozs7Ozs7O1FBQ0gsQ0FBQztRQUVEOzs7Ozs7Ozs7O1dBVUc7UUFDSyx1REFBMkIsR0FBbkMsVUFBb0MsSUFBYSxFQUFFLE9BQXdCOztZQUN6RSxJQUFNLEdBQUcsR0FBRyxJQUFJLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFFLDBCQUEwQjtZQUUvRCwwQ0FBMEM7WUFDMUMsSUFBTSxZQUFZLEdBQUcsb0JBQVksQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUM7WUFDN0MsSUFBTSxRQUFRLEdBQUcsWUFBWSxDQUFDLFNBQVMsQ0FBQyxJQUFJLENBQUMsVUFBQSxDQUFDO2dCQUM1QyxvREFBb0Q7Z0JBQ3BELEtBQUssSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsR0FBRyxDQUFDLENBQUMsS0FBSyxDQUFDLE1BQU0sRUFBRSxDQUFDLElBQUksQ0FBQyxFQUFFO29CQUMxQyxJQUFJLENBQUMsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLEtBQUssR0FBRyxFQUFFO3dCQUN0QixPQUFPLElBQUksQ0FBQztxQkFDYjtpQkFDRjtZQUNILENBQUMsQ0FBQyxDQUFDO1lBRUgsSUFBSSxDQUFDLFFBQVEsRUFBRTtnQkFDYixPQUFPO2FBQ1I7WUFFRCxJQUFNLHFCQUFxQixHQUFHLElBQUksQ0FBQyxRQUFRLEdBQUcsSUFBSSxDQUFDLFVBQVUsQ0FBQyxLQUFLLENBQUMsTUFBTSxDQUFDO1lBRTNFLElBQUksT0FBTyxZQUFZLDBCQUFlLEVBQUU7Z0JBQ3RDLHVFQUF1RTtnQkFDdkUsdUVBQXVFO2dCQUN2RSwwQkFBMEI7Z0JBQzFCLElBQU0sYUFBYSxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxDQUFDO2dCQUM5QyxJQUFJLGFBQWEsR0FBRyxDQUFDLElBQUkscUJBQXFCLEdBQUcsYUFBYSxFQUFFO29CQUM5RCxxRkFBcUY7b0JBQ3JGLHVDQUF1QztvQkFDdkMsSUFBTSxpQkFBaUIsR0FBRyxZQUFZLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBQyxRQUFRLENBQUMsQ0FBQztvQkFDekQsSUFBSSxpQkFBaUIsRUFBRTt3QkFDckIsSUFBTSxZQUFZLEdBQ2QsSUFBSSxDQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsS0FBSyxDQUFDLGtCQUFrQixDQUFDLGlCQUFpQixDQUFDLElBQUksQ0FBQyxTQUFTLENBQUMsQ0FBQzt3QkFDbEYsSUFBSSxZQUFZLEVBQUU7NEJBQ2hCLHVEQUF1RDs0QkFDdkQsSUFBSSxDQUFDLHVCQUF1QixDQUFDLFlBQVksQ0FBQyxNQUFNLEVBQUUsQ0FBQyxDQUFDOzRCQUNwRCxPQUFPO3lCQUNSO3FCQUNGO2lCQUNGO2FBQ0Y7aUJBQU0sSUFBSSxPQUFPLFlBQVksNEJBQWlCLEVBQUU7Z0JBQy9DLElBQUksY0FBTSxDQUFDLElBQUksQ0FBQyxRQUFRLFFBQUUsT0FBTyxDQUFDLEtBQUssMENBQUUsR0FBRyxDQUFDLFVBQVUsQ0FBQyxFQUFFO29CQUN4RCxJQUFJLENBQUMsNEJBQTRCLENBQUMsT0FBTyxDQUFDLEtBQU0sQ0FBQyxHQUFHLENBQUMsQ0FBQztvQkFDdEQsT0FBTztpQkFDUjtxQkFBTSxJQUFJLENBQUMsT0FBTyxDQUFDLEtBQUssSUFBSSxJQUFJLENBQUMsUUFBUSxHQUFHLE9BQU8sQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLEdBQUcsRUFBRTtvQkFDakUsMEZBQTBGO29CQUMxRixzRkFBc0Y7b0JBQ3RGLGVBQWU7b0JBQ2Ysd0JBQXdCO29CQUN4Qix1RkFBdUY7b0JBQ3ZGLElBQUksQ0FBQyw0QkFBNEIsQ0FBQyxJQUFJLG9CQUFTLENBQzNDLElBQUksb0JBQVMsQ0FBQyxxQkFBcUIsRUFBRSxxQkFBcUIsQ0FBQyxFQUMzRCxJQUFJLDZCQUFrQixDQUFDLElBQUksQ0FBQyxRQUFRLEVBQUUsSUFBSSxDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUMsQ0FBQztvQkFDM0QsT0FBTztpQkFDUjthQUNGO1FBQ0gsQ0FBQztRQUNILHdCQUFDO0lBQUQsQ0FBQyxBQWpMRCxDQUFnQyw4QkFBbUIsR0FpTGxEO0lBeUJEOzs7O09BSUc7SUFDSCxTQUFTLGlCQUFpQixDQUFDLElBQWtCLEVBQUUsV0FBbUI7O1FBQzFELElBQUEsS0FBZ0Msb0JBQVksQ0FBQyxJQUFJLENBQUMsRUFBakQsU0FBUyxlQUFBLEVBQU8sV0FBVyxTQUFzQixDQUFDO1FBQ3pELElBQU0sWUFBWSxHQUFHLElBQUksR0FBRyxFQUFVLENBQUM7UUFDdkMsSUFBTSxNQUFNLEdBQUcsSUFBSSxHQUFHLEVBQVUsQ0FBQztRQUNqQyxJQUFNLE9BQU8sR0FBRyxJQUFJLEdBQUcsRUFBVSxDQUFDO1FBQ2xDLElBQU0sT0FBTyxHQUFHLElBQUksR0FBRyxFQUFVLENBQUM7UUFDbEMsSUFBTSxNQUFNLEdBQUcsSUFBSSxHQUFHLEVBQVUsQ0FBQzs7WUFDakMsS0FBdUIsSUFBQSxjQUFBLGlCQUFBLFNBQVMsQ0FBQSxvQ0FBQSwyREFBRTtnQkFBN0IsSUFBTSxRQUFRLHNCQUFBO2dCQUNqQixJQUFJLFFBQVEsQ0FBQyxPQUFPLElBQUksUUFBUSxDQUFDLE9BQU8sS0FBSyxXQUFXLEVBQUU7b0JBQ3hELFNBQVM7aUJBQ1Y7Z0JBQ0QsSUFBTSxPQUFPLEdBQUcsV0FBVyxDQUFDLEdBQUcsQ0FBQyxRQUFRLENBQUUsQ0FBQztnQkFDM0MsSUFBTSxjQUFjLEdBQUcsNkJBQXFCLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxDQUFDO2dCQUMzRCxvREFBb0Q7Z0JBQ3BELEtBQUssSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsR0FBRyxRQUFRLENBQUMsS0FBSyxDQUFDLE1BQU0sRUFBRSxDQUFDLElBQUksQ0FBQyxFQUFFO29CQUNqRCxJQUFNLElBQUksR0FBRyxRQUFRLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDO29CQUMvQixJQUFJLGNBQWMsRUFBRTt3QkFDbEIsWUFBWSxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsQ0FBQztxQkFDeEI7eUJBQU07d0JBQ0wsTUFBTSxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsQ0FBQztxQkFDbEI7aUJBQ0Y7O29CQUNELEtBQW9CLElBQUEsb0JBQUEsaUJBQUEsTUFBTSxDQUFDLE1BQU0sQ0FBQyxPQUFPLENBQUMsTUFBTSxDQUFDLENBQUEsQ0FBQSxnQkFBQSw0QkFBRTt3QkFBOUMsSUFBTSxLQUFLLFdBQUE7d0JBQ2QsTUFBTSxDQUFDLEdBQUcsQ0FBQyxLQUFLLENBQUMsQ0FBQztxQkFDbkI7Ozs7Ozs7Ozs7b0JBQ0QsS0FBcUIsSUFBQSxvQkFBQSxpQkFBQSxNQUFNLENBQUMsTUFBTSxDQUFDLE9BQU8sQ0FBQyxPQUFPLENBQUMsQ0FBQSxDQUFBLGdCQUFBLDRCQUFFO3dCQUFoRCxJQUFNLE1BQU0sV0FBQTt3QkFDZixPQUFPLENBQUMsR0FBRyxDQUFDLE1BQU0sQ0FBQyxDQUFDO3FCQUNyQjs7Ozs7Ozs7O2FBQ0Y7Ozs7Ozs7Ozs7WUFDRCxLQUFtQixJQUFBLFdBQUEsaUJBQUEsTUFBTSxDQUFBLDhCQUFBLGtEQUFFO2dCQUF0QixJQUFNLE1BQUksbUJBQUE7Z0JBQ2IsNkJBQTZCO2dCQUM3Qiw0REFBNEQ7Z0JBQzVELElBQUksT0FBTyxDQUFDLEdBQUcsQ0FBSSxNQUFJLFdBQVEsQ0FBQyxFQUFFO29CQUNoQyxPQUFPLENBQUMsR0FBRyxDQUFDLE1BQUksQ0FBQyxDQUFDO2lCQUNuQjthQUNGOzs7Ozs7Ozs7UUFDRCxPQUFPLEVBQUMsWUFBWSxjQUFBLEVBQUUsTUFBTSxRQUFBLEVBQUUsT0FBTyxTQUFBLEVBQUUsT0FBTyxTQUFBLEVBQUUsTUFBTSxRQUFBLEVBQUMsQ0FBQztJQUMxRCxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBAbGljZW5zZVxuICogQ29weXJpZ2h0IEdvb2dsZSBMTEMgQWxsIFJpZ2h0cyBSZXNlcnZlZC5cbiAqXG4gKiBVc2Ugb2YgdGhpcyBzb3VyY2UgY29kZSBpcyBnb3Zlcm5lZCBieSBhbiBNSVQtc3R5bGUgbGljZW5zZSB0aGF0IGNhbiBiZVxuICogZm91bmQgaW4gdGhlIExJQ0VOU0UgZmlsZSBhdCBodHRwczovL2FuZ3VsYXIuaW8vbGljZW5zZVxuICovXG5cbmltcG9ydCB7QWJzb2x1dGVTb3VyY2VTcGFuLCBBU1QsIEFzdFBhdGgsIEF0dHJBc3QsIEF0dHJpYnV0ZSwgQm91bmREaXJlY3RpdmVQcm9wZXJ0eUFzdCwgQm91bmRFbGVtZW50UHJvcGVydHlBc3QsIEJvdW5kRXZlbnRBc3QsIEJvdW5kVGV4dEFzdCwgRWxlbWVudCwgRWxlbWVudEFzdCwgRW1wdHlFeHByLCBFeHByZXNzaW9uQmluZGluZywgZ2V0SHRtbFRhZ0RlZmluaXRpb24sIEh0bWxBc3RQYXRoLCBOb2RlIGFzIEh0bWxBc3QsIE51bGxUZW1wbGF0ZVZpc2l0b3IsIFBhcnNlU3BhbiwgUmVmZXJlbmNlQXN0LCBUYWdDb250ZW50VHlwZSwgVGVtcGxhdGVCaW5kaW5nLCBUZXh0LCBWYXJpYWJsZUJpbmRpbmcsIFZpc2l0b3J9IGZyb20gJ0Bhbmd1bGFyL2NvbXBpbGVyJztcbmltcG9ydCB7JCQsICRfLCBpc0FzY2lpTGV0dGVyLCBpc0RpZ2l0fSBmcm9tICdAYW5ndWxhci9jb21waWxlci9zcmMvY2hhcnMnO1xuXG5pbXBvcnQge0FUVFIsIGdldEJpbmRpbmdEZXNjcmlwdG9yfSBmcm9tICcuL2JpbmRpbmdfdXRpbHMnO1xuaW1wb3J0IHtnZXRFeHByZXNzaW9uU2NvcGV9IGZyb20gJy4vZXhwcmVzc2lvbl9kaWFnbm9zdGljcyc7XG5pbXBvcnQge2dldEV4cHJlc3Npb25Db21wbGV0aW9uc30gZnJvbSAnLi9leHByZXNzaW9ucyc7XG5pbXBvcnQge2F0dHJpYnV0ZU5hbWVzLCBlbGVtZW50TmFtZXMsIGV2ZW50TmFtZXMsIHByb3BlcnR5TmFtZXN9IGZyb20gJy4vaHRtbF9pbmZvJztcbmltcG9ydCB7SW5saW5lVGVtcGxhdGV9IGZyb20gJy4vdGVtcGxhdGUnO1xuaW1wb3J0ICogYXMgbmcgZnJvbSAnLi90eXBlcyc7XG5pbXBvcnQge2RpYWdub3N0aWNJbmZvRnJvbVRlbXBsYXRlSW5mbywgZmluZFRlbXBsYXRlQXN0QXQsIGdldFBhdGhUb05vZGVBdFBvc2l0aW9uLCBnZXRTZWxlY3RvcnMsIGluU3BhbiwgaXNTdHJ1Y3R1cmFsRGlyZWN0aXZlLCBzcGFuT2Z9IGZyb20gJy4vdXRpbHMnO1xuXG5jb25zdCBISURERU5fSFRNTF9FTEVNRU5UUzogUmVhZG9ubHlTZXQ8c3RyaW5nPiA9XG4gICAgbmV3IFNldChbJ2h0bWwnLCAnc2NyaXB0JywgJ25vc2NyaXB0JywgJ2Jhc2UnLCAnYm9keScsICd0aXRsZScsICdoZWFkJywgJ2xpbmsnXSk7XG5jb25zdCBIVE1MX0VMRU1FTlRTOiBSZWFkb25seUFycmF5PG5nLkNvbXBsZXRpb25FbnRyeT4gPVxuICAgIGVsZW1lbnROYW1lcygpLmZpbHRlcihuYW1lID0+ICFISURERU5fSFRNTF9FTEVNRU5UUy5oYXMobmFtZSkpLm1hcChuYW1lID0+IHtcbiAgICAgIHJldHVybiB7XG4gICAgICAgIG5hbWUsXG4gICAgICAgIGtpbmQ6IG5nLkNvbXBsZXRpb25LaW5kLkhUTUxfRUxFTUVOVCxcbiAgICAgICAgc29ydFRleHQ6IG5hbWUsXG4gICAgICB9O1xuICAgIH0pO1xuY29uc3QgQU5HVUxBUl9FTEVNRU5UUzogUmVhZG9ubHlBcnJheTxuZy5Db21wbGV0aW9uRW50cnk+ID0gW1xuICB7XG4gICAgbmFtZTogJ25nLWNvbnRhaW5lcicsXG4gICAga2luZDogbmcuQ29tcGxldGlvbktpbmQuQU5HVUxBUl9FTEVNRU5ULFxuICAgIHNvcnRUZXh0OiAnbmctY29udGFpbmVyJyxcbiAgfSxcbiAge1xuICAgIG5hbWU6ICduZy1jb250ZW50JyxcbiAgICBraW5kOiBuZy5Db21wbGV0aW9uS2luZC5BTkdVTEFSX0VMRU1FTlQsXG4gICAgc29ydFRleHQ6ICduZy1jb250ZW50JyxcbiAgfSxcbiAge1xuICAgIG5hbWU6ICduZy10ZW1wbGF0ZScsXG4gICAga2luZDogbmcuQ29tcGxldGlvbktpbmQuQU5HVUxBUl9FTEVNRU5ULFxuICAgIHNvcnRUZXh0OiAnbmctdGVtcGxhdGUnLFxuICB9LFxuXTtcblxuZnVuY3Rpb24gaXNJZGVudGlmaWVyUGFydChjb2RlOiBudW1iZXIpIHtcbiAgLy8gSWRlbnRpZmllcnMgY29uc2lzdCBvZiBhbHBoYW51bWVyaWMgY2hhcmFjdGVycywgJ18nLCBvciAnJCcuXG4gIHJldHVybiBpc0FzY2lpTGV0dGVyKGNvZGUpIHx8IGlzRGlnaXQoY29kZSkgfHwgY29kZSA9PSAkJCB8fCBjb2RlID09ICRfO1xufVxuXG4vKipcbiAqIEdldHMgdGhlIHNwYW4gb2Ygd29yZCBpbiBhIHRlbXBsYXRlIHRoYXQgc3Vycm91bmRzIGBwb3NpdGlvbmAuIElmIHRoZXJlIGlzIG5vIHdvcmQgYXJvdW5kXG4gKiBgcG9zaXRpb25gLCBub3RoaW5nIGlzIHJldHVybmVkLlxuICovXG5mdW5jdGlvbiBnZXRCb3VuZGVkV29yZFNwYW4oXG4gICAgdGVtcGxhdGVJbmZvOiBuZy5Bc3RSZXN1bHQsIHBvc2l0aW9uOiBudW1iZXIsIGFzdDogSHRtbEFzdHx1bmRlZmluZWQpOiB0cy5UZXh0U3Bhbnx1bmRlZmluZWQge1xuICBjb25zdCB7dGVtcGxhdGV9ID0gdGVtcGxhdGVJbmZvO1xuICBjb25zdCB0ZW1wbGF0ZVNyYyA9IHRlbXBsYXRlLnNvdXJjZTtcblxuICBpZiAoIXRlbXBsYXRlU3JjKSByZXR1cm47XG5cbiAgaWYgKGFzdCBpbnN0YW5jZW9mIEVsZW1lbnQpIHtcbiAgICAvLyBUaGUgSFRNTCB0YWcgbWF5IGluY2x1ZGUgYC1gIChlLmcuIGBhcHAtcm9vdGApLFxuICAgIC8vIHNvIHVzZSB0aGUgSHRtbEFzdCB0byBnZXQgdGhlIHNwYW4gYmVmb3JlIGF5YXpoYWZpeiByZWZhY3RvciB0aGUgY29kZS5cbiAgICByZXR1cm4ge1xuICAgICAgc3RhcnQ6IHRlbXBsYXRlSW5mby50ZW1wbGF0ZS5zcGFuLnN0YXJ0ICsgYXN0LnN0YXJ0U291cmNlU3Bhbi5zdGFydC5vZmZzZXQgKyAxLFxuICAgICAgbGVuZ3RoOiBhc3QubmFtZS5sZW5ndGhcbiAgICB9O1xuICB9XG5cbiAgLy8gVE9ETyhheWF6aGFmaXopOiBBIHNvbHV0aW9uIGJhc2VkIG9uIHdvcmQgZXhwYW5zaW9uIHdpbGwgYWx3YXlzIGJlIGV4cGVuc2l2ZSBjb21wYXJlZCB0byBvbmVcbiAgLy8gYmFzZWQgb24gQVNUcy4gV2hhdGV2ZXIgcGVuYWx0eSB3ZSBpbmN1ciBpcyBwcm9iYWJseSBtYW5hZ2VhYmxlIGZvciBzbWFsbC1sZW5ndGggKGkuZS4gdGhlXG4gIC8vIG1ham9yaXR5IG9mKSBpZGVudGlmaWVycywgYnV0IHRoZSBjdXJyZW50IHNvbHV0aW9uIGludm9sZXMgYSBudW1iZXIgb2YgYnJhbmNoaW5ncyBhbmQgd2UgY2FuJ3RcbiAgLy8gY29udHJvbCBwb3RlbnRpYWxseSB2ZXJ5IGxvbmcgaWRlbnRpZmllcnMuIENvbnNpZGVyIG1vdmluZyB0byBhbiBBU1QtYmFzZWQgc29sdXRpb24gb25jZVxuICAvLyBleGlzdGluZyBkaWZmaWN1bHRpZXMgd2l0aCBBU1Qgc3BhbnMgYXJlIG1vcmUgY2xlYXJseSByZXNvbHZlZCAoc2VlICMzMTg5OCBmb3IgZGlzY3Vzc2lvbiBvZlxuICAvLyBrbm93biBwcm9ibGVtcywgYW5kICMzMzA5MSBmb3IgaG93IHRoZXkgYWZmZWN0IHRleHQgcmVwbGFjZW1lbnQpLlxuICAvL1xuICAvLyBgdGVtcGxhdGVQb3NpdGlvbmAgcmVwcmVzZW50cyB0aGUgcmlnaHQtYm91bmQgbG9jYXRpb24gb2YgYSBjdXJzb3IgaW4gdGhlIHRlbXBsYXRlLlxuICAvLyAgICBrZXkuZW50fHJ5XG4gIC8vICAgICAgICAgICBeLS0tLSBjdXJzb3IsIGF0IHBvc2l0aW9uIGByYCBpcyBhdC5cbiAgLy8gQSBjdXJzb3IgaXMgbm90IGl0c2VsZiBhIGNoYXJhY3RlciBpbiB0aGUgdGVtcGxhdGU7IGl0IGhhcyBhIGxlZnQgKGxvd2VyKSBhbmQgcmlnaHQgKHVwcGVyKVxuICAvLyBpbmRleCBib3VuZCB0aGF0IGh1Z3MgdGhlIGN1cnNvciBpdHNlbGYuXG4gIGxldCB0ZW1wbGF0ZVBvc2l0aW9uID0gcG9zaXRpb24gLSB0ZW1wbGF0ZS5zcGFuLnN0YXJ0O1xuICAvLyBUbyBwZXJmb3JtIHdvcmQgZXhwYW5zaW9uLCB3ZSB3YW50IHRvIGRldGVybWluZSB0aGUgbGVmdCBhbmQgcmlnaHQgaW5kaWNlcyB0aGF0IGh1ZyB0aGUgY3Vyc29yLlxuICAvLyBUaGVyZSBhcmUgdGhyZWUgY2FzZXMgaGVyZS5cbiAgbGV0IGxlZnQsIHJpZ2h0O1xuICBpZiAodGVtcGxhdGVQb3NpdGlvbiA9PT0gMCkge1xuICAgIC8vIDEuIENhc2UgbGlrZVxuICAgIC8vICAgICAgfHJlc3Qgb2YgdGVtcGxhdGVcbiAgICAvLyAgICB0aGUgY3Vyc29yIGlzIGF0IHRoZSBzdGFydCBvZiB0aGUgdGVtcGxhdGUsIGh1Z2dlZCBvbmx5IGJ5IHRoZSByaWdodCBzaWRlICgwLWluZGV4KS5cbiAgICBsZWZ0ID0gcmlnaHQgPSAwO1xuICB9IGVsc2UgaWYgKHRlbXBsYXRlUG9zaXRpb24gPT09IHRlbXBsYXRlU3JjLmxlbmd0aCkge1xuICAgIC8vIDIuIENhc2UgbGlrZVxuICAgIC8vICAgICAgcmVzdCBvZiB0ZW1wbGF0ZXxcbiAgICAvLyAgICB0aGUgY3Vyc29yIGlzIGF0IHRoZSBlbmQgb2YgdGhlIHRlbXBsYXRlLCBodWdnZWQgb25seSBieSB0aGUgbGVmdCBzaWRlIChsYXN0LWluZGV4KS5cbiAgICBsZWZ0ID0gcmlnaHQgPSB0ZW1wbGF0ZVNyYy5sZW5ndGggLSAxO1xuICB9IGVsc2Uge1xuICAgIC8vIDMuIENhc2UgbGlrZVxuICAgIC8vICAgICAgd298cmRcbiAgICAvLyAgICB0aGVyZSBpcyBhIGNsZWFyIGxlZnQgYW5kIHJpZ2h0IGluZGV4LlxuICAgIGxlZnQgPSB0ZW1wbGF0ZVBvc2l0aW9uIC0gMTtcbiAgICByaWdodCA9IHRlbXBsYXRlUG9zaXRpb247XG4gIH1cblxuICBpZiAoIWlzSWRlbnRpZmllclBhcnQodGVtcGxhdGVTcmMuY2hhckNvZGVBdChsZWZ0KSkgJiZcbiAgICAgICFpc0lkZW50aWZpZXJQYXJ0KHRlbXBsYXRlU3JjLmNoYXJDb2RlQXQocmlnaHQpKSkge1xuICAgIC8vIENhc2UgbGlrZVxuICAgIC8vICAgICAgICAgLnwuXG4gICAgLy8gbGVmdCAtLS1eIF4tLS0gcmlnaHRcbiAgICAvLyBUaGVyZSBpcyBubyB3b3JkIGhlcmUuXG4gICAgcmV0dXJuO1xuICB9XG5cbiAgLy8gRXhwYW5kIG9uIHRoZSBsZWZ0IGFuZCByaWdodCBzaWRlIHVudGlsIGEgd29yZCBib3VuZGFyeSBpcyBoaXQuIEJhY2sgdXAgb25lIGV4cGFuc2lvbiBvbiBib3RoXG4gIC8vIHNpZGUgdG8gc3RheSBpbnNpZGUgdGhlIHdvcmQuXG4gIHdoaWxlIChsZWZ0ID49IDAgJiYgaXNJZGVudGlmaWVyUGFydCh0ZW1wbGF0ZVNyYy5jaGFyQ29kZUF0KGxlZnQpKSkgLS1sZWZ0O1xuICArK2xlZnQ7XG4gIHdoaWxlIChyaWdodCA8IHRlbXBsYXRlU3JjLmxlbmd0aCAmJiBpc0lkZW50aWZpZXJQYXJ0KHRlbXBsYXRlU3JjLmNoYXJDb2RlQXQocmlnaHQpKSkgKytyaWdodDtcbiAgLS1yaWdodDtcblxuICBjb25zdCBhYnNvbHV0ZVN0YXJ0UG9zaXRpb24gPSBwb3NpdGlvbiAtICh0ZW1wbGF0ZVBvc2l0aW9uIC0gbGVmdCk7XG4gIGNvbnN0IGxlbmd0aCA9IHJpZ2h0IC0gbGVmdCArIDE7XG4gIHJldHVybiB7c3RhcnQ6IGFic29sdXRlU3RhcnRQb3NpdGlvbiwgbGVuZ3RofTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGdldFRlbXBsYXRlQ29tcGxldGlvbnMoXG4gICAgdGVtcGxhdGVJbmZvOiBuZy5Bc3RSZXN1bHQsIHBvc2l0aW9uOiBudW1iZXIpOiBuZy5Db21wbGV0aW9uRW50cnlbXSB7XG4gIGNvbnN0IHtodG1sQXN0LCB0ZW1wbGF0ZX0gPSB0ZW1wbGF0ZUluZm87XG4gIC8vIENhbGN1bGF0ZSB0aGUgcG9zaXRpb24gcmVsYXRpdmUgdG8gdGhlIHN0YXJ0IG9mIHRoZSB0ZW1wbGF0ZS4gVGhpcyBpcyBuZWVkZWRcbiAgLy8gYmVjYXVzZSBzcGFucyBpbiBIVE1MIEFTVCBhcmUgcmVsYXRpdmUuIElubGluZSB0ZW1wbGF0ZSBoYXMgbm9uLXplcm8gc3RhcnQgcG9zaXRpb24uXG4gIGNvbnN0IHRlbXBsYXRlUG9zaXRpb24gPSBwb3NpdGlvbiAtIHRlbXBsYXRlLnNwYW4uc3RhcnQ7XG4gIGNvbnN0IGh0bWxQYXRoOiBIdG1sQXN0UGF0aCA9IGdldFBhdGhUb05vZGVBdFBvc2l0aW9uKGh0bWxBc3QsIHRlbXBsYXRlUG9zaXRpb24pO1xuICBjb25zdCBtb3N0U3BlY2lmaWMgPSBodG1sUGF0aC50YWlsO1xuICBjb25zdCB2aXNpdG9yID0gbmV3IEh0bWxWaXNpdG9yKHRlbXBsYXRlSW5mbywgaHRtbFBhdGgpO1xuICBjb25zdCByZXN1bHRzOiBuZy5Db21wbGV0aW9uRW50cnlbXSA9IG1vc3RTcGVjaWZpYyA/XG4gICAgICBtb3N0U3BlY2lmaWMudmlzaXQodmlzaXRvciwgbnVsbCAvKiBjb250ZXh0ICovKSA6XG4gICAgICBlbGVtZW50Q29tcGxldGlvbnModGVtcGxhdGVJbmZvKTtcbiAgY29uc3QgcmVwbGFjZW1lbnRTcGFuID0gZ2V0Qm91bmRlZFdvcmRTcGFuKHRlbXBsYXRlSW5mbywgcG9zaXRpb24sIG1vc3RTcGVjaWZpYyk7XG4gIHJldHVybiByZXN1bHRzLm1hcChlbnRyeSA9PiB7XG4gICAgcmV0dXJuIHtcbiAgICAgIC4uLmVudHJ5LFxuICAgICAgcmVwbGFjZW1lbnRTcGFuLFxuICAgIH07XG4gIH0pO1xufVxuXG5jbGFzcyBIdG1sVmlzaXRvciBpbXBsZW1lbnRzIFZpc2l0b3Ige1xuICAvKipcbiAgICogUG9zaXRpb24gcmVsYXRpdmUgdG8gdGhlIHN0YXJ0IG9mIHRoZSB0ZW1wbGF0ZS5cbiAgICovXG4gIHByaXZhdGUgcmVhZG9ubHkgcmVsYXRpdmVQb3NpdGlvbjogbnVtYmVyO1xuICBjb25zdHJ1Y3Rvcihwcml2YXRlIHJlYWRvbmx5IHRlbXBsYXRlSW5mbzogbmcuQXN0UmVzdWx0LCBwcml2YXRlIHJlYWRvbmx5IGh0bWxQYXRoOiBIdG1sQXN0UGF0aCkge1xuICAgIHRoaXMucmVsYXRpdmVQb3NpdGlvbiA9IGh0bWxQYXRoLnBvc2l0aW9uO1xuICB9XG4gIC8vIE5vdGUgdGhhdCBldmVyeSB2aXNpdG9yIG1ldGhvZCBtdXN0IGV4cGxpY2l0bHkgc3BlY2lmeSByZXR1cm4gdHlwZSBiZWNhdXNlXG4gIC8vIFZpc2l0b3IgcmV0dXJucyBgYW55YCBmb3IgYWxsIG1ldGhvZHMuXG4gIHZpc2l0RWxlbWVudChhc3Q6IEVsZW1lbnQpOiBuZy5Db21wbGV0aW9uRW50cnlbXSB7XG4gICAgY29uc3Qgc3RhcnRUYWdTcGFuID0gc3Bhbk9mKGFzdC5zb3VyY2VTcGFuKTtcbiAgICBjb25zdCB0YWdMZW4gPSBhc3QubmFtZS5sZW5ndGg7XG4gICAgLy8gKyAxIGZvciB0aGUgb3BlbmluZyBhbmdsZSBicmFja2V0XG4gICAgaWYgKHRoaXMucmVsYXRpdmVQb3NpdGlvbiA8PSBzdGFydFRhZ1NwYW4uc3RhcnQgKyB0YWdMZW4gKyAxKSB7XG4gICAgICAvLyBJZiB3ZSBhcmUgaW4gdGhlIHRhZyB0aGVuIHJldHVybiB0aGUgZWxlbWVudCBjb21wbGV0aW9ucy5cbiAgICAgIHJldHVybiBlbGVtZW50Q29tcGxldGlvbnModGhpcy50ZW1wbGF0ZUluZm8pO1xuICAgIH1cbiAgICBpZiAodGhpcy5yZWxhdGl2ZVBvc2l0aW9uIDwgc3RhcnRUYWdTcGFuLmVuZCkge1xuICAgICAgLy8gV2UgYXJlIGluIHRoZSBhdHRyaWJ1dGUgc2VjdGlvbiBvZiB0aGUgZWxlbWVudCAoYnV0IG5vdCBpbiBhbiBhdHRyaWJ1dGUpLlxuICAgICAgLy8gUmV0dXJuIHRoZSBhdHRyaWJ1dGUgY29tcGxldGlvbnMuXG4gICAgICByZXR1cm4gYXR0cmlidXRlQ29tcGxldGlvbnNGb3JFbGVtZW50KHRoaXMudGVtcGxhdGVJbmZvLCBhc3QubmFtZSk7XG4gICAgfVxuICAgIHJldHVybiBbXTtcbiAgfVxuICB2aXNpdEF0dHJpYnV0ZShhc3Q6IEF0dHJpYnV0ZSk6IG5nLkNvbXBsZXRpb25FbnRyeVtdIHtcbiAgICAvLyBBbiBhdHRyaWJ1dGUgY29uc2lzdHMgb2YgdHdvIHBhcnRzLCBMSFM9XCJSSFNcIi5cbiAgICAvLyBEZXRlcm1pbmUgaWYgY29tcGxldGlvbnMgYXJlIHJlcXVlc3RlZCBmb3IgTEhTIG9yIFJIU1xuICAgIGlmIChhc3QudmFsdWVTcGFuICYmIGluU3Bhbih0aGlzLnJlbGF0aXZlUG9zaXRpb24sIHNwYW5PZihhc3QudmFsdWVTcGFuKSkpIHtcbiAgICAgIC8vIFJIUyBjb21wbGV0aW9uXG4gICAgICByZXR1cm4gYXR0cmlidXRlVmFsdWVDb21wbGV0aW9ucyh0aGlzLnRlbXBsYXRlSW5mbywgdGhpcy5odG1sUGF0aCk7XG4gICAgfVxuICAgIC8vIExIUyBjb21wbGV0aW9uXG4gICAgcmV0dXJuIGF0dHJpYnV0ZUNvbXBsZXRpb25zKHRoaXMudGVtcGxhdGVJbmZvLCB0aGlzLmh0bWxQYXRoKTtcbiAgfVxuICB2aXNpdFRleHQoKTogbmcuQ29tcGxldGlvbkVudHJ5W10ge1xuICAgIGNvbnN0IHRlbXBsYXRlUGF0aCA9IGZpbmRUZW1wbGF0ZUFzdEF0KHRoaXMudGVtcGxhdGVJbmZvLnRlbXBsYXRlQXN0LCB0aGlzLnJlbGF0aXZlUG9zaXRpb24pO1xuICAgIGlmICh0ZW1wbGF0ZVBhdGgudGFpbCBpbnN0YW5jZW9mIEJvdW5kVGV4dEFzdCkge1xuICAgICAgLy8gSWYgd2Uga25vdyB0aGF0IHRoaXMgaXMgYW4gaW50ZXJwb2xhdGlvbiB0aGVuIGRvIG5vdCB0cnkgb3RoZXIgc2NlbmFyaW9zLlxuICAgICAgY29uc3QgdmlzaXRvciA9IG5ldyBFeHByZXNzaW9uVmlzaXRvcihcbiAgICAgICAgICB0aGlzLnRlbXBsYXRlSW5mbywgdGhpcy5yZWxhdGl2ZVBvc2l0aW9uLFxuICAgICAgICAgICgpID0+XG4gICAgICAgICAgICAgIGdldEV4cHJlc3Npb25TY29wZShkaWFnbm9zdGljSW5mb0Zyb21UZW1wbGF0ZUluZm8odGhpcy50ZW1wbGF0ZUluZm8pLCB0ZW1wbGF0ZVBhdGgpKTtcbiAgICAgIHRlbXBsYXRlUGF0aC50YWlsPy52aXNpdCh2aXNpdG9yLCBudWxsKTtcbiAgICAgIHJldHVybiB2aXNpdG9yLnJlc3VsdHM7XG4gICAgfVxuICAgIC8vIFRPRE8oa3lsaWF1KTogTm90IHN1cmUgaWYgdGhpcyBjaGVjayBpcyByZWFsbHkgbmVlZGVkIHNpbmNlIHdlIGRvbid0IGhhdmVcbiAgICAvLyBhbnkgdGVzdCBjYXNlcyBmb3IgaXQuXG4gICAgY29uc3QgZWxlbWVudCA9IHRoaXMuaHRtbFBhdGguZmlyc3QoRWxlbWVudCk7XG4gICAgaWYgKGVsZW1lbnQgJiZcbiAgICAgICAgZ2V0SHRtbFRhZ0RlZmluaXRpb24oZWxlbWVudC5uYW1lKS5jb250ZW50VHlwZSAhPT0gVGFnQ29udGVudFR5cGUuUEFSU0FCTEVfREFUQSkge1xuICAgICAgcmV0dXJuIFtdO1xuICAgIH1cbiAgICAvLyBUaGlzIGlzIHRvIGFjY291bnQgZm9yIGNhc2VzIGxpa2UgPGgxPiA8YT4gdGV4dCB8IDwvaDE+IHdoZXJlIHRoZVxuICAgIC8vIGNsb3Nlc3QgZWxlbWVudCBoYXMgbm8gY2xvc2luZyB0YWcgYW5kIHRodXMgaXMgY29uc2lkZXJlZCBwbGFpbiB0ZXh0LlxuICAgIGNvbnN0IHJlc3VsdHMgPSB2b2lkRWxlbWVudEF0dHJpYnV0ZUNvbXBsZXRpb25zKHRoaXMudGVtcGxhdGVJbmZvLCB0aGlzLmh0bWxQYXRoKTtcbiAgICBpZiAocmVzdWx0cy5sZW5ndGgpIHtcbiAgICAgIHJldHVybiByZXN1bHRzO1xuICAgIH1cbiAgICByZXR1cm4gZWxlbWVudENvbXBsZXRpb25zKHRoaXMudGVtcGxhdGVJbmZvKTtcbiAgfVxuICB2aXNpdENvbW1lbnQoKTogbmcuQ29tcGxldGlvbkVudHJ5W10ge1xuICAgIHJldHVybiBbXTtcbiAgfVxuICB2aXNpdEV4cGFuc2lvbigpOiBuZy5Db21wbGV0aW9uRW50cnlbXSB7XG4gICAgcmV0dXJuIFtdO1xuICB9XG4gIHZpc2l0RXhwYW5zaW9uQ2FzZSgpOiBuZy5Db21wbGV0aW9uRW50cnlbXSB7XG4gICAgcmV0dXJuIFtdO1xuICB9XG59XG5cbmZ1bmN0aW9uIGF0dHJpYnV0ZUNvbXBsZXRpb25zKGluZm86IG5nLkFzdFJlc3VsdCwgcGF0aDogQXN0UGF0aDxIdG1sQXN0Pik6IG5nLkNvbXBsZXRpb25FbnRyeVtdIHtcbiAgY29uc3QgYXR0ciA9IHBhdGgudGFpbDtcbiAgY29uc3QgZWxlbSA9IHBhdGgucGFyZW50T2YoYXR0cik7XG4gIGlmICghKGF0dHIgaW5zdGFuY2VvZiBBdHRyaWJ1dGUpIHx8ICEoZWxlbSBpbnN0YW5jZW9mIEVsZW1lbnQpKSB7XG4gICAgcmV0dXJuIFtdO1xuICB9XG5cbiAgLy8gVE9ETzogQ29uc2lkZXIgcGFyc2luZyB0aGUgYXR0cmludXRlIG5hbWUgdG8gYSBwcm9wZXIgQVNUIGluc3RlYWQgb2ZcbiAgLy8gbWF0Y2hpbmcgdXNpbmcgcmVnZXguIFRoaXMgaXMgYmVjYXVzZSB0aGUgcmVnZXhwIHdvdWxkIGluY29ycmVjdGx5IGlkZW50aWZ5XG4gIC8vIGJpbmQgcGFydHMgZm9yIGNhc2VzIGxpa2UgWygpfF1cbiAgLy8gICAgICAgICAgICAgICAgICAgICAgICAgICAgICBeIGN1cnNvciBpcyBoZXJlXG4gIGNvbnN0IGJpbmRpbmcgPSBnZXRCaW5kaW5nRGVzY3JpcHRvcihhdHRyLm5hbWUpO1xuICBpZiAoIWJpbmRpbmcpIHtcbiAgICAvLyBUaGlzIGlzIGEgbm9ybWFsIEhUTUwgYXR0cmlidXRlLCBub3QgYW4gQW5ndWxhciBhdHRyaWJ1dGUuXG4gICAgcmV0dXJuIGF0dHJpYnV0ZUNvbXBsZXRpb25zRm9yRWxlbWVudChpbmZvLCBlbGVtLm5hbWUpO1xuICB9XG5cbiAgY29uc3QgcmVzdWx0czogc3RyaW5nW10gPSBbXTtcbiAgY29uc3QgbmdBdHRycyA9IGFuZ3VsYXJBdHRyaWJ1dGVzKGluZm8sIGVsZW0ubmFtZSk7XG4gIHN3aXRjaCAoYmluZGluZy5raW5kKSB7XG4gICAgY2FzZSBBVFRSLktXX01JQ1JPU1lOVEFYOlxuICAgICAgLy8gdGVtcGxhdGUgcmVmZXJlbmNlIGF0dHJpYnV0ZTogKmF0dHJOYW1lXG4gICAgICByZXN1bHRzLnB1c2goLi4ubmdBdHRycy50ZW1wbGF0ZVJlZnMpO1xuICAgICAgYnJlYWs7XG5cbiAgICBjYXNlIEFUVFIuS1dfQklORDpcbiAgICBjYXNlIEFUVFIuSURFTlRfUFJPUEVSVFk6XG4gICAgICAvLyBwcm9wZXJ0eSBiaW5kaW5nIHZpYSBiaW5kLSBvciBbXVxuICAgICAgcmVzdWx0cy5wdXNoKC4uLnByb3BlcnR5TmFtZXMoZWxlbS5uYW1lKSwgLi4ubmdBdHRycy5pbnB1dHMpO1xuICAgICAgYnJlYWs7XG5cbiAgICBjYXNlIEFUVFIuS1dfT046XG4gICAgY2FzZSBBVFRSLklERU5UX0VWRU5UOlxuICAgICAgLy8gZXZlbnQgYmluZGluZyB2aWEgb24tIG9yICgpXG4gICAgICByZXN1bHRzLnB1c2goLi4uZXZlbnROYW1lcyhlbGVtLm5hbWUpLCAuLi5uZ0F0dHJzLm91dHB1dHMpO1xuICAgICAgYnJlYWs7XG5cbiAgICBjYXNlIEFUVFIuS1dfQklORE9OOlxuICAgIGNhc2UgQVRUUi5JREVOVF9CQU5BTkFfQk9YOlxuICAgICAgLy8gYmFuYW5hLWluLWEtYm94IGJpbmRpbmcgdmlhIGJpbmRvbi0gb3IgWygpXVxuICAgICAgcmVzdWx0cy5wdXNoKC4uLm5nQXR0cnMuYmFuYW5hcyk7XG4gICAgICBicmVhaztcbiAgfVxuXG4gIHJldHVybiByZXN1bHRzLm1hcChuYW1lID0+IHtcbiAgICByZXR1cm4ge1xuICAgICAgbmFtZSxcbiAgICAgIGtpbmQ6IG5nLkNvbXBsZXRpb25LaW5kLkFUVFJJQlVURSxcbiAgICAgIHNvcnRUZXh0OiBuYW1lLFxuICAgIH07XG4gIH0pO1xufVxuXG5mdW5jdGlvbiBhdHRyaWJ1dGVDb21wbGV0aW9uc0ZvckVsZW1lbnQoXG4gICAgaW5mbzogbmcuQXN0UmVzdWx0LCBlbGVtZW50TmFtZTogc3RyaW5nKTogbmcuQ29tcGxldGlvbkVudHJ5W10ge1xuICBjb25zdCByZXN1bHRzOiBuZy5Db21wbGV0aW9uRW50cnlbXSA9IFtdO1xuXG4gIGlmIChpbmZvLnRlbXBsYXRlIGluc3RhbmNlb2YgSW5saW5lVGVtcGxhdGUpIHtcbiAgICAvLyBQcm92aWRlIEhUTUwgYXR0cmlidXRlcyBjb21wbGV0aW9uIG9ubHkgZm9yIGlubGluZSB0ZW1wbGF0ZXNcbiAgICBmb3IgKGNvbnN0IG5hbWUgb2YgYXR0cmlidXRlTmFtZXMoZWxlbWVudE5hbWUpKSB7XG4gICAgICByZXN1bHRzLnB1c2goe1xuICAgICAgICBuYW1lLFxuICAgICAgICBraW5kOiBuZy5Db21wbGV0aW9uS2luZC5IVE1MX0FUVFJJQlVURSxcbiAgICAgICAgc29ydFRleHQ6IG5hbWUsXG4gICAgICB9KTtcbiAgICB9XG4gIH1cblxuICAvLyBBZGQgQW5ndWxhciBhdHRyaWJ1dGVzXG4gIGNvbnN0IG5nQXR0cnMgPSBhbmd1bGFyQXR0cmlidXRlcyhpbmZvLCBlbGVtZW50TmFtZSk7XG4gIGZvciAoY29uc3QgbmFtZSBvZiBuZ0F0dHJzLm90aGVycykge1xuICAgIHJlc3VsdHMucHVzaCh7XG4gICAgICBuYW1lLFxuICAgICAga2luZDogbmcuQ29tcGxldGlvbktpbmQuQVRUUklCVVRFLFxuICAgICAgc29ydFRleHQ6IG5hbWUsXG4gICAgfSk7XG4gIH1cblxuICByZXR1cm4gcmVzdWx0cztcbn1cblxuLyoqXG4gKiBQcm92aWRlIGNvbXBsZXRpb25zIHRvIHRoZSBSSFMgb2YgYW4gYXR0cmlidXRlLCB3aGljaCBpcyBvZiB0aGUgZm9ybVxuICogTEhTPVwiUkhTXCIuIFRoZSB0ZW1wbGF0ZSBwYXRoIGlzIGNvbXB1dGVkIGZyb20gdGhlIHNwZWNpZmllZCBgaW5mb2Agd2hlcmVhc1xuICogdGhlIGNvbnRleHQgaXMgZGV0ZXJtaW5lZCBmcm9tIHRoZSBzcGVjaWZpZWQgYGh0bWxQYXRoYC5cbiAqIEBwYXJhbSBpbmZvIE9iamVjdCB0aGF0IGNvbnRhaW5zIHRoZSB0ZW1wbGF0ZSBBU1RcbiAqIEBwYXJhbSBodG1sUGF0aCBQYXRoIHRvIHRoZSBIVE1MIG5vZGVcbiAqL1xuZnVuY3Rpb24gYXR0cmlidXRlVmFsdWVDb21wbGV0aW9ucyhcbiAgICBpbmZvOiBuZy5Bc3RSZXN1bHQsIGh0bWxQYXRoOiBIdG1sQXN0UGF0aCk6IG5nLkNvbXBsZXRpb25FbnRyeVtdIHtcbiAgLy8gRmluZCB0aGUgY29ycmVzcG9uZGluZyBUZW1wbGF0ZSBBU1QgcGF0aC5cbiAgY29uc3QgdGVtcGxhdGVQYXRoID0gZmluZFRlbXBsYXRlQXN0QXQoaW5mby50ZW1wbGF0ZUFzdCwgaHRtbFBhdGgucG9zaXRpb24pO1xuICBjb25zdCB2aXNpdG9yID0gbmV3IEV4cHJlc3Npb25WaXNpdG9yKGluZm8sIGh0bWxQYXRoLnBvc2l0aW9uLCAoKSA9PiB7XG4gICAgY29uc3QgZGluZm8gPSBkaWFnbm9zdGljSW5mb0Zyb21UZW1wbGF0ZUluZm8oaW5mbyk7XG4gICAgcmV0dXJuIGdldEV4cHJlc3Npb25TY29wZShkaW5mbywgdGVtcGxhdGVQYXRoKTtcbiAgfSk7XG4gIGlmICh0ZW1wbGF0ZVBhdGgudGFpbCBpbnN0YW5jZW9mIEF0dHJBc3QgfHxcbiAgICAgIHRlbXBsYXRlUGF0aC50YWlsIGluc3RhbmNlb2YgQm91bmRFbGVtZW50UHJvcGVydHlBc3QgfHxcbiAgICAgIHRlbXBsYXRlUGF0aC50YWlsIGluc3RhbmNlb2YgQm91bmRFdmVudEFzdCkge1xuICAgIHRlbXBsYXRlUGF0aC50YWlsLnZpc2l0KHZpc2l0b3IsIG51bGwpO1xuICAgIHJldHVybiB2aXNpdG9yLnJlc3VsdHM7XG4gIH1cbiAgLy8gSW4gb3JkZXIgdG8gcHJvdmlkZSBhY2N1cmF0ZSBhdHRyaWJ1dGUgdmFsdWUgY29tcGxldGlvbiwgd2UgbmVlZCB0byBrbm93XG4gIC8vIHdoYXQgdGhlIExIUyBpcywgYW5kIGNvbnN0cnVjdCB0aGUgcHJvcGVyIEFTVCBpZiBpdCBpcyBtaXNzaW5nLlxuICBjb25zdCBodG1sQXR0ciA9IGh0bWxQYXRoLnRhaWwgYXMgQXR0cmlidXRlO1xuICBjb25zdCBiaW5kaW5nID0gZ2V0QmluZGluZ0Rlc2NyaXB0b3IoaHRtbEF0dHIubmFtZSk7XG4gIGlmIChiaW5kaW5nICYmIGJpbmRpbmcua2luZCA9PT0gQVRUUi5LV19SRUYpIHtcbiAgICBsZXQgcmVmQXN0OiBSZWZlcmVuY2VBc3R8dW5kZWZpbmVkO1xuICAgIGxldCBlbGVtQXN0OiBFbGVtZW50QXN0fHVuZGVmaW5lZDtcbiAgICBpZiAodGVtcGxhdGVQYXRoLnRhaWwgaW5zdGFuY2VvZiBSZWZlcmVuY2VBc3QpIHtcbiAgICAgIHJlZkFzdCA9IHRlbXBsYXRlUGF0aC50YWlsO1xuICAgICAgY29uc3QgcGFyZW50ID0gdGVtcGxhdGVQYXRoLnBhcmVudE9mKHJlZkFzdCk7XG4gICAgICBpZiAocGFyZW50IGluc3RhbmNlb2YgRWxlbWVudEFzdCkge1xuICAgICAgICBlbGVtQXN0ID0gcGFyZW50O1xuICAgICAgfVxuICAgIH0gZWxzZSBpZiAodGVtcGxhdGVQYXRoLnRhaWwgaW5zdGFuY2VvZiBFbGVtZW50QXN0KSB7XG4gICAgICByZWZBc3QgPSBuZXcgUmVmZXJlbmNlQXN0KGh0bWxBdHRyLm5hbWUsIG51bGwhLCBodG1sQXR0ci52YWx1ZSwgaHRtbEF0dHIudmFsdWVTcGFuISk7XG4gICAgICBlbGVtQXN0ID0gdGVtcGxhdGVQYXRoLnRhaWw7XG4gICAgfVxuICAgIGlmIChyZWZBc3QgJiYgZWxlbUFzdCkge1xuICAgICAgcmVmQXN0LnZpc2l0KHZpc2l0b3IsIGVsZW1Bc3QpO1xuICAgIH1cbiAgfSBlbHNlIHtcbiAgICAvLyBIdG1sQXN0IGNvbnRhaW5zIHRoZSBgQXR0cmlidXRlYCBub2RlLCBob3dldmVyIHRoZSBjb3JyZXNwb25kaW5nIGBBdHRyQXN0YFxuICAgIC8vIG5vZGUgaXMgbWlzc2luZyBmcm9tIHRoZSBUZW1wbGF0ZUFzdC5cbiAgICBjb25zdCBhdHRyQXN0ID0gbmV3IEF0dHJBc3QoaHRtbEF0dHIubmFtZSwgaHRtbEF0dHIudmFsdWUsIGh0bWxBdHRyLnZhbHVlU3BhbiEpO1xuICAgIGF0dHJBc3QudmlzaXQodmlzaXRvciwgbnVsbCk7XG4gIH1cbiAgcmV0dXJuIHZpc2l0b3IucmVzdWx0cztcbn1cblxuZnVuY3Rpb24gZWxlbWVudENvbXBsZXRpb25zKGluZm86IG5nLkFzdFJlc3VsdCk6IG5nLkNvbXBsZXRpb25FbnRyeVtdIHtcbiAgY29uc3QgcmVzdWx0czogbmcuQ29tcGxldGlvbkVudHJ5W10gPSBbLi4uQU5HVUxBUl9FTEVNRU5UU107XG5cbiAgaWYgKGluZm8udGVtcGxhdGUgaW5zdGFuY2VvZiBJbmxpbmVUZW1wbGF0ZSkge1xuICAgIC8vIFByb3ZpZGUgSFRNTCBlbGVtZW50cyBjb21wbGV0aW9uIG9ubHkgZm9yIGlubGluZSB0ZW1wbGF0ZXNcbiAgICByZXN1bHRzLnB1c2goLi4uSFRNTF9FTEVNRU5UUyk7XG4gIH1cblxuICAvLyBDb2xsZWN0IHRoZSBlbGVtZW50cyByZWZlcmVuY2VkIGJ5IHRoZSBzZWxlY3RvcnNcbiAgY29uc3QgY29tcG9uZW50cyA9IG5ldyBTZXQ8c3RyaW5nPigpO1xuICBmb3IgKGNvbnN0IHNlbGVjdG9yIG9mIGdldFNlbGVjdG9ycyhpbmZvKS5zZWxlY3RvcnMpIHtcbiAgICBjb25zdCBuYW1lID0gc2VsZWN0b3IuZWxlbWVudDtcbiAgICBpZiAobmFtZSAmJiAhY29tcG9uZW50cy5oYXMobmFtZSkpIHtcbiAgICAgIGNvbXBvbmVudHMuYWRkKG5hbWUpO1xuICAgICAgcmVzdWx0cy5wdXNoKHtcbiAgICAgICAgbmFtZSxcbiAgICAgICAga2luZDogbmcuQ29tcGxldGlvbktpbmQuQ09NUE9ORU5ULFxuICAgICAgICBzb3J0VGV4dDogbmFtZSxcbiAgICAgIH0pO1xuICAgIH1cbiAgfVxuXG4gIHJldHVybiByZXN1bHRzO1xufVxuXG4vLyBUaGVyZSBpcyBhIHNwZWNpYWwgY2FzZSBvZiBIVE1MIHdoZXJlIHRleHQgdGhhdCBjb250YWlucyBhIHVuY2xvc2VkIHRhZyBpcyB0cmVhdGVkIGFzXG4vLyB0ZXh0LiBGb3IgZXhhcGxlICc8aDE+IFNvbWUgPGEgdGV4dCA8L2gxPicgcHJvZHVjZXMgYSB0ZXh0IG5vZGVzIGluc2lkZSBvZiB0aGUgSDFcbi8vIGVsZW1lbnQgXCJTb21lIDxhIHRleHRcIi4gV2UsIGhvd2V2ZXIsIHdhbnQgdG8gdHJlYXQgdGhpcyBhcyBpZiB0aGUgdXNlciB3YXMgcmVxdWVzdGluZ1xuLy8gdGhlIGF0dHJpYnV0ZXMgb2YgYW4gXCJhXCIgZWxlbWVudCwgbm90IHJlcXVlc3RpbmcgY29tcGxldGlvbiBpbiB0aGUgYSB0ZXh0IGVsZW1lbnQuIFRoaXNcbi8vIGNvZGUgY2hlY2tzIGZvciB0aGlzIGNhc2UgYW5kIHJldHVybnMgZWxlbWVudCBjb21wbGV0aW9ucyBpZiBpdCBpcyBkZXRlY3RlZCBvciB1bmRlZmluZWRcbi8vIGlmIGl0IGlzIG5vdC5cbmZ1bmN0aW9uIHZvaWRFbGVtZW50QXR0cmlidXRlQ29tcGxldGlvbnMoXG4gICAgaW5mbzogbmcuQXN0UmVzdWx0LCBwYXRoOiBBc3RQYXRoPEh0bWxBc3Q+KTogbmcuQ29tcGxldGlvbkVudHJ5W10ge1xuICBjb25zdCB0YWlsID0gcGF0aC50YWlsO1xuICBpZiAodGFpbCBpbnN0YW5jZW9mIFRleHQpIHtcbiAgICBjb25zdCBtYXRjaCA9IHRhaWwudmFsdWUubWF0Y2goLzwoXFx3KFxcd3xcXGR8LSkqOik/KFxcdyhcXHd8XFxkfC0pKilcXHMvKTtcbiAgICAvLyBUaGUgcG9zaXRpb24gbXVzdCBiZSBhZnRlciB0aGUgbWF0Y2gsIG90aGVyd2lzZSB3ZSBhcmUgc3RpbGwgaW4gYSBwbGFjZSB3aGVyZSBlbGVtZW50c1xuICAgIC8vIGFyZSBleHBlY3RlZCAoc3VjaCBhcyBgPHxhYCBvciBgPGF8YDsgd2Ugb25seSB3YW50IGF0dHJpYnV0ZXMgZm9yIGA8YSB8YCBvciBhZnRlcikuXG4gICAgaWYgKG1hdGNoICYmXG4gICAgICAgIHBhdGgucG9zaXRpb24gPj0gKG1hdGNoLmluZGV4IHx8IDApICsgbWF0Y2hbMF0ubGVuZ3RoICsgdGFpbC5zb3VyY2VTcGFuLnN0YXJ0Lm9mZnNldCkge1xuICAgICAgcmV0dXJuIGF0dHJpYnV0ZUNvbXBsZXRpb25zRm9yRWxlbWVudChpbmZvLCBtYXRjaFszXSk7XG4gICAgfVxuICB9XG4gIHJldHVybiBbXTtcbn1cblxuY2xhc3MgRXhwcmVzc2lvblZpc2l0b3IgZXh0ZW5kcyBOdWxsVGVtcGxhdGVWaXNpdG9yIHtcbiAgcHJpdmF0ZSByZWFkb25seSBjb21wbGV0aW9ucyA9IG5ldyBNYXA8c3RyaW5nLCBuZy5Db21wbGV0aW9uRW50cnk+KCk7XG5cbiAgY29uc3RydWN0b3IoXG4gICAgICBwcml2YXRlIHJlYWRvbmx5IGluZm86IG5nLkFzdFJlc3VsdCwgcHJpdmF0ZSByZWFkb25seSBwb3NpdGlvbjogbnVtYmVyLFxuICAgICAgcHJpdmF0ZSByZWFkb25seSBnZXRFeHByZXNzaW9uU2NvcGU6ICgpID0+IG5nLlN5bWJvbFRhYmxlKSB7XG4gICAgc3VwZXIoKTtcbiAgfVxuXG4gIGdldCByZXN1bHRzKCk6IG5nLkNvbXBsZXRpb25FbnRyeVtdIHtcbiAgICByZXR1cm4gQXJyYXkuZnJvbSh0aGlzLmNvbXBsZXRpb25zLnZhbHVlcygpKTtcbiAgfVxuXG4gIHZpc2l0RGlyZWN0aXZlUHJvcGVydHkoYXN0OiBCb3VuZERpcmVjdGl2ZVByb3BlcnR5QXN0KTogdm9pZCB7XG4gICAgdGhpcy5wcm9jZXNzRXhwcmVzc2lvbkNvbXBsZXRpb25zKGFzdC52YWx1ZSk7XG4gIH1cblxuICB2aXNpdEVsZW1lbnRQcm9wZXJ0eShhc3Q6IEJvdW5kRWxlbWVudFByb3BlcnR5QXN0KTogdm9pZCB7XG4gICAgdGhpcy5wcm9jZXNzRXhwcmVzc2lvbkNvbXBsZXRpb25zKGFzdC52YWx1ZSk7XG4gIH1cblxuICB2aXNpdEV2ZW50KGFzdDogQm91bmRFdmVudEFzdCk6IHZvaWQge1xuICAgIHRoaXMucHJvY2Vzc0V4cHJlc3Npb25Db21wbGV0aW9ucyhhc3QuaGFuZGxlcik7XG4gIH1cblxuICB2aXNpdEVsZW1lbnQoKTogdm9pZCB7XG4gICAgLy8gbm8tb3AgZm9yIG5vd1xuICB9XG5cbiAgdmlzaXRBdHRyKGFzdDogQXR0ckFzdCkge1xuICAgIGNvbnN0IGJpbmRpbmcgPSBnZXRCaW5kaW5nRGVzY3JpcHRvcihhc3QubmFtZSk7XG4gICAgaWYgKGJpbmRpbmcgJiYgYmluZGluZy5raW5kID09PSBBVFRSLktXX01JQ1JPU1lOVEFYKSB7XG4gICAgICAvLyBUaGlzIGEgdGVtcGxhdGUgYmluZGluZyBnaXZlbiBieSBtaWNybyBzeW50YXggZXhwcmVzc2lvbi5cbiAgICAgIC8vIEZpcnN0LCB2ZXJpZnkgdGhlIGF0dHJpYnV0ZSBjb25zaXN0cyBvZiBzb21lIGJpbmRpbmcgd2UgY2FuIGdpdmUgY29tcGxldGlvbnMgZm9yLlxuICAgICAgLy8gVGhlIHNvdXJjZVNwYW4gb2YgQXR0ckFzdCBwb2ludHMgdG8gdGhlIFJIUyBvZiB0aGUgYXR0cmlidXRlXG4gICAgICBjb25zdCB0ZW1wbGF0ZUtleSA9IGJpbmRpbmcubmFtZTtcbiAgICAgIGNvbnN0IHRlbXBsYXRlVmFsdWUgPSBhc3Quc291cmNlU3Bhbi50b1N0cmluZygpO1xuICAgICAgY29uc3QgdGVtcGxhdGVVcmwgPSBhc3Quc291cmNlU3Bhbi5zdGFydC5maWxlLnVybDtcbiAgICAgIC8vIFRPRE8oa3lsaWF1KTogV2UgYXJlIHVuYWJsZSB0byBkZXRlcm1pbmUgdGhlIGFic29sdXRlIG9mZnNldCBvZiB0aGUga2V5XG4gICAgICAvLyBidXQgaXQgaXMgb2theSBoZXJlLCBiZWNhdXNlIHdlIGFyZSBvbmx5IGxvb2tpbmcgYXQgdGhlIFJIUyBvZiB0aGUgYXR0clxuICAgICAgY29uc3QgYWJzS2V5T2Zmc2V0ID0gMDtcbiAgICAgIGNvbnN0IGFic1ZhbHVlT2Zmc2V0ID0gYXN0LnNvdXJjZVNwYW4uc3RhcnQub2Zmc2V0O1xuICAgICAgY29uc3Qge3RlbXBsYXRlQmluZGluZ3N9ID0gdGhpcy5pbmZvLmV4cHJlc3Npb25QYXJzZXIucGFyc2VUZW1wbGF0ZUJpbmRpbmdzKFxuICAgICAgICAgIHRlbXBsYXRlS2V5LCB0ZW1wbGF0ZVZhbHVlLCB0ZW1wbGF0ZVVybCwgYWJzS2V5T2Zmc2V0LCBhYnNWYWx1ZU9mZnNldCk7XG4gICAgICAvLyBGaW5kIHRoZSBuZWFyZXN0IHRlbXBsYXRlIGJpbmRpbmcgdG8gdGhlIHBvc2l0aW9uLlxuICAgICAgY29uc3QgbGFzdEJpbmRpbmdFbmQgPSB0ZW1wbGF0ZUJpbmRpbmdzLmxlbmd0aCA+IDAgJiZcbiAgICAgICAgICB0ZW1wbGF0ZUJpbmRpbmdzW3RlbXBsYXRlQmluZGluZ3MubGVuZ3RoIC0gMV0uc291cmNlU3Bhbi5lbmQ7XG4gICAgICBjb25zdCBub3JtYWxpemVkUG9zaXRpb25Ub0JpbmRpbmcgPVxuICAgICAgICAgIGxhc3RCaW5kaW5nRW5kICYmIHRoaXMucG9zaXRpb24gPiBsYXN0QmluZGluZ0VuZCA/IGxhc3RCaW5kaW5nRW5kIDogdGhpcy5wb3NpdGlvbjtcbiAgICAgIGNvbnN0IHRlbXBsYXRlQmluZGluZyA9XG4gICAgICAgICAgdGVtcGxhdGVCaW5kaW5ncy5maW5kKGIgPT4gaW5TcGFuKG5vcm1hbGl6ZWRQb3NpdGlvblRvQmluZGluZywgYi5zb3VyY2VTcGFuKSk7XG5cbiAgICAgIGlmICghdGVtcGxhdGVCaW5kaW5nKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgdGhpcy5taWNyb1N5bnRheEluQXR0cmlidXRlVmFsdWUoYXN0LCB0ZW1wbGF0ZUJpbmRpbmcpO1xuICAgIH0gZWxzZSB7XG4gICAgICBjb25zdCBleHByZXNzaW9uQXN0ID0gdGhpcy5pbmZvLmV4cHJlc3Npb25QYXJzZXIucGFyc2VCaW5kaW5nKFxuICAgICAgICAgIGFzdC52YWx1ZSwgYXN0LnNvdXJjZVNwYW4udG9TdHJpbmcoKSwgYXN0LnNvdXJjZVNwYW4uc3RhcnQub2Zmc2V0KTtcbiAgICAgIHRoaXMucHJvY2Vzc0V4cHJlc3Npb25Db21wbGV0aW9ucyhleHByZXNzaW9uQXN0KTtcbiAgICB9XG4gIH1cblxuICB2aXNpdFJlZmVyZW5jZShfYXN0OiBSZWZlcmVuY2VBc3QsIGNvbnRleHQ6IEVsZW1lbnRBc3QpIHtcbiAgICBjb250ZXh0LmRpcmVjdGl2ZXMuZm9yRWFjaChkaXIgPT4ge1xuICAgICAgY29uc3Qge2V4cG9ydEFzfSA9IGRpci5kaXJlY3RpdmU7XG4gICAgICBpZiAoZXhwb3J0QXMpIHtcbiAgICAgICAgdGhpcy5jb21wbGV0aW9ucy5zZXQoXG4gICAgICAgICAgICBleHBvcnRBcywge25hbWU6IGV4cG9ydEFzLCBraW5kOiBuZy5Db21wbGV0aW9uS2luZC5SRUZFUkVOQ0UsIHNvcnRUZXh0OiBleHBvcnRBc30pO1xuICAgICAgfVxuICAgIH0pO1xuICB9XG5cbiAgdmlzaXRCb3VuZFRleHQoYXN0OiBCb3VuZFRleHRBc3QpIHtcbiAgICBpZiAoaW5TcGFuKHRoaXMucG9zaXRpb24sIGFzdC52YWx1ZS5zb3VyY2VTcGFuKSkge1xuICAgICAgY29uc3QgY29tcGxldGlvbnMgPSBnZXRFeHByZXNzaW9uQ29tcGxldGlvbnMoXG4gICAgICAgICAgdGhpcy5nZXRFeHByZXNzaW9uU2NvcGUoKSwgYXN0LnZhbHVlLCB0aGlzLnBvc2l0aW9uLCB0aGlzLmluZm8udGVtcGxhdGUpO1xuICAgICAgaWYgKGNvbXBsZXRpb25zKSB7XG4gICAgICAgIHRoaXMuYWRkU3ltYm9sc1RvQ29tcGxldGlvbnMoY29tcGxldGlvbnMpO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIHByaXZhdGUgcHJvY2Vzc0V4cHJlc3Npb25Db21wbGV0aW9ucyh2YWx1ZTogQVNUKSB7XG4gICAgY29uc3Qgc3ltYm9scyA9IGdldEV4cHJlc3Npb25Db21wbGV0aW9ucyhcbiAgICAgICAgdGhpcy5nZXRFeHByZXNzaW9uU2NvcGUoKSwgdmFsdWUsIHRoaXMucG9zaXRpb24sIHRoaXMuaW5mby50ZW1wbGF0ZSk7XG4gICAgaWYgKHN5bWJvbHMpIHtcbiAgICAgIHRoaXMuYWRkU3ltYm9sc1RvQ29tcGxldGlvbnMoc3ltYm9scyk7XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBhZGRTeW1ib2xzVG9Db21wbGV0aW9ucyhzeW1ib2xzOiBuZy5TeW1ib2xbXSkge1xuICAgIGZvciAoY29uc3QgcyBvZiBzeW1ib2xzKSB7XG4gICAgICBpZiAocy5uYW1lLnN0YXJ0c1dpdGgoJ19fJykgfHwgIXMucHVibGljIHx8IHRoaXMuY29tcGxldGlvbnMuaGFzKHMubmFtZSkpIHtcbiAgICAgICAgY29udGludWU7XG4gICAgICB9XG5cbiAgICAgIC8vIFRoZSBwaXBlIG1ldGhvZCBzaG91bGQgbm90IGluY2x1ZGUgcGFyZW50aGVzZXMuXG4gICAgICAvLyBlLmcuIHt7IHZhbHVlX2V4cHJlc3Npb24gfCBzbGljZSA6IHN0YXJ0IFsgOiBlbmQgXSB9fVxuICAgICAgY29uc3Qgc2hvdWxkSW5zZXJ0UGFyZW50aGVzZXMgPSBzLmNhbGxhYmxlICYmIHMua2luZCAhPT0gbmcuQ29tcGxldGlvbktpbmQuUElQRTtcbiAgICAgIHRoaXMuY29tcGxldGlvbnMuc2V0KHMubmFtZSwge1xuICAgICAgICBuYW1lOiBzLm5hbWUsXG4gICAgICAgIGtpbmQ6IHMua2luZCBhcyBuZy5Db21wbGV0aW9uS2luZCxcbiAgICAgICAgc29ydFRleHQ6IHMubmFtZSxcbiAgICAgICAgaW5zZXJ0VGV4dDogc2hvdWxkSW5zZXJ0UGFyZW50aGVzZXMgPyBgJHtzLm5hbWV9KClgIDogcy5uYW1lLFxuICAgICAgfSk7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIFRoaXMgbWV0aG9kIGhhbmRsZXMgdGhlIGNvbXBsZXRpb25zIG9mIGF0dHJpYnV0ZSB2YWx1ZXMgZm9yIGRpcmVjdGl2ZXMgdGhhdFxuICAgKiBzdXBwb3J0IHRoZSBtaWNyb3N5bnRheCBmb3JtYXQuIEV4YW1wbGVzIGFyZSAqbmdGb3IgYW5kICpuZ0lmLlxuICAgKiBUaGVzZSBkaXJlY3RpdmVzIGFsbG93cyBkZWNsYXJhdGlvbiBvZiBcImxldFwiIHZhcmlhYmxlcywgYWRkcyBjb250ZXh0LXNwZWNpZmljXG4gICAqIHN5bWJvbHMgbGlrZSAkaW1wbGljaXQsIGluZGV4LCBjb3VudCwgYW1vbmcgb3RoZXIgYmVoYXZpb3JzLlxuICAgKiBGb3IgYSBjb21wbGV0ZSBkZXNjcmlwdGlvbiBvZiBzdWNoIGZvcm1hdCwgc2VlXG4gICAqIGh0dHBzOi8vYW5ndWxhci5pby9ndWlkZS9zdHJ1Y3R1cmFsLWRpcmVjdGl2ZXMjdGhlLWFzdGVyaXNrLS1wcmVmaXhcbiAgICpcbiAgICogQHBhcmFtIGF0dHIgZGVzY3JpcHRvciBmb3IgYXR0cmlidXRlIG5hbWUgYW5kIHZhbHVlIHBhaXJcbiAgICogQHBhcmFtIGJpbmRpbmcgdGVtcGxhdGUgYmluZGluZyBmb3IgdGhlIGV4cHJlc3Npb24gaW4gdGhlIGF0dHJpYnV0ZVxuICAgKi9cbiAgcHJpdmF0ZSBtaWNyb1N5bnRheEluQXR0cmlidXRlVmFsdWUoYXR0cjogQXR0ckFzdCwgYmluZGluZzogVGVtcGxhdGVCaW5kaW5nKSB7XG4gICAgY29uc3Qga2V5ID0gYXR0ci5uYW1lLnN1YnN0cmluZygxKTsgIC8vIHJlbW92ZSBsZWFkaW5nIGFzdGVyaXNrXG5cbiAgICAvLyBGaW5kIHRoZSBzZWxlY3RvciAtIGVnIG5nRm9yLCBuZ0lmLCBldGNcbiAgICBjb25zdCBzZWxlY3RvckluZm8gPSBnZXRTZWxlY3RvcnModGhpcy5pbmZvKTtcbiAgICBjb25zdCBzZWxlY3RvciA9IHNlbGVjdG9ySW5mby5zZWxlY3RvcnMuZmluZChzID0+IHtcbiAgICAgIC8vIGF0dHJpYnV0ZXMgYXJlIGxpc3RlZCBpbiAoYXR0cmlidXRlLCB2YWx1ZSkgcGFpcnNcbiAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgcy5hdHRycy5sZW5ndGg7IGkgKz0gMikge1xuICAgICAgICBpZiAocy5hdHRyc1tpXSA9PT0ga2V5KSB7XG4gICAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9KTtcblxuICAgIGlmICghc2VsZWN0b3IpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBjb25zdCB2YWx1ZVJlbGF0aXZlUG9zaXRpb24gPSB0aGlzLnBvc2l0aW9uIC0gYXR0ci5zb3VyY2VTcGFuLnN0YXJ0Lm9mZnNldDtcblxuICAgIGlmIChiaW5kaW5nIGluc3RhbmNlb2YgVmFyaWFibGVCaW5kaW5nKSB7XG4gICAgICAvLyBUT0RPKGt5bGlhdSk6IFdpdGggZXhwcmVzc2lvbiBzb3VyY2VTcGFuIHdlIHNob3VsZG4ndCBoYXZlIHRvIHNlYXJjaFxuICAgICAgLy8gdGhlIGF0dHJpYnV0ZSB2YWx1ZSBzdHJpbmcgYW55bW9yZS4gSnVzdCBjaGVjayBpZiBwb3NpdGlvbiBpcyBpbiB0aGVcbiAgICAgIC8vIGV4cHJlc3Npb24gc291cmNlIHNwYW4uXG4gICAgICBjb25zdCBlcXVhbExvY2F0aW9uID0gYXR0ci52YWx1ZS5pbmRleE9mKCc9Jyk7XG4gICAgICBpZiAoZXF1YWxMb2NhdGlvbiA+IDAgJiYgdmFsdWVSZWxhdGl2ZVBvc2l0aW9uID4gZXF1YWxMb2NhdGlvbikge1xuICAgICAgICAvLyBXZSBhcmUgYWZ0ZXIgdGhlICc9JyBpbiBhIGxldCBjbGF1c2UuIFRoZSB2YWxpZCB2YWx1ZXMgaGVyZSBhcmUgdGhlIG1lbWJlcnMgb2YgdGhlXG4gICAgICAgIC8vIHRlbXBsYXRlIHJlZmVyZW5jZSdzIHR5cGUgcGFyYW1ldGVyLlxuICAgICAgICBjb25zdCBkaXJlY3RpdmVNZXRhZGF0YSA9IHNlbGVjdG9ySW5mby5tYXAuZ2V0KHNlbGVjdG9yKTtcbiAgICAgICAgaWYgKGRpcmVjdGl2ZU1ldGFkYXRhKSB7XG4gICAgICAgICAgY29uc3QgY29udGV4dFRhYmxlID1cbiAgICAgICAgICAgICAgdGhpcy5pbmZvLnRlbXBsYXRlLnF1ZXJ5LmdldFRlbXBsYXRlQ29udGV4dChkaXJlY3RpdmVNZXRhZGF0YS50eXBlLnJlZmVyZW5jZSk7XG4gICAgICAgICAgaWYgKGNvbnRleHRUYWJsZSkge1xuICAgICAgICAgICAgLy8gVGhpcyBhZGRzIHN5bWJvbHMgbGlrZSAkaW1wbGljaXQsIGluZGV4LCBjb3VudCwgZXRjLlxuICAgICAgICAgICAgdGhpcy5hZGRTeW1ib2xzVG9Db21wbGV0aW9ucyhjb250ZXh0VGFibGUudmFsdWVzKCkpO1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfVxuICAgIH0gZWxzZSBpZiAoYmluZGluZyBpbnN0YW5jZW9mIEV4cHJlc3Npb25CaW5kaW5nKSB7XG4gICAgICBpZiAoaW5TcGFuKHRoaXMucG9zaXRpb24sIGJpbmRpbmcudmFsdWU/LmFzdC5zb3VyY2VTcGFuKSkge1xuICAgICAgICB0aGlzLnByb2Nlc3NFeHByZXNzaW9uQ29tcGxldGlvbnMoYmluZGluZy52YWx1ZSEuYXN0KTtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfSBlbHNlIGlmICghYmluZGluZy52YWx1ZSAmJiB0aGlzLnBvc2l0aW9uID4gYmluZGluZy5rZXkuc3Bhbi5lbmQpIHtcbiAgICAgICAgLy8gTm8gZXhwcmVzc2lvbiBpcyBkZWZpbmVkIGZvciB0aGUgdmFsdWUgb2YgdGhlIGtleSBleHByZXNzaW9uIGJpbmRpbmcsIGJ1dCB0aGUgY3Vyc29yIGlzXG4gICAgICAgIC8vIGluIGEgbG9jYXRpb24gd2hlcmUgdGhlIGV4cHJlc3Npb24gd291bGQgYmUgZGVmaW5lZC4gVGhpcyBjYW4gaGFwcGVuIGluIGEgY2FzZSBsaWtlXG4gICAgICAgIC8vICAgbGV0IGkgb2YgfFxuICAgICAgICAvLyAgICAgICAgICAgIF4tLSBjdXJzb3JcbiAgICAgICAgLy8gSW4gdGhpcyBjYXNlLCBiYWNrZmlsbCB0aGUgdmFsdWUgdG8gYmUgYW4gZW1wdHkgZXhwcmVzc2lvbiBhbmQgcmV0cmlldmUgY29tcGxldGlvbnMuXG4gICAgICAgIHRoaXMucHJvY2Vzc0V4cHJlc3Npb25Db21wbGV0aW9ucyhuZXcgRW1wdHlFeHByKFxuICAgICAgICAgICAgbmV3IFBhcnNlU3Bhbih2YWx1ZVJlbGF0aXZlUG9zaXRpb24sIHZhbHVlUmVsYXRpdmVQb3NpdGlvbiksXG4gICAgICAgICAgICBuZXcgQWJzb2x1dGVTb3VyY2VTcGFuKHRoaXMucG9zaXRpb24sIHRoaXMucG9zaXRpb24pKSk7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cbiAgICB9XG4gIH1cbn1cblxuaW50ZXJmYWNlIEFuZ3VsYXJBdHRyaWJ1dGVzIHtcbiAgLyoqXG4gICAqIEF0dHJpYnV0ZXMgdGhhdCBzdXBwb3J0IHRoZSAqIHN5bnRheC4gU2VlIGh0dHBzOi8vYW5ndWxhci5pby9hcGkvY29yZS9UZW1wbGF0ZVJlZlxuICAgKi9cbiAgdGVtcGxhdGVSZWZzOiBTZXQ8c3RyaW5nPjtcbiAgLyoqXG4gICAqIEF0dHJpYnV0ZXMgd2l0aCB0aGUgQElucHV0IGFubm90YXRpb24uXG4gICAqL1xuICBpbnB1dHM6IFNldDxzdHJpbmc+O1xuICAvKipcbiAgICogQXR0cmlidXRlcyB3aXRoIHRoZSBAT3V0cHV0IGFubm90YXRpb24uXG4gICAqL1xuICBvdXRwdXRzOiBTZXQ8c3RyaW5nPjtcbiAgLyoqXG4gICAqIEF0dHJpYnV0ZXMgdGhhdCBzdXBwb3J0IHRoZSBbKCldIG9yIGJpbmRvbi0gc3ludGF4LlxuICAgKi9cbiAgYmFuYW5hczogU2V0PHN0cmluZz47XG4gIC8qKlxuICAgKiBHZW5lcmFsIGF0dHJpYnV0ZXMgdGhhdCBtYXRjaCB0aGUgc3BlY2lmaWVkIGVsZW1lbnQuXG4gICAqL1xuICBvdGhlcnM6IFNldDxzdHJpbmc+O1xufVxuXG4vKipcbiAqIFJldHVybiBhbGwgQW5ndWxhci1zcGVjaWZpYyBhdHRyaWJ1dGVzIGZvciB0aGUgZWxlbWVudCB3aXRoIGBlbGVtZW50TmFtZWAuXG4gKiBAcGFyYW0gaW5mb1xuICogQHBhcmFtIGVsZW1lbnROYW1lXG4gKi9cbmZ1bmN0aW9uIGFuZ3VsYXJBdHRyaWJ1dGVzKGluZm86IG5nLkFzdFJlc3VsdCwgZWxlbWVudE5hbWU6IHN0cmluZyk6IEFuZ3VsYXJBdHRyaWJ1dGVzIHtcbiAgY29uc3Qge3NlbGVjdG9ycywgbWFwOiBzZWxlY3Rvck1hcH0gPSBnZXRTZWxlY3RvcnMoaW5mbyk7XG4gIGNvbnN0IHRlbXBsYXRlUmVmcyA9IG5ldyBTZXQ8c3RyaW5nPigpO1xuICBjb25zdCBpbnB1dHMgPSBuZXcgU2V0PHN0cmluZz4oKTtcbiAgY29uc3Qgb3V0cHV0cyA9IG5ldyBTZXQ8c3RyaW5nPigpO1xuICBjb25zdCBiYW5hbmFzID0gbmV3IFNldDxzdHJpbmc+KCk7XG4gIGNvbnN0IG90aGVycyA9IG5ldyBTZXQ8c3RyaW5nPigpO1xuICBmb3IgKGNvbnN0IHNlbGVjdG9yIG9mIHNlbGVjdG9ycykge1xuICAgIGlmIChzZWxlY3Rvci5lbGVtZW50ICYmIHNlbGVjdG9yLmVsZW1lbnQgIT09IGVsZW1lbnROYW1lKSB7XG4gICAgICBjb250aW51ZTtcbiAgICB9XG4gICAgY29uc3Qgc3VtbWFyeSA9IHNlbGVjdG9yTWFwLmdldChzZWxlY3RvcikhO1xuICAgIGNvbnN0IGhhc1RlbXBsYXRlUmVmID0gaXNTdHJ1Y3R1cmFsRGlyZWN0aXZlKHN1bW1hcnkudHlwZSk7XG4gICAgLy8gYXR0cmlidXRlcyBhcmUgbGlzdGVkIGluIChhdHRyaWJ1dGUsIHZhbHVlKSBwYWlyc1xuICAgIGZvciAobGV0IGkgPSAwOyBpIDwgc2VsZWN0b3IuYXR0cnMubGVuZ3RoOyBpICs9IDIpIHtcbiAgICAgIGNvbnN0IGF0dHIgPSBzZWxlY3Rvci5hdHRyc1tpXTtcbiAgICAgIGlmIChoYXNUZW1wbGF0ZVJlZikge1xuICAgICAgICB0ZW1wbGF0ZVJlZnMuYWRkKGF0dHIpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgb3RoZXJzLmFkZChhdHRyKTtcbiAgICAgIH1cbiAgICB9XG4gICAgZm9yIChjb25zdCBpbnB1dCBvZiBPYmplY3QudmFsdWVzKHN1bW1hcnkuaW5wdXRzKSkge1xuICAgICAgaW5wdXRzLmFkZChpbnB1dCk7XG4gICAgfVxuICAgIGZvciAoY29uc3Qgb3V0cHV0IG9mIE9iamVjdC52YWx1ZXMoc3VtbWFyeS5vdXRwdXRzKSkge1xuICAgICAgb3V0cHV0cy5hZGQob3V0cHV0KTtcbiAgICB9XG4gIH1cbiAgZm9yIChjb25zdCBuYW1lIG9mIGlucHV0cykge1xuICAgIC8vIEFkZCBiYW5hbmEtaW4tYS1ib3ggc3ludGF4XG4gICAgLy8gaHR0cHM6Ly9hbmd1bGFyLmlvL2d1aWRlL3RlbXBsYXRlLXN5bnRheCN0d28td2F5LWJpbmRpbmctXG4gICAgaWYgKG91dHB1dHMuaGFzKGAke25hbWV9Q2hhbmdlYCkpIHtcbiAgICAgIGJhbmFuYXMuYWRkKG5hbWUpO1xuICAgIH1cbiAgfVxuICByZXR1cm4ge3RlbXBsYXRlUmVmcywgaW5wdXRzLCBvdXRwdXRzLCBiYW5hbmFzLCBvdGhlcnN9O1xufVxuIl19
\No newline at end of file