UNPKG

carbon-components-angular

Version:
478 lines (472 loc) 41.7 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" [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"], 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" [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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29kZS1zbmlwcGV0LmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9jb2RlLXNuaXBwZXQvY29kZS1zbmlwcGV0LmNvbXBvbmVudC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQ04sU0FBUyxFQUNULEtBQUssRUFDTCxXQUFXLEVBQ1gsU0FBUyxFQUdULE1BQU0sZUFBZSxDQUFDO0FBSXZCLE9BQU8sRUFBRSxjQUFjLEVBQUUsTUFBTSxrQ0FBa0MsQ0FBQzs7Ozs7OztBQUVsRSxNQUFNLENBQU4sSUFBWSxXQUlYO0FBSkQsV0FBWSxXQUFXO0lBQ3RCLGdDQUFpQixDQUFBO0lBQ2pCLDhCQUFlLENBQUE7SUFDZixnQ0FBaUIsQ0FBQTtBQUNsQixDQUFDLEVBSlcsV0FBVyxLQUFYLFdBQVcsUUFJdEI7QUFFRDs7Ozs7Ozs7Ozs7O0dBWUc7QUF3R0gsTUFBTSxPQUFPLFdBQVksU0FBUSxjQUFjO0lBNEY5Qzs7T0FFRztJQUNILFlBQXNCLElBQVUsRUFBWSxZQUEwQjtRQUNyRSxLQUFLLEVBQUUsQ0FBQztRQURhLFNBQUksR0FBSixJQUFJLENBQU07UUFBWSxpQkFBWSxHQUFaLFlBQVksQ0FBYztRQTlFN0QscUJBQWdCLEdBQVcsRUFBRSxDQUFDO1FBRXZDOztXQUVHO1FBQ00sWUFBTyxHQUFnQixXQUFXLENBQUMsTUFBTSxDQUFDO1FBQzFDLGlCQUFZLEdBQUcsSUFBSSxDQUFDLElBQUksQ0FBQyxHQUFHLEVBQUUsQ0FBQyxZQUFZLENBQUM7UUFLckQ7O1dBRUc7UUFDTSxtQkFBYyxHQUFHLEtBQUssQ0FBQztRQUNoQzs7V0FFRztRQUNNLGFBQVEsR0FBRyxLQUFLLENBQUM7UUFDMUI7OztXQUdHO1FBQ00sNkJBQXdCLEdBQUcsRUFBRSxDQUFDO1FBQ3ZDOzs7V0FHRztRQUNNLDZCQUF3QixHQUFHLENBQUMsQ0FBQztRQUN0Qzs7O1dBR0c7UUFDTSw0QkFBdUIsR0FBRyxDQUFDLENBQUM7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QkFJRyxZQUFZO3NCQUFwQixLQUFLO2dCQUtHLGVBQWU7c0JBQXZCLEtBQUs7Z0JBRThDLFFBQVE7c0JBQTNELFdBQVc7dUJBQUMsNEJBQTRCOztzQkFBRyxLQUFLO2dCQUNKLFFBQVE7c0JBQXBELFdBQVc7dUJBQUMscUJBQXFCOztzQkFBRyxLQUFLO2dCQUd2QixJQUFJO3NCQUF0QixTQUFTO3VCQUFDLE1BQU07Z0JBQ1MsV0FBVztzQkFBcEMsU0FBUzt1QkFBQyxhQUFhO2dCQUNJLGFBQWE7c0JBQXhDLFNBQVM7dUJBQUMsZUFBZSIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7XG5cdENvbXBvbmVudCxcblx0SW5wdXQsXG5cdEhvc3RCaW5kaW5nLFxuXHRWaWV3Q2hpbGQsXG5cdEFmdGVyVmlld0luaXQsXG5cdE9uSW5pdFxufSBmcm9tIFwiQGFuZ3VsYXIvY29yZVwiO1xuXG5pbXBvcnQgeyBJMThuIH0gZnJvbSBcImNhcmJvbi1jb21wb25lbnRzLWFuZ3VsYXIvaTE4blwiO1xuaW1wb3J0IHsgRXZlbnRTZXJ2aWNlIH0gZnJvbSBcImNhcmJvbi1jb21wb25lbnRzLWFuZ3VsYXIvdXRpbHNcIjtcbmltcG9ydCB7IEJhc2VJY29uQnV0dG9uIH0gZnJvbSBcImNhcmJvbi1jb21wb25lbnRzLWFuZ3VsYXIvYnV0dG9uXCI7XG5cbmV4cG9ydCBlbnVtIFNuaXBwZXRUeXBlIHtcblx0c2luZ2xlID0gXCJzaW5nbGVcIixcblx0bXVsdGkgPSBcIm11bHRpXCIsXG5cdGlubGluZSA9IFwiaW5saW5lXCJcbn1cblxuLyoqXG4gKiBHZXQgc3RhcnRlZCB3aXRoIGltcG9ydGluZyB0aGUgbW9kdWxlOlxuICpcbiAqIGBgYHR5cGVzY3JpcHRcbiAqIGltcG9ydCB7IENvZGVTbmlwcGV0TW9kdWxlIH0gZnJvbSAnY2FyYm9uLWNvbXBvbmVudHMtYW5ndWxhcic7XG4gKiBgYGBcbiAqXG4gKiBgYGBodG1sXG4gKiA8Y2RzLWNvZGUtc25pcHBldD5Db2RlPC9jZHMtY29kZS1zbmlwcGV0PlxuICogYGBgXG4gKlxuICogW1NlZSBkZW1vXSguLi8uLi8/cGF0aD0vc3RvcnkvY29tcG9uZW50cy1jb2RlLXNuaXBwZXQtLWJhc2ljKVxuICovXG5AQ29tcG9uZW50KHtcblx0c2VsZWN0b3I6IFwiY2RzLWNvZGUtc25pcHBldCwgaWJtLWNvZGUtc25pcHBldFwiLFxuXHR0ZW1wbGF0ZTogYFxuXHRcdDxuZy1jb250YWluZXIgKm5nSWY9XCJkaXNwbGF5ID09PSAnaW5saW5lJzsgZWxzZSBub3RJbmxpbmVcIj5cblx0XHRcdDxuZy1jb250YWluZXIgKm5nSWY9XCIhaGlkZUNvcHlCdXR0b247IGVsc2Ugbm9CdG5JbmxpbmVcIj5cblx0XHRcdFx0PG5nLWNvbnRhaW5lciAqbmdUZW1wbGF0ZU91dGxldD1cImJ1dHRvblRlbXBsYXRlXCI+PC9uZy1jb250YWluZXI+XG5cdFx0XHQ8L25nLWNvbnRhaW5lcj5cblx0XHRcdDxuZy10ZW1wbGF0ZSAjbm9CdG5JbmxpbmU+XG5cdFx0XHRcdDxzcGFuXG5cdFx0XHRcdFx0Y2xhc3M9XCJjZHMtLXNuaXBwZXQgY2RzLS1zbmlwcGV0LS1pbmxpbmUgY2RzLS1zbmlwcGV0LS1uby1jb3B5XCJcblx0XHRcdFx0XHRbbmdDbGFzc109XCJ7XG5cdFx0XHRcdFx0XHQnY2RzLS1zbmlwcGV0LS1saWdodCc6IHRoZW1lID09PSAnbGlnaHQnXG5cdFx0XHRcdFx0fVwiPlxuXHRcdFx0XHRcdDxjb2RlICNjb2RlPlxuXHRcdFx0XHRcdFx0PG5nLWNvbnRhaW5lciAqbmdUZW1wbGF0ZU91dGxldD1cImNvZGVUZW1wbGF0ZVwiPjwvbmctY29udGFpbmVyPlxuXHRcdFx0XHRcdDwvY29kZT5cblx0XHRcdFx0PC9zcGFuPlxuXHRcdFx0PC9uZy10ZW1wbGF0ZT5cblx0XHQ8L25nLWNvbnRhaW5lcj5cblxuXHRcdDxuZy10ZW1wbGF0ZSAjbm90SW5saW5lPlxuXHRcdFx0PGRpdlxuXHRcdFx0XHQjY29kZUNvbnRhaW5lclxuXHRcdFx0XHRjbGFzcz1cImNkcy0tc25pcHBldC1jb250YWluZXJcIlxuXHRcdFx0XHRbYXR0ci5hcmlhLWxhYmVsXT1cInRyYW5zbGF0aW9ucy5DT0RFX1NOSVBQRVRfVEVYVFwiXG5cdFx0XHRcdFthdHRyLnRhYmluZGV4XT1cImRpc3BsYXkgPT09ICdzaW5nbGUnICYmICFkaXNhYmxlZCA/ICcwJyA6IG51bGxcIlxuXHRcdFx0XHRbYXR0ci5yb2xlXT1cImRpc3BsYXk9PT0nc2luZ2xlJyA/ICd0ZXh0YXJlYScgOiBudWxsXCJcblx0XHRcdFx0W25nU3R5bGVdPVwic3R5bGVzXCJcblx0XHRcdFx0KHNjcm9sbCk9XCIoZGlzcGxheSA9PT0gJ3NpbmdsZScgPyBoYW5kbGVTY3JvbGwoKSA6IG51bGwpXCI+XG5cdFx0XHRcdDxuZy1jb250YWluZXIgKm5nSWY9XCJza2VsZXRvblwiPlxuXHRcdFx0XHRcdDxzcGFuICpuZ0lmPVwiZGlzcGxheSA9PT0gJ3NpbmdsZSc7IGVsc2UgbXVsdGlTa2VsZXRvblwiPjwvc3Bhbj5cblx0XHRcdFx0XHQ8bmctdGVtcGxhdGUgI211bHRpU2tlbGV0b24+XG5cdFx0XHRcdFx0XHQ8c3Bhbj48L3NwYW4+XG5cdFx0XHRcdFx0XHQ8c3Bhbj48L3NwYW4+XG5cdFx0XHRcdFx0XHQ8c3Bhbj48L3NwYW4+XG5cdFx0XHRcdFx0PC9uZy10ZW1wbGF0ZT5cblx0XHRcdFx0PC9uZy1jb250YWluZXI+XG5cdFx0XHRcdDxwcmVcblx0XHRcdFx0XHQjY29kZUNvbnRlbnRcblx0XHRcdFx0XHQqbmdJZj1cIiFza2VsZXRvblwiXG5cdFx0XHRcdFx0KHNjcm9sbCk9XCIoZGlzcGxheSA9PT0gJ211bHRpJyA/IGhhbmRsZVNjcm9sbCgpIDogbnVsbClcIj48Y29kZSAjY29kZT48bmctY29udGFpbmVyICpuZ1RlbXBsYXRlT3V0bGV0PVwiY29kZVRlbXBsYXRlXCI+PC9uZy1jb250YWluZXI+PC9jb2RlPjwvcHJlPlxuXHRcdFx0PC9kaXY+XG5cdFx0XHQ8ZGl2ICpuZ0lmPVwiaGFzTGVmdFwiIGNsYXNzPVwiY2RzLS1zbmlwcGV0X19vdmVyZmxvdy1pbmRpY2F0b3ItLWxlZnRcIj48L2Rpdj5cblx0XHRcdDxkaXYgKm5nSWY9XCJoYXNSaWdodFwiIGNsYXNzPVwiY2RzLS1zbmlwcGV0X19vdmVyZmxvdy1pbmRpY2F0b3ItLXJpZ2h0XCI+PC9kaXY+XG5cdFx0XHQ8bmctY29udGFpbmVyICpuZ0lmPVwiIWhpZGVDb3B5QnV0dG9uO1wiPlxuXHRcdFx0XHQ8bmctY29udGFpbmVyICpuZ1RlbXBsYXRlT3V0bGV0PVwiYnV0dG9uVGVtcGxhdGVcIj48L25nLWNvbnRhaW5lcj5cblx0XHRcdDwvbmctY29udGFpbmVyPlxuXHRcdFx0PGJ1dHRvblxuXHRcdFx0XHQqbmdJZj1cImlzRXhwYW5kYWJsZVwiXG5cdFx0XHRcdGNsYXNzPVwiY2RzLS1idG4gY2RzLS1idG4tLWdob3N0IGNkcy0tYnRuLS1zbSBjZHMtLXNuaXBwZXQtYnRuLS1leHBhbmRcIlxuXHRcdFx0XHQoY2xpY2spPVwidG9nZ2xlU25pcHBldEV4cGFuc2lvbigpXCJcblx0XHRcdFx0dHlwZT1cImJ1dHRvblwiPlxuXHRcdFx0XHQ8c3BhbiBjbGFzcz1cImNkcy0tc25pcHBldC1idG4tLXRleHRcIj57e2V4cGFuZGVkID8gdHJhbnNsYXRpb25zLlNIT1dfTEVTUyA6IHRyYW5zbGF0aW9ucy5TSE9XX01PUkV9fTwvc3Bhbj5cblx0XHRcdFx0PHN2ZyBjZHNJY29uPVwiY2hldnJvbi0tZG93blwiIHNpemU9XCIxNlwiIGNsYXNzPVwiY2RzLS1pY29uLWNoZXZyb24tLWRvd25cIiBbYXR0ci5hcmlhLWxhYmVsXT1cInRyYW5zbGF0aW9ucy5TSE9XX01PUkVfSUNPTlwiPjwvc3ZnPlxuXHRcdFx0PC9idXR0b24+XG5cdFx0PC9uZy10ZW1wbGF0ZT5cblxuXHRcdDxuZy10ZW1wbGF0ZSAjYnV0dG9uVGVtcGxhdGU+XG5cdFx0XHQ8Y2RzLWljb24tYnV0dG9uXG5cdFx0XHRcdCpuZ0lmPVwiIXNrZWxldG9uXCJcblx0XHRcdFx0W2Rlc2NyaXB0aW9uXT1cInNob3dGZWVkYmFjayA/IGZlZWRiYWNrVGV4dCA6IGNvcHlCdXR0b25EZXNjcmlwdGlvblwiXG5cdFx0XHRcdFthbGlnbl09XCJhbGlnblwiXG5cdFx0XHRcdFtkcm9wU2hhZG93XT1cImRyb3BTaGFkb3dcIlxuXHRcdFx0XHRbY2FyZXRdPVwiY2FyZXRcIlxuXHRcdFx0XHRbaGlnaENvbnRyYXN0XT1cImhpZ2hDb250cmFzdFwiXG5cdFx0XHRcdFtpc09wZW5dPVwiaXNPcGVuXCJcblx0XHRcdFx0W2VudGVyRGVsYXlNc109XCJlbnRlckRlbGF5TXNcIlxuXHRcdFx0XHRbbGVhdmVEZWxheU1zXT1cImxlYXZlRGVsYXlNc1wiXG5cdFx0XHRcdHR5cGU9XCJidXR0b25cIlxuXHRcdFx0XHRraW5kPVwicHJpbWFyeVwiXG5cdFx0XHRcdHNpemU9XCJtZFwiXG5cdFx0XHRcdChjbGljayk9XCJvbkNvcHlCdXR0b25DbGlja2VkKCRldmVudClcIlxuXHRcdFx0XHRbYnV0dG9uTmdDbGFzc109XCJ7XG5cdFx0XHRcdFx0J2Nkcy0tc25pcHBldC0tbGlnaHQnOiB0aGVtZSA9PT0gJ2xpZ2h0Jyxcblx0XHRcdFx0XHQnY2RzLS1zbmlwcGV0LS1pbmxpbmUnOiBkaXNwbGF5ID09PSAnaW5saW5lJyxcblx0XHRcdFx0XHQnY2RzLS1idG4tLWljb24tb25seSc6IGRpc3BsYXkgIT09ICdpbmxpbmUnLFxuXHRcdFx0XHRcdCdjZHMtLWNvcHktYnRuJzogZGlzcGxheSAhPT0gJ2lubGluZScsXG5cdFx0XHRcdFx0J2Nkcy0tY29weS1idG4tLWFuaW1hdGluZyc6IGFuaW1hdGluZyxcblx0XHRcdFx0XHQnY2RzLS1jb3B5LWJ0bi0tZmFkZS1pbic6IHNob3dGZWVkYmFjayxcblx0XHRcdFx0XHQnY2RzLS1jb3B5LWJ0bi0tZmFkZS1vdXQnOiAhc2hvd0ZlZWRiYWNrICYmIGFuaW1hdGluZyxcblx0XHRcdFx0XHQnY2RzLS1zbmlwcGV0IGNkcy0tY29weSc6IHRydWVcblx0XHRcdFx0fVwiXG5cdFx0XHRcdFtidXR0b25BdHRyaWJ1dGVzXT1cIntcblx0XHRcdFx0XHQnYXJpYS1sYWJlbCc6IHRyYW5zbGF0aW9ucy5DT1BZX0NPREUsXG5cdFx0XHRcdFx0J2FyaWEtbGl2ZSc6ICdwb2xpdGUnLFxuXHRcdFx0XHRcdCd0YWJpbmRleCc6ICcwJ1xuXHRcdFx0XHR9XCI+XG5cdFx0XHRcdDxuZy1jb250YWluZXIgKm5nSWY9XCJkaXNwbGF5ID09PSAnaW5saW5lJ1wiPlxuXHRcdFx0XHRcdDxjb2RlICNjb2RlPlxuXHRcdFx0XHRcdFx0PG5nLWNvbnRhaW5lciAqbmdUZW1wbGF0ZU91dGxldD1cImNvZGVUZW1wbGF0ZVwiPjwvbmctY29udGFpbmVyPlxuXHRcdFx0XHRcdDwvY29kZT5cblx0XHRcdFx0PC9uZy1jb250YWluZXI+XG5cdFx0XHRcdDxuZy1jb250YWluZXIgKm5nSWY9XCJkaXNwbGF5ICE9PSAnaW5saW5lJ1wiPlxuXHRcdFx0XHRcdDxzdmcgY2RzSWNvbj1cImNvcHlcIiBzaXplPVwiMTZcIiBjbGFzcz1cImNkcy0tc25pcHBldF9faWNvblwiPjwvc3ZnPlxuXHRcdFx0XHQ8L25nLWNvbnRhaW5lcj5cblx0XHRcdDwvY2RzLWljb24tYnV0dG9uPlxuXHRcdDwvbmctdGVtcGxhdGU+XG5cblx0XHQ8bmctdGVtcGxhdGUgI2NvZGVUZW1wbGF0ZT5cblx0XHRcdDxuZy1jb250ZW50PjwvbmctY29udGVudD5cblx0XHQ8L25nLXRlbXBsYXRlPlxuXHRgXG59KVxuZXhwb3J0IGNsYXNzIENvZGVTbmlwcGV0IGV4dGVuZHMgQmFzZUljb25CdXR0b24gaW1wbGVtZW50cyBPbkluaXQsIEFmdGVyVmlld0luaXQge1xuXHRASG9zdEJpbmRpbmcoXCJjbGFzcy5jZHMtLXNuaXBwZXRcIikgZ2V0IHNuaXBwZXRDbGFzcygpIHtcblx0XHRyZXR1cm4gdGhpcy5kaXNwbGF5ICE9PSBTbmlwcGV0VHlwZS5pbmxpbmU7XG5cdH1cblx0QEhvc3RCaW5kaW5nKFwiY2xhc3MuY2RzLS1zbmlwcGV0LS1zaW5nbGVcIikgZ2V0IHNuaXBwZXRTaW5nbGVDbGFzcygpIHtcblx0XHRyZXR1cm4gdGhpcy5kaXNwbGF5ID09PSBTbmlwcGV0VHlwZS5zaW5nbGU7XG5cdH1cblx0QEhvc3RCaW5kaW5nKFwiY2xhc3MuY2RzLS1zbmlwcGV0LS1tdWx0aVwiKSBnZXQgc25pcHBldE11bHRpQ2xhc3MoKSB7XG5cdFx0cmV0dXJuIHRoaXMuZGlzcGxheSA9PT0gU25pcHBldFR5cGUubXVsdGk7XG5cdH1cblx0QEhvc3RCaW5kaW5nKFwiY2xhc3MuY2RzLS1zbmlwcGV0LS1kaXNhYmxlZFwiKSBnZXQgc25pcHBldERpc2FibGVkQ2xhc3MoKSB7XG5cdFx0cmV0dXJuIHRoaXMuZGlzcGxheSAhPT0gXCJpbmxpbmVcIiAmJiB0aGlzLmRpc2FibGVkO1xuXHR9XG5cdEBIb3N0QmluZGluZyhcImNsYXNzLmNkcy0tc25pcHBldC0tbGlnaHRcIikgZ2V0IHNuaXBwZXRJbmxpbmVMaWdodENsYXNzKCkge1xuXHRcdHJldHVybiB0aGlzLnRoZW1lID09PSBcImxpZ2h0XCI7XG5cdH1cblxuXHRyZWFkb25seSByb3dIZWlnaHRJblBpeGVsOiBudW1iZXIgPSAxNjtcblxuXHQvKipcblx0ICogSXQgY2FuIGJlIGBcInNpbmdsZVwiYCwgYFwibXVsdGlcImAgb3IgYFwiaW5saW5lXCJgXG5cdCAqL1xuXHRASW5wdXQoKSBkaXNwbGF5OiBTbmlwcGV0VHlwZSA9IFNuaXBwZXRUeXBlLnNpbmdsZTtcblx0QElucHV0KCkgdHJhbnNsYXRpb25zID0gdGhpcy5pMThuLmdldCgpLkNPREVfU05JUFBFVDtcblx0LyoqXG5cdCAqIGNvcHkgYnV0dG9uIGRlc2NyaXB0aW9uIHRvIHNob3cgb24gaG92ZXJcblx0ICovXG5cdEBJbnB1dCgpIGNvcHlCdXR0b25EZXNjcmlwdGlvbjogc3RyaW5nO1xuXHQvKipcblx0ICogU2V0IHRvIGB0cnVlYCB0byBoaWRlIGNvcHkgYnV0dG9uXG5cdCAqL1xuXHRASW5wdXQoKSBoaWRlQ29weUJ1dHRvbiA9IGZhbHNlO1xuXHQvKipcblx0ICogU2V0IHRvIGB0cnVlYCB0byBkaXNhYmxlIHRoZSBjb2RlIHNuaXBwZXRcblx0ICovXG5cdEBJbnB1dCgpIGRpc2FibGVkID0gZmFsc2U7XG5cdC8qKlxuXHQgKiBTcGVjaWZ5IHRoZSBtYXggbnVtYmVyIG9mIHJvd3MgdG8gc2hvdyB3aGVuIGNvbGxhcHNlZFxuXHQgKiBEZWZhdWx0IGlzIGAxNWBcblx0ICovXG5cdEBJbnB1dCgpIG1heENvbGxhcHNlZE51bWJlck9mUm93cyA9IDE1O1xuXHQvKipcblx0ICogU3BlY2lmeSB0aGUgbWluIG51bWJlciBvZiByb3dzIHRvIHNob3cgd2hlbiBjb2xsYXBzZWRcblx0ICogRGVmYXVsdCBpcyBgM2Bcblx0ICovXG5cdEBJbnB1dCgpIG1pbkNvbGxhcHNlZE51bWJlck9mUm93cyA9IDM7XG5cdC8qKlxuXHQgKiBTcGVjaWZ5IHRoZSBtYXggbnVtYmVyIG9mIHJvd3MgdG8gc2hvdyB3aGVuIGV4cGFuZGVkXG5cdCAqIERlZmF1bHQgaXMgYDBgLCBoZW5jZSBhbGwgY29udGVudCB3aWxsIGJlIHZpc2libGUgd2hlbiBleHBhbmRlZFxuXHQgKi9cblx0QElucHV0KCkgbWF4RXhwYW5kZWROdW1iZXJPZlJvd3MgPSAwO1xuXHQvKipcblx0ICogU3BlY2lmeSB0aGUgbWluIG51bWJlciBvZiByb3dzIHRvIHNob3cgd2hlbiBleHBhbmRlZFxuXHQgKiBEZWZhdWx0IGlzIGAxNmAsIGhlbmNlIGhlaWdodCBvZiBleHBhbmRlZCByb3cgd2lsbCBiZSAxNiAqIHJvd0hlaWdodEluUGl4ZWwgKDE2KSA9ICAyNTZweFxuXHQgKi9cblx0QElucHV0KCkgbWluRXhwYW5kZWROdW1iZXJPZlJvd3MgPSAxNjtcblx0LyoqXG5cdCAqIFNldCB0byBgdHJ1ZWAgdG8gd3JhcCB0aGUgdGV4dFxuXHQgKi9cblx0QEhvc3RCaW5kaW5nKFwiY2xhc3MuY2RzLS1zbmlwcGV0LS13cmFwdGV4dFwiKSBASW5wdXQoKSB3cmFwVGV4dCA9IGZhbHNlO1xuXHQvKipcblx0ICogQGRlcHJlY2F0ZWQgc2luY2UgdjUgLSBVc2UgYGNkc0xheWVyYCBkaXJlY3RpdmUgaW5zdGVhZFxuXHQgKiBTZXQgdG8gYFwibGlnaHRcImAgdG8gYXBwbHkgdGhlIGxpZ2h0IHN0eWxlXG5cdCAqL1xuXHRASW5wdXQoKSB0aGVtZTogXCJsaWdodFwiIHwgXCJkYXJrXCIgPSBcImRhcmtcIjtcblx0LyoqXG5cdCAqIFRleHQgZGlzcGxheWVkIGluIHRoZSB0b29sdGlwIHdoZW4gdXNlciBjbGlja3MgYnV0dG9uIHRvIGNvcHkgY29kZS5cblx0ICovXG5cdEBJbnB1dCgpIGZlZWRiYWNrVGV4dCA9IHRoaXMudHJhbnNsYXRpb25zLkNPUElFRDtcblx0LyoqXG5cdCAqIFRpbWUgaW4gbWlsaXNlY29uZHMgdG8ga2VlcCB0aGUgZmVlZGJhY2sgdG9vbHRpcCBkaXNwbGF5ZWQuXG5cdCAqIERlZmF1bHRzIHRvIDIgc2Vjb25kc1xuXHQgKi9cblx0QElucHV0KCkgZmVlZGJhY2tUaW1lb3V0ID0gMjAwMDtcblxuXHRASG9zdEJpbmRpbmcoXCJjbGFzcy5jZHMtLXNuaXBwZXQtLWV4cGFuZFwiKSBASW5wdXQoKSBleHBhbmRlZCA9IGZhbHNlO1xuXHRASG9zdEJpbmRpbmcoXCJjbGFzcy5jZHMtLXNrZWxldG9uXCIpIEBJbnB1dCgpIHNrZWxldG9uID0gZmFsc2U7XG5cdHN0eWxlczogYW55ID0ge307XG5cblx0QFZpZXdDaGlsZChcImNvZGVcIikgY29kZTtcblx0QFZpZXdDaGlsZChcImNvZGVDb250ZW50XCIpIGNvZGVDb250ZW50O1xuXHRAVmlld0NoaWxkKFwiY29kZUNvbnRhaW5lclwiKSBjb2RlQ29udGFpbmVyO1xuXG5cdHNob3dGZWVkYmFjayA9IGZhbHNlO1xuXHRhbmltYXRpbmcgPSBmYWxzZTtcblx0aGFzRXhwYW5kQnV0dG9uID0gbnVsbDtcblx0aXNFeHBhbmRhYmxlID0gZmFsc2U7XG5cdGhhc1JpZ2h0T3ZlcmZsb3cgPSBmYWxzZTtcblxuXHRoYXNSaWdodCA9IGZhbHNlO1xuXHRoYXNMZWZ0ID0gZmFsc2U7XG5cblx0LyoqXG5cdCAqIENyZWF0ZXMgYW4gaW5zdGFuY2Ugb2YgQ29kZVNuaXBwZXQuXG5cdCAqL1xuXHRjb25zdHJ1Y3Rvcihwcm90ZWN0ZWQgaTE4bjogSTE4biwgcHJvdGVjdGVkIGV2ZW50U2VydmljZTogRXZlbnRTZXJ2aWNlKSB7XG5cdFx0c3VwZXIoKTtcblx0XHR0aGlzLmRyb3BTaGFkb3cgPSBmYWxzZTtcblx0fVxuXG5cdGhhbmRsZVNjcm9sbCgpIHtcblx0XHRpZiAodGhpcy5za2VsZXRvbikge1xuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblxuXHRcdGxldCByZWY7XG5cdFx0c3dpdGNoICh0aGlzLmRpc3BsYXkpIHtcblx0XHRcdGNhc2UgXCJtdWx0aVwiOlxuXHRcdFx0XHRyZWYgPSB0aGlzLmNvZGVDb250ZW50Lm5hdGl2ZUVsZW1lbnQ7XG5cdFx0XHRcdGJyZWFrO1xuXHRcdFx0Y2FzZSBcInNpbmdsZVwiOlxuXHRcdFx0XHRyZWYgPSB0aGlzLmNvZGVDb250YWluZXIubmF0aXZlRWxlbWVudDtcblx0XHRcdFx0YnJlYWs7XG5cdFx0XHRkZWZhdWx0OlxuXHRcdFx0XHRyZXR1cm47XG5cdFx0fVxuXHRcdGlmIChyZWYpIHtcblx0XHRcdGNvbnN0IHtcblx0XHRcdFx0c2Nyb2xsV2lkdGgsXG5cdFx0XHRcdGNsaWVudFdpZHRoLFxuXHRcdFx0XHRzY3JvbGxMZWZ0XG5cdFx0XHR9ID0gcmVmO1xuXHRcdFx0Y29uc3QgaG9yaXpvbnRhbE92ZXJmbG93ID0gc2Nyb2xsV2lkdGggPiBjbGllbnRXaWR0aDtcblx0XHRcdHRoaXMuaGFzTGVmdCA9IGhvcml6b250YWxPdmVyZmxvdyAmJiAhIXNjcm9sbExlZnQ7XG5cdFx0XHR0aGlzLmhhc1JpZ2h0ID0gaG9yaXpvbnRhbE92ZXJmbG93ICYmIHNjcm9sbExlZnQgKyBjbGllbnRXaWR0aCAhPT0gc2Nyb2xsV2lkdGg7XG5cdFx0fVxuXHR9XG5cblx0dG9nZ2xlU25pcHBldEV4cGFuc2lvbigpIHtcblx0XHR0aGlzLmV4cGFuZGVkID0gIXRoaXMuZXhwYW5kZWQ7XG5cdFx0dGhpcy5jYWxjdWxhdGVDb250YWluZXJIZWlnaHQoKTtcblx0fVxuXG5cdG9uQ29weUJ1dHRvbkNsaWNrZWQoKSB7XG5cdFx0aWYgKCF0aGlzLmRpc2FibGVkKSB7XG5cdFx0XHR3aW5kb3cubmF2aWdhdG9yLmNsaXBib2FyZFxuXHRcdFx0XHQud3JpdGVUZXh0KHRoaXMuY29kZS5uYXRpdmVFbGVtZW50LmlubmVyVGV4dCB8fCB0aGlzLmNvZGUubmF0aXZlRWxlbWVudC50ZXh0Q29udGVudCkudGhlbigoKSA9PiB7XG5cdFx0XHRcdFx0dGhpcy5zaG93RmVlZGJhY2sgPSB0cnVlO1xuXHRcdFx0XHRcdHRoaXMuYW5pbWF0aW5nID0gdHJ1ZTtcblx0XHRcdFx0XHRzZXRUaW1lb3V0KCgpID0+IHtcblx0XHRcdFx0XHRcdHRoaXMuc2hvd0ZlZWRiYWNrID0gZmFsc2U7XG5cdFx0XHRcdFx0XHR0aGlzLmFuaW1hdGluZyA9IGZhbHNlO1xuXHRcdFx0XHRcdH0sIHRoaXMuZmVlZGJhY2tUaW1lb3V0KTtcblx0XHRcdFx0fSk7XG5cdFx0fVxuXHR9XG5cblx0bmdPbkluaXQoKSB7XG5cdFx0dGhpcy5jYWxjdWxhdGVDb250YWluZXJIZWlnaHQoKTtcblx0fVxuXG5cdG5nQWZ0ZXJWaWV3SW5pdCgpIHtcblx0XHR0aGlzLmNhbkV4cGFuZCgpO1xuXHRcdHRoaXMuaGFuZGxlU2Nyb2xsKCk7XG5cdFx0aWYgKHdpbmRvdykge1xuXHRcdFx0dGhpcy5ldmVudFNlcnZpY2Uub24od2luZG93IGFzIGFueSwgXCJyZXNpemVcIiwgKCkgPT4ge1xuXHRcdFx0XHR0aGlzLmNhbkV4cGFuZCgpO1xuXHRcdFx0XHR0aGlzLmhhbmRsZVNjcm9sbCgpO1xuXHRcdFx0fSk7XG5cdFx0fVxuXHR9XG5cblx0Y2FsY3VsYXRlQ29udGFpbmVySGVpZ2h0KCkge1xuXHRcdGlmICh0aGlzLmRpc3BsYXkgPT09IFwibXVsdGlcIiAmJiAhdGhpcy5za2VsZXRvbikge1xuXHRcdFx0dGhpcy5zdHlsZXMgPSB7fTtcblx0XHRcdGlmICh0aGlzLmV4cGFuZGVkKSB7XG5cdFx0XHRcdGlmICh0aGlzLm1heEV4cGFuZGVkTnVtYmVyT2ZSb3dzID4gMCkge1xuXHRcdFx0XHRcdHRoaXMuc3R5bGVzW1wibWF4LWhlaWdodFwiXSA9IGAke3RoaXMubWF4RXhwYW5kZWROdW1iZXJPZlJvd3MgKiB0aGlzLnJvd0hlaWdodEluUGl4ZWx9cHhgO1xuXHRcdFx0XHR9XG5cdFx0XHRcdGlmICh0aGlzLm1pbkV4cGFuZGVkTnVtYmVyT2ZSb3dzID4gMCkge1xuXHRcdFx0XHRcdHRoaXMuc3R5bGVzW1wibWluLWhlaWdodFwiXSA9IGAke3RoaXMubWluRXhwYW5kZWROdW1iZXJPZlJvd3MgKiB0aGlzLnJvd0hlaWdodEluUGl4ZWx9cHhgO1xuXHRcdFx0XHR9XG5cdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRpZiAodGhpcy5tYXhDb2xsYXBzZWROdW1iZXJPZlJvd3MgPiAwKSB7XG5cdFx0XHRcdFx0dGhpcy5zdHlsZXNbXCJtYXgtaGVpZ2h0XCJdID0gYCR7dGhpcy5tYXhDb2xsYXBzZWROdW1iZXJPZlJvd3MgKiB0aGlzLnJvd0hlaWdodEluUGl4ZWx9cHhgO1xuXHRcdFx0XHR9XG5cdFx0XHRcdGlmICh0aGlzLm1pbkNvbGxhcHNlZE51bWJlck9mUm93cyA+IDApIHtcblx0XHRcdFx0XHR0aGlzLnN0eWxlc1tcIm1pbi1oZWlnaHRcIl0gPSBgJHt0aGlzLm1pbkNvbGxhcHNlZE51bWJlck9mUm93cyAqIHRoaXMucm93SGVpZ2h0SW5QaXhlbH1weGA7XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHR9XG5cdH1cblxuXHRwcm90ZWN0ZWQgY2FuRXhwYW5kKCkge1xuXHRcdGlmICh0aGlzLmRpc3BsYXkgPT09IFwibXVsdGlcIiAmJiAhdGhpcy5za2VsZXRvbikge1xuXHRcdFx0Y29uc3QgaGVpZ2h0ID0gdGhpcy5jb2RlQ29udGVudC5uYXRpdmVFbGVtZW50LmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpLmhlaWdodDtcblx0XHRcdGlmIChcblx0XHRcdFx0dGhpcy5tYXhDb2xsYXBzZWROdW1iZXJPZlJvd3MgPiAwICYmXG5cdFx0XHRcdCh0aGlzLm1heEV4cGFuZGVkTnVtYmVyT2ZSb3dzIDw9IDAgfHxcblx0XHRcdFx0XHR0aGlzLm1heEV4cGFuZGVkTnVtYmVyT2ZSb3dzID4gdGhpcy5tYXhDb2xsYXBzZWROdW1iZXJPZlJvd3MpICYmXG5cdFx0XHRcdGhlaWdodCA+IHRoaXMubWF4Q29sbGFwc2VkTnVtYmVyT2ZSb3dzICogdGhpcy5yb3dIZWlnaHRJblBpeGVsXG5cdFx0XHQpIHtcblx0XHRcdFx0dGhpcy5pc0V4cGFuZGFibGUgPSB0cnVlO1xuXHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0dGhpcy5pc0V4cGFuZGFibGUgPSBmYWxzZTtcblx0XHRcdH1cblxuXHRcdFx0aWYgKFxuXHRcdFx0XHR0aGlzLmV4cGFuZGVkICYmXG5cdFx0XHRcdHRoaXMubWluRXhwYW5kZWROdW1iZXJPZlJvd3MgPiAwICYmXG5cdFx0XHRcdGhlaWdodCA8PSB0aGlzLm1pbkV4cGFuZGVkTnVtYmVyT2ZSb3dzICogdGhpcy5yb3dIZWlnaHRJblBpeGVsXG5cdFx0XHQpIHtcblx0XHRcdFx0dGhpcy5pc0V4cGFuZGFibGUgPSBmYWxzZTtcblx0XHRcdH1cblx0XHR9XG5cdH1cbn1cbiJdfQ==