UNPKG

@nova-ui/bits

Version:

SolarWinds Nova Framework

153 lines 30.9 kB
// © 2022 SolarWinds Worldwide, LLC. All rights reserved. // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to // deal in the Software without restriction, including without limitation the // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or // sell copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. import { animate, style, transition, trigger } from "@angular/animations"; import { ChangeDetectorRef, Component, EventEmitter, HostBinding, Input, NgZone, Output, ViewEncapsulation, } from "@angular/core"; import { ButtonIcon, SpinnerSize } from "./public-api"; import { LoggerService } from "../../services/log-service"; import * as i0 from "@angular/core"; import * as i1 from "../../services/log-service"; import * as i2 from "@angular/common"; import * as i3 from "../button/button.component"; import * as i4 from "../tooltip/tooltip.directive"; /** * <example-url>./../examples/index.html#/spinner</example-url> */ export class SpinnerComponent { static { this.defaultSize = SpinnerSize.Small; } set size(val) { const sizes = Object.values(SpinnerSize); if (sizes.includes(val)) { this._size = val; return; } this.logger.warn(`Allowed sizes for nui-spinner are ${sizes.join(", ")}. ` + `Default is ${SpinnerComponent.defaultSize}.`); this._size = SpinnerComponent.defaultSize; } get size() { return this._size || SpinnerComponent.defaultSize; } get icon() { return ButtonIcon[this.size]; } get showText() { return this.size !== SpinnerSize.Small; } constructor(logger, changeDetector, ngZone) { this.logger = logger; this.changeDetector = changeDetector; this.ngZone = ngZone; this.tooltipText = $localize `Cancel`; this.showSpinner = false; this.isDeterminate = false; this.show = false; this.delay = 250; /** * Input to set aria label text */ this.ariaLabel = "Spinner"; this.cancel = new EventEmitter(); } ngOnChanges(changes) { if (changes?.percent) { this.ariaValueNow = this.percent ? String(this.percent) : undefined; } if (!changes["show"]) { return; } this.isDeterminate = this.percent !== undefined; this.cancelShowTimer(); if (this.delay && this.show) { this.ngZone.runOutsideAngular(() => { this.showTimer = setTimeout(() => { this.ngZone.run(() => { this.showSpinner = this.show; this.changeDetector.detectChanges(); }); }, this.delay); }); } else { this.showSpinner = this.show; } } cancelShowTimer() { if (this.showTimer) { clearTimeout(this.showTimer); } } cancelProgress() { this.cancel.emit(); } ngOnDestroy() { this.cancelShowTimer(); } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: SpinnerComponent, deps: [{ token: i1.LoggerService }, { token: i0.ChangeDetectorRef }, { token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Component }); } static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.12", type: SpinnerComponent, selector: "nui-spinner", inputs: { percent: "percent", show: "show", delay: "delay", allowCancel: "allowCancel", message: "message", helpText: "helpText", ariaLabel: "ariaLabel", size: "size" }, outputs: { cancel: "cancel" }, host: { attributes: { "role": "progressbar", "aria-valuemin": "0", "aria-valuemax": "100" }, properties: { "attr.aria-label": "ariaLabel", "attr.aria-valuenow": "this.ariaValueNow" } }, usesOnChanges: true, ngImport: i0, template: "<span\n class=\"nui-icon-busy-circular nui-spinner nui-spinner__container--{{\n size\n }}\"\n *ngIf=\"showSpinner\"\n [ngClass]=\"{ 'nui-spinner--determinate': isDeterminate }\"\n [@spinnerAppear]\n>\n <div class=\"nui-spinner__container\">\n <svg\n class=\"nui-spinner__circular\"\n viewBox=\"25 25 50 50\"\n *ngIf=\"!isDeterminate\"\n >\n <circle\n class=\"nui-spinner__path-under\"\n cx=\"50\"\n cy=\"50\"\n r=\"22\"\n fill=\"none\"\n stroke-width=\"5\"\n stroke-miterlimit=\"10\"\n />\n <circle\n class=\"nui-spinner__path\"\n cx=\"50\"\n cy=\"50\"\n r=\"22\"\n fill=\"none\"\n stroke-width=\"5\"\n stroke-miterlimit=\"10\"\n />\n </svg>\n <svg\n class=\"nui-spinner__circular\"\n viewBox=\"0 0 36 36\"\n *ngIf=\"isDeterminate\"\n >\n <circle\n class=\"nui-spinner__path-under\"\n cx=\"18\"\n cy=\"18\"\n r=\"15.9155\"\n fill=\"none\"\n stroke-width=\"4\"\n stroke-miterlimit=\"10\"\n />\n <circle\n class=\"nui-spinner__path\"\n cx=\"18\"\n cy=\"18\"\n r=\"15.9155\"\n fill=\"none\"\n stroke-width=\"4\"\n stroke-miterlimit=\"10\"\n [ngStyle]=\"{ 'stroke-dasharray': percent + ', 100' }\"\n />\n </svg>\n\n <button\n nui-button\n type=\"button\"\n class=\"nui-spinner__cancel\"\n icon=\"close\"\n *ngIf=\"allowCancel\"\n (click)=\"cancelProgress()\"\n displayStyle=\"action\"\n [nuiTooltip]=\"tooltipText\"\n ></button>\n </div>\n\n <div class=\"nui-spinner__text-content\" *ngIf=\"showText\">\n <div class=\"nui-spinner__label\" *ngIf=\"message !== undefined\">\n <span class=\"nui-text-label nui-spinner__label-item\">{{\n message\n }}</span>\n </div>\n <span\n class=\"nui-spinner__hint nui-help-hint\"\n *ngIf=\"helpText !== undefined\"\n >\n {{ helpText }}\n </span>\n </div>\n</span>\n", styles: [".nui-spinner{display:inline-flex;align-items:center;position:relative;margin:0 auto;box-sizing:border-box;vertical-align:middle}.nui-spinner__container{display:inline-flex;align-items:center;justify-content:center;position:relative;box-sizing:border-box}.nui-spinner__container--small .nui-spinner__container{width:20px;height:20px}.nui-spinner__container--small .nui-spinner__cancel.nui-button{border-radius:50%;min-height:10px;min-width:10px;padding:0}.nui-spinner__container--large .nui-spinner__container{width:50px;height:50px}.nui-spinner__container--large .nui-spinner__cancel.nui-button{border-radius:50%;min-height:10px;min-width:10px;padding:3px}.nui-spinner__label{margin-left:10px}.nui-spinner__hint{display:block;margin-left:10px}.nui-spinner__circular{position:absolute;width:100%;height:100%;animation:rotate 2s linear infinite;transform-origin:center center;inset:0;margin:auto}.nui-spinner__path-under{stroke:var(--nui-color-line-default,#d9d9d9)}.nui-spinner__path{stroke-dashoffset:0px;animation:dash 1.5s ease-in-out infinite;stroke-linecap:square;stroke:var(--nui-color-progress,#00c4d2)}@keyframes rotate{to{transform:rotate(360deg)}}@keyframes dash{0%{stroke-dasharray:1,200;stroke-dashoffset:0}50%{stroke-dasharray:67,200;stroke-dashoffset:-35px}to{stroke-dasharray:134,200;stroke-dashoffset:-134px}}.nui-spinner--determinate .nui-spinner__circular{animation:none}.nui-spinner--determinate .nui-spinner__path{transition:.5s linear;animation:none}\n"], dependencies: [{ kind: "directive", type: i2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i2.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "component", type: i3.ButtonComponent, selector: "[nui-button]", inputs: ["displayStyle", "icon", "iconColor", "iconRight", "isBusy", "isEmpty", "ariaLabel", "isRepeat", "size"] }, { kind: "directive", type: i4.TooltipDirective, selector: "[nuiTooltip]", inputs: ["tooltipPlacement", "nuiTooltipDisabled", "nuiTooltipEllipsis", "nuiTooltip"], exportAs: ["nuiTooltip"] }], animations: [ trigger("spinnerAppear", [ transition(":enter", [ animate(".2s ease-in-out", style({ opacity: 1 })), ]), transition(":leave", [ animate(".2s ease-in-out", style({ opacity: 0 })), ]), ]), ], encapsulation: i0.ViewEncapsulation.None }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: SpinnerComponent, decorators: [{ type: Component, args: [{ selector: "nui-spinner", encapsulation: ViewEncapsulation.None, animations: [ trigger("spinnerAppear", [ transition(":enter", [ animate(".2s ease-in-out", style({ opacity: 1 })), ]), transition(":leave", [ animate(".2s ease-in-out", style({ opacity: 0 })), ]), ]), ], host: { role: "progressbar", "aria-valuemin": "0", "aria-valuemax": "100", "[attr.aria-label]": "ariaLabel", }, template: "<span\n class=\"nui-icon-busy-circular nui-spinner nui-spinner__container--{{\n size\n }}\"\n *ngIf=\"showSpinner\"\n [ngClass]=\"{ 'nui-spinner--determinate': isDeterminate }\"\n [@spinnerAppear]\n>\n <div class=\"nui-spinner__container\">\n <svg\n class=\"nui-spinner__circular\"\n viewBox=\"25 25 50 50\"\n *ngIf=\"!isDeterminate\"\n >\n <circle\n class=\"nui-spinner__path-under\"\n cx=\"50\"\n cy=\"50\"\n r=\"22\"\n fill=\"none\"\n stroke-width=\"5\"\n stroke-miterlimit=\"10\"\n />\n <circle\n class=\"nui-spinner__path\"\n cx=\"50\"\n cy=\"50\"\n r=\"22\"\n fill=\"none\"\n stroke-width=\"5\"\n stroke-miterlimit=\"10\"\n />\n </svg>\n <svg\n class=\"nui-spinner__circular\"\n viewBox=\"0 0 36 36\"\n *ngIf=\"isDeterminate\"\n >\n <circle\n class=\"nui-spinner__path-under\"\n cx=\"18\"\n cy=\"18\"\n r=\"15.9155\"\n fill=\"none\"\n stroke-width=\"4\"\n stroke-miterlimit=\"10\"\n />\n <circle\n class=\"nui-spinner__path\"\n cx=\"18\"\n cy=\"18\"\n r=\"15.9155\"\n fill=\"none\"\n stroke-width=\"4\"\n stroke-miterlimit=\"10\"\n [ngStyle]=\"{ 'stroke-dasharray': percent + ', 100' }\"\n />\n </svg>\n\n <button\n nui-button\n type=\"button\"\n class=\"nui-spinner__cancel\"\n icon=\"close\"\n *ngIf=\"allowCancel\"\n (click)=\"cancelProgress()\"\n displayStyle=\"action\"\n [nuiTooltip]=\"tooltipText\"\n ></button>\n </div>\n\n <div class=\"nui-spinner__text-content\" *ngIf=\"showText\">\n <div class=\"nui-spinner__label\" *ngIf=\"message !== undefined\">\n <span class=\"nui-text-label nui-spinner__label-item\">{{\n message\n }}</span>\n </div>\n <span\n class=\"nui-spinner__hint nui-help-hint\"\n *ngIf=\"helpText !== undefined\"\n >\n {{ helpText }}\n </span>\n </div>\n</span>\n", styles: [".nui-spinner{display:inline-flex;align-items:center;position:relative;margin:0 auto;box-sizing:border-box;vertical-align:middle}.nui-spinner__container{display:inline-flex;align-items:center;justify-content:center;position:relative;box-sizing:border-box}.nui-spinner__container--small .nui-spinner__container{width:20px;height:20px}.nui-spinner__container--small .nui-spinner__cancel.nui-button{border-radius:50%;min-height:10px;min-width:10px;padding:0}.nui-spinner__container--large .nui-spinner__container{width:50px;height:50px}.nui-spinner__container--large .nui-spinner__cancel.nui-button{border-radius:50%;min-height:10px;min-width:10px;padding:3px}.nui-spinner__label{margin-left:10px}.nui-spinner__hint{display:block;margin-left:10px}.nui-spinner__circular{position:absolute;width:100%;height:100%;animation:rotate 2s linear infinite;transform-origin:center center;inset:0;margin:auto}.nui-spinner__path-under{stroke:var(--nui-color-line-default,#d9d9d9)}.nui-spinner__path{stroke-dashoffset:0px;animation:dash 1.5s ease-in-out infinite;stroke-linecap:square;stroke:var(--nui-color-progress,#00c4d2)}@keyframes rotate{to{transform:rotate(360deg)}}@keyframes dash{0%{stroke-dasharray:1,200;stroke-dashoffset:0}50%{stroke-dasharray:67,200;stroke-dashoffset:-35px}to{stroke-dasharray:134,200;stroke-dashoffset:-134px}}.nui-spinner--determinate .nui-spinner__circular{animation:none}.nui-spinner--determinate .nui-spinner__path{transition:.5s linear;animation:none}\n"] }] }], ctorParameters: () => [{ type: i1.LoggerService }, { type: i0.ChangeDetectorRef }, { type: i0.NgZone }], propDecorators: { ariaValueNow: [{ type: HostBinding, args: ["attr.aria-valuenow"] }], percent: [{ type: Input }], show: [{ type: Input }], delay: [{ type: Input }], allowCancel: [{ type: Input }], message: [{ type: Input }], helpText: [{ type: Input }], ariaLabel: [{ type: Input }], cancel: [{ type: Output }], size: [{ type: Input }] } }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3Bpbm5lci5jb21wb25lbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9zcmMvbGliL3NwaW5uZXIvc3Bpbm5lci5jb21wb25lbnQudHMiLCIuLi8uLi8uLi8uLi9zcmMvbGliL3NwaW5uZXIvc3Bpbm5lci5jb21wb25lbnQuaHRtbCJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSx5REFBeUQ7QUFDekQsRUFBRTtBQUNGLCtFQUErRTtBQUMvRSw0RUFBNEU7QUFDNUUsOEVBQThFO0FBQzlFLCtFQUErRTtBQUMvRSw4RUFBOEU7QUFDOUUsNERBQTREO0FBQzVELEVBQUU7QUFDRiw2RUFBNkU7QUFDN0UsdURBQXVEO0FBQ3ZELEVBQUU7QUFDRiw2RUFBNkU7QUFDN0UsNEVBQTRFO0FBQzVFLCtFQUErRTtBQUMvRSwwRUFBMEU7QUFDMUUsaUZBQWlGO0FBQ2pGLDZFQUE2RTtBQUM3RSxpQkFBaUI7QUFFakIsT0FBTyxFQUFFLE9BQU8sRUFBRSxLQUFLLEVBQUUsVUFBVSxFQUFFLE9BQU8sRUFBRSxNQUFNLHFCQUFxQixDQUFDO0FBQzFFLE9BQU8sRUFDSCxpQkFBaUIsRUFDakIsU0FBUyxFQUNULFlBQVksRUFDWixXQUFXLEVBQ1gsS0FBSyxFQUNMLE1BQU0sRUFHTixNQUFNLEVBRU4saUJBQWlCLEdBQ3BCLE1BQU0sZUFBZSxDQUFDO0FBRXZCLE9BQU8sRUFBRSxVQUFVLEVBQUUsV0FBVyxFQUFFLE1BQU0sY0FBYyxDQUFDO0FBQ3ZELE9BQU8sRUFBRSxhQUFhLEVBQUUsTUFBTSw0QkFBNEIsQ0FBQzs7Ozs7O0FBRTNEOztHQUVHO0FBdUJILE1BQU0sT0FBTyxnQkFBZ0I7YUFDVixnQkFBVyxHQUFnQixXQUFXLENBQUMsS0FBSyxBQUFqQyxDQUFrQztJQXdCNUQsSUFBb0IsSUFBSSxDQUFDLEdBQWdCO1FBQ3JDLE1BQU0sS0FBSyxHQUFHLE1BQU0sQ0FBQyxNQUFNLENBQUMsV0FBVyxDQUFDLENBQUM7UUFFekMsSUFBSSxL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O2dCQUNVLFFBQVE7c0JBQXZCLEtBQUs7Z0JBS1UsU0FBUztzQkFBeEIsS0FBSztnQkFFVyxNQUFNO3NCQUF0QixNQUFNO2dCQUVhLElBQUk7c0JBQXZCLEtBQUsiLCJzb3VyY2VzQ29udGVudCI6WyIvLyDCqSAyMDIyIFNvbGFyV2luZHMgV29ybGR3aWRlLCBMTEMuIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4vL1xuLy8gUGVybWlzc2lvbiBpcyBoZXJlYnkgZ3JhbnRlZCwgZnJlZSBvZiBjaGFyZ2UsIHRvIGFueSBwZXJzb24gb2J0YWluaW5nIGEgY29weVxuLy8gIG9mIHRoaXMgc29mdHdhcmUgYW5kIGFzc29jaWF0ZWQgZG9jdW1lbnRhdGlvbiBmaWxlcyAodGhlIFwiU29mdHdhcmVcIiksIHRvXG4vLyAgZGVhbCBpbiB0aGUgU29mdHdhcmUgd2l0aG91dCByZXN0cmljdGlvbiwgaW5jbHVkaW5nIHdpdGhvdXQgbGltaXRhdGlvbiB0aGVcbi8vICByaWdodHMgdG8gdXNlLCBjb3B5LCBtb2RpZnksIG1lcmdlLCBwdWJsaXNoLCBkaXN0cmlidXRlLCBzdWJsaWNlbnNlLCBhbmQvb3Jcbi8vICBzZWxsIGNvcGllcyBvZiB0aGUgU29mdHdhcmUsIGFuZCB0byBwZXJtaXQgcGVyc29ucyB0byB3aG9tIHRoZSBTb2Z0d2FyZSBpc1xuLy8gIGZ1cm5pc2hlZCB0byBkbyBzbywgc3ViamVjdCB0byB0aGUgZm9sbG93aW5nIGNvbmRpdGlvbnM6XG4vL1xuLy8gVGhlIGFib3ZlIGNvcHlyaWdodCBub3RpY2UgYW5kIHRoaXMgcGVybWlzc2lvbiBub3RpY2Ugc2hhbGwgYmUgaW5jbHVkZWQgaW5cbi8vICBhbGwgY29waWVzIG9yIHN1YnN0YW50aWFsIHBvcnRpb25zIG9mIHRoZSBTb2Z0d2FyZS5cbi8vXG4vLyBUSEUgU09GVFdBUkUgSVMgUFJPVklERUQgXCJBUyBJU1wiLCBXSVRIT1VUIFdBUlJBTlRZIE9GIEFOWSBLSU5ELCBFWFBSRVNTIE9SXG4vLyAgSU1QTElFRCwgSU5DTFVESU5HIEJVVCBOT1QgTElNSVRFRCBUTyBUSEUgV0FSUkFOVElFUyBPRiBNRVJDSEFOVEFCSUxJVFksXG4vLyAgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UgQU5EIE5PTklORlJJTkdFTUVOVC4gSU4gTk8gRVZFTlQgU0hBTEwgVEhFXG4vLyAgQVVUSE9SUyBPUiBDT1BZUklHSFQgSE9MREVSUyBCRSBMSUFCTEUgRk9SIEFOWSBDTEFJTSwgREFNQUdFUyBPUiBPVEhFUlxuLy8gIExJQUJJTElUWSwgV0hFVEhFUiBJTiBBTiBBQ1RJT04gT0YgQ09OVFJBQ1QsIFRPUlQgT1IgT1RIRVJXSVNFLCBBUklTSU5HIEZST00sXG4vLyAgT1VUIE9GIE9SIElOIENPTk5FQ1RJT04gV0lUSCBUSEUgU09GVFdBUkUgT1IgVEhFIFVTRSBPUiBPVEhFUiBERUFMSU5HUyBJTlxuLy8gIFRIRSBTT0ZUV0FSRS5cblxuaW1wb3J0IHsgYW5pbWF0ZSwgc3R5bGUsIHRyYW5zaXRpb24sIHRyaWdnZXIgfSBmcm9tIFwiQGFuZ3VsYXIvYW5pbWF0aW9uc1wiO1xuaW1wb3J0IHtcbiAgICBDaGFuZ2VEZXRlY3RvclJlZixcbiAgICBDb21wb25lbnQsXG4gICAgRXZlbnRFbWl0dGVyLFxuICAgIEhvc3RCaW5kaW5nLFxuICAgIElucHV0LFxuICAgIE5nWm9uZSxcbiAgICBPbkNoYW5nZXMsXG4gICAgT25EZXN0cm95LFxuICAgIE91dHB1dCxcbiAgICBTaW1wbGVDaGFuZ2VzLFxuICAgIFZpZXdFbmNhcHN1bGF0aW9uLFxufSBmcm9tIFwiQGFuZ3VsYXIvY29yZVwiO1xuXG5pbXBvcnQgeyBCdXR0b25JY29uLCBTcGlubmVyU2l6ZSB9IGZyb20gXCIuL3B1YmxpYy1hcGlcIjtcbmltcG9ydCB7IExvZ2dlclNlcnZpY2UgfSBmcm9tIFwiLi4vLi4vc2VydmljZXMvbG9nLXNlcnZpY2VcIjtcblxuLyoqXG4gKiA8ZXhhbXBsZS11cmw+Li8uLi9leGFtcGxlcy9pbmRleC5odG1sIy9zcGlubmVyPC9leGFtcGxlLXVybD5cbiAqL1xuQENvbXBvbmVudCh7XG4gICAgc2VsZWN0b3I6IFwibnVpLXNwaW5uZXJcIixcbiAgICB0ZW1wbGF0ZVVybDogXCIuL3NwaW5uZXIuY29tcG9uZW50Lmh0bWxcIixcbiAgICBzdHlsZVVybHM6IFtcIi4vc3Bpbm5lci5jb21wb25lbnQubGVzc1wiXSxcbiAgICBlbmNhcHN1bGF0aW9uOiBWaWV3RW5jYXBzdWxhdGlvbi5Ob25lLFxuICAgIGFuaW1hdGlvbnM6IFtcbiAgICAgICAgdHJpZ2dlcihcInNwaW5uZXJBcHBlYXJcIiwgW1xuICAgICAgICAgICAgdHJhbnNpdGlvbihcIjplbnRlclwiLCBbXG4gICAgICAgICAgICAgICAgYW5pbWF0ZShcIi4ycyBlYXNlLWluLW91dFwiLCBzdHlsZSh7IG9wYWNpdHk6IDEgfSkpLFxuICAgICAgICAgICAgXSksXG4gICAgICAgICAgICB0cmFuc2l0aW9uKFwiOmxlYXZlXCIsIFtcbiAgICAgICAgICAgICAgICBhbmltYXRlKFwiLjJzIGVhc2UtaW4tb3V0XCIsIHN0eWxlKHsgb3BhY2l0eTogMCB9KSksXG4gICAgICAgICAgICBdKSxcbiAgICAgICAgXSksXG4gICAgXSxcbiAgICBob3N0OiB7XG4gICAgICAgIHJvbGU6IFwicHJvZ3Jlc3NiYXJcIixcbiAgICAgICAgXCJhcmlhLXZhbHVlbWluXCI6IFwiMFwiLFxuICAgICAgICBcImFyaWEtdmFsdWVtYXhcIjogXCIxMDBcIixcbiAgICAgICAgXCJbYXR0ci5hcmlhLWxhYmVsXVwiOiBcImFyaWFMYWJlbFwiLFxuICAgIH0sXG59KVxuZXhwb3J0IGNsYXNzIFNwaW5uZXJDb21wb25lbnQgaW1wbGVtZW50cyBPbkNoYW5nZXMsIE9uRGVzdHJveSB7XG4gICAgcHJpdmF0ZSBzdGF0aWMgZGVmYXVsdFNpemU6IFNwaW5uZXJTaXplID0gU3Bpbm5lclNpemUuU21hbGw7XG4gICAgcHJpdmF0ZSBzaG93VGltZXI6IGFueTtcbiAgICBwcml2YXRlIF9zaXplOiBTcGlubmVyU2l6ZTtcbiAgICBwdWJsaWMgdG9vbHRpcFRleHQgPSAkbG9jYWxpemVgQ2FuY2VsYDtcblxuICAgIHB1YmxpYyBzaG93U3Bpbm5lciA9IGZhbHNlO1xuICAgIHB1YmxpYyBpc0RldGVybWluYXRlID0gZmFsc2U7XG5cbiAgICBASG9zdEJpbmRpbmcoXCJhdHRyLmFyaWEtdmFsdWVub3dcIikgYXJpYVZhbHVlTm93OiBzdHJpbmcgfCB1bmRlZmluZWQ7XG5cbiAgICBASW5wdXQoKSBwdWJsaWMgcGVyY2VudD86IG51bWJlcjtcbiAgICBASW5wdXQoKSBwdWJsaWMgc2hvdyA9IGZhbHNlO1xuICAgIEBJbnB1dCgpIHB1YmxpYyBkZWxheSA9IDI1MDtcbiAgICBASW5wdXQoKSBwdWJsaWMgYWxsb3dDYW5jZWw/OiBib29sZWFuO1xuICAgIEBJbnB1dCgpIHB1YmxpYyBtZXNzYWdlPzogc3RyaW5nO1xuICAgIEBJbnB1dCgpIHB1YmxpYyBoZWxwVGV4dD86IHN0cmluZztcblxuICAgIC8qKlxuICAgICAqIElucHV0IHRvIHNldCBhcmlhIGxhYmVsIHRleHRcbiAgICAgKi9cbiAgICBASW5wdXQoKSBwdWJsaWMgYXJpYUxhYmVsOiBzdHJpbmcgPSBcIlNwaW5uZXJcIjtcblxuICAgIEBPdXRwdXQoKSBwdWJsaWMgY2FuY2VsID0gbmV3IEV2ZW50RW1pdHRlcigpO1xuXG4gICAgQElucHV0KCkgcHVibGljIHNldCBzaXplKHZhbDogU3Bpbm5lclNpemUpIHtcbiAgICAgICAgY29uc3Qgc2l6ZXMgPSBPYmplY3QudmFsdWVzKFNwaW5uZXJTaXplKTtcblxuICAgICAgICBpZiAoc2l6ZXMuaW5jbHVkZXModmFsKSkge1xuICAgICAgICAgICAgdGhpcy5fc2l6ZSA9IHZhbDtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIHRoaXMubG9nZ2VyLndhcm4oXG4gICAgICAgICAgICBgQWxsb3dlZCBzaXplcyBmb3IgbnVpLXNwaW5uZXIgYXJlICR7c2l6ZXMuam9pbihcIiwgXCIpfS4gYCArXG4gICAgICAgICAgICAgICAgYERlZmF1bHQgaXMgJHtTcGlubmVyQ29tcG9uZW50LmRlZmF1bHRTaXplfS5gXG4gICAgICAgICk7XG5cbiAgICAgICAgdGhpcy5fc2l6ZSA9IFNwaW5uZXJDb21wb25lbnQuZGVmYXVsdFNpemU7XG4gICAgfVxuXG4gICAgcHVibGljIGdldCBzaXplKCk6IFNwaW5uZXJTaXplIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuX3NpemUgfHwgU3Bpbm5lckNvbXBvbmVudC5kZWZhdWx0U2l6ZTtcbiAgICB9XG5cbiAgICBwdWJsaWMgZ2V0IGljb24oKTogQnV0dG9uSWNvbiB7XG4gICAgICAgIHJldHVybiBCdXR0b25JY29uW3RoaXMuc2l6ZV07XG4gICAgfVxuXG4gICAgcHVibGljIGdldCBzaG93VGV4dCgpOiBib29sZWFuIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuc2l6ZSAhPT0gU3Bpbm5lclNpemUuU21hbGw7XG4gICAgfVxuXG4gICAgY29uc3RydWN0b3IoXG4gICAgICAgIHByaXZhdGUgbG9nZ2VyOiBMb2dnZXJTZXJ2aWNlLFxuICAgICAgICBwcml2YXRlIGNoYW5nZURldGVjdG9yOiBDaGFuZ2VEZXRlY3RvclJlZixcbiAgICAgICAgcHJpdmF0ZSBuZ1pvbmU6IE5nWm9uZVxuICAgICkge31cblxuICAgIHB1YmxpYyBuZ09uQ2hhbmdlcyhjaGFuZ2VzOiBTaW1wbGVDaGFuZ2VzKTogdm9pZCB7XG4gICAgICAgIGlmIChjaGFuZ2VzPy5wZXJjZW50KSB7XG4gICAgICAgICAgICB0aGlzLmFyaWFWYWx1ZU5vdyA9IHRoaXMucGVyY2VudCA/IFN0cmluZyh0aGlzLnBlcmNlbnQpIDogdW5kZWZpbmVkO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKCFjaGFuZ2VzW1wic2hvd1wiXSkge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy5pc0RldGVybWluYXRlID0gdGhpcy5wZXJjZW50ICE9PSB1bmRlZmluZWQ7XG5cbiAgICAgICAgdGhpcy5jYW5jZWxTaG93VGltZXIoKTtcblxuICAgICAgICBpZiAodGhpcy5kZWxheSAmJiB0aGlzLnNob3cpIHtcbiAgICAgICAgICAgIHRoaXMubmdab25lLnJ1bk91dHNpZGVBbmd1bGFyKCgpID0+IHtcbiAgICAgICAgICAgICAgICB0aGlzLnNob3dUaW1lciA9IHNldFRpbWVvdXQoKCkgPT4ge1xuICAgICAgICAgICAgICAgICAgICB0aGlzLm5nWm9uZS5ydW4oKCkgPT4ge1xuICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5zaG93U3Bpbm5lciA9IHRoaXMuc2hvdztcbiAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMuY2hhbmdlRGV0ZWN0b3IuZGV0ZWN0Q2hhbmdlcygpO1xuICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICB9LCB0aGlzLmRlbGF5KTtcbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgdGhpcy5zaG93U3Bpbm5lciA9IHRoaXMuc2hvdztcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHB1YmxpYyBjYW5jZWxTaG93VGltZXIoKTogdm9pZCB7XG4gICAgICAgIGlmICh0aGlzLnNob3dUaW1lcikge1xuICAgICAgICAgICAgY2xlYXJUaW1lb3V0KHRoaXMuc2hvd1RpbWVyKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHB1YmxpYyBjYW5jZWxQcm9ncmVzcygpOiB2b2lkIHtcbiAgICAgICAgdGhpcy5jYW5jZWwuZW1pdCgpO1xuICAgIH1cblxuICAgIHB1YmxpYyBuZ09uRGVzdHJveSgpOiB2b2lkIHtcbiAgICAgICAgdGhpcy5jYW5jZWxTaG93VGltZXIoKTtcbiAgICB9XG59XG4iLCI8c3BhblxuICAgIGNsYXNzPVwibnVpLWljb24tYnVzeS1jaXJjdWxhciBudWktc3Bpbm5lciBudWktc3Bpbm5lcl9fY29udGFpbmVyLS17e1xuICAgICAgICBzaXplXG4gICAgfX1cIlxuICAgICpuZ0lmPVwic2hvd1NwaW5uZXJcIlxuICAgIFtuZ0NsYXNzXT1cInsgJ251aS1zcGlubmVyLS1kZXRlcm1pbmF0ZSc6IGlzRGV0ZXJtaW5hdGUgfVwiXG4gICAgW0BzcGlubmVyQXBwZWFyXVxuPlxuICAgIDxkaXYgY2xhc3M9XCJudWktc3Bpbm5lcl9fY29udGFpbmVyXCI+XG4gICAgICAgIDxzdmdcbiAgICAgICAgICAgIGNsYXNzPVwibnVpLXNwaW5uZXJfX2NpcmN1bGFyXCJcbiAgICAgICAgICAgIHZpZXdCb3g9XCIyNSAyNSA1MCA1MFwiXG4gICAgICAgICAgICAqbmdJZj1cIiFpc0RldGVybWluYXRlXCJcbiAgICAgICAgPlxuICAgICAgICAgICAgPGNpcmNsZVxuICAgICAgICAgICAgICAgIGNsYXNzPVwibnVpLXNwaW5uZXJfX3BhdGgtdW5kZXJcIlxuICAgICAgICAgICAgICAgIGN4PVwiNTBcIlxuICAgICAgICAgICAgICAgIGN5PVwiNTBcIlxuICAgICAgICAgICAgICAgIHI9XCIyMlwiXG4gICAgICAgICAgICAgICAgZmlsbD1cIm5vbmVcIlxuICAgICAgICAgICAgICAgIHN0cm9rZS13aWR0aD1cIjVcIlxuICAgICAgICAgICAgICAgIHN0cm9rZS1taXRlcmxpbWl0PVwiMTBcIlxuICAgICAgICAgICAgLz5cbiAgICAgICAgICAgIDxjaXJjbGVcbiAgICAgICAgICAgICAgICBjbGFzcz1cIm51aS1zcGlubmVyX19wYXRoXCJcbiAgICAgICAgICAgICAgICBjeD1cIjUwXCJcbiAgICAgICAgICAgICAgICBjeT1cIjUwXCJcbiAgICAgICAgICAgICAgICByPVwiMjJcIlxuICAgICAgICAgICAgICAgIGZpbGw9XCJub25lXCJcbiAgICAgICAgICAgICAgICBzdHJva2Utd2lkdGg9XCI1XCJcbiAgICAgICAgICAgICAgICBzdHJva2UtbWl0ZXJsaW1pdD1cIjEwXCJcbiAgICAgICAgICAgIC8+XG4gICAgICAgIDwvc3ZnPlxuICAgICAgICA8c3ZnXG4gICAgICAgICAgICBjbGFzcz1cIm51aS1zcGlubmVyX19jaXJjdWxhclwiXG4gICAgICAgICAgICB2aWV3Qm94PVwiMCAwIDM2IDM2XCJcbiAgICAgICAgICAgICpuZ0lmPVwiaXNEZXRlcm1pbmF0ZVwiXG4gICAgICAgID5cbiAgICAgICAgICAgIDxjaXJjbGVcbiAgICAgICAgICAgICAgICBjbGFzcz1cIm51aS1zcGlubmVyX19wYXRoLXVuZGVyXCJcbiAgICAgICAgICAgICAgICBjeD1cIjE4XCJcbiAgICAgICAgICAgICAgICBjeT1cIjE4XCJcbiAgICAgICAgICAgICAgICByPVwiMTUuOTE1NVwiXG4gICAgICAgICAgICAgICAgZmlsbD1cIm5vbmVcIlxuICAgICAgICAgICAgICAgIHN0cm9rZS13aWR0aD1cIjRcIlxuICAgICAgICAgICAgICAgIHN0cm9rZS1taXRlcmxpbWl0PVwiMTBcIlxuICAgICAgICAgICAgLz5cbiAgICAgICAgICAgIDxjaXJjbGVcbiAgICAgICAgICAgICAgICBjbGFzcz1cIm51aS1zcGlubmVyX19wYXRoXCJcbiAgICAgICAgICAgICAgICBjeD1cIjE4XCJcbiAgICAgICAgICAgICAgICBjeT1cIjE4XCJcbiAgICAgICAgICAgICAgICByPVwiMTUuOTE1NVwiXG4gICAgICAgICAgICAgICAgZmlsbD1cIm5vbmVcIlxuICAgICAgICAgICAgICAgIHN0cm9rZS13aWR0aD1cIjRcIlxuICAgICAgICAgICAgICAgIHN0cm9rZS1taXRlcmxpbWl0PVwiMTBcIlxuICAgICAgICAgICAgICAgIFtuZ1N0eWxlXT1cInsgJ3N0cm9rZS1kYXNoYXJyYXknOiBwZXJjZW50ICsgJywgMTAwJyB9XCJcbiAgICAgICAgICAgIC8+XG4gICAgICAgIDwvc3ZnPlxuXG4gICAgICAgIDxidXR0b25cbiAgICAgICAgICAgIG51aS1idXR0b25cbiAgICAgICAgICAgIHR5cGU9XCJidXR0b25cIlxuICAgICAgICAgICAgY2xhc3M9XCJudWktc3Bpbm5lcl9fY2FuY2VsXCJcbiAgICAgICAgICAgIGljb249XCJjbG9zZVwiXG4gICAgICAgICAgICAqbmdJZj1cImFsbG93Q2FuY2VsXCJcbiAgICAgICAgICAgIChjbGljayk9XCJjYW5jZWxQcm9ncmVzcygpXCJcbiAgICAgICAgICAgIGRpc3BsYXlTdHlsZT1cImFjdGlvblwiXG4gICAgICAgICAgICBbbnVpVG9vbHRpcF09XCJ0b29sdGlwVGV4dFwiXG4gICAgICAgID48L2J1dHRvbj5cbiAgICA8L2Rpdj5cblxuICAgIDxkaXYgY2xhc3M9XCJudWktc3Bpbm5lcl9fdGV4dC1jb250ZW50XCIgKm5nSWY9XCJzaG93VGV4dFwiPlxuICAgICAgICA8ZGl2IGNsYXNzPVwibnVpLXNwaW5uZXJfX2xhYmVsXCIgKm5nSWY9XCJtZXNzYWdlICE9PSB1bmRlZmluZWRcIj5cbiAgICAgICAgICAgIDxzcGFuIGNsYXNzPVwibnVpLXRleHQtbGFiZWwgbnVpLXNwaW5uZXJfX2xhYmVsLWl0ZW1cIj57e1xuICAgICAgICAgICAgICAgIG1lc3NhZ2VcbiAgICAgICAgICAgIH19PC9zcGFuPlxuICAgICAgICA8L2Rpdj5cbiAgICAgICAgPHNwYW5cbiAgICAgICAgICAgIGNsYXNzPVwibnVpLXNwaW5uZXJfX2hpbnQgbnVpLWhlbHAtaGludFwiXG4gICAgICAgICAgICAqbmdJZj1cImhlbHBUZXh0ICE9PSB1bmRlZmluZWRcIlxuICAgICAgICA+XG4gICAgICAgICAgICB7eyBoZWxwVGV4dCB9fVxuICAgICAgICA8L3NwYW4+XG4gICAgPC9kaXY+XG48L3NwYW4+XG4iXX0=