UNPKG

74.5 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/ivy/attribute_completions", ["require", "exports", "tslib", "@angular/compiler", "typescript", "@angular/language-service/ivy/display_parts", "@angular/language-service/ivy/utils"], factory);
15 }
16})(function (require, exports) {
17 "use strict";
18 Object.defineProperty(exports, "__esModule", { value: true });
19 exports.getAttributeCompletionSymbol = exports.addAttributeCompletionEntries = exports.buildAttributeCompletionTable = exports.AttributeCompletionKind = void 0;
20 var tslib_1 = require("tslib");
21 var compiler_1 = require("@angular/compiler");
22 var ts = require("typescript");
23 var display_parts_1 = require("@angular/language-service/ivy/display_parts");
24 var utils_1 = require("@angular/language-service/ivy/utils");
25 /**
26 * Differentiates different kinds of `AttributeCompletion`s.
27 */
28 var AttributeCompletionKind;
29 (function (AttributeCompletionKind) {
30 /**
31 * Completion of an attribute from the HTML schema.
32 *
33 * Attributes often have a corresponding DOM property of the same name.
34 */
35 AttributeCompletionKind[AttributeCompletionKind["DomAttribute"] = 0] = "DomAttribute";
36 /**
37 * Completion of a property from the DOM schema.
38 *
39 * `DomProperty` completions are generated only for properties which don't share their name with
40 * an HTML attribute.
41 */
42 AttributeCompletionKind[AttributeCompletionKind["DomProperty"] = 1] = "DomProperty";
43 /**
44 * Completion of an attribute that results in a new directive being matched on an element.
45 */
46 AttributeCompletionKind[AttributeCompletionKind["DirectiveAttribute"] = 2] = "DirectiveAttribute";
47 /**
48 * Completion of an attribute that results in a new structural directive being matched on an
49 * element.
50 */
51 AttributeCompletionKind[AttributeCompletionKind["StructuralDirectiveAttribute"] = 3] = "StructuralDirectiveAttribute";
52 /**
53 * Completion of an input from a directive which is either present on the element, or becomes
54 * present after the addition of this attribute.
55 */
56 AttributeCompletionKind[AttributeCompletionKind["DirectiveInput"] = 4] = "DirectiveInput";
57 /**
58 * Completion of an output from a directive which is either present on the element, or becomes
59 * present after the addition of this attribute.
60 */
61 AttributeCompletionKind[AttributeCompletionKind["DirectiveOutput"] = 5] = "DirectiveOutput";
62 })(AttributeCompletionKind = exports.AttributeCompletionKind || (exports.AttributeCompletionKind = {}));
63 /**
64 * Given an element and its context, produce a `Map` of all possible attribute completions.
65 *
66 * 3 kinds of attributes are considered for completion, from highest to lowest priority:
67 *
68 * 1. Inputs/outputs of directives present on the element already.
69 * 2. Inputs/outputs of directives that are not present on the element, but which would become
70 * present if such a binding is added.
71 * 3. Attributes from the DOM schema for the element.
72 *
73 * The priority of these options determines which completions are added to the `Map`. If a directive
74 * input shares the same name as a DOM attribute, the `Map` will reflect the directive input
75 * completion, not the DOM completion for that name.
76 */
77 function buildAttributeCompletionTable(component, element, checker) {
78 var e_1, _a, e_2, _b, e_3, _c, e_4, _d, e_5, _e, e_6, _f, e_7, _g, e_8, _h;
79 var table = new Map();
80 // Use the `ElementSymbol` or `TemplateSymbol` to iterate over directives present on the node, and
81 // their inputs/outputs. These have the highest priority of completion results.
82 var symbol = checker.getSymbolOfNode(element, component);
83 var presentDirectives = new Set();
84 if (symbol !== null) {
85 try {
86 // An `ElementSymbol` was available. This means inputs and outputs for directives on the
87 // element can be added to the completion table.
88 for (var _j = tslib_1.__values(symbol.directives), _k = _j.next(); !_k.done; _k = _j.next()) {
89 var dirSymbol = _k.value;
90 var directive = dirSymbol.tsSymbol.valueDeclaration;
91 if (!ts.isClassDeclaration(directive)) {
92 continue;
93 }
94 presentDirectives.add(directive);
95 var meta = checker.getDirectiveMetadata(directive);
96 if (meta === null) {
97 continue;
98 }
99 try {
100 for (var _l = (e_2 = void 0, tslib_1.__values(meta.inputs)), _m = _l.next(); !_m.done; _m = _l.next()) {
101 var _o = tslib_1.__read(_m.value, 2), propertyName = _o[0], classPropertyName = _o[1];
102 if (table.has(propertyName)) {
103 continue;
104 }
105 table.set(propertyName, {
106 kind: AttributeCompletionKind.DirectiveInput,
107 propertyName: propertyName,
108 directive: dirSymbol,
109 classPropertyName: classPropertyName,
110 twoWayBindingSupported: meta.outputs.hasBindingPropertyName(propertyName + 'Change'),
111 });
112 }
113 }
114 catch (e_2_1) { e_2 = { error: e_2_1 }; }
115 finally {
116 try {
117 if (_m && !_m.done && (_b = _l.return)) _b.call(_l);
118 }
119 finally { if (e_2) throw e_2.error; }
120 }
121 try {
122 for (var _p = (e_3 = void 0, tslib_1.__values(meta.outputs)), _q = _p.next(); !_q.done; _q = _p.next()) {
123 var _r = tslib_1.__read(_q.value, 2), propertyName = _r[0], classPropertyName = _r[1];
124 if (table.has(propertyName)) {
125 continue;
126 }
127 table.set(propertyName, {
128 kind: AttributeCompletionKind.DirectiveOutput,
129 eventName: propertyName,
130 directive: dirSymbol,
131 classPropertyName: classPropertyName,
132 });
133 }
134 }
135 catch (e_3_1) { e_3 = { error: e_3_1 }; }
136 finally {
137 try {
138 if (_q && !_q.done && (_c = _p.return)) _c.call(_p);
139 }
140 finally { if (e_3) throw e_3.error; }
141 }
142 }
143 }
144 catch (e_1_1) { e_1 = { error: e_1_1 }; }
145 finally {
146 try {
147 if (_k && !_k.done && (_a = _j.return)) _a.call(_j);
148 }
149 finally { if (e_1) throw e_1.error; }
150 }
151 }
152 // Next, explore hypothetical directives and determine if the addition of any single attributes
153 // can cause the directive to match the element.
154 var directivesInScope = checker.getDirectivesInScope(component);
155 if (directivesInScope !== null) {
156 var elementSelector = utils_1.makeElementSelector(element);
157 try {
158 for (var directivesInScope_1 = tslib_1.__values(directivesInScope), directivesInScope_1_1 = directivesInScope_1.next(); !directivesInScope_1_1.done; directivesInScope_1_1 = directivesInScope_1.next()) {
159 var dirInScope = directivesInScope_1_1.value;
160 var directive = dirInScope.tsSymbol.valueDeclaration;
161 // Skip directives that are present on the element.
162 if (!ts.isClassDeclaration(directive) || presentDirectives.has(directive)) {
163 continue;
164 }
165 var meta = checker.getDirectiveMetadata(directive);
166 if (meta === null || meta.selector === null) {
167 continue;
168 }
169 if (!meta.isStructural) {
170 // For non-structural directives, the directive's attribute selector(s) are matched against
171 // a hypothetical version of the element with those attributes. A match indicates that
172 // adding that attribute/input/output binding would cause the directive to become present,
173 // meaning that such a binding is a valid completion.
174 var selectors = compiler_1.CssSelector.parse(meta.selector);
175 var matcher = new compiler_1.SelectorMatcher();
176 matcher.addSelectables(selectors);
177 try {
178 for (var selectors_1 = (e_5 = void 0, tslib_1.__values(selectors)), selectors_1_1 = selectors_1.next(); !selectors_1_1.done; selectors_1_1 = selectors_1.next()) {
179 var selector = selectors_1_1.value;
180 try {
181 for (var _s = (e_6 = void 0, tslib_1.__values(selectorAttributes(selector))), _t = _s.next(); !_t.done; _t = _s.next()) {
182 var _u = tslib_1.__read(_t.value, 2), attrName = _u[0], attrValue = _u[1];
183 if (attrValue !== '') {
184 // This attribute selector requires a value, which is not supported in completion.
185 continue;
186 }
187 if (table.has(attrName)) {
188 // Skip this attribute as there's already a binding for it.
189 continue;
190 }
191 // Check whether adding this attribute would cause the directive to start matching.
192 var newElementSelector = elementSelector + ("[" + attrName + "]");
193 if (!matcher.match(compiler_1.CssSelector.parse(newElementSelector)[0], null)) {
194 // Nope, move on with our lives.
195 continue;
196 }
197 // Adding this attribute causes a new directive to be matched. Decide how to categorize
198 // it based on the directive's inputs and outputs.
199 if (meta.inputs.hasBindingPropertyName(attrName)) {
200 // This attribute corresponds to an input binding.
201 table.set(attrName, {
202 kind: AttributeCompletionKind.DirectiveInput,
203 directive: dirInScope,
204 propertyName: attrName,
205 classPropertyName: meta.inputs.getByBindingPropertyName(attrName)[0].classPropertyName,
206 twoWayBindingSupported: meta.outputs.hasBindingPropertyName(attrName + 'Change'),
207 });
208 }
209 else if (meta.outputs.hasBindingPropertyName(attrName)) {
210 // This attribute corresponds to an output binding.
211 table.set(attrName, {
212 kind: AttributeCompletionKind.DirectiveOutput,
213 directive: dirInScope,
214 eventName: attrName,
215 classPropertyName: meta.outputs.getByBindingPropertyName(attrName)[0].classPropertyName,
216 });
217 }
218 else {
219 // This attribute causes a new directive to be matched, but does not also correspond
220 // to an input or output binding.
221 table.set(attrName, {
222 kind: AttributeCompletionKind.DirectiveAttribute,
223 attribute: attrName,
224 directive: dirInScope,
225 });
226 }
227 }
228 }
229 catch (e_6_1) { e_6 = { error: e_6_1 }; }
230 finally {
231 try {
232 if (_t && !_t.done && (_f = _s.return)) _f.call(_s);
233 }
234 finally { if (e_6) throw e_6.error; }
235 }
236 }
237 }
238 catch (e_5_1) { e_5 = { error: e_5_1 }; }
239 finally {
240 try {
241 if (selectors_1_1 && !selectors_1_1.done && (_e = selectors_1.return)) _e.call(selectors_1);
242 }
243 finally { if (e_5) throw e_5.error; }
244 }
245 }
246 else {
247 // Hypothetically matching a structural directive is a litle different than a plain
248 // directive. Use of the '*' structural directive syntactic sugar means that the actual
249 // directive is applied to a plain <ng-template> node, not the existing element with any
250 // other attributes it might already have.
251 // Additionally, more than one attribute/input might need to be present in order for the
252 // directive to match (e.g. `ngFor` has a selector of `[ngFor][ngForOf]`). This gets a
253 // little tricky.
254 var structuralAttributes = getStructuralAttributes(meta);
255 try {
256 for (var structuralAttributes_1 = (e_7 = void 0, tslib_1.__values(structuralAttributes)), structuralAttributes_1_1 = structuralAttributes_1.next(); !structuralAttributes_1_1.done; structuralAttributes_1_1 = structuralAttributes_1.next()) {
257 var attrName = structuralAttributes_1_1.value;
258 table.set(attrName, {
259 kind: AttributeCompletionKind.StructuralDirectiveAttribute,
260 attribute: attrName,
261 directive: dirInScope,
262 });
263 }
264 }
265 catch (e_7_1) { e_7 = { error: e_7_1 }; }
266 finally {
267 try {
268 if (structuralAttributes_1_1 && !structuralAttributes_1_1.done && (_g = structuralAttributes_1.return)) _g.call(structuralAttributes_1);
269 }
270 finally { if (e_7) throw e_7.error; }
271 }
272 }
273 }
274 }
275 catch (e_4_1) { e_4 = { error: e_4_1 }; }
276 finally {
277 try {
278 if (directivesInScope_1_1 && !directivesInScope_1_1.done && (_d = directivesInScope_1.return)) _d.call(directivesInScope_1);
279 }
280 finally { if (e_4) throw e_4.error; }
281 }
282 }
283 // Finally, add any DOM attributes not already covered by inputs.
284 if (element instanceof compiler_1.TmplAstElement) {
285 try {
286 for (var _v = tslib_1.__values(checker.getPotentialDomBindings(element.name)), _w = _v.next(); !_w.done; _w = _v.next()) {
287 var _x = _w.value, attribute = _x.attribute, property = _x.property;
288 var isAlsoProperty = attribute === property;
289 if (!table.has(attribute)) {
290 table.set(attribute, {
291 kind: AttributeCompletionKind.DomAttribute,
292 attribute: attribute,
293 isAlsoProperty: isAlsoProperty,
294 });
295 }
296 if (!isAlsoProperty && !table.has(property)) {
297 table.set(property, {
298 kind: AttributeCompletionKind.DomProperty,
299 property: property,
300 });
301 }
302 }
303 }
304 catch (e_8_1) { e_8 = { error: e_8_1 }; }
305 finally {
306 try {
307 if (_w && !_w.done && (_h = _v.return)) _h.call(_v);
308 }
309 finally { if (e_8) throw e_8.error; }
310 }
311 }
312 return table;
313 }
314 exports.buildAttributeCompletionTable = buildAttributeCompletionTable;
315 /**
316 * Given an `AttributeCompletion`, add any available completions to a `ts.CompletionEntry` array of
317 * results.
318 *
319 * The kind of completions generated depends on whether the current context is an attribute context
320 * or not. For example, completing on `<element attr|>` will generate two results: `attribute` and
321 * `[attribute]` - either a static attribute can be generated, or a property binding. However,
322 * `<element [attr|]>` is not an attribute context, and so only the property completion `attribute`
323 * is generated. Note that this completion does not have the `[]` property binding sugar as its
324 * implicitly present in a property binding context (we're already completing within an `[attr|]`
325 * expression).
326 */
327 function addAttributeCompletionEntries(entries, completion, isAttributeContext, isElementContext, replacementSpan) {
328 switch (completion.kind) {
329 case AttributeCompletionKind.DirectiveAttribute: {
330 entries.push({
331 kind: display_parts_1.unsafeCastDisplayInfoKindToScriptElementKind(display_parts_1.DisplayInfoKind.DIRECTIVE),
332 name: completion.attribute,
333 sortText: completion.attribute,
334 replacementSpan: replacementSpan,
335 });
336 break;
337 }
338 case AttributeCompletionKind.StructuralDirectiveAttribute: {
339 // In an element, the completion is offered with a leading '*' to activate the structural
340 // directive. Once present, the structural attribute will be parsed as a template and not an
341 // element, and the prefix is no longer necessary.
342 var prefix = isElementContext ? '*' : '';
343 entries.push({
344 kind: display_parts_1.unsafeCastDisplayInfoKindToScriptElementKind(display_parts_1.DisplayInfoKind.DIRECTIVE),
345 name: prefix + completion.attribute,
346 sortText: prefix + completion.attribute,
347 replacementSpan: replacementSpan,
348 });
349 break;
350 }
351 case AttributeCompletionKind.DirectiveInput: {
352 if (isAttributeContext) {
353 // Offer a completion of a property binding.
354 entries.push({
355 kind: display_parts_1.unsafeCastDisplayInfoKindToScriptElementKind(display_parts_1.DisplayInfoKind.PROPERTY),
356 name: "[" + completion.propertyName + "]",
357 sortText: completion.propertyName,
358 replacementSpan: replacementSpan,
359 });
360 // If the directive supports banana-in-a-box for this input, offer that as well.
361 if (completion.twoWayBindingSupported) {
362 entries.push({
363 kind: display_parts_1.unsafeCastDisplayInfoKindToScriptElementKind(display_parts_1.DisplayInfoKind.PROPERTY),
364 name: "[(" + completion.propertyName + ")]",
365 // This completion should sort after the property binding.
366 sortText: completion.propertyName + '_1',
367 replacementSpan: replacementSpan,
368 });
369 }
370 // Offer a completion of the input binding as an attribute.
371 entries.push({
372 kind: display_parts_1.unsafeCastDisplayInfoKindToScriptElementKind(display_parts_1.DisplayInfoKind.ATTRIBUTE),
373 name: completion.propertyName,
374 // This completion should sort after both property binding options (one-way and two-way).
375 sortText: completion.propertyName + '_2',
376 replacementSpan: replacementSpan,
377 });
378 }
379 else {
380 entries.push({
381 kind: display_parts_1.unsafeCastDisplayInfoKindToScriptElementKind(display_parts_1.DisplayInfoKind.PROPERTY),
382 name: completion.propertyName,
383 sortText: completion.propertyName,
384 replacementSpan: replacementSpan,
385 });
386 }
387 break;
388 }
389 case AttributeCompletionKind.DirectiveOutput: {
390 if (isAttributeContext) {
391 entries.push({
392 kind: display_parts_1.unsafeCastDisplayInfoKindToScriptElementKind(display_parts_1.DisplayInfoKind.EVENT),
393 name: "(" + completion.eventName + ")",
394 sortText: completion.eventName,
395 replacementSpan: replacementSpan,
396 });
397 }
398 else {
399 entries.push({
400 kind: display_parts_1.unsafeCastDisplayInfoKindToScriptElementKind(display_parts_1.DisplayInfoKind.EVENT),
401 name: completion.eventName,
402 sortText: completion.eventName,
403 replacementSpan: replacementSpan,
404 });
405 }
406 break;
407 }
408 case AttributeCompletionKind.DomAttribute: {
409 if (isAttributeContext) {
410 // Offer a completion of an attribute binding.
411 entries.push({
412 kind: display_parts_1.unsafeCastDisplayInfoKindToScriptElementKind(display_parts_1.DisplayInfoKind.ATTRIBUTE),
413 name: completion.attribute,
414 sortText: completion.attribute,
415 replacementSpan: replacementSpan,
416 });
417 if (completion.isAlsoProperty) {
418 // Offer a completion of a property binding to the DOM property.
419 entries.push({
420 kind: display_parts_1.unsafeCastDisplayInfoKindToScriptElementKind(display_parts_1.DisplayInfoKind.PROPERTY),
421 name: "[" + completion.attribute + "]",
422 // In the case of DOM attributes, the property binding should sort after the attribute
423 // binding.
424 sortText: completion.attribute + '_1',
425 replacementSpan: replacementSpan,
426 });
427 }
428 }
429 else if (completion.isAlsoProperty) {
430 entries.push({
431 kind: display_parts_1.unsafeCastDisplayInfoKindToScriptElementKind(display_parts_1.DisplayInfoKind.PROPERTY),
432 name: completion.attribute,
433 sortText: completion.attribute,
434 replacementSpan: replacementSpan,
435 });
436 }
437 break;
438 }
439 case AttributeCompletionKind.DomProperty: {
440 if (!isAttributeContext) {
441 entries.push({
442 kind: display_parts_1.unsafeCastDisplayInfoKindToScriptElementKind(display_parts_1.DisplayInfoKind.PROPERTY),
443 name: completion.property,
444 sortText: completion.property,
445 replacementSpan: replacementSpan,
446 });
447 }
448 }
449 }
450 }
451 exports.addAttributeCompletionEntries = addAttributeCompletionEntries;
452 function getAttributeCompletionSymbol(completion, checker) {
453 var _a;
454 switch (completion.kind) {
455 case AttributeCompletionKind.DomAttribute:
456 case AttributeCompletionKind.DomProperty:
457 return null;
458 case AttributeCompletionKind.DirectiveAttribute:
459 case AttributeCompletionKind.StructuralDirectiveAttribute:
460 return completion.directive.tsSymbol;
461 case AttributeCompletionKind.DirectiveInput:
462 case AttributeCompletionKind.DirectiveOutput:
463 return (_a = checker.getDeclaredTypeOfSymbol(completion.directive.tsSymbol)
464 .getProperty(completion.classPropertyName)) !== null && _a !== void 0 ? _a : null;
465 }
466 }
467 exports.getAttributeCompletionSymbol = getAttributeCompletionSymbol;
468 /**
469 * Iterates over `CssSelector` attributes, which are internally represented in a zipped array style
470 * which is not conducive to straightforward iteration.
471 */
472 function selectorAttributes(selector) {
473 var i;
474 return tslib_1.__generator(this, function (_a) {
475 switch (_a.label) {
476 case 0:
477 i = 0;
478 _a.label = 1;
479 case 1:
480 if (!(i < selector.attrs.length)) return [3 /*break*/, 4];
481 return [4 /*yield*/, [selector.attrs[0], selector.attrs[1]]];
482 case 2:
483 _a.sent();
484 _a.label = 3;
485 case 3:
486 i += 2;
487 return [3 /*break*/, 1];
488 case 4: return [2 /*return*/];
489 }
490 });
491 }
492 function getStructuralAttributes(meta) {
493 var e_9, _a;
494 if (meta.selector === null) {
495 return [];
496 }
497 var structuralAttributes = [];
498 var selectors = compiler_1.CssSelector.parse(meta.selector);
499 var _loop_1 = function (selector) {
500 if (selector.element !== null && selector.element !== 'ng-template') {
501 return "continue";
502 }
503 // Every attribute of this selector must be name-only - no required values.
504 var attributeSelectors = Array.from(selectorAttributes(selector));
505 if (!attributeSelectors.every(function (_a) {
506 var _b = tslib_1.__read(_a, 2), _ = _b[0], attrValue = _b[1];
507 return attrValue === '';
508 })) {
509 return "continue";
510 }
511 // Get every named selector.
512 var attributes = attributeSelectors.map(function (_a) {
513 var _b = tslib_1.__read(_a, 2), attrName = _b[0], _ = _b[1];
514 return attrName;
515 });
516 // Find the shortest attribute. This is the structural directive "base", and all potential
517 // input bindings must begin with the base. E.g. in `*ngFor="let a of b"`, `ngFor` is the
518 // base attribute, and the `of` binding key corresponds to an input of `ngForOf`.
519 var baseAttr = attributes.reduce(function (prev, curr) { return prev === null || curr.length < prev.length ? curr : prev; }, null);
520 if (baseAttr === null) {
521 return "continue";
522 }
523 // Validate that the attributes are compatible with use as a structural directive.
524 var isValid = function (attr) {
525 // The base attribute is valid by default.
526 if (attr === baseAttr) {
527 return true;
528 }
529 // Non-base attributes must all be prefixed with the base attribute.
530 if (!attr.startsWith(baseAttr)) {
531 return false;
532 }
533 // Non-base attributes must also correspond to directive inputs.
534 if (!meta.inputs.hasBindingPropertyName(attr)) {
535 return false;
536 }
537 // This attribute is compatible.
538 return true;
539 };
540 if (!attributes.every(isValid)) {
541 return "continue";
542 }
543 // This attribute is valid as a structural attribute for this directive.
544 structuralAttributes.push(baseAttr);
545 };
546 try {
547 for (var selectors_2 = tslib_1.__values(selectors), selectors_2_1 = selectors_2.next(); !selectors_2_1.done; selectors_2_1 = selectors_2.next()) {
548 var selector = selectors_2_1.value;
549 _loop_1(selector);
550 }
551 }
552 catch (e_9_1) { e_9 = { error: e_9_1 }; }
553 finally {
554 try {
555 if (selectors_2_1 && !selectors_2_1.done && (_a = selectors_2.return)) _a.call(selectors_2);
556 }
557 finally { if (e_9) throw e_9.error; }
558 }
559 return structuralAttributes;
560 }
561});
562//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXR0cmlidXRlX2NvbXBsZXRpb25zLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vcGFja2FnZXMvbGFuZ3VhZ2Utc2VydmljZS9pdnkvYXR0cmlidXRlX2NvbXBsZXRpb25zLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7Ozs7R0FNRzs7Ozs7Ozs7Ozs7Ozs7SUFFSCw4Q0FBZ0c7SUFFaEcsK0JBQWlDO0lBRWpDLDZFQUE4RjtJQUM5Riw2REFBNEM7SUFFNUM7O09BRUc7SUFDSCxJQUFZLHVCQXNDWDtJQXRDRCxXQUFZLHVCQUF1QjtRQUNqQzs7OztXQUlHO1FBQ0gscUZBQVksQ0FBQTtRQUVaOzs7OztXQUtHO1FBQ0gsbUZBQVcsQ0FBQTtRQUVYOztXQUVHO1FBQ0gsaUdBQWtCLENBQUE7UUFFbEI7OztXQUdHO1FBQ0gscUhBQTRCLENBQUE7UUFFNUI7OztXQUdHO1FBQ0gseUZBQWMsQ0FBQTtRQUVkOzs7V0FHRztRQUNILDJGQUFlLENBQUE7SUFDakIsQ0FBQyxFQXRDVyx1QkFBdUIsR0FBdkIsK0JBQXVCLEtBQXZCLCtCQUF1QixRQXNDbEM7SUE4R0Q7Ozs7Ozs7Ozs7Ozs7T0FhRztJQUNILFNBQWdCLDZCQUE2QixDQUN6QyxTQUE4QixFQUFFLE9BQXVDLEVBQ3ZFLE9BQTRCOztRQUM5QixJQUFNLEtBQUssR0FBRyxJQUFJLEdBQUcsRUFBK0IsQ0FBQztRQUVyRCxrR0FBa0c7UUFDbEcsK0VBQStFO1FBQy9FLElBQU0sTUFBTSxHQUNSLE9BQU8sQ0FBQyxlQUFlLENBQUMsT0FBTyxFQUFFLFNBQVMsQ0FBbUMsQ0FBQztRQUNsRixJQUFNLGlCQUFpQixHQUFHLElBQUksR0FBRyxFQUF1QixDQUFDO1FBQ3pELElBQUksTUFBTSxLQUFLLElBQUksRUFBRTs7Z0JBQ25CLHdGQUF3RjtnQkFDeEYsZ0RBQWdEO2dCQUNoRCxLQUF3QixJQUFBLEtBQUEsaUJBQUEsTUFBTSxDQUFDLFVBQVUsQ0FBQSxnQkFBQSw0QkFBRTtvQkFBdEMsSUFBTSxTQUFTLFdBQUE7b0JBQ2xCLElBQU0sU0FBUyxHQUFHLFNBQVMsQ0FBQyxRQUFRLENBQUMsZ0JBQWdCLENBQUM7b0JBQ3RELElBQUksQ0FBQyxFQUFFLENBQUMsa0JBQWtCLENBQUMsU0FBUyxDQUFDLEVBQUU7d0JBQ3JDLFNBQVM7cUJBQ1Y7b0JBQ0QsaUJBQWlCLENBQUMsR0FBRyxDQUFDLFNBQVMsQ0FBQyxDQUFDO29CQUVqQyxJQUFNLElBQUksR0FBRyxPQUFPLENBQUMsb0JBQW9CLENBQUMsU0FBUyxDQUFDLENBQUM7b0JBQ3JELElBQUksSUFBSSxLQUFLLElBQUksRUFBRTt3QkFDakIsU0FBUztxQkFDVjs7d0JBRUQsS0FBZ0QsSUFBQSxvQkFBQSxpQkFBQSxJQUFJLENBQUMsTUFBTSxDQUFBLENBQUEsZ0JBQUEsNEJBQUU7NEJBQWxELElBQUEsS0FBQSwyQkFBaUMsRUFBaEMsWUFBWSxRQUFBLEVBQUUsaUJBQWlCLFFBQUE7NEJBQ3pDLElBQUksS0FBSyxDQUFDLEdBQUcsQ0FBQyxZQUFZLENBQUMsRUFBRTtnQ0FDM0IsU0FBUzs2QkFDVjs0QkFFRCxLQUFLLENBQUMsR0FBRyxDQUFDLFlBQVksRUFBRTtnQ0FDdEIsSUFBSSxFQUFFLHVCQUF1QixDQUFDLGNBQWM7Z0NBQzVDLFlBQVksY0FBQTtnQ0FDWixTQUFTLEVBQUUsU0FBUztnQ0FDcEIsaUJBQWlCLG1CQUFBO2dDQUNqQixzQkFBc0IsRUFBRSxJQUFJLENBQUMsT0FBTyxDQUFDLHNCQUFzQixDQUFDLFlBQVksR0FBRyxRQUFRLENBQUM7NkJBQ3JGLENBQUMsQ0FBQzt5QkFDSjs7Ozs7Ozs7Ozt3QkFFRCxLQUFnRCxJQUFBLG9CQUFBLGlCQUFBLElBQUksQ0FBQyxPQUFPLENBQUEsQ0FBQSxnQkFBQSw0QkFBRTs0QkFBbkQsSUFBQSxLQUFBLDJCQUFpQyxFQUFoQyxZQUFZLFFBQUEsRUFBRSxpQkFBaUIsUUFBQTs0QkFDekMsSUFBSSxLQUFLLENBQUMsR0FBRyxDQUFDLFlBQVksQ0FBQyxFQUFFO2dDQUMzQixTQUFTOzZCQUNWOzRCQUVELEtBQUssQ0FBQyxHQUFHLENBQUMsWUFBWSxFQUFFO2dDQUN0QixJQUFJLEVBQUUsdUJBQXVCLENBQUMsZUFBZTtnQ0FDN0MsU0FBUyxFQUFFLFlBQVk7Z0NBQ3ZCLFNBQVMsRUFBRSxTQUFTO2dDQUNwQixpQkFBaUIsbUJBQUE7NkJBQ2xCLENBQUMsQ0FBQzt5QkFDSjs7Ozs7Ozs7O2lCQUNGOzs7Ozs7Ozs7U0FDRjtRQUVELCtGQUErRjtRQUMvRixnREFBZ0Q7UUFDaEQsSUFBTSxpQkFBaUIsR0FBRyxPQUFPLENBQUMsb0JBQW9CLENBQUMsU0FBUyxDQUFDLENBQUM7UUFDbEUsSUFBSSxpQkFBaUIsS0FBSyxJQUFJLEVBQUU7WUFDOUIsSUFBTSxlQUFlLEdBQUcsMkJBQW1CLENBQUMsT0FBTyxDQUFDLENBQUM7O2dCQUVyRCxLQUF5QixJQUFBLHNCQUFBLGlCQUFBLGlCQUFpQixDQUFBLG9EQUFBLG1GQUFFO29CQUF2QyxJQUFNLFVBQVUsOEJBQUE7b0JBQ25CLElBQU0sU0FBUyxHQUFHLFVBQVUsQ0FBQyxRQUFRLENBQUMsZ0JBQWdCLENBQUM7b0JBQ3ZELG1EQUFtRDtvQkFDbkQsSUFBSSxDQUFDLEVBQUUsQ0FBQyxrQkFBa0IsQ0FBQyxTQUFTLENBQUMsSUFBSSxpQkFBaUIsQ0FBQyxHQUFHLENBQUMsU0FBUyxDQUFDLEVBQUU7d0JBQ3pFLFNBQVM7cUJBQ1Y7b0JBRUQsSUFBTSxJQUFJLEdBQUcsT0FBTyxDQUFDLG9CQUFvQixDQUFDLFNBQVMsQ0FBQyxDQUFDO29CQUNyRCxJQUFJLElBQUksS0FBSyxJQUFJLElBQUksSUFBSSxDQUFDLFFBQVEsS0FBSyxJQUFJLEVBQUU7d0JBQzNDLFNBQVM7cUJBQ1Y7b0JBRUQsSUFBSSxDQUFDLElBQUksQ0FBQyxZQUFZLEVBQUU7d0JBQ3RCLDJGQUEyRjt3QkFDM0Ysc0ZBQXNGO3dCQUN0RiwwRkFBMEY7d0JBQzFGLHFEQUFxRDt3QkFDckQsSUFBTSxTQUFTLEdBQUcsc0JBQVcsQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxDQUFDO3dCQUNuRCxJQUFNLE9BQU8sR0FBRyxJQUFJLDBCQUFlLEVBQUUsQ0FBQzt3QkFDdEMsT0FBTyxDQUFDLGNBQWMsQ0FBQyxTQUFTLENBQUMsQ0FBQzs7NEJBRWxDLEtBQXVCLElBQUEsNkJBQUEsaUJBQUEsU0FBUyxDQUFBLENBQUEsb0NBQUEsMkRBQUU7Z0NBQTdCLElBQU0sUUFBUSxzQkFBQTs7b0NBQ2pCLEtBQW9DLElBQUEsb0JBQUEsaUJBQUEsa0JBQWtCLENBQUMsUUFBUSxDQUFDLENBQUEsQ0FBQSxnQkFBQSw0QkFBRTt3Q0FBdkQsSUFBQSxLQUFBLDJCQUFxQixFQUFwQixRQUFRLFFBQUEsRUFBRSxTQUFTLFFBQUE7d0NBQzdCLElBQUksU0FBUyxLQUFLLEVBQUUsRUFBRTs0Q0FDcEIsa0ZBQWtGOzRDQUNsRixTQUFTO3lDQUNWO3dDQUVELElBQUksS0FBSyxDQUFDLEdBQUcsQ0FBQyxRQUFRLENBQUMsRUFBRTs0Q0FDdkIsMkRBQTJEOzRDQUMzRCxTQUFTO3lDQUNWO3dDQUVELG1GQUFtRjt3Q0FDbkYsSUFBTSxrQkFBa0IsR0FBRyxlQUFlLElBQUcsTUFBSSxRQUFRLE1BQUcsQ0FBQSxDQUFDO3dDQUM3RCxJQUFJLENBQUMsT0FBTyxDQUFDLEtBQUssQ0FBQyxzQkFBVyxDQUFDLEtBQUssQ0FBQyxrQkFBa0IsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFFLElBQUksQ0FBQyxFQUFFOzRDQUNsRSxnQ0FBZ0M7NENBQ2hDLFNBQVM7eUNBQ1Y7d0NBRUQsdUZBQXVGO3dDQUN2RixrREFBa0Q7d0NBQ2xELElBQUksSUFBSSxDQUFDLE1BQU0sQ0FBQyxzQkFBc0IsQ0FBQyxRQUFRLENBQUMsRUFBRTs0Q0FDaEQsa0RBQWtEOzRDQUNsRCxLQUFLLENBQUMsR0FBRyxDQUFDLFFBQVEsRUFBRTtnREFDbEIsSUFBSSxFQUFFLHVCQUF1QixDQUFDLGNBQWM7Z0RBQzVDLFNBQVMsRUFBRSxVQUFVO2dEQUNyQixZQUFZLEVBQUUsUUFBUTtnREFDdEIsaUJBQWlCLEVBQ2IsSUFBSSxDQUFDLE1BQU0sQ0FBQyx3QkFBd0IsQ0FBQyxRQUFRLENBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxpQkFBaUI7Z0RBQ3hFLHNCQUFzQixFQUFFLElBQUksQ0FBQyxPQUFPLENBQUMsc0JBQXNCLENBQUMsUUFBUSxHQUFHLFFBQVEsQ0FBQzs2Q0FDakYsQ0FBQyxDQUFDO3lDQUNKOzZDQUFNLElBQUksSUFBSSxDQUFDLE9BQU8sQ0FBQyxzQkFBc0IsQ0FBQyxRQUFRLENBQUMsRUFBRTs0Q0FDeEQsbURBQW1EOzRDQUNuRCxLQUFLLENBQUMsR0FBRyxDQUFDLFFBQVEsRUFBRTtnREFDbEIsSUFBSSxFQUFFLHVCQUF1QixDQUFDLGVBQWU7Z0RBQzdDLFNBQVMsRUFBRSxVQUFVO2dEQUNyQixTQUFTLEVBQUUsUUFBUTtnREFDbkIsaUJBQWlCLEVBQ2IsSUFBSSxDQUFDLE9BQU8sQ0FBQyx3QkFBd0IsQ0FBQyxRQUFRLENBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxpQkFBaUI7NkNBQzFFLENBQUMsQ0FBQzt5Q0FDSjs2Q0FBTTs0Q0FDTCxvRkFBb0Y7NENBQ3BGLGlDQUFpQzs0Q0FDakMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxRQUFRLEVBQUU7Z0RBQ2xCLElBQUksRUFBRSx1QkFBdUIsQ0FBQyxrQkFBa0I7Z0RBQ2hELFNBQVMsRUFBRSxRQUFRO2dEQUNuQixTQUFTLEVBQUUsVUFBVTs2Q0FDdEIsQ0FBQyxDQUFDO3lDQUNKO3FDQUNGOzs7Ozs7Ozs7NkJBQ0Y7Ozs7Ozs7OztxQkFDRjt5QkFBTTt3QkFDTCxtRkFBbUY7d0JBQ25GLHVGQUF1Rjt3QkFDdkYsd0ZBQXdGO3dCQUN4RiwwQ0FBMEM7d0JBQzFDLHdGQUF3Rjt3QkFDeEYsc0ZBQXNGO3dCQUN0RixpQkFBaUI7d0JBRWpCLElBQU0sb0JBQW9CLEdBQUcsdUJBQXVCLENBQUMsSUFBSSxDQUFDLENBQUM7OzRCQUMzRCxLQUF1QixJQUFBLHdDQUFBLGlCQUFBLG9CQUFvQixDQUFBLENBQUEsMERBQUEsNEZBQUU7Z0NBQXhDLElBQU0sUUFBUSxpQ0FBQTtnQ0FDakIsS0FBSyxDQUFDLEdBQUcsQ0FBQyxRQUFRLEVBQUU7b0NBQ2xCLElBQUksRUFBRSx1QkFBdUIsQ0FBQyw0QkFBNEI7b0NBQzFELFNBQVMsRUFBRSxRQUFRO29DQUNuQixTQUFTLEVBQUUsVUFBVTtpQ0FDdEIsQ0FBQyxDQUFDOzZCQUNKOzs7Ozs7Ozs7cUJBQ0Y7aUJBQ0Y7Ozs7Ozs7OztTQUNGO1FBRUQsaUVBQWlFO1FBQ2pFLElBQUksT0FBTyxZQUFZLHlCQUFjLEVBQUU7O2dCQUNyQyxLQUFvQyxJQUFBLEtBQUEsaUJBQUEsT0FBTyxDQUFDLHVCQUF1QixDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsQ0FBQSxnQkFBQSw0QkFBRTtvQkFBeEUsSUFBQSxhQUFxQixFQUFwQixTQUFTLGVBQUEsRUFBRSxRQUFRLGNBQUE7b0JBQzdCLElBQU0sY0FBYyxHQUFHLFNBQVMsS0FBSyxRQUFRLENBQUM7b0JBQzlDLElBQUksQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLFNBQVMsQ0FBQyxFQUFFO3dCQUN6QixLQUFLLENBQUMsR0FBRyxDQUFDLFNBQVMsRUFBRTs0QkFDbkIsSUFBSSxFQUFFLHVCQUF1QixDQUFDLFlBQVk7NEJBQzFDLFNBQVMsV0FBQTs0QkFDVCxjQUFjLGdCQUFBO3lCQUNmLENBQUMsQ0FBQztxQkFDSjtvQkFDRCxJQUFJLENBQUMsY0FBYyxJQUFJLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxRQUFRLENBQUMsRUFBRTt3QkFDM0MsS0FBSyxDQUFDLEdBQUcsQ0FBQyxRQUFRLEVBQUU7NEJBQ2xCLElBQUksRUFBRSx1QkFBdUIsQ0FBQyxXQUFXOzRCQUN6QyxRQUFRLFVBQUE7eUJBQ1QsQ0FBQyxDQUFDO3FCQUNKO2lCQUNGOzs7Ozs7Ozs7U0FDRjtRQUVELE9BQU8sS0FBSyxDQUFDO0lBQ2YsQ0FBQztJQTlLRCxzRUE4S0M7SUFFRDs7Ozs7Ozs7Ozs7T0FXRztJQUNILFNBQWdCLDZCQUE2QixDQUN6QyxPQUE2QixFQUFFLFVBQStCLEVBQUUsa0JBQTJCLEVBQzNGLGdCQUF5QixFQUFFLGVBQXNDO1FBQ25FLFFBQVEsVUFBVSxDQUFDLElBQUksRUFBRTtZQUN2QixLQUFLLHVCQUF1QixDQUFDLGtCQUFrQixDQUFDLENBQUM7Z0JBQy9DLE9BQU8sQ0FBQyxJQUFJLENBQUM7b0JBQ1gsSUFBSSxFQUFFLDREQUE0QyxDQUFDLCtCQUFlLENBQUMsU0FBUyxDQUFDO29CQUM3RSxJQUFJLEVBQUUsVUFBVSxDQUFDLFNBQVM7b0JBQzFCLFFBQVEsRUFBRSxVQUFVLENBQUMsU0FBUztvQkFDOUIsZUFBZSxpQkFBQTtpQkFDaEIsQ0FBQyxDQUFDO2dCQUNILE1BQU07YUFDUDtZQUNELEtBQUssdUJBQXVCLENBQUMsNEJBQTRCLENBQUMsQ0FBQztnQkFDekQseUZBQXlGO2dCQUN6Riw0RkFBNEY7Z0JBQzVGLGtEQUFrRDtnQkFDbEQsSUFBTSxNQUFNLEdBQUcsZ0JBQWdCLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDO2dCQUMzQyxPQUFPLENBQUMsSUFBSSxDQUFDO29CQUNYLElBQUksRUFBRSw0REFBNEMsQ0FBQywrQkFBZSxDQUFDLFNBQVMsQ0FBQztvQkFDN0UsSUFBSSxFQUFFLE1BQU0sR0FBRyxVQUFVLENBQUMsU0FBUztvQkFDbkMsUUFBUSxFQUFFLE1BQU0sR0FBRyxVQUFVLENBQUMsU0FBUztvQkFDdkMsZUFBZSxpQkFBQTtpQkFDaEIsQ0FBQyxDQUFDO2dCQUNILE1BQU07YUFDUDtZQUNELEtBQUssdUJBQXVCLENBQUMsY0FBYyxDQUFDLENBQUM7Z0JBQzNDLElBQUksa0JBQWtCLEVBQUU7b0JBQ3RCLDRDQUE0QztvQkFDNUMsT0FBTyxDQUFDLElBQUksQ0FBQzt3QkFDWCxJQUFJLEVBQUUsNERBQTRDLENBQUMsK0JBQWUsQ0FBQyxRQUFRLENBQUM7d0JBQzVFLElBQUksRUFBRSxNQUFJLFVBQVUsQ0FBQyxZQUFZLE1BQUc7d0JBQ3BDLFFBQVEsRUFBRSxVQUFVLENBQUMsWUFBWTt3QkFDakMsZUFBZSxpQkFBQTtxQkFDaEIsQ0FBQyxDQUFDO29CQUNILGdGQUFnRjtvQkFDaEYsSUFBSSxVQUFVLENBQUMsc0JBQXNCLEVBQUU7d0JBQ3JDLE9BQU8sQ0FBQyxJQUFJLENBQUM7NEJBQ1gsSUFBSSxFQUFFLDREQUE0QyxDQUFDLCtCQUFlLENBQUMsUUFBUSxDQUFDOzRCQUM1RSxJQUFJLEVBQUUsT0FBSyxVQUFVLENBQUMsWUFBWSxPQUFJOzRCQUN0QywwREFBMEQ7NEJBQzFELFFBQVEsRUFBRSxVQUFVLENBQUMsWUFBWSxHQUFHLElBQUk7NEJBQ3hDLGVBQWUsaUJBQUE7eUJBQ2hCLENBQUMsQ0FBQztxQkFDSjtvQkFDRCwyREFBMkQ7b0JBQzNELE9BQU8sQ0FBQyxJQUFJLENBQUM7d0JBQ1gsSUFBSSxFQUFFLDREQUE0QyxDQUFDLCtCQUFlLENBQUMsU0FBUyxDQUFDO3dCQUM3RSxJQUFJLEVBQUUsVUFBVSxDQUFDLFlBQVk7d0JBQzdCLHlGQUF5Rjt3QkFDekYsUUFBUSxFQUFFLFVBQVUsQ0FBQyxZQUFZLEdBQUcsSUFBSTt3QkFDeEMsZUFBZSxpQkFBQTtxQkFDaEIsQ0FBQyxDQUFDO2lCQUNKO3FCQUFNO29CQUNMLE9BQU8sQ0FBQyxJQUFJLENBQUM7d0JBQ1gsSUFBSSxFQUFFLDREQUE0QyxDQUFDLCtCQUFlLENBQUMsUUFBUSxDQUFDO3dCQUM1RSxJQUFJLEVBQUUsVUFBVSxDQUFDLFlBQVk7d0JBQzdCLFFBQVEsRUFBRSxVQUFVLENBQUMsWUFBWTt3QkFDakMsZUFBZSxpQkFBQTtxQkFDaEIsQ0FBQyxDQUFDO2lCQUNKO2dCQUNELE1BQU07YUFDUDtZQUNELEtBQUssdUJBQXVCLENBQUMsZUFBZSxDQUFDLENBQUM7Z0JBQzVDLElBQUksa0JBQWtCLEVBQUU7b0JBQ3RCLE9BQU8sQ0FBQyxJQUFJLENBQUM7d0JBQ1gsSUFBSSxFQUFFLDREQUE0QyxDQUFDLCtCQUFlLENBQUMsS0FBSyxDQUFDO3dCQUN6RSxJQUFJLEVBQUUsTUFBSSxVQUFVLENBQUMsU0FBUyxNQUFHO3dCQUNqQyxRQUFRLEVBQUUsVUFBVSxDQUFDLFNBQVM7d0JBQzlCLGVBQWUsaUJBQUE7cUJBQ2hCLENBQUMsQ0FBQztpQkFDSjtxQkFBTTtvQkFDTCxPQUFPLENBQUMsSUFBSSxDQUFDO3dCQUNYLElBQUksRUFBRSw0REFBNEMsQ0FBQywrQkFBZSxDQUFDLEtBQUssQ0FBQzt3QkFDekUsSUFBSSxFQUFFLFVBQVUsQ0FBQyxTQUFTO3dCQUMxQixRQUFRLEVBQUUsVUFBVSxDQUFDLFNBQVM7d0JBQzlCLGVBQWUsaUJBQUE7cUJBQ2hCLENBQUMsQ0FBQztpQkFDSjtnQkFDRCxNQUFNO2FBQ1A7WUFDRCxLQUFLLHVCQUF1QixDQUFDLFlBQVksQ0FBQyxDQUFDO2dCQUN6QyxJQUFJLGtCQUFrQixFQUFFO29CQUN0Qiw4Q0FBOEM7b0JBQzlDLE9BQU8sQ0FBQyxJQUFJLENBQUM7d0JBQ1gsSUFBSSxFQUFFLDREQUE0QyxDQUFDLCtCQUFlLENBQUMsU0FBUyxDQUFDO3dCQUM3RSxJQUFJLEVBQUUsVUFBVSxDQUFDLFNBQVM7d0JBQzFCLFFBQVEsRUFBRSxVQUFVLENBQUMsU0FBUzt3QkFDOUIsZUFBZSxpQkFBQTtxQkFDaEIsQ0FBQyxDQUFDO29CQUNILElBQUksVUFBVSxDQUFDLGNBQWMsRUFBRTt3QkFDN0IsZ0VBQWdFO3dCQUNoRSxPQUFPLENBQUMsSUFBSSxDQUFDOzRCQUNYLElBQUksRUFBRSw0REFBNEMsQ0FBQywrQkFBZSxDQUFDLFFBQVEsQ0FBQzs0QkFDNUUsSUFBSSxFQUFFLE1BQUksVUFBVSxDQUFDLFNBQVMsTUFBRzs0QkFDakMsc0ZBQXNGOzRCQUN0RixXQUFXOzRCQUNYLFFBQVEsRUFBRSxVQUFVLENBQUMsU0FBUyxHQUFHLElBQUk7NEJBQ3JDLGVBQWUsaUJBQUE7eUJBQ2hCLENBQUMsQ0FBQztxQkFDSjtpQkFDRjtxQkFBTSxJQUFJLFVBQVUsQ0FBQyxjQUFjLEVBQUU7b0JBQ3BDLE9BQU8sQ0FBQyxJQUFJLENBQUM7d0JBQ1gsSUFBSSxFQUFFLDREQUE0QyxDQUFDLCtCQUFlLENBQUMsUUFBUSxDQUFDO3dCQUM1RSxJQUFJLEVBQUUsVUFBVSxDQUFDLFNBQVM7d0JBQzFCLFFBQVEsRUFBRSxVQUFVLENBQUMsU0FBUzt3QkFDOUIsZUFBZSxpQkFBQTtxQkFDaEIsQ0FBQyxDQUFDO2lCQUNKO2dCQUNELE1BQU07YUFDUDtZQUNELEtBQUssdUJBQXVCLENBQUMsV0FBVyxDQUFDLENBQUM7Z0JBQ3hDLElBQUksQ0FBQyxrQkFBa0IsRUFBRTtvQkFDdkIsT0FBTyxDQUFDLElBQUksQ0FBQzt3QkFDWCxJQUFJLEVBQUUsNERBQTRDLENBQUMsK0JBQWUsQ0FBQyxRQUFRLENBQUM7d0JBQzVFLElBQUksRUFBRSxVQUFVLENBQUMsUUFBUTt3QkFDekIsUUFBUSxFQUFFLFVBQVUsQ0FBQyxRQUFRO3dCQUM3QixlQUFlLGlCQUFBO3FCQUNoQixDQUFDLENBQUM7aUJBQ0o7YUFDRjtTQUNGO0lBQ0gsQ0FBQztJQTFIRCxzRUEwSEM7SUFFRCxTQUFnQiw0QkFBNEIsQ0FDeEMsVUFBK0IsRUFBRSxPQUF1Qjs7UUFDMUQsUUFBUSxVQUFVLENBQUMsSUFBSSxFQUFFO1lBQ3ZCLEtBQUssdUJBQXVCLENBQUMsWUFBWSxDQUFDO1lBQzFDLEtBQUssdUJBQXVCLENBQUMsV0FBVztnQkFDdEMsT0FBTyxJQUFJLENBQUM7WUFDZCxLQUFLLHVCQUF1QixDQUFDLGtCQUFrQixDQUFDO1lBQ2hELEtBQUssdUJBQXVCLENBQUMsNEJBQTRCO2dCQUN2RCxPQUFPLFVBQVUsQ0FBQyxTQUFTLENBQUMsUUFBUSxDQUFDO1lBQ3ZDLEtBQUssdUJBQXVCLENBQUMsY0FBYyxDQUFDO1lBQzVDLEtBQUssdUJBQXVCLENBQUMsZUFBZTtnQkFDMUMsYUFBTyxPQUFPLENBQUMsdUJBQXVCLENBQUMsVUFBVSxDQUFDLFNBQVMsQ0FBQyxRQUFRLENBQUM7cUJBQ3pELFdBQVcsQ0FBQyxVQUFVLENBQUMsaUJBQWlCLENBQUMsbUNBQ2pELElBQUksQ0FBQztTQUNaO0lBQ0gsQ0FBQztJQWZELG9FQWVDO0lBRUQ7OztPQUdHO0lBQ0gsU0FBVSxrQkFBa0IsQ0FBQyxRQUFxQjs7Ozs7b0JBQ3ZDLENBQUMsR0FBRyxDQUFDOzs7eUJBQUUsQ0FBQSxDQUFDLEdBQUcsUUFBUSxDQUFDLEtBQUssQ0FBQyxNQUFNLENBQUE7b0JBQ3ZDLHFCQUFNLENBQUMsUUFBUSxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsRUFBRSxRQUFRLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUE7O29CQUE1QyxTQUE0QyxDQUFDOzs7b0JBREosQ0FBQyxJQUFJLENBQUMsQ0FBQTs7Ozs7S0FHbEQ7SUFFRCxTQUFTLHVCQUF1QixDQUFDLElBQWdDOztRQUMvRCxJQUFJLElBQUksQ0FBQyxRQUFRLEtBQUssSUFBSSxFQUFFO1lBQzFCLE9BQU8sRUFBRSxDQUFDO1NBQ1g7UUFFRCxJQUFNLG9CQUFvQixHQUFhLEVBQUUsQ0FBQztRQUMxQyxJQUFNLFNBQVMsR0FBRyxzQkFBVyxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLENBQUM7Z0NBQ3hDLFFBQVE7WUFDakIsSUFBSSxRQUFRLENBQUMsT0FBTyxLQUFLLElBQUksSUFBSSxRQUFRLENBQUMsT0FBTyxLQUFLLGFBQWEsRUFBRTs7YUFHcEU7WUFFRCwyRUFBMkU7WUFDM0UsSUFBTSxrQkFBa0IsR0FBRyxLQUFLLENBQUMsSUFBSSxDQUFDLGtCQUFrQixDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUM7WUFDcEUsSUFBSSxDQUFDLGtCQUFrQixDQUFDLEtBQUssQ0FBQyxVQUFDLEVBQWM7b0JBQWQsS0FBQSxxQkFBYyxFQUFiLENBQUMsUUFBQSxFQUFFLFNBQVMsUUFBQTtnQkFBTSxPQUFBLFNBQVMsS0FBSyxFQUFFO1lBQWhCLENBQWdCLENBQUMsRUFBRTs7YUFFcEU7WUFFRCw0QkFBNEI7WUFDNUIsSUFBTSxVQUFVLEdBQUcsa0JBQWtCLENBQUMsR0FBRyxDQUFDLFVBQUMsRUFBYTtvQkFBYixLQUFBLHFCQUFhLEVBQVosUUFBUSxRQUFBLEVBQUUsQ0FBQyxRQUFBO2dCQUFNLE9BQUEsUUFBUTtZQUFSLENBQVEsQ0FBQyxDQUFDO1lBRXZFLDBGQUEwRjtZQUMxRix5RkFBeUY7WUFDekYsaUZBQWlGO1lBQ2pGLElBQU0sUUFBUSxHQUFHLFVBQVUsQ0FBQyxNQUFNLENBQzlCLFVBQUMsSUFBSSxFQUFFLElBQUksSUFBSyxPQUFBLElBQUksS0FBSyxJQUFJLElBQUksSUFBSSxDQUFDLE1BQU0sR0FBRyxJQUFJLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLElBQUksRUFBeEQsQ0FBd0QsRUFDeEUsSUFBcUIsQ0FBQyxDQUFDO1lBQzNCLElBQUksUUFBUSxLQUFLLElBQUksRUFBRTs7YUFHdEI7WUFFRCxrRkFBa0Y7WUFDbEYsSUFBTSxPQUFPLEdBQUcsVUFBQyxJQUFZO2dCQUMzQiwwQ0FBMEM7Z0JBQzFDLElBQUksSUFBSSxLQUFLLFFBQVEsRUFBRTtvQkFDckIsT0FBTyxJQUFJLENBQUM7aUJBQ2I7Z0JBRUQsb0VBQW9FO2dCQUNwRSxJQUFJLENBQUMsSUFBSSxDQUFDLFVBQVUsQ0FBQyxRQUFRLENBQUMsRUFBRTtvQkFDOUIsT0FBTyxLQUFLLENBQUM7aUJBQ2Q7Z0JBRUQsZ0VBQWdFO2dCQUNoRSxJQUFJLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxzQkFBc0IsQ0FBQyxJQUFJLENBQUMsRUFBRTtvQkFDN0MsT0FBTyxLQUFLLENBQUM7aUJBQ2Q7Z0JBRUQsZ0NBQWdDO2dCQUNoQyxPQUFPLElBQUksQ0FBQztZQUNkLENBQUMsQ0FBQztZQUVGLElBQUksQ0FBQyxVQUFVLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBQyxFQUFFOzthQUUvQjtZQUVELHdFQUF3RTtZQUN4RSxvQkFBb0IsQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLENBQUM7OztZQXBEdEMsS0FBdUIsSUFBQSxjQUFBLGlCQUFBLFNBQVMsQ0FBQSxvQ0FBQTtnQkFBM0IsSUFBTSxRQUFRLHNCQUFBO3dCQUFSLFFBQVE7YUFxRGxCOzs7Ozs7Ozs7UUFFRCxPQUFPLG9CQUFvQixDQUFDO0lBQzlCLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIEBsaWNlbnNlXG4gKiBDb3B5cmlnaHQgR29vZ2xlIExMQyBBbGwgUmlnaHRzIFJlc2VydmVkLlxuICpcbiAqIFVzZSBvZiB0aGlzIHNvdXJjZSBjb2RlIGlzIGdvdmVybmVkIGJ5IGFuIE1JVC1zdHlsZSBsaWNlbnNlIHRoYXQgY2FuIGJlXG4gKiBmb3VuZCBpbiB0aGUgTElDRU5TRSBmaWxlIGF0IGh0dHBzOi8vYW5ndWxhci5pby9saWNlbnNlXG4gKi9cblxuaW1wb3J0IHtDc3NTZWxlY3RvciwgU2VsZWN0b3JNYXRjaGVyLCBUbXBsQXN0RWxlbWVudCwgVG1wbEFzdFRlbXBsYXRlfSBmcm9tICdAYW5ndWxhci9jb21waWxlcic7XG5pbXBvcnQge0RpcmVjdGl2ZUluU2NvcGUsIEVsZW1lbnRTeW1ib2wsIFRlbXBsYXRlU3ltYm9sLCBUZW1wbGF0ZVR5cGVDaGVja2VyLCBUeXBlQ2hlY2thYmxlRGlyZWN0aXZlTWV0YX0gZnJvbSAnQGFuZ3VsYXIvY29tcGlsZXItY2xpL3NyYy9uZ3RzYy90eXBlY2hlY2svYXBpJztcbmltcG9ydCAqIGFzIHRzIGZyb20gJ3R5cGVzY3JpcHQnO1xuXG5pbXBvcnQge0Rpc3BsYXlJbmZvS2luZCwgdW5zYWZlQ2FzdERpc3BsYXlJbmZvS2luZFRvU2NyaXB0RWxlbWVudEtpbmR9IGZyb20gJy4vZGlzcGxheV9wYXJ0cyc7XG5pbXBvcnQge21ha2VFbGVtZW50U2VsZWN0b3J9IGZyb20gJy4vdXRpbHMnO1xuXG4vKipcbiAqIERpZmZlcmVudGlhdGVzIGRpZmZlcmVudCBraW5kcyBvZiBgQXR0cmlidXRlQ29tcGxldGlvbmBzLlxuICovXG5leHBvcnQgZW51bSBBdHRyaWJ1dGVDb21wbGV0aW9uS2luZCB7XG4gIC8qKlxuICAgKiBDb21wbGV0aW9uIG9mIGFuIGF0dHJpYnV0ZSBmcm9tIHRoZSBIVE1MIHNjaGVtYS5cbiAgICpcbiAgICogQXR0cmlidXRlcyBvZnRlbiBoYXZlIGEgY29ycmVzcG9uZGluZyBET00gcHJvcGVydHkgb2YgdGhlIHNhbWUgbmFtZS5cbiAgICovXG4gIERvbUF0dHJpYnV0ZSxcblxuICAvKipcbiAgICogQ29tcGxldGlvbiBvZiBhIHByb3BlcnR5IGZyb20gdGhlIERPTSBzY2hlbWEuXG4gICAqXG4gICAqIGBEb21Qcm9wZXJ0eWAgY29tcGxldGlvbnMgYXJlIGdlbmVyYXRlZCBvbmx5IGZvciBwcm9wZXJ0aWVzIHdoaWNoIGRvbid0IHNoYXJlIHRoZWlyIG5hbWUgd2l0aFxuICAgKiBhbiBIVE1MIGF0dHJpYnV0ZS5cbiAgICovXG4gIERvbVByb3BlcnR5LFxuXG4gIC8qKlxuICAgKiBDb21wbGV0aW9uIG9mIGFuIGF0dHJpYnV0ZSB0aGF0IHJlc3VsdHMgaW4gYSBuZXcgZGlyZWN0aXZlIGJlaW5nIG1hdGNoZWQgb24gYW4gZWxlbWVudC5cbiAgICovXG4gIERpcmVjdGl2ZUF0dHJpYnV0ZSxcblxuICAvKipcbiAgICogQ29tcGxldGlvbiBvZiBhbiBhdHRyaWJ1dGUgdGhhdCByZXN1bHRzIGluIGEgbmV3IHN0cnVjdHVyYWwgZGlyZWN0aXZlIGJlaW5nIG1hdGNoZWQgb24gYW5cbiAgICogZWxlbWVudC5cbiAgICovXG4gIFN0cnVjdHVyYWxEaXJlY3RpdmVBdHRyaWJ1dGUsXG5cbiAgLyoqXG4gICAqIENvbXBsZXRpb24gb2YgYW4gaW5wdXQgZnJvbSBhIGRpcmVjdGl2ZSB3aGljaCBpcyBlaXRoZXIgcHJlc2VudCBvbiB0aGUgZWxlbWVudCwgb3IgYmVjb21lc1xuICAgKiBwcmVzZW50IGFmdGVyIHRoZSBhZGRpdGlvbiBvZiB0aGlzIGF0dHJpYnV0ZS5cbiAgICovXG4gIERpcmVjdGl2ZUlucHV0LFxuXG4gIC8qKlxuICAgKiBDb21wbGV0aW9uIG9mIGFuIG91dHB1dCBmcm9tIGEgZGlyZWN0aXZlIHdoaWNoIGlzIGVpdGhlciBwcmVzZW50IG9uIHRoZSBlbGVtZW50LCBvciBiZWNvbWVzXG4gICAqIHByZXNlbnQgYWZ0ZXIgdGhlIGFkZGl0aW9uIG9mIHRoaXMgYXR0cmlidXRlLlxuICAgKi9cbiAgRGlyZWN0aXZlT3V0cHV0LFxufVxuXG4vKipcbiAqIENvbXBsZXRpb24gb2YgYW4gYXR0cmlidXRlIGZyb20gdGhlIERPTSBzY2hlbWEuXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgRG9tQXR0cmlidXRlQ29tcGxldGlvbiB7XG4gIGtpbmQ6IEF0dHJpYnV0ZUNvbXBsZXRpb25LaW5kLkRvbUF0dHJpYnV0ZTtcblxuICAvKipcbiAgICogTmFtZSBvZiB0aGUgSFRNTCBhdHRyaWJ1dGUgKG5vdCB0byBiZSBjb25mdXNlZCB3aXRoIHRoZSBjb3JyZXNwb25kaW5nIERPTSBwcm9wZXJ0eSBuYW1lKS5cbiAgICovXG4gIGF0dHJpYnV0ZTogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBXaGV0aGVyIHRoaXMgYXR0cmlidXRlIGlzIGFsc28gYSBET00gcHJvcGVydHkuXG4gICAqL1xuICBpc0Fsc29Qcm9wZXJ0eTogYm9vbGVhbjtcbn1cblxuLyoqXG4gKiBDb21wbGV0aW9uIG9mIGEgRE9NIHByb3BlcnR5IG9mIGFuIGVsZW1lbnQgdGhhdCdzIGRpc3RpbmN0IGZyb20gYW4gSFRNTCBhdHRyaWJ1dGUuXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgRG9tUHJvcGVydHlDb21wbGV0aW9uIHtcbiAga2luZDogQXR0cmlidXRlQ29tcGxldGlvbktpbmQuRG9tUHJvcGVydHk7XG5cbiAgLyoqXG4gICAqIE5hbWUgb2YgdGhlIERPTSBwcm9wZXJ0eVxuICAgKi9cbiAgcHJvcGVydHk6IHN0cmluZztcbn1cblxuLyoqXG4gKiBDb21wbGV0aW9uIG9mIGFuIGF0dHJpYnV0ZSB3aGljaCByZXN1bHRzIGluIGEgbmV3IGRpcmVjdGl2ZSBiZWluZyBtYXRjaGVkIG9uIGFuIGVsZW1lbnQuXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgRGlyZWN0aXZlQXR0cmlidXRlQ29tcGxldGlvbiB7XG4gIGtpbmQ6IEF0dHJpYnV0ZUNvbXBsZXRpb25LaW5kLkRpcmVjdGl2ZUF0dHJpYnV0ZXxcbiAgICAgIEF0dHJpYnV0ZUNvbXBsZXRpb25LaW5kLlN0cnVjdHVyYWxEaXJlY3RpdmVBdHRyaWJ1dGU7XG5cbiAgLyoqXG4gICAqIE5hbWUgb2YgdGhlIGF0dHJpYnV0ZSB3aG9zZSBhZGRpdGlvbiBjYXVzZXMgdGhpcyBkaXJlY3RpdmUgdG8gbWF0Y2ggdGhlIGVsZW1lbnQuXG4gICAqL1xuICBhdHRyaWJ1dGU6IHN0cmluZztcblxuICAvKipcbiAgICogVGhlIGRpcmVjdGl2ZSB3aG9zZSBzZWxlY3RvciBnYXZlIHJpc2UgdG8gdGhpcyBjb21wbGV0aW9uLlxuICAgKi9cbiAgZGlyZWN0aXZlOiBEaXJlY3RpdmVJblNjb3BlO1xufVxuXG4vKipcbiAqIENvbXBsZXRpb24gb2YgYW4gaW5wdXQgb2YgYSBkaXJlY3RpdmUgd2hpY2ggbWF5IGVpdGhlciBiZSBwcmVzZW50IG9uIHRoZSBlbGVtZW50LCBvciBiZWNvbWVcbiAqIHByZXNlbnQgd2hlbiBhIGJpbmRpbmcgdG8gdGhpcyBpbnB1dCBpcyBhZGRlZC5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBEaXJlY3RpdmVJbnB1dENvbXBsZXRpb24ge1xuICBraW5kOiBBdHRyaWJ1dGVDb21wbGV0aW9uS2luZC5EaXJlY3RpdmVJbnB1dDtcblxuICAvKipcbiAgICogVGhlIHB1YmxpYyBwcm9wZXJ0eSBuYW1lIG9mIHRoZSBpbnB1dCAodGhlIG5hbWUgd2hpY2ggd291bGQgYmUgdXNlZCBpbiBhbnkgYmluZGluZyB0byB0aGF0XG4gICAqIGlucHV0KS5cbiAgICovXG4gIHByb3BlcnR5TmFtZTogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBUaGUgZGlyZWN0aXZlIHdoaWNoIGhhcyB0aGlzIGlucHV0LlxuICAgKi9cbiAgZGlyZWN0aXZlOiBEaXJlY3RpdmVJblNjb3BlO1xuXG4gIC8qKlxuICAgKiBUaGUgZmllbGQgbmFtZSBvbiB0aGUgZGlyZWN0aXZlIGNsYXNzIHdoaWNoIGNvcnJlc3BvbmRzIHRvIHRoaXMgaW5wdXQuXG4gICAqXG4gICAqIEN1cnJlbnRseSwgaW4gdGhlIGNhc2Ugd2hlcmUgYSBzaW5nbGUgcHJvcGVydHkgbmFtZSBjb3JyZXNwb25kcyB0byBtdWx0aXBsZSBpbnB1dCBmaWVsZHMsIG9ubHlcbiAgICogdGhlIGZpcnN0IHN1Y2ggZmllbGQgaXMgcmVwcmVzZW50ZWQgaGVyZS4gSW4gdGhlIGZ1dHVyZSBtdWx0aXBsZSByZXN1bHRzIG1heSBiZSB3YXJyYW50ZWQuXG4gICAqL1xuICBjbGFzc1Byb3BlcnR5TmFtZTogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBXaGV0aGVyIHRoaXMgaW5wdXQgY2FuIGJlIHVzZWQgd2l0aCB0d28td2F5IGJpbmRpbmcgKHRoYXQgaXMsIHdoZXRoZXIgYSBjb3JyZXNwb25kaW5nIGNoYW5nZVxuICAgKiBvdXRwdXQgZXhpc3RzIG9uIHRoZSBkaXJlY3RpdmUpLlxuICAgKi9cbiAgdHdvV2F5QmluZGluZ1N1cHBvcnRlZDogYm9vbGVhbjtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBEaXJlY3RpdmVPdXRwdXRDb21wbGV0aW9uIHtcbiAga2luZDogQXR0cmlidXRlQ29tcGxldGlvbktpbmQuRGlyZWN0aXZlT3V0cHV0O1xuXG4gIC8qKlxuICAgKiBUaGUgcHVibGljIGV2ZW50IG5hbWUgb2YgdGhlIG91dHB1dCAodGhlIG5hbWUgd2hpY2ggd291bGQgYmUgdXNlZCBpbiBhbnkgYmluZGluZyB0byB0aGF0XG4gICAqIG91dHB1dCkuXG4gICAqL1xuICBldmVudE5hbWU6IHN0cmluZztcblxuICAvKipcbiAgICpUaGUgZGlyZWN0aXZlIHdoaWNoIGhhcyB0aGlzIG91dHB1dC5cbiAgICovXG4gIGRpcmVjdGl2ZTogRGlyZWN0aXZlSW5TY29wZTtcblxuICAvKipcbiAgICogVGhlIGZpZWxkIG5hbWUgb24gdGhlIGRpcmVjdGl2ZSBjbGFzcyB3aGljaCBjb3JyZXNwb25kcyB0byB0aGlzIG91dHB1dC5cbiAgICovXG4gIGNsYXNzUHJvcGVydHlOYW1lOiBzdHJpbmc7XG59XG5cbi8qKlxuICogQW55IG5hbWVkIGF0dHJpYnV0ZSB3aGljaCBpcyBhdmFpbGFibGUgZm9yIGNvbXBsZXRpb24gb24gYSBnaXZlbiBlbGVtZW50LlxuICpcbiAqIERpc2FtYmlndWF0ZWQgYnkgdGhlIGBraW5kYCBwcm9wZXJ0eSBpbnRvIHZhcmlvdXMgdHlwZXMgb2YgY29tcGxldGlvbnMuXG4gKi9cbmV4cG9ydCB0eXBlIEF0dHJpYnV0ZUNvbXBsZXRpb24gPSBEb21BdHRyaWJ1dGVDb21wbGV0aW9ufERvbVByb3BlcnR5Q29tcGxldGlvbnxcbiAgICBEaXJlY3RpdmVBdHRyaWJ1dGVDb21wbGV0aW9ufERpcmVjdGl2ZUlucHV0Q29tcGxldGlvbnxEaXJlY3RpdmVPdXRwdXRDb21wbGV0aW9uO1xuXG4vKipcbiAqIEdpdmVuIGFuIGVsZW1lbnQgYW5kIGl0cyBjb250ZXh0LCBwcm9kdWNlIGEgYE1hcGAgb2YgYWxsIHBvc3NpYmxlIGF0dHJpYnV0ZSBjb21wbGV0aW9ucy5cbiAqXG4gKiAzIGtpbmRzIG9mIGF0dHJpYnV0ZXMgYXJlIGNvbnNpZGVyZWQgZm9yIGNvbXBsZXRpb24sIGZyb20gaGlnaGVzdCB0byBsb3dlc3QgcHJpb3JpdHk6XG4gKlxuICogMS4gSW5wdXRzL291dHB1dHMgb2YgZGlyZWN0aXZlcyBwcmVzZW50IG9uIHRoZSBlbGVtZW50IGFscmVhZHkuXG4gKiAyLiBJbnB1dHMvb3V0cHV0cyBvZiBkaXJlY3RpdmVzIHRoYXQgYXJlIG5vdCBwcmVzZW50IG9uIHRoZSBlbGVtZW50LCBidXQgd2hpY2ggd291bGQgYmVjb21lXG4gKiAgICBwcmVzZW50IGlmIHN1Y2ggYSBiaW5kaW5nIGlzIGFkZGVkLlxuICogMy4gQXR0cmlidXRlcyBmcm9tIHRoZSBET00gc2NoZW1hIGZvciB0aGUgZWxlbWVudC5cbiAqXG4gKiBUaGUgcHJpb3JpdHkgb2YgdGhlc2Ugb3B0aW9ucyBkZXRlcm1pbmVzIHdoaWNoIGNvbXBsZXRpb25zIGFyZSBhZGRlZCB0byB0aGUgYE1hcGAuIElmIGEgZGlyZWN0aXZlXG4gKiBpbnB1dCBzaGFyZXMgdGhlIHNhbWUgbmFtZSBhcyBhIERPTSBhdHRyaWJ1dGUsIHRoZSBgTWFwYCB3aWxsIHJlZmxlY3QgdGhlIGRpcmVjdGl2ZSBpbnB1dFxuICogY29tcGxldGlvbiwgbm90IHRoZSBET00gY29tcGxldGlvbiBmb3IgdGhhdCBuYW1lLlxuICovXG5leHBvcnQgZnVuY3Rpb24gYnVpbGRBdHRyaWJ1dGVDb21wbGV0aW9uVGFibGUoXG4gICAgY29tcG9uZW50OiB0cy5DbGFzc0RlY2xhcmF0aW9uLCBlbGVtZW50OiBUbXBsQXN0RWxlbWVudHxUbXBsQXN0VGVtcGxhdGUsXG4gICAgY2hlY2tlcjogVGVtcGxhdGVUeXBlQ2hlY2tlcik6IE1hcDxzdHJpbmcsIEF0dHJpYnV0ZUNvbXBsZXRpb24+IHtcbiAgY29uc3QgdGFibGUgPSBuZXcgTWFwPHN0cmluZywgQXR0cmlidXRlQ29tcGxldGlvbj4oKTtcblxuICAvLyBVc2UgdGhlIGBFbGVtZW50U3ltYm9sYCBvciBgVGVtcGxhdGVTeW1ib2xgIHRvIGl0ZXJhdGUgb3ZlciBkaXJlY3RpdmVzIHByZXNlbnQgb24gdGhlIG5vZGUsIGFuZFxuICAvLyB0aGVpciBpbnB1dHMvb3V0cHV0cy4gVGhlc2UgaGF2ZSB0aGUgaGlnaGVzdCBwcmlvcml0eSBvZiBjb21wbGV0aW9uIHJlc3VsdHMuXG4gIGNvbnN0IHN5bWJvbDogRWxlbWVudFN5bWJvbHxUZW1wbGF0ZVN5bWJvbCA9XG4gICAgICBjaGVja2VyLmdldFN5bWJvbE9mTm9kZShlbGVtZW50LCBjb21wb25lbnQpIGFzIEVsZW1lbnRTeW1ib2wgfCBUZW1wbGF0ZVN5bWJvbDtcbiAgY29uc3QgcHJlc2VudERpcmVjdGl2ZXMgPSBuZXcgU2V0PHRzLkNsYXNzRGVjbGFyYXRpb24+KCk7XG4gIGlmIChzeW1ib2wgIT09IG51bGwpIHtcbiAgICAvLyBBbiBgRWxlbWVudFN5bWJvbGAgd2FzIGF2YWlsYWJsZS4gVGhpcyBtZWFucyBpbnB1dHMgYW5kIG91dHB1dHMgZm9yIGRpcmVjdGl2ZXMgb24gdGhlXG4gICAgLy8gZWxlbWVudCBjYW4gYmUgYWRkZWQgdG8gdGhlIGNvbXBsZXRpb24gdGFibGUuXG4gICAgZm9yIChjb25zdCBkaXJTeW1ib2wgb2Ygc3ltYm9sLmRpcmVjdGl2ZXMpIHtcbiAgICAgIGNvbnN0IGRpcmVjdGl2ZSA9IGRpclN5bWJvbC50c1N5bWJvbC52YWx1ZURlY2xhcmF0aW9uO1xuICAgICAgaWYgKCF0cy5pc0NsYXNzRGVjbGFyYXRpb24oZGlyZWN0aXZlKSkge1xuICAgICAgICBjb250aW51ZTtcbiAgICAgIH1cbiAgICAgIHByZXNlbnREaXJlY3RpdmVzLmFkZChkaXJlY3RpdmUpO1xuXG4gICAgICBjb25zdCBtZXRhID0gY2hlY2tlci5nZXREaXJlY3RpdmVNZXRhZGF0YShkaXJlY3RpdmUpO1xuICAgICAgaWYgKG1ldGEgPT09IG51bGwpIHtcbiAgICAgICAgY29udGludWU7XG4gICAgICB9XG5cbiAgICAgIGZvciAoY29uc3QgW3Byb3BlcnR5TmFtZSwgY2xhc3NQcm9wZXJ0eU5hbWVdIG9mIG1ldGEuaW5wdXRzKSB7XG4gICAgICAgIGlmICh0YWJsZS5oYXMocHJvcGVydHlOYW1lKSkge1xuICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICB9XG5cbiAgICAgICAgdGFibGUuc2V0KHByb3BlcnR5TmFtZSwge1xuICAgICAgICAgIGtpbmQ6IEF0dHJpYnV0ZUNvbXBsZXRpb25LaW5kLkRpcmVjdGl2ZUlucHV0LFxuICAgICAgICAgIHByb3BlcnR5TmFtZSxcbiAgICAgICAgICBkaXJlY3RpdmU6IGRpclN5bWJvbCxcbiAgICAgICAgICBjbGFzc1Byb3BlcnR5TmFtZSxcbiAgICAgICAgICB0d29XYXlCaW5kaW5nU3VwcG9ydGVkOiBtZXRhLm91dHB1dHMuaGFzQmluZGluZ1Byb3BlcnR5TmFtZShwcm9wZXJ0eU5hbWUgKyAnQ2hhbmdlJyksXG4gICAgICAgIH0pO1xuICAgICAgfVxuXG4gICAgICBmb3IgKGNvbnN0IFtwcm9wZXJ0eU5hbWUsIGNsYXNzUHJvcGVydHlOYW1lXSBvZiBtZXRhLm91dHB1dHMpIHtcbiAgICAgICAgaWYgKHRhYmxlLmhhcyhwcm9wZXJ0eU5hbWUpKSB7XG4gICAgICAgICAgY29udGludWU7XG4gICAgICAgIH1cblxuICAgICAgICB0YWJsZS5zZXQocHJvcGVydHlOYW1lLCB7XG4gICAgICAgICAga2luZDogQXR0cmlidXRlQ29tcGxldGlvbktpbmQuRGlyZWN0aXZlT3V0cHV0LFxuICAgICAgICAgIGV2ZW50TmFtZTogcHJvcGVydHlOYW1lLFxuICAgICAgICAgIGRpcmVjdGl2ZTogZGlyU3ltYm9sLFxuICAgICAgICAgIGNsYXNzUHJvcGVydHlOYW1lLFxuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICAvLyBOZXh0LCBleHBsb3JlIGh5cG90aGV0aWNhbCBkaXJlY3RpdmVzIGFuZCBkZXRlcm1pbmUgaWYgdGhlIGFkZGl0aW9uIG9mIGFueSBzaW5nbGUgYXR0cmlidXRlc1xuICAvLyBjYW4gY2F1c2UgdGhlIGRpcmVjdGl2ZSB0byBtYXRjaCB0aGUgZWxlbWVudC5cbiAgY29uc3QgZGlyZWN0aXZlc0luU2NvcGUgPSBjaGVja2VyLmdldERpcmVjdGl2ZXNJblNjb3BlKGNvbXBvbmVudCk7XG4gIGlmIChkaXJlY3RpdmVzSW5TY29wZSAhPT0gbnVsbCkge1xuICAgIGNvbnN0IGVsZW1lbnRTZWxlY3RvciA9IG1ha2VFbGVtZW50U2VsZWN0b3IoZWxlbWVudCk7XG5cbiAgICBmb3IgKGNvbnN0IGRpckluU2NvcGUgb2YgZGlyZWN0aXZlc0luU2NvcGUpIHtcbiAgICAgIGNvbnN0IGRpcmVjdGl2ZSA9IGRpckluU2NvcGUudHNTeW1ib2wudmFsdWVEZWNsYXJhdGlvbjtcbiAgICAgIC8vIFNraXAgZGlyZWN0aXZlcyB0aGF0IGFyZSBwcmVzZW50IG9uIHRoZSBlbGVtZW50LlxuICAgICAgaWYgKCF0cy5pc0NsYXNzRGVjbGFyYXRpb24oZGlyZWN0aXZlKSB8fCBwcmVzZW50RGlyZWN0aXZlcy5oYXMoZGlyZWN0aXZlKSkge1xuICAgICAgICBjb250aW51ZTtcbiAgICAgIH1cblxuICAgICAgY29uc3QgbWV0YSA9IGNoZWNrZXIuZ2V0RGlyZWN0aXZlTWV0YWRhdGEoZGlyZWN0aXZlKTtcbiAgICAgIGlmIChtZXRhID09PSBudWxsIHx8IG1ldGEuc2VsZWN0b3IgPT09IG51bGwpIHtcbiAgICAgICAgY29udGludWU7XG4gICAgICB9XG5cbiAgICAgIGlmICghbWV0YS5pc1N0cnVjdHVyYWwpIHtcbiAgICAgICAgLy8gRm9yIG5vbi1zdHJ1Y3R1cmFsIGRpcmVjdGl2ZXMsIHRoZSBkaXJlY3RpdmUncyBhdHRyaWJ1dGUgc2VsZWN0b3IocykgYXJlIG1hdGNoZWQgYWdhaW5zdFxuICAgICAgICAvLyBhIGh5cG90aGV0aWNhbCB2ZXJzaW9uIG9mIHRoZSBlbGVtZW50IHdpdGggdGhvc2UgYXR0cmlidXRlcy4gQSBtYXRjaCBpbmRpY2F0ZXMgdGhhdFxuICAgICAgICAvLyBhZGRpbmcgdGhhdCBhdHRyaWJ1dGUvaW5wdXQvb3V0cHV0IGJpbmRpbmcgd291bGQgY2F1c2UgdGhlIGRpcmVjdGl2ZSB0byBiZWNvbWUgcHJlc2VudCxcbiAgICAgICAgLy8gbWVhbmluZyB0aGF0IHN1Y2ggYSBiaW5kaW5nIGlzIGEgdmFsaWQgY29tcGxldGlvbi5cbiAgICAgICAgY29uc3Qgc2VsZWN0b3JzID0gQ3NzU2VsZWN0b3IucGFyc2UobWV0YS5zZWxlY3Rvcik7XG4gICAgICAgIGNvbnN0IG1hdGNoZXIgPSBuZXcgU2VsZWN0b3JNYXRjaGVyKCk7XG4gICAgICAgIG1hdGNoZXIuYWRkU2VsZWN0YWJsZXMoc2VsZWN0b3JzKTtcblxuICAgICAgICBmb3IgKGNvbnN0IHNlbGVjdG9yIG9mIHNlbGVjdG9ycykge1xuICAgICAgICAgIGZvciAoY29uc3QgW2F0dHJOYW1lLCBhdHRyVmFsdWVdIG9mIHNlbGVjdG9yQXR0cmlidXRlcyhzZWxlY3RvcikpIHtcbiAgICAgICAgICAgIGlmIChhdHRyVmFsdWUgIT09ICcnKSB7XG4gICAgICAgICAgICAgIC8vIFRoaXMgYXR0cmlidXRlIHNlbGVjdG9yIHJlcXVpcmVzIGEgdmFsdWUsIHdoaWNoIGlzIG5vdCBzdXBwb3J0ZWQgaW4gY29tcGxldGlvbi5cbiAgICAgICAgICAgICAgY29udGludWU7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGlmICh0YWJsZS5oYXMoYXR0ck5hbWUpKSB7XG4gICAgICAgICAgICAgIC8vIFNraXAgdGhpcyBhdHRyaWJ1dGUgYXMgdGhlcmUncyBhbHJlYWR5IGEgYmluZGluZyBmb3IgaXQuXG4gICAgICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAvLyBDaGVjayB3aGV0aGVyIGFkZGluZyB0aGlzIGF0dHJpYnV0ZSB3b3VsZCBjYXVzZSB0aGUgZGlyZWN0aXZlIHRvIHN0YXJ0IG1hdGNoaW5nLlxuICAgICAgICAgICAgY29uc3QgbmV3RWxlbWVudFNlbGVjdG9yID0gZWxlbWVudFNlbGVjdG9yICsgYFske2F0dHJOYW1lfV1gO1xuICAgICAgICAgICAgaWYgKCFtYXRjaGVyLm1hdGNoKENzc1NlbGVjdG9yLnBhcnNlKG5ld0VsZW1lbnRTZWxlY3RvcilbMF0sIG51bGwpKSB7XG4gICAgICAgICAgICAgIC8vIE5vcGUsIG1vdmUgb24gd2l0aCBvdXIgbGl2ZXMuXG4gICAgICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAvLyBBZGRpbmcgdGhpcyBhdHRyaWJ1dGUgY2F1c2VzIGEgbmV3IGRpcmVjdGl2ZSB0byBiZSBtYXRjaGVkLiBEZWNpZGUgaG93IHRvIGNhdGVnb3JpemVcbiAgICAgICAgICAgIC8vIGl0IGJhc2VkIG9uIHRoZSBkaXJlY3RpdmUncyBpbnB1dHMgYW5kIG91dHB1dHMuXG4gICAgICAgICAgICBpZiAobWV0YS5pbnB1dHMuaGFzQmluZGluZ1Byb3BlcnR5TmFtZShhdHRyTmFtZSkpIHtcbiAgICAgICAgICAgICAgLy8gVGhpcyBhdHRyaWJ1dGUgY29ycmVzcG9uZHMgdG8gYW4gaW5wdXQgYmluZGluZy5cbiAgICAgICAgICAgICAgdGFibGUuc2V0KGF0dHJOYW1lLCB7XG4gICAgICAgICAgICAgICAga2luZDogQXR0cmlidXRlQ29tcGxldGlvbktpbmQuRGlyZWN0aXZlSW5wdXQsXG4gICAgICAgICAgICAgICAgZGlyZWN0aXZlOiBkaXJJblNjb3BlLFxuICAgICAgICAgICAgICAgIHByb3BlcnR5TmFtZTogYXR0ck5hbWUsXG4gICAgICAgICAgICAgICAgY2xhc3NQcm9wZXJ0eU5hbWU6XG4gICAgICAgICAgICAgICAgICAgIG1ldGEuaW5wdXRzLmdldEJ5QmluZGluZ1Byb3BlcnR5TmFtZShhdHRyTmFtZSkhWzBdLmNsYXNzUHJvcGVydHlOYW1lLFxuICAgICAgICAgICAgICAgIHR3b1dheUJpbmRpbmdTdXBwb3J0ZWQ6IG1ldGEub3V0cHV0cy5oYXNCaW5kaW5nUHJvcGVydHlOYW1lKGF0dHJOYW1lICsgJ0NoYW5nZScpLFxuICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH0gZWxzZSBpZiAobWV0YS5vdXRwdXRzLmhhc0JpbmRpbmdQcm9wZXJ0eU5hbWUoYXR0ck5hbWUpKSB7XG4gICAgICAgICAgICAgIC8vIFRoaXMgYXR0cmlidXRlIGNvcnJlc3BvbmRzIHRvIGFuIG91dHB1dCBiaW5kaW5nLlxuICAgICAgICAgICAgICB0YWJsZS5zZXQoYXR0ck5hbWUsIHtcbiAgICAgICAgICAgICAgICBraW5kOiBBdHRyaWJ1dGVDb21wbGV0aW9uS2luZC5EaXJlY3RpdmVPdXRwdXQsXG4gICAgICAgICAgICAgICAgZGlyZWN0aXZlOiBkaXJJblNjb3BlLFxuICAgICAgICAgICAgICAgIGV2ZW50TmFtZTogYXR0ck5hbWUsXG4gICAgICAgICAgICAgICAgY2xhc3NQcm9wZXJ0eU5hbWU6XG4gICAgICAgICAgICAgICAgICAgIG1ldGEub3V0cHV0cy5nZXRCeUJpbmRpbmdQcm9wZXJ0eU5hbWUoYXR0ck5hbWUpIVswXS5jbGFzc1Byb3BlcnR5TmFtZSxcbiAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAvLyBUaGlzIGF0dHJpYnV0ZSBjYXVzZXMgYSBuZXcgZGlyZWN0aXZlIHRvIGJlIG1hdGNoZWQsIGJ1dCBkb2VzIG5vdCBhbHNvIGNvcnJlc3BvbmRcbiAgICAgICAgICAgICAgLy8gdG8gYW4gaW5wdXQgb3Igb3V0cHV0IGJpbmRpbmcuXG4gICAgICAgICAgICAgIHRhYmxlLnNldChhdHRyTmFtZSwge1xuICAgICAgICAgICAgICAgIGtpbmQ6IEF0dHJpYnV0ZUNvbXBsZXRpb25LaW5kLkRpcmVjdGl2ZUF0dHJpYnV0ZSxcbiAgICAgICAgICAgICAgICBhdHRyaWJ1dGU6IGF0dHJOYW1lLFxuICAgICAgICAgICAgICAgIGRpcmVjdGl2ZTogZGlySW5TY29wZSxcbiAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9IGVsc2Uge1xuICAgICAgICAvLyBIeXBvdGhldGljYWxseSBtYXRjaGluZyBhIHN0cnVjdHVyYWwgZGlyZWN0aXZlIGlzIGEgbGl0bGUgZGlmZmVyZW50IHRoYW4gYSBwbGFpblxuICAgICAgICAvLyBkaXJlY3RpdmUuIFVzZSBvZiB0aGUgJyonIHN0cnVjdHVyYWwgZGlyZWN0aXZlIHN5bnRhY3RpYyBzdWdhciBtZWFucyB0aGF0IHRoZSBhY3R1YWxcbiAgICAgICAgLy8gZGlyZWN0aXZlIGlzIGFwcGxpZWQgdG8gYSBwbGFpbiA8bmctdGVtcGxhdGU+IG5vZGUsIG5vdCB0aGUgZXhpc3RpbmcgZWxlbWVudCB3aXRoIGFueVxuICAgICAgICAvLyBvdGhlciBhdHRyaWJ1dGVzIGl0IG1pZ2h0IGFscmVhZHkgaGF2ZS5cbiAgICAgICAgLy8gQWRkaXRpb25hbGx5LCBtb3JlIHRoYW4gb25lIGF0dHJpYnV0ZS9pbnB1dCBtaWdodCBuZWVkIHRvIGJlIHByZXNlbnQgaW4gb3JkZXIgZm9yIHRoZVxuICAgICAgICAvLyBkaXJlY3RpdmUgdG8gbWF0Y2ggKGUuZy4gYG5nRm9yYCBoYXMgYSBzZWxlY3RvciBvZiBgW25nRm9yXVtuZ0Zvck9mXWApLiBUaGlzIGdldHMgYVxuICAgICAgICAvLyBsaXR0bGUgdHJpY2t5LlxuXG4gICAgICAgIGNvbnN0IHN0cnVjdHVyYWxBdHRyaWJ1dGVzID0gZ2V0U3RydWN0dXJhbEF0dHJpYnV0ZXMobWV0YSk7XG4gICAgICAgIGZvciAoY29uc3QgYXR0ck5hbWUgb2Ygc3RydWN0dXJhbEF0dHJpYnV0ZXMpIHtcbiAgICAgICAgICB0YWJsZS5zZXQoYXR0ck5hbWUsIHtcbiAgICAgICAgICAgIGtpbmQ6IEF0dHJpYnV0ZUNvbXBsZXRpb25LaW5kLlN0cnVjdHVyYWxEaXJlY3RpdmVBdHRyaWJ1dGUsXG4gICAgICAgICAgICBhdHRyaWJ1dGU6IGF0dHJOYW1lLFxuICAgICAgICAgICAgZGlyZWN0aXZlOiBkaXJJblNjb3BlLFxuICAgICAgICAgIH0pO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgLy8gRmluYWxseSwgYWRkIGFueSBET00gYXR0cmlidXRlcyBub3QgYWxyZWFkeSBjb3ZlcmVkIGJ5IGlucHV0cy5cbiAgaWYgKGVsZW1lbnQgaW5zdGFuY2VvZiBUbXBsQXN0RWxlbWVudCkge1xuICAgIGZvciAoY29uc3Qge2F0dHJpYnV0ZSwgcHJvcGVydHl9IG9mIGNoZWNrZXIuZ2V0UG90ZW50aWFsRG9tQmluZGluZ3MoZWxlbWVudC5uYW1lKSkge1xuICAgICAgY29uc3QgaXNBbHNvUHJvcGVydHkgPSBhdHRyaWJ1dGUgPT09IHByb3BlcnR5O1xuICAgICAgaWYgKCF0YWJsZS5oYXMoYXR0cmlidXRlKSkge1xuICAgICAgICB0YWJsZS5zZXQoYXR0cmlidXRlLCB7XG4gICAgICAgICAga2luZDogQXR0cmlidXRlQ29tcGxldGlvbktpbmQuRG9tQXR0cmlidXRlLFxuICAgICAgICAgIGF0dHJpYnV0ZSxcbiAgICAgICAgICBpc0Fsc29Qcm9wZXJ0eSxcbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgICBpZiAoIWlzQWxzb1Byb3BlcnR5ICYmICF0YWJsZS5oYXMocHJvcGVydHkpKSB7XG4gICAgICAgIHRhYmxlLnNldChwcm9wZXJ0eSwge1xuICAgICAgICAgIGtpbmQ6IEF0dHJpYnV0ZUNvbXBsZXRpb25LaW5kLkRvbVByb3BlcnR5LFxuICAgICAgICAgIHByb3BlcnR5LFxuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICByZXR1cm4gdGFibGU7XG59XG5cbi8qKlxuICogR2l2ZW4gYW4gYEF0dHJpYnV0ZUNvbXBsZXRpb25gLCBhZGQgYW55IGF2YWlsYWJsZSBjb21wbGV0aW9ucyB0byBhIGB0cy5Db21wbGV0aW9uRW50cnlgIGFycmF5IG9mXG4gKiByZXN1bHRzLlxuICpcbiAqIFRoZSBraW5kIG9mIGNvbXBsZXRpb25zIGdlbmVyYXRlZCBkZXBlbmRzIG9uIHdoZXRoZXIgdGhlIGN1cnJlbnQgY29udGV4dCBpcyBhbiBhdHRyaWJ1dGUgY29udGV4dFxuICogb3Igbm90LiBGb3IgZXhhbXBsZSwgY29tcGxldGluZyBvbiBgPGVsZW1lbnQgYXR0cnw+YCB3aWxsIGdlbmVyYXRlIHR3byByZXN1bHRzOiBgYXR0cmlidXRlYCBhbmRcbiAqIGBbYXR0cmlidXRlXWAgLSBlaXRoZXIgYSBzdGF0aWMgYXR0cmlidXRlIGNhbiBiZSBnZW5lcmF0ZWQsIG9yIGEgcHJvcGVydHkgYmluZGluZy4gSG93ZXZlcixcbiAqIGA8ZWxlbWVudCBbYXR0cnxdPmAgaXMgbm90IGFuIGF0dHJpYnV0ZSBjb250ZXh0LCBhbmQgc28gb25seSB0aGUgcHJvcGVydHkgY29tcGxldGlvbiBgYXR0cmlidXRlYFxuICogaXMgZ2VuZXJhdGVkLiBOb3RlIHRoYXQgdGhpcyBjb21wbGV0aW9uIGRvZXMgbm90IGhhdmUgdGhlIGBbXWAgcHJvcGVydHkgYmluZGluZyBzdWdhciBhcyBpdHNcbiAqIGltcGxpY2l0bHkgcHJlc2VudCBpbiBhIHByb3BlcnR5IGJpbmRpbmcgY29udGV4dCAod2UncmUgYWxyZWFkeSBjb21wbGV0aW5nIHdpdGhpbiBhbiBgW2F0dHJ8XWBcbiAqIGV4cHJlc3Npb24pLlxuICovXG5leHBvcnQgZnVuY3Rpb24gYWRkQXR0cmlidXRlQ29tcGxldGlvbkVudHJpZXMoXG4gICAgZW50cmllczogdHMuQ29tcGxldGlvbkVudHJ5W10sIGNvbXBsZXRpb246IEF0dHJpYnV0ZUNvbXBsZXRpb24sIGlzQXR0cmlidXRlQ29udGV4dDogYm9vbGVhbixcbiAgICBpc0VsZW1lbnRDb250ZXh0OiBib29sZWFuLCByZXBsYWNlbWVudFNwYW46IHRzLlRleHRTcGFufHVuZGVmaW5lZCk6IHZvaWQge1xuICBzd2l0Y2ggKGNvbXBsZXRpb24ua2luZCkge1xuICAgIGNhc2UgQXR0cmlidXRlQ29tcGxldGlvbktpbmQuRGlyZWN0aXZlQXR0cmlidXRlOiB7XG4gICAgICBlbnRyaWVzLnB1c2goe1xuICAgICAgICBraW5kOiB1bnNhZmVDYXN0RGlzcGxheUluZm9LaW5kVG9TY3JpcHRFbGVtZW50S2luZChEaXNwbGF5SW5mb0tpbmQuRElSRUNUSVZFKSxcbiAgICAgICAgbmFtZTogY29tcGxldGlvbi5hdHRyaWJ1dGUsXG4gICAgICAgIHNvcnRUZXh0OiBjb21wbGV0aW9uLmF0dHJpYnV0ZSxcbiAgICAgICAgcmVwbGFjZW1lbnRTcGFuLFxuICAgICAgfSk7XG4gICAgICBicmVhaztcbiAgICB9XG4gICAgY2FzZSBBdHRyaWJ1dGVDb21wbGV0aW9uS2luZC5TdHJ1Y3R1cmFsRGlyZWN0aXZlQXR0cmlidXRlOiB7XG4gICAgICAvLyBJbiBhbiBlbGVtZW50LCB0aGUgY29tcGxldGlvbiBpcyBvZmZlcmVkIHdpdGggYSBsZWFkaW5nICcqJyB0byBhY3RpdmF0ZSB0aGUgc3RydWN0dXJhbFxuICAgICAgLy8gZGlyZWN0aXZlLiBPbmNlIHByZXNlbnQsIHRoZSBzdHJ1Y3R1cmFsIGF0dHJpYnV0ZSB3aWxsIGJlIHBhcnNlZCBhcyBhIHRlbXBsYXRlIGFuZCBub3QgYW5cbiAgICAgIC8vIGVsZW1lbnQsIGFuZCB0aGUgcHJlZml4IGlzIG5vIGxvbmdlciBuZWNlc3NhcnkuXG4gICAgICBjb25zdCBwcmVmaXggPSBpc0VsZW1lbnRDb250ZXh0ID8gJyonIDogJyc7XG4gICAgICBlbnRyaWVzLnB1c2goe1xuICAgICAgICBraW5kOiB1bnNhZmVDYXN0RGlzcGxheUluZm9LaW5kVG9TY3JpcHRFbGVtZW50S2luZChEaXNwbGF5SW5mb0tpbmQuRElSRUNUSVZFKSxcbiAgICAgICAgbmFtZTogcHJlZml4ICsgY29tcGxldGlvbi5hdHRyaWJ1dGUsXG4gICAgICAgIHNvcnRUZXh0OiBwcmVmaXggKyBjb21wbGV0aW9uLmF0dHJpYnV0ZSxcbiAgICAgICAgcmVwbGFjZW1lbnRTcGFuLFxuICAgICAgfSk7XG4gICAgICBicmVhaztcbiAgICB9XG4gICAgY2FzZSBBdHRyaWJ1dGVDb21wbGV0aW9uS2luZC5EaXJlY3RpdmVJbnB1dDoge1xuICAgICAgaWYgKGlzQXR0cmlidXRlQ29udGV4dCkge1xuICAgICAgICAvLyBPZmZlciBhIGNvbXBsZXRpb24gb2YgYSBwcm9wZXJ0eSBiaW5kaW5nLlxuICAgICAgICBlbnRyaWVzLnB1c2goe1xuICAgICAgICAgIGtpbmQ6IHVuc2FmZUNhc3REaXNwbGF5SW5mb0tpbmRUb1NjcmlwdEVsZW1lbnRLaW5kKERpc3BsYXlJbmZvS2luZC5QUk9QRVJUWSksXG4gICAgICAgICAgbmFtZTogYFske2NvbXBsZXRpb24ucHJvcGVydHlOYW1lfV1gLFxuICAgICAgICAgIHNvcnRUZXh0OiBjb21wbGV0aW9uLnByb3BlcnR5TmFtZSxcbiAgICAgICAgICByZXBsYWNlbWVudFNwYW4sXG4gICAgICAgIH0pO1xuICAgICAgICAvLyBJZiB0aGUgZGlyZWN0aXZlIHN1cHBvcnRzIGJhbmFuYS1pbi1hLWJveCBmb3IgdGhpcyBpbnB1dCwgb2ZmZXIgdGhhdCBhcyB3ZWxsLlxuICAgICAgICBpZiAoY29tcGxldGlvbi50d29XYXlCaW5kaW5nU3VwcG9ydGVkKSB7XG4gICAgICAgICAgZW50cmllcy5wdXNoKHtcbiAgICAgICAgICAgIGtpbmQ6IHVuc2FmZUNhc3REaXNwbGF5SW5mb0tpbmRUb1NjcmlwdEVsZW1lbnRLaW5kKERpc3BsYXlJbmZvS2luZC5QUk9QRVJUWSksXG4gICAgICAgICAgICBuYW1lOiBgWygke2NvbXBsZXRpb24ucHJvcGVydHlOYW1lfSldYCxcbiAgICAgICAgICAgIC8vIFRoaXMgY29tcGxldGlvbiBzaG91bGQgc29ydCBhZnRlciB0aGUgcHJvcGVydHkgYmluZGluZy5cbiAgICAgICAgICAgIHNvcnRUZXh0OiBjb21wbGV0aW9uLnByb3BlcnR5TmFtZSArICdfMScsXG4gICAgICAgICAgICByZXBsYWNlbWVudFNwYW4sXG4gICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICAgICAgLy8gT2ZmZXIgYSBjb21wbGV0aW9uIG9mIHRoZSBpbnB1dCBiaW5kaW5nIGFzIGFuIGF0dHJpYnV0ZS5cbiAgICAgICAgZW50cmllcy5wdXNoKHtcbiAgICAgICAgICBraW5kOiB1bnNhZmVDYXN0RGlzcGxheUluZm9LaW5kVG9TY3JpcHRFbGVtZW50S2luZChEaXNwbGF5SW5mb0tpbmQuQVRUUklCVVRFKSxcbiAgICAgICAgICBuYW1lOiBjb21wbGV0aW9uLnByb3BlcnR5TmFtZSxcbiAgICAgICAgICAvLyBUaGlzIGNvbXBsZXRpb24gc2hvdWxkIHNvcnQgYWZ0ZXIgYm90aCBwcm9wZXJ0eSBiaW5kaW5nIG9wdGlvbnMgKG9uZS13YXkgYW5kIHR3by13YXkpLlxuICAgICAgICAgIHNvcnRUZXh0OiBjb21wbGV0aW9uLnByb3BlcnR5TmFtZSArICdfMicsXG4gICAgICAgICAgcmVwbGFjZW1lbnRTcGFuLFxuICAgICAgICB9KTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGVudHJpZXMucHVzaCh7XG4gICAgICAgICAga2luZDogdW5zYWZlQ2FzdERpc3BsYXlJbmZvS2luZFRvU2NyaXB0RWxlbWVudEtpbmQoRGlzcGxheUluZm9LaW5kLlBST1BFUlRZKSxcbiAgICAgICAgICBuYW1lOiBjb21wbGV0aW9uLnByb3BlcnR5TmFtZSxcbiAgICAgICAgICBzb3J0VGV4dDogY29tcGxldGlvbi5wcm9wZXJ0eU5hbWUsXG4gICAgICAgICAgcmVwbGFjZW1lbnRTcGFuLFxuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICAgIGJyZWFrO1xuICAgIH1cbiAgICBjYXNlIEF0dHJpYnV0ZUNvbXBsZXRpb25LaW5kLkRpcmVjdGl2ZU91dHB1dDoge1xuICAgICAgaWYgKGlzQXR0cmlidXRlQ29udGV4dCkge1xuICAgICAgICBlbnRyaWVzLnB1c2goe1xuICAgICAgICAgIGtpbmQ6IHVuc2FmZUNhc3REaXNwbGF5SW5mb0tpbmRUb1NjcmlwdEVsZW1lbnRLaW5kKERpc3BsYXlJbmZvS2luZC5FVkVOVCksXG4gICAgICAgICAgbmFtZTogYCgke2NvbXBsZXRpb24uZXZlbnROYW1lfSlgLFxuICAgICAgICAgIHNvcnRUZXh0OiBjb21wbGV0aW9uLmV2ZW50TmFtZSxcbiAgICAgICAgICByZXBsYWNlbWVudFNwYW4sXG4gICAgICAgIH0pO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgZW50cmllcy5wdXNoKHtcbiAgICAgICAgICBraW5kOiB1bnNhZmVDYXN0RGlzcGxheUluZm9LaW5kVG9TY3JpcHRFbGVtZW50S2luZChEaXNwbGF5SW5mb0tpbmQuRVZFTlQpLFxuICAgICAgICAgIG5hbWU6IGNvbXBsZXRpb24uZXZlbnROYW1lLFxuICAgICAgICAgIHNvcnRUZXh0OiBjb21wbGV0aW9uLmV2ZW50TmFtZSxcbiAgICAgICAgICByZXBsYWNlbWVudFNwYW4sXG4gICAgICAgIH0pO1xuICAgICAgfVxuICAgICAgYnJlYWs7XG4gICAgfVxuICAgIGNhc2UgQXR0cmlidXRlQ29tcGxldGlvbktpbmQuRG9tQXR0cmlidXRlOiB7XG4gICAgICBpZiAoaXNBdHRyaWJ1dGVDb250ZXh0KSB7XG4gICAgICAgIC8vIE9mZmVyIGEgY29tcGxldGlvbiBvZiBhbiBhdHRyaWJ1dGUgYmluZGluZy5cbiAgICAgICAgZW50cmllcy5wdXNoKHtcbiAgICAgICAgICBraW5kOiB1bnNhZmVDYXN0RGlzcGxheUluZm9LaW5kVG9TY3JpcHRFbGVtZW50S2luZChEaXNwbGF5SW5mb0tpbmQuQVRUUklCVVRFKSxcbiAgICAgICAgICBuYW1lOiBjb21wbGV0aW9uLmF0dHJpYnV0ZSxcbiAgICAgICAgICBzb3J0VGV4dDogY29tcGxldGlvbi5hdHRyaWJ1dGUsXG4gICAgICAgICAgcmVwbGFjZW1lbnRTcGFuLFxuICAgICAgICB9KTtcbiAgICAgICAgaWYgKGNvbXBsZXRpb24uaXNBbHNvUHJvcGVydHkpIHtcbiAgICAgICAgICAvLyBPZmZlciBhIGNvbXBsZXRpb24gb2YgYSBwcm9wZXJ0eSBiaW5kaW5nIHRvIHRoZSBET00gcHJvcGVydHkuXG4gICAgICAgICAgZW50cmllcy5wdXNoKHtcbiAgICAgICAgICAgIGtpbmQ6IHVuc2FmZUNhc3REaXNwbGF5SW5mb0tpbmRUb1NjcmlwdEVsZW1lbnRLaW5kKERpc3BsYXlJbmZvS2luZC5QUk9QRVJUWSksXG4gICAgICAgICAgICBuYW1lOiBgWyR7Y29tcGxldGlvbi5hdHRyaWJ1dGV9XWAsXG4gICAgICAgICAgICAvLyBJbiB0aGUgY2FzZSBvZiBET00gYXR0cmlidXRlcywgdGhlIHByb3BlcnR5IGJpbmRpbmcgc2hvdWxkIHNvcnQgYWZ0ZXIgdGhlIGF0dHJpYnV0ZVxuICAgICAgICAgICAgLy8gYmluZGluZy5cbiAgICAgICAgICAgIHNvcnRUZXh0OiBjb21wbGV0aW9uLmF0dHJpYnV0ZSArICdfMScsXG4gICAgICAgICAgICByZXBsYWNlbWVudFNwYW4sXG4gICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICAgIH0gZWxzZSBpZiAoY29tcGxldGlvbi5pc0Fsc29Qcm9wZXJ0eSkge1xuICAgICAgICBlbnRyaWVzLnB1c2goe1xuICAgICAgICAgIGtpbmQ6IHVuc2FmZUNhc3REaXNwbGF5SW5mb0tpbmRUb1NjcmlwdEVsZW1lbnRLaW5kKERpc3BsYXlJbmZvS2luZC5QUk9QRVJUWSksXG4gICAgICAgICAgbmFtZTogY29tcGxldGlvbi5hdHRyaWJ1dGUsXG4gICAgICAgICAgc29ydFRleHQ6IGNvbXBsZXRpb24uYXR0cmlidXRlLFxuICAgICAgICAgIHJlcGxhY2VtZW50U3BhbixcbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgICBicmVhaztcbiAgICB9XG4gICAgY2FzZSBBdHRyaWJ1dGVDb21wbGV0aW9uS2luZC5Eb21Qcm9wZXJ0eToge1xuICAgICAgaWYgKCFpc0F0dHJpYnV0ZUNvbnRleHQpIHtcbiAgICAgICAgZW50cmllcy5wdXNoKHtcbiAgICAgICAgICBraW5kOiB1bnNhZmVDYXN0RGlzcGxheUluZm9LaW5kVG9TY3JpcHRFbGVtZW50S2luZChEaXNwbGF5SW5mb0tpbmQuUFJPUEVSVFkpLFxuICAgICAgICAgIG5hbWU6IGNvbXBsZXRpb24ucHJvcGVydHksXG4gICAgICAgICAgc29ydFRleHQ6IGNvbXBsZXRpb24ucHJvcGVydHksXG4gICAgICAgICAgcmVwbGFjZW1lbnRTcGFuLFxuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICB9XG4gIH1cbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGdldEF0dHJpYnV0ZUNvbXBsZXRpb25TeW1ib2woXG4gICAgY29tcGxldGlvbjogQXR0cmlidXRlQ29tcGxldGlvbiwgY2hlY2tlcjogdHMuVHlwZUNoZWNrZXIpOiB0cy5TeW1ib2x8bnVsbCB7XG4gIHN3aXRjaCAoY29tcGxldGlvbi5raW5kKSB7XG4gICAgY2FzZSBBdHRyaWJ1dGVDb21wbGV0aW9uS2luZC5Eb21BdHRyaWJ1dGU6XG4gICAgY2FzZSBBdHRyaWJ1dGVDb21wbGV0aW9uS2luZC5Eb21Qcm9wZXJ0eTpcbiAgICAgIHJldHVybiBudWxsO1xuICAgIGNhc2UgQXR0cmlidXRlQ29tcGxldGlvbktpbmQuRGlyZWN0aXZlQXR0cmlidXRlOlxuICAgIGNhc2UgQXR0cmlidXRlQ29tcGxldGlvbktpbmQuU3RydWN0dXJhbERpcmVjdGl2ZUF0dHJpYnV0ZTpcbiAgICAgIHJldHVybiBjb21wbGV0aW9uLmRpcmVjdGl2ZS50c1N5bWJvbDtcbiAgICBjYXNlIEF0dHJpYnV0ZUNvbXBsZXRpb25LaW5kLkRpcmVjdGl2ZUlucHV0OlxuICAgIGNhc2UgQXR0cmlidXRlQ29tcGxldGlvbktpbmQuRGlyZWN0aXZlT3V0cHV0OlxuICAgICAgcmV0dXJuIGNoZWNrZXIuZ2V0RGVjbGFyZWRUeXBlT2ZTeW1ib2woY29tcGxldGlvbi5kaXJlY3RpdmUudHNTeW1ib2wpXG4gICAgICAgICAgICAgICAgIC5nZXRQcm9wZXJ0eShjb21wbGV0aW9uLmNsYXNzUHJvcGVydHlOYW1lKSA/P1xuICAgICAgICAgIG51bGw7XG4gIH1cbn1cblxuLyoqXG4gKiBJdGVyYXRlcyBvdmVyIGBDc3NTZWxlY3RvcmAgYXR0cmlidXRlcywgd2hpY2ggYXJlIGludGVybmFsbHkgcmVwcmVzZW50ZWQgaW4gYSB6aXBwZWQgYXJyYXkgc3R5bGVcbiAqIHdoaWNoIGlzIG5vdCBjb25kdWNpdmUgdG8gc3RyYWlnaHRmb3J3YXJkIGl0ZXJhdGlvbi5cbiAqL1xuZnVuY3Rpb24qIHNlbGVjdG9yQXR0cmlidXRlcyhzZWxlY3RvcjogQ3NzU2VsZWN0b3IpOiBJdGVyYWJsZTxbc3RyaW5nLCBzdHJpbmddPiB7XG4gIGZvciAobGV0IGkgPSAwOyBpIDwgc2VsZWN0b3IuYXR0cnMubGVuZ3RoOyBpICs9IDIpIHtcbiAgICB5aWVsZCBbc2VsZWN0b3IuYXR0cnNbMF0sIHNlbGVjdG9yLmF0dHJzWzFdXTtcbiAgfVxufVxuXG5mdW5jdGlvbiBnZXRTdHJ1Y3R1cmFsQXR0cmlidXRlcyhtZXRhOiBUeXBlQ2hlY2thYmxlRGlyZWN0aXZlTWV0YSk6IHN0cmluZ1tdIHtcbiAgaWYgKG1ldGEuc2VsZWN0b3IgPT09IG51bGwpIHtcbiAgICByZXR1cm4gW107XG4gIH1cblxuICBjb25zdCBzdHJ1Y3R1cmFsQXR0cmlidXRlczogc3RyaW5nW10gPSBbXTtcbiAgY29uc3Qgc2VsZWN0b3JzID0gQ3NzU2VsZWN0b3IucGFyc2UobWV0YS5zZWxlY3Rvcik7XG4gIGZvciAoY29uc3Qgc2VsZWN0b3Igb2Ygc2VsZWN0b3JzKSB7XG4gICAgaWYgKHNlbGVjdG9yLmVsZW1lbnQgIT09IG51bGwgJiYgc2VsZWN0b3IuZWxlbWVudCAhPT0gJ25nLXRlbXBsYXRlJykge1xuICAgICAgLy8gVGhpcyBwYXJ0aWN1bGFyIHNlbGVjdG9yIGRvZXMgbm90IGFwcGx5IHVuZGVyIHN0cnVjdHVyYWwgZGlyZWN0aXZlIHN5bnRheC5cbiAgICAgIGNvbnRpbnVlO1xuICAgIH1cblxuICAgIC8vIEV2ZXJ5IGF0dHJpYnV0ZSBvZiB0aGlzIHNlbGVjdG9yIG11c3QgYmUgbmFtZS1vbmx5IC0gbm8gcmVxdWlyZWQgdmFsdWVzLlxuICAgIGNvbnN0IGF0dHJpYnV0ZVNlbGVjdG9ycyA9IEFycmF5LmZyb20oc2VsZWN0b3JBdHRyaWJ1dGVzKHNlbGVjdG9yKSk7XG4gICAgaWYgKCFhdHRyaWJ1dGVTZWxlY3RvcnMuZXZlcnkoKFtfLCBhdHRyVmFsdWVdKSA9PiBhdHRyVmFsdWUgPT09ICcnKSkge1xuICAgICAgY29udGludWU7XG4gICAgfVxuXG4gICAgLy8gR2V0IGV2ZXJ5IG5hbWVkIHNlbGVjdG9yLlxuICAgIGNvbnN0IGF0dHJpYnV0ZXMgPSBhdHRyaWJ1dGVTZWxlY3RvcnMubWFwKChbYXR0ck5hbWUsIF9dKSA9PiBhdHRyTmFtZSk7XG5cbiAgICAvLyBGaW5kIHRoZSBzaG9ydGVzdCBhdHRyaWJ1dGUuIFRoaXMgaXMgdGhlIHN0cnVjdHVyYWwgZGlyZWN0aXZlIFwiYmFzZVwiLCBhbmQgYWxsIHBvdGVudGlhbFxuICAgIC8vIGlucHV0IGJpbmRpbmdzIG11c3QgYmVnaW4gd2l0aCB0aGUgYmFzZS4gRS5nLiBpbiBgKm5nRm9yPVwibGV0IGEgb2YgYlwiYCwgYG5nRm9yYCBpcyB0aGVcbiAgICAvLyBiYXNlIGF0dHJpYnV0ZSwgYW5kIHRoZSBgb2ZgIGJpbmRpbmcga2V5IGNvcnJlc3BvbmRzIHRvIGFuIGlucHV0IG9mIGBuZ0Zvck9mYC5cbiAgICBjb25zdCBiYXNlQXR0ciA9IGF0dHJpYnV0ZXMucmVkdWNlKFxuICAgICAgICAocHJldiwgY3VycikgPT4gcHJldiA9PT0gbnVsbCB8fCBjdXJyLmxlbmd0aCA8IHByZXYubGVuZ3RoID8gY3VyciA6IHByZXYsXG4gICAgICAgIG51bGwgYXMgc3RyaW5nIHwgbnVsbCk7XG4gICAgaWYgKGJhc2VBdHRyID09PSBudWxsKSB7XG4gICAgICAvLyBObyBhdHRyaWJ1dGVzIGluIHRoaXMgc2VsZWN0b3I/XG4gICAgICBjb250aW51ZTtcbiAgICB9XG5cbiAgICAvLyBWYWxpZGF0ZSB0aGF0IHRoZSBhdHRyaWJ1dGVzIGFyZSBjb21wYXRpYmxlIHdpdGggdXNlIGFzIGEgc3RydWN0dXJhbCBkaXJlY3RpdmUuXG4gICAgY29uc3QgaXNWYWxpZCA9IChhdHRyOiBzdHJpbmcpOiBib29sZWFuID0+IHtcbiAgICAgIC8vIFRoZSBiYXNlIGF0dHJpYnV0ZSBpcyB2YWxpZCBieSBkZWZhdWx0LlxuICAgICAgaWYgKGF0dHIgPT09IGJhc2VBdHRyKSB7XG4gICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgfVxuXG4gICAgICAvLyBOb24tYmFzZSBhdHRyaWJ1dGVzIG11c3QgYWxsIGJlIHByZWZpeGVkIHdpdGggdGhlIGJhc2UgYXR0cmlidXRlLlxuICAgICAgaWYgKCFhdHRyLnN0YXJ0c1dpdGgoYmFzZUF0dHIpKSB7XG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgIH1cblxuICAgICAgLy8gTm9uLWJhc2UgYXR0cmlidXRlcyBtdXN0IGFsc28gY29ycmVzcG9uZCB0byBkaXJlY3RpdmUgaW5wdXRzLlxuICAgICAgaWYgKCFtZXRhLmlucHV0cy5oYXNCaW5kaW5nUHJvcGVydHlOYW1lKGF0dHIpKSB7XG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgIH1cblxuICAgICAgLy8gVGhpcyBhdHRyaWJ1dGUgaXMgY29tcGF0aWJsZS5cbiAgICAgIHJldHVybiB0cnVlO1xuICAgIH07XG5cbiAgICBpZiAoIWF0dHJpYnV0ZXMuZXZlcnkoaXNWYWxpZCkpIHtcbiAgICAgIGNvbnRpbnVlO1xuICAgIH1cblxuICAgIC8vIFRoaXMgYXR0cmlidXRlIGlzIHZhbGlkIGFzIGEgc3RydWN0dXJhbCBhdHRyaWJ1dGUgZm9yIHRoaXMgZGlyZWN0aXZlLlxuICAgIHN0cnVjdHVyYWxBdHRyaWJ1dGVzLnB1c2goYmFzZUF0dHIpO1xuICB9XG5cbiAgcmV0dXJuIHN0cnVjdHVyYWxBdHRyaWJ1dGVzO1xufVxuIl19
\No newline at end of file