UNPKG

carbon-components-angular

Version:
480 lines (474 loc) 41.8 kB
import { Component, Input, HostBinding, ViewChild } from "@angular/core"; import { BaseIconButton } from "carbon-components-angular/button"; import * as i0 from "@angular/core"; import * as i1 from "carbon-components-angular/i18n"; import * as i2 from "carbon-components-angular/utils"; import * as i3 from "@angular/common"; import * as i4 from "carbon-components-angular/button"; import * as i5 from "carbon-components-angular/icon"; export var SnippetType; (function (SnippetType) { SnippetType["single"] = "single"; SnippetType["multi"] = "multi"; SnippetType["inline"] = "inline"; })(SnippetType || (SnippetType = {})); /** * Get started with importing the module: * * ```typescript * import { CodeSnippetModule } from 'carbon-components-angular'; * ``` * * ```html * <cds-code-snippet>Code</cds-code-snippet> * ``` * * [See demo](../../?path=/story/components-code-snippet--basic) */ export class CodeSnippet extends BaseIconButton { /** * Creates an instance of CodeSnippet. */ constructor(i18n, eventService) { super(); this.i18n = i18n; this.eventService = eventService; this.rowHeightInPixel = 16; /** * It can be `"single"`, `"multi"` or `"inline"` */ this.display = SnippetType.single; this.translations = this.i18n.get().CODE_SNIPPET; /** * Set to `true` to hide copy button */ this.hideCopyButton = false; /** * Set to `true` to disable the code snippet */ this.disabled = false; /** * Specify the max number of rows to show when collapsed * Default is `15` */ this.maxCollapsedNumberOfRows = 15; /** * Specify the min number of rows to show when collapsed * Default is `3` */ this.minCollapsedNumberOfRows = 3; /** * Specify the max number of rows to show when expanded * Default is `0`, hence all content will be visible when expanded */ this.maxExpandedNumberOfRows = 0; /** * Specify the min number of rows to show when expanded * Default is `16`, hence height of expanded row will be 16 * rowHeightInPixel (16) = 256px */ this.minExpandedNumberOfRows = 16; /** * Set to `true` to wrap the text */ this.wrapText = false; /** * @deprecated since v5 - Use `cdsLayer` directive instead * Set to `"light"` to apply the light style */ this.theme = "dark"; /** * Text displayed in the tooltip when user clicks button to copy code. */ this.feedbackText = this.translations.COPIED; /** * Time in miliseconds to keep the feedback tooltip displayed. * Defaults to 2 seconds */ this.feedbackTimeout = 2000; this.expanded = false; this.skeleton = false; this.styles = {}; this.showFeedback = false; this.animating = false; this.hasExpandButton = null; this.isExpandable = false; this.hasRightOverflow = false; this.hasRight = false; this.hasLeft = false; this.dropShadow = false; } get snippetClass() { return this.display !== SnippetType.inline; } get snippetSingleClass() { return this.display === SnippetType.single; } get snippetMultiClass() { return this.display === SnippetType.multi; } get snippetDisabledClass() { return this.display !== "inline" && this.disabled; } get snippetInlineLightClass() { return this.theme === "light"; } handleScroll() { if (this.skeleton) { return; } let ref; switch (this.display) { case "multi": ref = this.codeContent.nativeElement; break; case "single": ref = this.codeContainer.nativeElement; break; default: return; } if (ref) { const { scrollWidth, clientWidth, scrollLeft } = ref; const horizontalOverflow = scrollWidth > clientWidth; this.hasLeft = horizontalOverflow && !!scrollLeft; this.hasRight = horizontalOverflow && scrollLeft + clientWidth !== scrollWidth; } } toggleSnippetExpansion() { this.expanded = !this.expanded; this.calculateContainerHeight(); } onCopyButtonClicked() { if (!this.disabled) { window.navigator.clipboard .writeText(this.code.nativeElement.innerText || this.code.nativeElement.textContent).then(() => { this.showFeedback = true; this.animating = true; setTimeout(() => { this.showFeedback = false; this.animating = false; }, this.feedbackTimeout); }); } } ngOnInit() { this.calculateContainerHeight(); } ngAfterViewInit() { this.canExpand(); this.handleScroll(); if (window) { this.eventService.on(window, "resize", () => { this.canExpand(); this.handleScroll(); }); } } calculateContainerHeight() { if (this.display === "multi" && !this.skeleton) { this.styles = {}; if (this.expanded) { if (this.maxExpandedNumberOfRows > 0) { this.styles["max-height"] = `${this.maxExpandedNumberOfRows * this.rowHeightInPixel}px`; } if (this.minExpandedNumberOfRows > 0) { this.styles["min-height"] = `${this.minExpandedNumberOfRows * this.rowHeightInPixel}px`; } } else { if (this.maxCollapsedNumberOfRows > 0) { this.styles["max-height"] = `${this.maxCollapsedNumberOfRows * this.rowHeightInPixel}px`; } if (this.minCollapsedNumberOfRows > 0) { this.styles["min-height"] = `${this.minCollapsedNumberOfRows * this.rowHeightInPixel}px`; } } } } canExpand() { if (this.display === "multi" && !this.skeleton) { const height = this.codeContent.nativeElement.getBoundingClientRect().height; if (this.maxCollapsedNumberOfRows > 0 && (this.maxExpandedNumberOfRows <= 0 || this.maxExpandedNumberOfRows > this.maxCollapsedNumberOfRows) && height > this.maxCollapsedNumberOfRows * this.rowHeightInPixel) { this.isExpandable = true; } else { this.isExpandable = false; } if (this.expanded && this.minExpandedNumberOfRows > 0 && height <= this.minExpandedNumberOfRows * this.rowHeightInPixel) { this.isExpandable = false; } } } } CodeSnippet.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: CodeSnippet, deps: [{ token: i1.I18n }, { token: i2.EventService }], target: i0.ɵɵFactoryTarget.Component }); CodeSnippet.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.3.0", type: CodeSnippet, selector: "cds-code-snippet, ibm-code-snippet", inputs: { display: "display", translations: "translations", copyButtonDescription: "copyButtonDescription", hideCopyButton: "hideCopyButton", disabled: "disabled", maxCollapsedNumberOfRows: "maxCollapsedNumberOfRows", minCollapsedNumberOfRows: "minCollapsedNumberOfRows", maxExpandedNumberOfRows: "maxExpandedNumberOfRows", minExpandedNumberOfRows: "minExpandedNumberOfRows", wrapText: "wrapText", theme: "theme", feedbackText: "feedbackText", feedbackTimeout: "feedbackTimeout", expanded: "expanded", skeleton: "skeleton" }, host: { properties: { "class.cds--snippet": "this.snippetClass", "class.cds--snippet--single": "this.snippetSingleClass", "class.cds--snippet--multi": "this.snippetMultiClass", "class.cds--snippet--disabled": "this.snippetDisabledClass", "class.cds--snippet--light": "this.snippetInlineLightClass", "class.cds--snippet--wraptext": "this.wrapText", "class.cds--snippet--expand": "this.expanded", "class.cds--skeleton": "this.skeleton" } }, viewQueries: [{ propertyName: "code", first: true, predicate: ["code"], descendants: true }, { propertyName: "codeContent", first: true, predicate: ["codeContent"], descendants: true }, { propertyName: "codeContainer", first: true, predicate: ["codeContainer"], descendants: true }], usesInheritance: true, ngImport: i0, template: ` <ng-container *ngIf="display === 'inline'; else notInline"> <ng-container *ngIf="!hideCopyButton; else noBtnInline"> <ng-container *ngTemplateOutlet="buttonTemplate"></ng-container> </ng-container> <ng-template #noBtnInline> <span class="cds--snippet cds--snippet--inline cds--snippet--no-copy" [ngClass]="{ 'cds--snippet--light': theme === 'light' }"> <code #code> <ng-container *ngTemplateOutlet="codeTemplate"></ng-container> </code> </span> </ng-template> </ng-container> <ng-template #notInline> <div #codeContainer class="cds--snippet-container" [attr.aria-label]="translations.CODE_SNIPPET_TEXT" [attr.tabindex]="display === 'single' && !disabled ? '0' : null" [attr.role]="display==='single' ? 'textarea' : null" [ngStyle]="styles" (scroll)="(display === 'single' ? handleScroll() : null)"> <ng-container *ngIf="skeleton"> <span *ngIf="display === 'single'; else multiSkeleton"></span> <ng-template #multiSkeleton> <span></span> <span></span> <span></span> </ng-template> </ng-container> <pre #codeContent *ngIf="!skeleton" (scroll)="(display === 'multi' ? handleScroll() : null)"><code #code><ng-container *ngTemplateOutlet="codeTemplate"></ng-container></code></pre> </div> <div *ngIf="hasLeft" class="cds--snippet__overflow-indicator--left"></div> <div *ngIf="hasRight" class="cds--snippet__overflow-indicator--right"></div> <ng-container *ngIf="!hideCopyButton;"> <ng-container *ngTemplateOutlet="buttonTemplate"></ng-container> </ng-container> <button *ngIf="isExpandable" class="cds--btn cds--btn--ghost cds--btn--sm cds--snippet-btn--expand" (click)="toggleSnippetExpansion()" type="button"> <span class="cds--snippet-btn--text">{{expanded ? translations.SHOW_LESS : translations.SHOW_MORE}}</span> <svg cdsIcon="chevron--down" size="16" class="cds--icon-chevron--down" [attr.aria-label]="translations.SHOW_MORE_ICON"></svg> </button> </ng-template> <ng-template #buttonTemplate> <cds-icon-button *ngIf="!skeleton" [description]="showFeedback ? feedbackText : copyButtonDescription" [align]="align" [autoAlign]="autoAlign" [dropShadow]="dropShadow" [caret]="caret" [highContrast]="highContrast" [isOpen]="isOpen" [enterDelayMs]="enterDelayMs" [leaveDelayMs]="leaveDelayMs" type="button" kind="primary" size="md" (click)="onCopyButtonClicked($event)" [buttonNgClass]="{ 'cds--snippet--light': theme === 'light', 'cds--snippet--inline': display === 'inline', 'cds--btn--icon-only': display !== 'inline', 'cds--copy-btn': display !== 'inline', 'cds--copy-btn--animating': animating, 'cds--copy-btn--fade-in': showFeedback, 'cds--copy-btn--fade-out': !showFeedback && animating, 'cds--snippet cds--copy': true }" [buttonAttributes]="{ 'aria-label': translations.COPY_CODE, 'aria-live': 'polite', 'tabindex': '0' }"> <ng-container *ngIf="display === 'inline'"> <code #code> <ng-container *ngTemplateOutlet="codeTemplate"></ng-container> </code> </ng-container> <ng-container *ngIf="display !== 'inline'"> <svg cdsIcon="copy" size="16" class="cds--snippet__icon"></svg> </ng-container> </cds-icon-button> </ng-template> <ng-template #codeTemplate> <ng-content></ng-content> </ng-template> `, isInline: true, dependencies: [{ kind: "directive", type: i3.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i3.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i3.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "component", type: i4.IconButton, selector: "cds-icon-button, ibm-icon-button", inputs: ["buttonNgClass", "buttonAttributes", "buttonId", "kind", "size", "type", "isExpressive", "disabled", "description", "showTooltipWhenDisabled"], outputs: ["click", "focus", "blur", "tooltipClick"] }, { kind: "directive", type: i5.IconDirective, selector: "[cdsIcon], [ibmIcon]", inputs: ["ibmIcon", "cdsIcon", "size", "title", "ariaLabel", "ariaLabelledBy", "ariaHidden", "isFocusable"] }] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: CodeSnippet, decorators: [{ type: Component, args: [{ selector: "cds-code-snippet, ibm-code-snippet", template: ` <ng-container *ngIf="display === 'inline'; else notInline"> <ng-container *ngIf="!hideCopyButton; else noBtnInline"> <ng-container *ngTemplateOutlet="buttonTemplate"></ng-container> </ng-container> <ng-template #noBtnInline> <span class="cds--snippet cds--snippet--inline cds--snippet--no-copy" [ngClass]="{ 'cds--snippet--light': theme === 'light' }"> <code #code> <ng-container *ngTemplateOutlet="codeTemplate"></ng-container> </code> </span> </ng-template> </ng-container> <ng-template #notInline> <div #codeContainer class="cds--snippet-container" [attr.aria-label]="translations.CODE_SNIPPET_TEXT" [attr.tabindex]="display === 'single' && !disabled ? '0' : null" [attr.role]="display==='single' ? 'textarea' : null" [ngStyle]="styles" (scroll)="(display === 'single' ? handleScroll() : null)"> <ng-container *ngIf="skeleton"> <span *ngIf="display === 'single'; else multiSkeleton"></span> <ng-template #multiSkeleton> <span></span> <span></span> <span></span> </ng-template> </ng-container> <pre #codeContent *ngIf="!skeleton" (scroll)="(display === 'multi' ? handleScroll() : null)"><code #code><ng-container *ngTemplateOutlet="codeTemplate"></ng-container></code></pre> </div> <div *ngIf="hasLeft" class="cds--snippet__overflow-indicator--left"></div> <div *ngIf="hasRight" class="cds--snippet__overflow-indicator--right"></div> <ng-container *ngIf="!hideCopyButton;"> <ng-container *ngTemplateOutlet="buttonTemplate"></ng-container> </ng-container> <button *ngIf="isExpandable" class="cds--btn cds--btn--ghost cds--btn--sm cds--snippet-btn--expand" (click)="toggleSnippetExpansion()" type="button"> <span class="cds--snippet-btn--text">{{expanded ? translations.SHOW_LESS : translations.SHOW_MORE}}</span> <svg cdsIcon="chevron--down" size="16" class="cds--icon-chevron--down" [attr.aria-label]="translations.SHOW_MORE_ICON"></svg> </button> </ng-template> <ng-template #buttonTemplate> <cds-icon-button *ngIf="!skeleton" [description]="showFeedback ? feedbackText : copyButtonDescription" [align]="align" [autoAlign]="autoAlign" [dropShadow]="dropShadow" [caret]="caret" [highContrast]="highContrast" [isOpen]="isOpen" [enterDelayMs]="enterDelayMs" [leaveDelayMs]="leaveDelayMs" type="button" kind="primary" size="md" (click)="onCopyButtonClicked($event)" [buttonNgClass]="{ 'cds--snippet--light': theme === 'light', 'cds--snippet--inline': display === 'inline', 'cds--btn--icon-only': display !== 'inline', 'cds--copy-btn': display !== 'inline', 'cds--copy-btn--animating': animating, 'cds--copy-btn--fade-in': showFeedback, 'cds--copy-btn--fade-out': !showFeedback && animating, 'cds--snippet cds--copy': true }" [buttonAttributes]="{ 'aria-label': translations.COPY_CODE, 'aria-live': 'polite', 'tabindex': '0' }"> <ng-container *ngIf="display === 'inline'"> <code #code> <ng-container *ngTemplateOutlet="codeTemplate"></ng-container> </code> </ng-container> <ng-container *ngIf="display !== 'inline'"> <svg cdsIcon="copy" size="16" class="cds--snippet__icon"></svg> </ng-container> </cds-icon-button> </ng-template> <ng-template #codeTemplate> <ng-content></ng-content> </ng-template> ` }] }], ctorParameters: function () { return [{ type: i1.I18n }, { type: i2.EventService }]; }, propDecorators: { snippetClass: [{ type: HostBinding, args: ["class.cds--snippet"] }], snippetSingleClass: [{ type: HostBinding, args: ["class.cds--snippet--single"] }], snippetMultiClass: [{ type: HostBinding, args: ["class.cds--snippet--multi"] }], snippetDisabledClass: [{ type: HostBinding, args: ["class.cds--snippet--disabled"] }], snippetInlineLightClass: [{ type: HostBinding, args: ["class.cds--snippet--light"] }], display: [{ type: Input }], translations: [{ type: Input }], copyButtonDescription: [{ type: Input }], hideCopyButton: [{ type: Input }], disabled: [{ type: Input }], maxCollapsedNumberOfRows: [{ type: Input }], minCollapsedNumberOfRows: [{ type: Input }], maxExpandedNumberOfRows: [{ type: Input }], minExpandedNumberOfRows: [{ type: Input }], wrapText: [{ type: HostBinding, args: ["class.cds--snippet--wraptext"] }, { type: Input }], theme: [{ type: Input }], feedbackText: [{ type: Input }], feedbackTimeout: [{ type: Input }], expanded: [{ type: HostBinding, args: ["class.cds--snippet--expand"] }, { type: Input }], skeleton: [{ type: HostBinding, args: ["class.cds--skeleton"] }, { type: Input }], code: [{ type: ViewChild, args: ["code"] }], codeContent: [{ type: ViewChild, args: ["codeContent"] }], codeContainer: [{ type: ViewChild, args: ["codeContainer"] }] } }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29kZS1zbmlwcGV0LmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9jb2RlLXNuaXBwZXQvY29kZS1zbmlwcGV0LmNvbXBvbmVudC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQ04sU0FBUyxFQUNULEtBQUssRUFDTCxXQUFXLEVBQ1gsU0FBUyxFQUdULE1BQU0sZUFBZSxDQUFDO0FBSXZCLE9BQU8sRUFBRSxjQUFjLEVBQUUsTUFBTSxrQ0FBa0MsQ0FBQzs7Ozs7OztBQUVsRSxNQUFNLENBQU4sSUFBWSxXQUlYO0FBSkQsV0FBWSxXQUFXO0lBQ3RCLGdDQUFpQixDQUFBO0lBQ2pCLDhCQUFlLENBQUE7SUFDZixnQ0FBaUIsQ0FBQTtBQUNsQixDQUFDLEVBSlcsV0FBVyxLQUFYLFdBQVcsUUFJdEI7QUFFRDs7Ozs7Ozs7Ozs7O0dBWUc7QUF5R0gsTUFBTSxPQUFPLFdBQVksU0FBUSxjQUFjO0lBNEY5Qzs7T0FFRztJQUNILFlBQXNCLElBQVUsRUFBWSxZQUEwQjtRQUNyRSxLQUFLLEVBQUUsQ0FBQztRQURhLFNBQUksR0FBSixJQUFJLENBQU07UUFBWSxpQkFBWSxHQUFaLFlBQVksQ0FBYztRQTlFN0QscUJBQWdCLEdBQVcsRUFBRSxDQUFDO1FBRXZDOztXQUVHO1FBQ00sWUFBTyxHQUFnQixXQUFXLENBQUMsTUFBTSxDQUFDO1FBQzFDLGlCQUFZLEdBQUcsSUFBSSxDQUFDLElBQUksQ0FBQyxHQUFHLEVBQUUsQ0FBQyxZQUFZLENBQUM7UUFLckQ7O1dBRUc7UUFDTSxtQkFBYyxHQUFHLEtBQUssQ0FBQztRQUNoQzs7V0FFRztRQUNNLGFBQVEsR0FBRyxLQUFLLENBQUM7UUFDMUI7OztXQUdHO1FBQ00sNkJBQXdCLEdBQUcsRUFBRSxDQUFDO1FBQ3ZDOzs7V0FHRztRQUNNLDZCQUF3QixHQUFHLENBQUMsQ0FBQztRQUN0Qzs7O1dBR0c7UUFDTSw0QkFBdUIsR0FBRyxDQUFDLENBQUM7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O2dCQUlHLFlBQVk7c0JBQXBCLEtBQUs7Z0JBS0csZUFBZTtzQkFBdkIsS0FBSztnQkFFOEMsUUFBUTtzQkFBM0QsV0FBVzt1QkFBQyw0QkFBNEI7O3NCQUFHLEtBQUs7Z0JBQ0osUUFBUTtzQkFBcEQsV0FBVzt1QkFBQyxxQkFBcUI7O3NCQUFHLEtBQUs7Z0JBR3ZCLElBQUk7c0JBQXRCLFNBQVM7dUJBQUMsTUFBTTtnQkFDUyxXQUFXO3NCQUFwQyxTQUFTO3VCQUFDLGFBQWE7Z0JBQ0ksYUFBYTtzQkFBeEMsU0FBUzt1QkFBQyxlQUFlIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHtcblx0Q29tcG9uZW50LFxuXHRJbnB1dCxcblx0SG9zdEJpbmRpbmcsXG5cdFZpZXdDaGlsZCxcblx0QWZ0ZXJWaWV3SW5pdCxcblx0T25Jbml0XG59IGZyb20gXCJAYW5ndWxhci9jb3JlXCI7XG5cbmltcG9ydCB7IEkxOG4gfSBmcm9tIFwiY2FyYm9uLWNvbXBvbmVudHMtYW5ndWxhci9pMThuXCI7XG5pbXBvcnQgeyBFdmVudFNlcnZpY2UgfSBmcm9tIFwiY2FyYm9uLWNvbXBvbmVudHMtYW5ndWxhci91dGlsc1wiO1xuaW1wb3J0IHsgQmFzZUljb25CdXR0b24gfSBmcm9tIFwiY2FyYm9uLWNvbXBvbmVudHMtYW5ndWxhci9idXR0b25cIjtcblxuZXhwb3J0IGVudW0gU25pcHBldFR5cGUge1xuXHRzaW5nbGUgPSBcInNpbmdsZVwiLFxuXHRtdWx0aSA9IFwibXVsdGlcIixcblx0aW5saW5lID0gXCJpbmxpbmVcIlxufVxuXG4vKipcbiAqIEdldCBzdGFydGVkIHdpdGggaW1wb3J0aW5nIHRoZSBtb2R1bGU6XG4gKlxuICogYGBgdHlwZXNjcmlwdFxuICogaW1wb3J0IHsgQ29kZVNuaXBwZXRNb2R1bGUgfSBmcm9tICdjYXJib24tY29tcG9uZW50cy1hbmd1bGFyJztcbiAqIGBgYFxuICpcbiAqIGBgYGh0bWxcbiAqIDxjZHMtY29kZS1zbmlwcGV0PkNvZGU8L2Nkcy1jb2RlLXNuaXBwZXQ+XG4gKiBgYGBcbiAqXG4gKiBbU2VlIGRlbW9dKC4uLy4uLz9wYXRoPS9zdG9yeS9jb21wb25lbnRzLWNvZGUtc25pcHBldC0tYmFzaWMpXG4gKi9cbkBDb21wb25lbnQoe1xuXHRzZWxlY3RvcjogXCJjZHMtY29kZS1zbmlwcGV0LCBpYm0tY29kZS1zbmlwcGV0XCIsXG5cdHRlbXBsYXRlOiBgXG5cdFx0PG5nLWNvbnRhaW5lciAqbmdJZj1cImRpc3BsYXkgPT09ICdpbmxpbmUnOyBlbHNlIG5vdElubGluZVwiPlxuXHRcdFx0PG5nLWNvbnRhaW5lciAqbmdJZj1cIiFoaWRlQ29weUJ1dHRvbjsgZWxzZSBub0J0bklubGluZVwiPlxuXHRcdFx0XHQ8bmctY29udGFpbmVyICpuZ1RlbXBsYXRlT3V0bGV0PVwiYnV0dG9uVGVtcGxhdGVcIj48L25nLWNvbnRhaW5lcj5cblx0XHRcdDwvbmctY29udGFpbmVyPlxuXHRcdFx0PG5nLXRlbXBsYXRlICNub0J0bklubGluZT5cblx0XHRcdFx0PHNwYW5cblx0XHRcdFx0XHRjbGFzcz1cImNkcy0tc25pcHBldCBjZHMtLXNuaXBwZXQtLWlubGluZSBjZHMtLXNuaXBwZXQtLW5vLWNvcHlcIlxuXHRcdFx0XHRcdFtuZ0NsYXNzXT1cIntcblx0XHRcdFx0XHRcdCdjZHMtLXNuaXBwZXQtLWxpZ2h0JzogdGhlbWUgPT09ICdsaWdodCdcblx0XHRcdFx0XHR9XCI+XG5cdFx0XHRcdFx0PGNvZGUgI2NvZGU+XG5cdFx0XHRcdFx0XHQ8bmctY29udGFpbmVyICpuZ1RlbXBsYXRlT3V0bGV0PVwiY29kZVRlbXBsYXRlXCI+PC9uZy1jb250YWluZXI+XG5cdFx0XHRcdFx0PC9jb2RlPlxuXHRcdFx0XHQ8L3NwYW4+XG5cdFx0XHQ8L25nLXRlbXBsYXRlPlxuXHRcdDwvbmctY29udGFpbmVyPlxuXG5cdFx0PG5nLXRlbXBsYXRlICNub3RJbmxpbmU+XG5cdFx0XHQ8ZGl2XG5cdFx0XHRcdCNjb2RlQ29udGFpbmVyXG5cdFx0XHRcdGNsYXNzPVwiY2RzLS1zbmlwcGV0LWNvbnRhaW5lclwiXG5cdFx0XHRcdFthdHRyLmFyaWEtbGFiZWxdPVwidHJhbnNsYXRpb25zLkNPREVfU05JUFBFVF9URVhUXCJcblx0XHRcdFx0W2F0dHIudGFiaW5kZXhdPVwiZGlzcGxheSA9PT0gJ3NpbmdsZScgJiYgIWRpc2FibGVkID8gJzAnIDogbnVsbFwiXG5cdFx0XHRcdFthdHRyLnJvbGVdPVwiZGlzcGxheT09PSdzaW5nbGUnID8gJ3RleHRhcmVhJyA6IG51bGxcIlxuXHRcdFx0XHRbbmdTdHlsZV09XCJzdHlsZXNcIlxuXHRcdFx0XHQoc2Nyb2xsKT1cIihkaXNwbGF5ID09PSAnc2luZ2xlJyA/IGhhbmRsZVNjcm9sbCgpIDogbnVsbClcIj5cblx0XHRcdFx0PG5nLWNvbnRhaW5lciAqbmdJZj1cInNrZWxldG9uXCI+XG5cdFx0XHRcdFx0PHNwYW4gKm5nSWY9XCJkaXNwbGF5ID09PSAnc2luZ2xlJzsgZWxzZSBtdWx0aVNrZWxldG9uXCI+PC9zcGFuPlxuXHRcdFx0XHRcdDxuZy10ZW1wbGF0ZSAjbXVsdGlTa2VsZXRvbj5cblx0XHRcdFx0XHRcdDxzcGFuPjwvc3Bhbj5cblx0XHRcdFx0XHRcdDxzcGFuPjwvc3Bhbj5cblx0XHRcdFx0XHRcdDxzcGFuPjwvc3Bhbj5cblx0XHRcdFx0XHQ8L25nLXRlbXBsYXRlPlxuXHRcdFx0XHQ8L25nLWNvbnRhaW5lcj5cblx0XHRcdFx0PHByZVxuXHRcdFx0XHRcdCNjb2RlQ29udGVudFxuXHRcdFx0XHRcdCpuZ0lmPVwiIXNrZWxldG9uXCJcblx0XHRcdFx0XHQoc2Nyb2xsKT1cIihkaXNwbGF5ID09PSAnbXVsdGknID8gaGFuZGxlU2Nyb2xsKCkgOiBudWxsKVwiPjxjb2RlICNjb2RlPjxuZy1jb250YWluZXIgKm5nVGVtcGxhdGVPdXRsZXQ9XCJjb2RlVGVtcGxhdGVcIj48L25nLWNvbnRhaW5lcj48L2NvZGU+PC9wcmU+XG5cdFx0XHQ8L2Rpdj5cblx0XHRcdDxkaXYgKm5nSWY9XCJoYXNMZWZ0XCIgY2xhc3M9XCJjZHMtLXNuaXBwZXRfX292ZXJmbG93LWluZGljYXRvci0tbGVmdFwiPjwvZGl2PlxuXHRcdFx0PGRpdiAqbmdJZj1cImhhc1JpZ2h0XCIgY2xhc3M9XCJjZHMtLXNuaXBwZXRfX292ZXJmbG93LWluZGljYXRvci0tcmlnaHRcIj48L2Rpdj5cblx0XHRcdDxuZy1jb250YWluZXIgKm5nSWY9XCIhaGlkZUNvcHlCdXR0b247XCI+XG5cdFx0XHRcdDxuZy1jb250YWluZXIgKm5nVGVtcGxhdGVPdXRsZXQ9XCJidXR0b25UZW1wbGF0ZVwiPjwvbmctY29udGFpbmVyPlxuXHRcdFx0PC9uZy1jb250YWluZXI+XG5cdFx0XHQ8YnV0dG9uXG5cdFx0XHRcdCpuZ0lmPVwiaXNFeHBhbmRhYmxlXCJcblx0XHRcdFx0Y2xhc3M9XCJjZHMtLWJ0biBjZHMtLWJ0bi0tZ2hvc3QgY2RzLS1idG4tLXNtIGNkcy0tc25pcHBldC1idG4tLWV4cGFuZFwiXG5cdFx0XHRcdChjbGljayk9XCJ0b2dnbGVTbmlwcGV0RXhwYW5zaW9uKClcIlxuXHRcdFx0XHR0eXBlPVwiYnV0dG9uXCI+XG5cdFx0XHRcdDxzcGFuIGNsYXNzPVwiY2RzLS1zbmlwcGV0LWJ0bi0tdGV4dFwiPnt7ZXhwYW5kZWQgPyB0cmFuc2xhdGlvbnMuU0hPV19MRVNTIDogdHJhbnNsYXRpb25zLlNIT1dfTU9SRX19PC9zcGFuPlxuXHRcdFx0XHQ8c3ZnIGNkc0ljb249XCJjaGV2cm9uLS1kb3duXCIgc2l6ZT1cIjE2XCIgY2xhc3M9XCJjZHMtLWljb24tY2hldnJvbi0tZG93blwiIFthdHRyLmFyaWEtbGFiZWxdPVwidHJhbnNsYXRpb25zLlNIT1dfTU9SRV9JQ09OXCI+PC9zdmc+XG5cdFx0XHQ8L2J1dHRvbj5cblx0XHQ8L25nLXRlbXBsYXRlPlxuXG5cdFx0PG5nLXRlbXBsYXRlICNidXR0b25UZW1wbGF0ZT5cblx0XHRcdDxjZHMtaWNvbi1idXR0b25cblx0XHRcdFx0Km5nSWY9XCIhc2tlbGV0b25cIlxuXHRcdFx0XHRbZGVzY3JpcHRpb25dPVwic2hvd0ZlZWRiYWNrID8gZmVlZGJhY2tUZXh0IDogY29weUJ1dHRvbkRlc2NyaXB0aW9uXCJcblx0XHRcdFx0W2FsaWduXT1cImFsaWduXCJcblx0XHRcdFx0W2F1dG9BbGlnbl09XCJhdXRvQWxpZ25cIlxuXHRcdFx0XHRbZHJvcFNoYWRvd109XCJkcm9wU2hhZG93XCJcblx0XHRcdFx0W2NhcmV0XT1cImNhcmV0XCJcblx0XHRcdFx0W2hpZ2hDb250cmFzdF09XCJoaWdoQ29udHJhc3RcIlxuXHRcdFx0XHRbaXNPcGVuXT1cImlzT3BlblwiXG5cdFx0XHRcdFtlbnRlckRlbGF5TXNdPVwiZW50ZXJEZWxheU1zXCJcblx0XHRcdFx0W2xlYXZlRGVsYXlNc109XCJsZWF2ZURlbGF5TXNcIlxuXHRcdFx0XHR0eXBlPVwiYnV0dG9uXCJcblx0XHRcdFx0a2luZD1cInByaW1hcnlcIlxuXHRcdFx0XHRzaXplPVwibWRcIlxuXHRcdFx0XHQoY2xpY2spPVwib25Db3B5QnV0dG9uQ2xpY2tlZCgkZXZlbnQpXCJcblx0XHRcdFx0W2J1dHRvbk5nQ2xhc3NdPVwie1xuXHRcdFx0XHRcdCdjZHMtLXNuaXBwZXQtLWxpZ2h0JzogdGhlbWUgPT09ICdsaWdodCcsXG5cdFx0XHRcdFx0J2Nkcy0tc25pcHBldC0taW5saW5lJzogZGlzcGxheSA9PT0gJ2lubGluZScsXG5cdFx0XHRcdFx0J2Nkcy0tYnRuLS1pY29uLW9ubHknOiBkaXNwbGF5ICE9PSAnaW5saW5lJyxcblx0XHRcdFx0XHQnY2RzLS1jb3B5LWJ0bic6IGRpc3BsYXkgIT09ICdpbmxpbmUnLFxuXHRcdFx0XHRcdCdjZHMtLWNvcHktYnRuLS1hbmltYXRpbmcnOiBhbmltYXRpbmcsXG5cdFx0XHRcdFx0J2Nkcy0tY29weS1idG4tLWZhZGUtaW4nOiBzaG93RmVlZGJhY2ssXG5cdFx0XHRcdFx0J2Nkcy0tY29weS1idG4tLWZhZGUtb3V0JzogIXNob3dGZWVkYmFjayAmJiBhbmltYXRpbmcsXG5cdFx0XHRcdFx0J2Nkcy0tc25pcHBldCBjZHMtLWNvcHknOiB0cnVlXG5cdFx0XHRcdH1cIlxuXHRcdFx0XHRbYnV0dG9uQXR0cmlidXRlc109XCJ7XG5cdFx0XHRcdFx0J2FyaWEtbGFiZWwnOiB0cmFuc2xhdGlvbnMuQ09QWV9DT0RFLFxuXHRcdFx0XHRcdCdhcmlhLWxpdmUnOiAncG9saXRlJyxcblx0XHRcdFx0XHQndGFiaW5kZXgnOiAnMCdcblx0XHRcdFx0fVwiPlxuXHRcdFx0XHQ8bmctY29udGFpbmVyICpuZ0lmPVwiZGlzcGxheSA9PT0gJ2lubGluZSdcIj5cblx0XHRcdFx0XHQ8Y29kZSAjY29kZT5cblx0XHRcdFx0XHRcdDxuZy1jb250YWluZXIgKm5nVGVtcGxhdGVPdXRsZXQ9XCJjb2RlVGVtcGxhdGVcIj48L25nLWNvbnRhaW5lcj5cblx0XHRcdFx0XHQ8L2NvZGU+XG5cdFx0XHRcdDwvbmctY29udGFpbmVyPlxuXHRcdFx0XHQ8bmctY29udGFpbmVyICpuZ0lmPVwiZGlzcGxheSAhPT0gJ2lubGluZSdcIj5cblx0XHRcdFx0XHQ8c3ZnIGNkc0ljb249XCJjb3B5XCIgc2l6ZT1cIjE2XCIgY2xhc3M9XCJjZHMtLXNuaXBwZXRfX2ljb25cIj48L3N2Zz5cblx0XHRcdFx0PC9uZy1jb250YWluZXI+XG5cdFx0XHQ8L2Nkcy1pY29uLWJ1dHRvbj5cblx0XHQ8L25nLXRlbXBsYXRlPlxuXG5cdFx0PG5nLXRlbXBsYXRlICNjb2RlVGVtcGxhdGU+XG5cdFx0XHQ8bmctY29udGVudD48L25nLWNvbnRlbnQ+XG5cdFx0PC9uZy10ZW1wbGF0ZT5cblx0YFxufSlcbmV4cG9ydCBjbGFzcyBDb2RlU25pcHBldCBleHRlbmRzIEJhc2VJY29uQnV0dG9uIGltcGxlbWVudHMgT25Jbml0LCBBZnRlclZpZXdJbml0IHtcblx0QEhvc3RCaW5kaW5nKFwiY2xhc3MuY2RzLS1zbmlwcGV0XCIpIGdldCBzbmlwcGV0Q2xhc3MoKSB7XG5cdFx0cmV0dXJuIHRoaXMuZGlzcGxheSAhPT0gU25pcHBldFR5cGUuaW5saW5lO1xuXHR9XG5cdEBIb3N0QmluZGluZyhcImNsYXNzLmNkcy0tc25pcHBldC0tc2luZ2xlXCIpIGdldCBzbmlwcGV0U2luZ2xlQ2xhc3MoKSB7XG5cdFx0cmV0dXJuIHRoaXMuZGlzcGxheSA9PT0gU25pcHBldFR5cGUuc2luZ2xlO1xuXHR9XG5cdEBIb3N0QmluZGluZyhcImNsYXNzLmNkcy0tc25pcHBldC0tbXVsdGlcIikgZ2V0IHNuaXBwZXRNdWx0aUNsYXNzKCkge1xuXHRcdHJldHVybiB0aGlzLmRpc3BsYXkgPT09IFNuaXBwZXRUeXBlLm11bHRpO1xuXHR9XG5cdEBIb3N0QmluZGluZyhcImNsYXNzLmNkcy0tc25pcHBldC0tZGlzYWJsZWRcIikgZ2V0IHNuaXBwZXREaXNhYmxlZENsYXNzKCkge1xuXHRcdHJldHVybiB0aGlzLmRpc3BsYXkgIT09IFwiaW5saW5lXCIgJiYgdGhpcy5kaXNhYmxlZDtcblx0fVxuXHRASG9zdEJpbmRpbmcoXCJjbGFzcy5jZHMtLXNuaXBwZXQtLWxpZ2h0XCIpIGdldCBzbmlwcGV0SW5saW5lTGlnaHRDbGFzcygpIHtcblx0XHRyZXR1cm4gdGhpcy50aGVtZSA9PT0gXCJsaWdodFwiO1xuXHR9XG5cblx0cmVhZG9ubHkgcm93SGVpZ2h0SW5QaXhlbDogbnVtYmVyID0gMTY7XG5cblx0LyoqXG5cdCAqIEl0IGNhbiBiZSBgXCJzaW5nbGVcImAsIGBcIm11bHRpXCJgIG9yIGBcImlubGluZVwiYFxuXHQgKi9cblx0QElucHV0KCkgZGlzcGxheTogU25pcHBldFR5cGUgPSBTbmlwcGV0VHlwZS5zaW5nbGU7XG5cdEBJbnB1dCgpIHRyYW5zbGF0aW9ucyA9IHRoaXMuaTE4bi5nZXQoKS5DT0RFX1NOSVBQRVQ7XG5cdC8qKlxuXHQgKiBjb3B5IGJ1dHRvbiBkZXNjcmlwdGlvbiB0byBzaG93IG9uIGhvdmVyXG5cdCAqL1xuXHRASW5wdXQoKSBjb3B5QnV0dG9uRGVzY3JpcHRpb246IHN0cmluZztcblx0LyoqXG5cdCAqIFNldCB0byBgdHJ1ZWAgdG8gaGlkZSBjb3B5IGJ1dHRvblxuXHQgKi9cblx0QElucHV0KCkgaGlkZUNvcHlCdXR0b24gPSBmYWxzZTtcblx0LyoqXG5cdCAqIFNldCB0byBgdHJ1ZWAgdG8gZGlzYWJsZSB0aGUgY29kZSBzbmlwcGV0XG5cdCAqL1xuXHRASW5wdXQoKSBkaXNhYmxlZCA9IGZhbHNlO1xuXHQvKipcblx0ICogU3BlY2lmeSB0aGUgbWF4IG51bWJlciBvZiByb3dzIHRvIHNob3cgd2hlbiBjb2xsYXBzZWRcblx0ICogRGVmYXVsdCBpcyBgMTVgXG5cdCAqL1xuXHRASW5wdXQoKSBtYXhDb2xsYXBzZWROdW1iZXJPZlJvd3MgPSAxNTtcblx0LyoqXG5cdCAqIFNwZWNpZnkgdGhlIG1pbiBudW1iZXIgb2Ygcm93cyB0byBzaG93IHdoZW4gY29sbGFwc2VkXG5cdCAqIERlZmF1bHQgaXMgYDNgXG5cdCAqL1xuXHRASW5wdXQoKSBtaW5Db2xsYXBzZWROdW1iZXJPZlJvd3MgPSAzO1xuXHQvKipcblx0ICogU3BlY2lmeSB0aGUgbWF4IG51bWJlciBvZiByb3dzIHRvIHNob3cgd2hlbiBleHBhbmRlZFxuXHQgKiBEZWZhdWx0IGlzIGAwYCwgaGVuY2UgYWxsIGNvbnRlbnQgd2lsbCBiZSB2aXNpYmxlIHdoZW4gZXhwYW5kZWRcblx0ICovXG5cdEBJbnB1dCgpIG1heEV4cGFuZGVkTnVtYmVyT2ZSb3dzID0gMDtcblx0LyoqXG5cdCAqIFNwZWNpZnkgdGhlIG1pbiBudW1iZXIgb2Ygcm93cyB0byBzaG93IHdoZW4gZXhwYW5kZWRcblx0ICogRGVmYXVsdCBpcyBgMTZgLCBoZW5jZSBoZWlnaHQgb2YgZXhwYW5kZWQgcm93IHdpbGwgYmUgMTYgKiByb3dIZWlnaHRJblBpeGVsICgxNikgPSAgMjU2cHhcblx0ICovXG5cdEBJbnB1dCgpIG1pbkV4cGFuZGVkTnVtYmVyT2ZSb3dzID0gMTY7XG5cdC8qKlxuXHQgKiBTZXQgdG8gYHRydWVgIHRvIHdyYXAgdGhlIHRleHRcblx0ICovXG5cdEBIb3N0QmluZGluZyhcImNsYXNzLmNkcy0tc25pcHBldC0td3JhcHRleHRcIikgQElucHV0KCkgd3JhcFRleHQgPSBmYWxzZTtcblx0LyoqXG5cdCAqIEBkZXByZWNhdGVkIHNpbmNlIHY1IC0gVXNlIGBjZHNMYXllcmAgZGlyZWN0aXZlIGluc3RlYWRcblx0ICogU2V0IHRvIGBcImxpZ2h0XCJgIHRvIGFwcGx5IHRoZSBsaWdodCBzdHlsZVxuXHQgKi9cblx0QElucHV0KCkgdGhlbWU6IFwibGlnaHRcIiB8IFwiZGFya1wiID0gXCJkYXJrXCI7XG5cdC8qKlxuXHQgKiBUZXh0IGRpc3BsYXllZCBpbiB0aGUgdG9vbHRpcCB3aGVuIHVzZXIgY2xpY2tzIGJ1dHRvbiB0byBjb3B5IGNvZGUuXG5cdCAqL1xuXHRASW5wdXQoKSBmZWVkYmFja1RleHQgPSB0aGlzLnRyYW5zbGF0aW9ucy5DT1BJRUQ7XG5cdC8qKlxuXHQgKiBUaW1lIGluIG1pbGlzZWNvbmRzIHRvIGtlZXAgdGhlIGZlZWRiYWNrIHRvb2x0aXAgZGlzcGxheWVkLlxuXHQgKiBEZWZhdWx0cyB0byAyIHNlY29uZHNcblx0ICovXG5cdEBJbnB1dCgpIGZlZWRiYWNrVGltZW91dCA9IDIwMDA7XG5cblx0QEhvc3RCaW5kaW5nKFwiY2xhc3MuY2RzLS1zbmlwcGV0LS1leHBhbmRcIikgQElucHV0KCkgZXhwYW5kZWQgPSBmYWxzZTtcblx0QEhvc3RCaW5kaW5nKFwiY2xhc3MuY2RzLS1za2VsZXRvblwiKSBASW5wdXQoKSBza2VsZXRvbiA9IGZhbHNlO1xuXHRzdHlsZXM6IGFueSA9IHt9O1xuXG5cdEBWaWV3Q2hpbGQoXCJjb2RlXCIpIGNvZGU7XG5cdEBWaWV3Q2hpbGQoXCJjb2RlQ29udGVudFwiKSBjb2RlQ29udGVudDtcblx0QFZpZXdDaGlsZChcImNvZGVDb250YWluZXJcIikgY29kZUNvbnRhaW5lcjtcblxuXHRzaG93RmVlZGJhY2sgPSBmYWxzZTtcblx0YW5pbWF0aW5nID0gZmFsc2U7XG5cdGhhc0V4cGFuZEJ1dHRvbiA9IG51bGw7XG5cdGlzRXhwYW5kYWJsZSA9IGZhbHNlO1xuXHRoYXNSaWdodE92ZXJmbG93ID0gZmFsc2U7XG5cblx0aGFzUmlnaHQgPSBmYWxzZTtcblx0aGFzTGVmdCA9IGZhbHNlO1xuXG5cdC8qKlxuXHQgKiBDcmVhdGVzIGFuIGluc3RhbmNlIG9mIENvZGVTbmlwcGV0LlxuXHQgKi9cblx0Y29uc3RydWN0b3IocHJvdGVjdGVkIGkxOG46IEkxOG4sIHByb3RlY3RlZCBldmVudFNlcnZpY2U6IEV2ZW50U2VydmljZSkge1xuXHRcdHN1cGVyKCk7XG5cdFx0dGhpcy5kcm9wU2hhZG93ID0gZmFsc2U7XG5cdH1cblxuXHRoYW5kbGVTY3JvbGwoKSB7XG5cdFx0aWYgKHRoaXMuc2tlbGV0b24pIHtcblx0XHRcdHJldHVybjtcblx0XHR9XG5cblx0XHRsZXQgcmVmO1xuXHRcdHN3aXRjaCAodGhpcy5kaXNwbGF5KSB7XG5cdFx0XHRjYXNlIFwibXVsdGlcIjpcblx0XHRcdFx0cmVmID0gdGhpcy5jb2RlQ29udGVudC5uYXRpdmVFbGVtZW50O1xuXHRcdFx0XHRicmVhaztcblx0XHRcdGNhc2UgXCJzaW5nbGVcIjpcblx0XHRcdFx0cmVmID0gdGhpcy5jb2RlQ29udGFpbmVyLm5hdGl2ZUVsZW1lbnQ7XG5cdFx0XHRcdGJyZWFrO1xuXHRcdFx0ZGVmYXVsdDpcblx0XHRcdFx0cmV0dXJuO1xuXHRcdH1cblx0XHRpZiAocmVmKSB7XG5cdFx0XHRjb25zdCB7XG5cdFx0XHRcdHNjcm9sbFdpZHRoLFxuXHRcdFx0XHRjbGllbnRXaWR0aCxcblx0XHRcdFx0c2Nyb2xsTGVmdFxuXHRcdFx0fSA9IHJlZjtcblx0XHRcdGNvbnN0IGhvcml6b250YWxPdmVyZmxvdyA9IHNjcm9sbFdpZHRoID4gY2xpZW50V2lkdGg7XG5cdFx0XHR0aGlzLmhhc0xlZnQgPSBob3Jpem9udGFsT3ZlcmZsb3cgJiYgISFzY3JvbGxMZWZ0O1xuXHRcdFx0dGhpcy5oYXNSaWdodCA9IGhvcml6b250YWxPdmVyZmxvdyAmJiBzY3JvbGxMZWZ0ICsgY2xpZW50V2lkdGggIT09IHNjcm9sbFdpZHRoO1xuXHRcdH1cblx0fVxuXG5cdHRvZ2dsZVNuaXBwZXRFeHBhbnNpb24oKSB7XG5cdFx0dGhpcy5leHBhbmRlZCA9ICF0aGlzLmV4cGFuZGVkO1xuXHRcdHRoaXMuY2FsY3VsYXRlQ29udGFpbmVySGVpZ2h0KCk7XG5cdH1cblxuXHRvbkNvcHlCdXR0b25DbGlja2VkKCkge1xuXHRcdGlmICghdGhpcy5kaXNhYmxlZCkge1xuXHRcdFx0d2luZG93Lm5hdmlnYXRvci5jbGlwYm9hcmRcblx0XHRcdFx0LndyaXRlVGV4dCh0aGlzLmNvZGUubmF0aXZlRWxlbWVudC5pbm5lclRleHQgfHwgdGhpcy5jb2RlLm5hdGl2ZUVsZW1lbnQudGV4dENvbnRlbnQpLnRoZW4oKCkgPT4ge1xuXHRcdFx0XHRcdHRoaXMuc2hvd0ZlZWRiYWNrID0gdHJ1ZTtcblx0XHRcdFx0XHR0aGlzLmFuaW1hdGluZyA9IHRydWU7XG5cdFx0XHRcdFx0c2V0VGltZW91dCgoKSA9PiB7XG5cdFx0XHRcdFx0XHR0aGlzLnNob3dGZWVkYmFjayA9IGZhbHNlO1xuXHRcdFx0XHRcdFx0dGhpcy5hbmltYXRpbmcgPSBmYWxzZTtcblx0XHRcdFx0XHR9LCB0aGlzLmZlZWRiYWNrVGltZW91dCk7XG5cdFx0XHRcdH0pO1xuXHRcdH1cblx0fVxuXG5cdG5nT25Jbml0KCkge1xuXHRcdHRoaXMuY2FsY3VsYXRlQ29udGFpbmVySGVpZ2h0KCk7XG5cdH1cblxuXHRuZ0FmdGVyVmlld0luaXQoKSB7XG5cdFx0dGhpcy5jYW5FeHBhbmQoKTtcblx0XHR0aGlzLmhhbmRsZVNjcm9sbCgpO1xuXHRcdGlmICh3aW5kb3cpIHtcblx0XHRcdHRoaXMuZXZlbnRTZXJ2aWNlLm9uKHdpbmRvdyBhcyBhbnksIFwicmVzaXplXCIsICgpID0+IHtcblx0XHRcdFx0dGhpcy5jYW5FeHBhbmQoKTtcblx0XHRcdFx0dGhpcy5oYW5kbGVTY3JvbGwoKTtcblx0XHRcdH0pO1xuXHRcdH1cblx0fVxuXG5cdGNhbGN1bGF0ZUNvbnRhaW5lckhlaWdodCgpIHtcblx0XHRpZiAodGhpcy5kaXNwbGF5ID09PSBcIm11bHRpXCIgJiYgIXRoaXMuc2tlbGV0b24pIHtcblx0XHRcdHRoaXMuc3R5bGVzID0ge307XG5cdFx0XHRpZiAodGhpcy5leHBhbmRlZCkge1xuXHRcdFx0XHRpZiAodGhpcy5tYXhFeHBhbmRlZE51bWJlck9mUm93cyA+IDApIHtcblx0XHRcdFx0XHR0aGlzLnN0eWxlc1tcIm1heC1oZWlnaHRcIl0gPSBgJHt0aGlzLm1heEV4cGFuZGVkTnVtYmVyT2ZSb3dzICogdGhpcy5yb3dIZWlnaHRJblBpeGVsfXB4YDtcblx0XHRcdFx0fVxuXHRcdFx0XHRpZiAodGhpcy5taW5FeHBhbmRlZE51bWJlck9mUm93cyA+IDApIHtcblx0XHRcdFx0XHR0aGlzLnN0eWxlc1tcIm1pbi1oZWlnaHRcIl0gPSBgJHt0aGlzLm1pbkV4cGFuZGVkTnVtYmVyT2ZSb3dzICogdGhpcy5yb3dIZWlnaHRJblBpeGVsfXB4YDtcblx0XHRcdFx0fVxuXHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0aWYgKHRoaXMubWF4Q29sbGFwc2VkTnVtYmVyT2ZSb3dzID4gMCkge1xuXHRcdFx0XHRcdHRoaXMuc3R5bGVzW1wibWF4LWhlaWdodFwiXSA9IGAke3RoaXMubWF4Q29sbGFwc2VkTnVtYmVyT2ZSb3dzICogdGhpcy5yb3dIZWlnaHRJblBpeGVsfXB4YDtcblx0XHRcdFx0fVxuXHRcdFx0XHRpZiAodGhpcy5taW5Db2xsYXBzZWROdW1iZXJPZlJvd3MgPiAwKSB7XG5cdFx0XHRcdFx0dGhpcy5zdHlsZXNbXCJtaW4taGVpZ2h0XCJdID0gYCR7dGhpcy5taW5Db2xsYXBzZWROdW1iZXJPZlJvd3MgKiB0aGlzLnJvd0hlaWdodEluUGl4ZWx9cHhgO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0fVxuXHR9XG5cblx0cHJvdGVjdGVkIGNhbkV4cGFuZCgpIHtcblx0XHRpZiAodGhpcy5kaXNwbGF5ID09PSBcIm11bHRpXCIgJiYgIXRoaXMuc2tlbGV0b24pIHtcblx0XHRcdGNvbnN0IGhlaWdodCA9IHRoaXMuY29kZUNvbnRlbnQubmF0aXZlRWxlbWVudC5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKS5oZWlnaHQ7XG5cdFx0XHRpZiAoXG5cdFx0XHRcdHRoaXMubWF4Q29sbGFwc2VkTnVtYmVyT2ZSb3dzID4gMCAmJlxuXHRcdFx0XHQodGhpcy5tYXhFeHBhbmRlZE51bWJlck9mUm93cyA8PSAwIHx8XG5cdFx0XHRcdFx0dGhpcy5tYXhFeHBhbmRlZE51bWJlck9mUm93cyA+IHRoaXMubWF4Q29sbGFwc2VkTnVtYmVyT2ZSb3dzKSAmJlxuXHRcdFx0XHRoZWlnaHQgPiB0aGlzLm1heENvbGxhcHNlZE51bWJlck9mUm93cyAqIHRoaXMucm93SGVpZ2h0SW5QaXhlbFxuXHRcdFx0KSB7XG5cdFx0XHRcdHRoaXMuaXNFeHBhbmRhYmxlID0gdHJ1ZTtcblx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdHRoaXMuaXNFeHBhbmRhYmxlID0gZmFsc2U7XG5cdFx0XHR9XG5cblx0XHRcdGlmIChcblx0XHRcdFx0dGhpcy5leHBhbmRlZCAmJlxuXHRcdFx0XHR0aGlzLm1pbkV4cGFuZGVkTnVtYmVyT2ZSb3dzID4gMCAmJlxuXHRcdFx0XHRoZWlnaHQgPD0gdGhpcy5taW5FeHBhbmRlZE51bWJlck9mUm93cyAqIHRoaXMucm93SGVpZ2h0SW5QaXhlbFxuXHRcdFx0KSB7XG5cdFx0XHRcdHRoaXMuaXNFeHBhbmRhYmxlID0gZmFsc2U7XG5cdFx0XHR9XG5cdFx0fVxuXHR9XG59XG4iXX0=