UNPKG

ng-toast-notify

Version:

Lightweight and flexible toast notifications for Angular

112 lines 26.2 kB
import { AsyncPipe, NgClass, NgStyle } from '@angular/common'; import { Component, HostListener, Input } from '@angular/core'; import * as i0 from "@angular/core"; import * as i1 from "../toasty.service"; var ToastyContainerPosition; (function (ToastyContainerPosition) { ToastyContainerPosition["TOP_LEFT"] = "top-left"; ToastyContainerPosition["TOP"] = "top"; ToastyContainerPosition["TOP_RIGHT"] = "top-right"; ToastyContainerPosition["BOTTOM_LEFT"] = "bottom-left"; ToastyContainerPosition["BOTTOM"] = "bottom"; ToastyContainerPosition["BOTTOM_RIGHT"] = "bottom-right"; })(ToastyContainerPosition || (ToastyContainerPosition = {})); export class ToastyComponent { constructor(_toastService) { this._toastService = _toastService; this.position = ToastyContainerPosition.BOTTOM_RIGHT; this.duration = this._toastService.getDefaultDuration(); this.capacity = this._toastService.getCapacity(); this.toasts$ = this._toastService.newToast$; this.positionMap = { 'top-left': ['top', 'left'], 'top': ['top', 'center'], 'top-right': ['top', 'right'], 'bottom-left': ['bottom', 'left'], 'bottom': ['bottom', 'center'], 'bottom-right': ['bottom', 'right'], }; } ngOnInit() { // Subscribe to the toast service to receive new toasts // this._toastService.newToast$.subscribe(t => { // if (t) { // // console.log(t); // } // }); this._toastService.deleteToast$.subscribe(t => { if (t) { // we dont need to delete toast, because internally in the service the toast has been deleted and in future toasts, only live toasts will be received from the service // console.log(t); } }); this._toastService.updateToast$.subscribe(t => { if (t) { // console.log(t); } }); } ngOnChanges(changes) { if (changes['duration']) { this._toastService.setDefaultDuration(this.duration); } if (changes['capacity']) { this._toastService.setCapacity(changes['capacity'].currentValue); } } closeToast(id) { this._toastService.closeToast(id); } containerClass() { return this.positionMap[this.position] ?? [ToastyContainerPosition.BOTTOM_RIGHT]; } expires(t) { return (t.expires < Date.now()); } getDurationUntilExpire(expires) { const duration = expires - Date.now(); return duration > 0 ? duration : 0; } // Swipe to close functionality onTouchStart(event) { const toastid = this.localizeToastIdFromTouch(event); this._toastService.updateTouchStart(toastid, event.changedTouches[0]); } onTouchEnd(event) { this._toastService.updateTouchEnd(event.changedTouches[0]); } onTouchMove(event) { this._toastService.updateTouchMove(event.changedTouches[0]); } localizeToastIdFromTouch(event) { let current = event.target; let maxnesting = 4; while (!current.classList.contains('toasty') && maxnesting > 0) { current = current.parentElement; maxnesting--; } return parseInt(current.getAttribute('data-toast-id') || '0'); } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: ToastyComponent, deps: [{ token: i1.ToastyService }], target: i0.ɵɵFactoryTarget.Component }); } static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "17.3.12", type: ToastyComponent, isStandalone: true, selector: "toasty", inputs: { position: "position", duration: "duration", capacity: "capacity" }, host: { listeners: { "touchstart": "onTouchStart($event)", "touchend": "onTouchEnd($event)", "touchmove": "onTouchMove($event)" } }, usesOnChanges: true, ngImport: i0, template: "<div class=\"toasty-container\" [ngClass]=\"containerClass()\">\r\n @for (item of toasts$ | async; track item.id) {\r\n <div class=\"toasty-wrapper\" [style.transform]=\"'translateX(' + (item.gesture?.offsetX || 0) + 'px)'\"\r\n [style.transition]=\"item.gesture ? 'none' : 'transform 0.3s ease'\">\r\n <div class=\"toasty\" [attr.data-toast-id]=\"item.id\" [ngClass]=\"item.type\" [class.fadeout]=\"expires(item)\"\r\n [ngStyle]=\"item.config?.customStyle\">\r\n @if (item.icon) {\r\n <div class=\"toasty-icon\">{{item.icon}}</div>\r\n } @else if (item.config?.loading){\r\n <div class=\"toasty-loading\"></div>\r\n } @else {\r\n <div class=\"toasty-noicon\"></div>\r\n }\r\n <div class=\"toasty-content\">\r\n @if (item.title) {\r\n <div class=\"toasty-header\">\r\n <strong class=\"toasty-title\">{{item.title}}</strong>\r\n <!-- <small class=\"toasty-time\">{{item.timestamp}}</small> -->\r\n </div>\r\n }\r\n @if (item.config?.enableHtml) {\r\n <div class=\"toasty-body\" [innerHTML]=\"item.message\"></div>\r\n } @else {\r\n <div class=\"toasty-body\">{{item.message}}</div>\r\n }\r\n </div>\r\n <div class=\"toasty-close\">\r\n <button type=\"button\" class=\"toasty-close\" (click)=\"closeToast(item.id)\">&times;</button>\r\n </div>\r\n @if (item.config?.progressBar) {\r\n <div class=\"toasty-progress\" [class.animate]=\"item.animatePbar\" [style.transition-duration.ms]=\"item.duration\"></div>\r\n }\r\n </div>\r\n </div>\r\n }\r\n</div>", styles: [".toasty-container{position:fixed;width:350px;padding:.5rem;right:0;bottom:0;pointer-events:none}.toasty-container.left{left:12px}.toasty-container.center{left:50%;transform:translate(-50%)}.toasty-container.right{right:12px}.toasty-container.top{top:10px;display:flex;flex-direction:column-reverse;justify-content:flex-end}.toasty-container.bottom{bottom:0}.toasty{padding:10px;border:1px solid rgba(0,0,0,.15);border-radius:8px;box-shadow:0 4px 10px #00000026;background-color:#fff;overflow:hidden;margin-bottom:1rem;font-family:Arial,Helvetica,sans-serif;animation-name:toasty_fadein;animation-duration:.3s;animation-timing-function:ease-out;animation-delay:0s;animation-iteration-count:1;animation-fill-mode:forwards;display:flex;align-items:center;pointer-events:auto;touch-action:manipulation}@keyframes toasty_fadein{0%{opacity:0;transform:translate(100%)}to{opacity:1;transform:translate(0)}}@keyframes toasty_fadeout{0%{opacity:1}to{opacity:0;pointer-events:none}}.toasty.fadeout{animation-name:toasty_fadeout;animation-duration:.5s;animation-timing-function:ease-in;animation-delay:0s;animation-iteration-count:1;animation-fill-mode:forwards;pointer-events:none}.toasty-icon{width:20px;height:20px;margin-right:.5rem;border-radius:4px}.toasty-loading{width:10px;height:10px;margin-right:.6rem;border-radius:50%;display:inline-block;border-top:3px solid;border-right:3px solid transparent;box-sizing:border-box;animation:loading-toasty-anim 1s linear infinite}@keyframes loading-toasty-anim{0%{transform:rotate(0)}to{transform:rotate(360deg)}}.toasty-noicon{width:7px}.toasty-content{flex-direction:column;flex:1}.toasty-header{display:flex;align-items:center}.toasty-title{font-size:.9rem;font-weight:700;margin-right:auto}.toasty-time{font-size:.85rem;color:#6c757d;margin-right:1rem}.toasty-close{background:none;border:none;font-size:1.4rem;line-height:1;cursor:pointer;color:inherit;opacity:.6}.toasty-body{font-size:.85rem;margin-top:1px}.toasty-close:hover{opacity:1}.toasty.none{background-color:#fff;border-color:#ededed;color:#171717}.toasty.success{background-color:#ecfdf3;border-color:#bffcd9;color:#008a2e}.toasty.error{background-color:#fff0f0;border-color:#ffe0e1;color:#e60000}.toasty.info{background-color:#f0f8ff;border-color:#dde7fd;color:#0973dc}.toasty.warning{background-color:#fffcf0;border-color:#fbeeb1;color:#dc7609}.toasty.custom{background-color:#fff}.toasty-progress{position:absolute;bottom:0;left:0;height:4px;width:100%;background-color:currentColor;opacity:.3;transform-origin:left;transform:scaleX(1);transition-property:transform;transition-timing-function:linear}.toasty-progress.animate{transform:scaleX(0)}\n"], dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "pipe", type: AsyncPipe, name: "async" }] }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: ToastyComponent, decorators: [{ type: Component, args: [{ selector: 'toasty', standalone: true, imports: [NgClass, NgStyle, AsyncPipe], template: "<div class=\"toasty-container\" [ngClass]=\"containerClass()\">\r\n @for (item of toasts$ | async; track item.id) {\r\n <div class=\"toasty-wrapper\" [style.transform]=\"'translateX(' + (item.gesture?.offsetX || 0) + 'px)'\"\r\n [style.transition]=\"item.gesture ? 'none' : 'transform 0.3s ease'\">\r\n <div class=\"toasty\" [attr.data-toast-id]=\"item.id\" [ngClass]=\"item.type\" [class.fadeout]=\"expires(item)\"\r\n [ngStyle]=\"item.config?.customStyle\">\r\n @if (item.icon) {\r\n <div class=\"toasty-icon\">{{item.icon}}</div>\r\n } @else if (item.config?.loading){\r\n <div class=\"toasty-loading\"></div>\r\n } @else {\r\n <div class=\"toasty-noicon\"></div>\r\n }\r\n <div class=\"toasty-content\">\r\n @if (item.title) {\r\n <div class=\"toasty-header\">\r\n <strong class=\"toasty-title\">{{item.title}}</strong>\r\n <!-- <small class=\"toasty-time\">{{item.timestamp}}</small> -->\r\n </div>\r\n }\r\n @if (item.config?.enableHtml) {\r\n <div class=\"toasty-body\" [innerHTML]=\"item.message\"></div>\r\n } @else {\r\n <div class=\"toasty-body\">{{item.message}}</div>\r\n }\r\n </div>\r\n <div class=\"toasty-close\">\r\n <button type=\"button\" class=\"toasty-close\" (click)=\"closeToast(item.id)\">&times;</button>\r\n </div>\r\n @if (item.config?.progressBar) {\r\n <div class=\"toasty-progress\" [class.animate]=\"item.animatePbar\" [style.transition-duration.ms]=\"item.duration\"></div>\r\n }\r\n </div>\r\n </div>\r\n }\r\n</div>", styles: [".toasty-container{position:fixed;width:350px;padding:.5rem;right:0;bottom:0;pointer-events:none}.toasty-container.left{left:12px}.toasty-container.center{left:50%;transform:translate(-50%)}.toasty-container.right{right:12px}.toasty-container.top{top:10px;display:flex;flex-direction:column-reverse;justify-content:flex-end}.toasty-container.bottom{bottom:0}.toasty{padding:10px;border:1px solid rgba(0,0,0,.15);border-radius:8px;box-shadow:0 4px 10px #00000026;background-color:#fff;overflow:hidden;margin-bottom:1rem;font-family:Arial,Helvetica,sans-serif;animation-name:toasty_fadein;animation-duration:.3s;animation-timing-function:ease-out;animation-delay:0s;animation-iteration-count:1;animation-fill-mode:forwards;display:flex;align-items:center;pointer-events:auto;touch-action:manipulation}@keyframes toasty_fadein{0%{opacity:0;transform:translate(100%)}to{opacity:1;transform:translate(0)}}@keyframes toasty_fadeout{0%{opacity:1}to{opacity:0;pointer-events:none}}.toasty.fadeout{animation-name:toasty_fadeout;animation-duration:.5s;animation-timing-function:ease-in;animation-delay:0s;animation-iteration-count:1;animation-fill-mode:forwards;pointer-events:none}.toasty-icon{width:20px;height:20px;margin-right:.5rem;border-radius:4px}.toasty-loading{width:10px;height:10px;margin-right:.6rem;border-radius:50%;display:inline-block;border-top:3px solid;border-right:3px solid transparent;box-sizing:border-box;animation:loading-toasty-anim 1s linear infinite}@keyframes loading-toasty-anim{0%{transform:rotate(0)}to{transform:rotate(360deg)}}.toasty-noicon{width:7px}.toasty-content{flex-direction:column;flex:1}.toasty-header{display:flex;align-items:center}.toasty-title{font-size:.9rem;font-weight:700;margin-right:auto}.toasty-time{font-size:.85rem;color:#6c757d;margin-right:1rem}.toasty-close{background:none;border:none;font-size:1.4rem;line-height:1;cursor:pointer;color:inherit;opacity:.6}.toasty-body{font-size:.85rem;margin-top:1px}.toasty-close:hover{opacity:1}.toasty.none{background-color:#fff;border-color:#ededed;color:#171717}.toasty.success{background-color:#ecfdf3;border-color:#bffcd9;color:#008a2e}.toasty.error{background-color:#fff0f0;border-color:#ffe0e1;color:#e60000}.toasty.info{background-color:#f0f8ff;border-color:#dde7fd;color:#0973dc}.toasty.warning{background-color:#fffcf0;border-color:#fbeeb1;color:#dc7609}.toasty.custom{background-color:#fff}.toasty-progress{position:absolute;bottom:0;left:0;height:4px;width:100%;background-color:currentColor;opacity:.3;transform-origin:left;transform:scaleX(1);transition-property:transform;transition-timing-function:linear}.toasty-progress.animate{transform:scaleX(0)}\n"] }] }], ctorParameters: () => [{ type: i1.ToastyService }], propDecorators: { position: [{ type: Input }], duration: [{ type: Input }], capacity: [{ type: Input }], onTouchStart: [{ type: HostListener, args: ['touchstart', ['$event']] }], onTouchEnd: [{ type: HostListener, args: ['touchend', ['$event']] }], onTouchMove: [{ type: HostListener, args: ['touchmove', ['$event']] }] } }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidG9hc3R5LmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL3Byb2plY3RzL25nLXRvYXN0LW5vdGlmeS9zcmMvbGliL3RvYXN0eS90b2FzdHkuY29tcG9uZW50LnRzIiwiLi4vLi4vLi4vLi4vLi4vcHJvamVjdHMvbmctdG9hc3Qtbm90aWZ5L3NyYy9saWIvdG9hc3R5L3RvYXN0eS5jb21wb25lbnQuaHRtbCJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsU0FBUyxFQUFFLE9BQU8sRUFBRSxPQUFPLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQztBQUM5RCxPQUFPLEVBQUUsU0FBUyxFQUFFLFlBQVksRUFBRSxLQUFLLEVBQWlCLE1BQU0sZUFBZSxDQUFDOzs7QUFHOUUsSUFBSyx1QkFPSjtBQVBELFdBQUssdUJBQXVCO0lBQzFCLGdEQUFxQixDQUFBO0lBQ3JCLHNDQUFXLENBQUE7SUFDWCxrREFBdUIsQ0FBQTtJQUN2QixzREFBMkIsQ0FBQTtJQUMzQiw0Q0FBaUIsQ0FBQTtJQUNqQix3REFBNkIsQ0FBQTtBQUMvQixDQUFDLEVBUEksdUJBQXVCLEtBQXZCLHVCQUF1QixRQU8zQjtBQVNELE1BQU0sT0FBTyxlQUFlO0lBZ0IxQixZQUFvQixhQUE0QjtRQUE1QixrQkFBYSxHQUFiLGFBQWEsQ0FBZTtRQWR2QyxhQUFRLEdBQVcsdUJBQXVCLENBQUMsWUFBWSxDQUFDO1FBQ3hELGFBQVEsR0FBVyxJQUFJLENBQUMsYUFBYSxDQUFDLGtCQUFrQixFQUFFLENBQUM7UUFDM0QsYUFBUSxHQUFXLElBQUksQ0FBQyxhQUFhLENBQUMsV0FBVyxFQUFFLENBQUM7UUFFbkQsWUFBTyxHQUFHLElBQUksQ0FBQyxhQUFhLENBQUMsU0FBUyxDQUFDO1FBRWhDLGdCQUFXLEdBQTZCO1lBQ3ZELFVBQVUsRUFBRSxDQUFDLEtBQUssRUFBRSxNQUFNLENBQUM7WUFDM0IsS0FBSyxFQUFFLENBQUMsS0FBSyxFQUFFLFFBQVEsQ0FBQztZQUN4QixXQUFXLEVBQUUsQ0FBQyxLQUFLLEVBQUUsT0FBTyxDQUFDO1lBQzdCLGFBQWEsRUFBRSxDQUFDLFFBQVEsRUFBRSxNQUFNLENBQUM7WUFDakMsUUFBUSxFQUFFLENBQUMsUUFBUSxFQUFFLFFBQVEsQ0FBQztZQUM5QixjQUFjLEVBQUUsQ0FBQyxRQUFRLEVBQUUsT0FBTyxDQUFDO1NBQ3BDLENBQUM7SUFHRixDQUFDO0lBRUQsUUFBUTtRQUNOLHVEQUF1RDtRQUN2RCxnREFBZ0Q7UUFDaEQsYUFBYTtRQUNiLHlCQUF5QjtRQUN6QixNQUFNO1FBQ04sTUFBTTtRQUVOLElBQUksQ0FBQyxhQUFhLENBQUMsWUFBWSxDQUFDLFNBQVMsQ0FBQyxDQUFDLENBQUMsRUFBRTtZQUM1QyxJQUFJLENBQUMsRUFBRSxDQUFDO2dCQUNOLHNLQUFzSztnQkFDdEssa0JBQWtCO1lBQ3BCLENBQUM7UUFDSCxDQUFDLENBQUMsQ0FBQztRQUVILElBQUksQ0FBQyxhQUFhLENBQUMsWUFBWSxDQUFDLFNBQVMsQ0FBQyxDQUFDLENBQUMsRUFBRTtZQUM1QyxJQUFJLENBQUMsRUFBRSxDQUFDO2dCQUNOLGtCQUFrQjtZQUNwQixDQUFDO1FBQ0gsQ0FBQyxDQUFDLENBQUE7SUFDSixDQUFDO0lBRUQsV0FBVyxDQUFDLE9BQXNCO1FBQ2hDLElBQUksT0FBTyxDQUFDLFVBQVUsQ0FBQyxFQUFFLENBQUM7WUFDeEIsSUFBSSxDQUFDLGFBQWEsQ0FBQyxrQkFBa0IsQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLENBQUM7UUFDdkQsQ0FBQztRQUNELElBQUksT0FBTyxDQUFDLFVBQVUsQ0FBQyxFQUFFLENBQUM7WUFDeEIsSUFBSSxDQUFDLGFBQWEsQ0FBQyxXQUFXLENBQUMsT0FBTyxDQUFDLFVBQVUsQ0FBQyxDQUFDLFlBQVksQ0FBQyxDQUFDO1FBQ25FLENBQUM7SUFDSCxDQUFDO0lBR0QsVUFBVSxDQUFDLEVBQVU7UUFDbkIsSUFBSSxDQUFDLGFBQWEsQ0FBQyxVQUFVLENBQUMsRUFBRSxDQUFDLENBQUM7SUFDcEMsQ0FBQztJQUVELGNBQWM7UUFDWixPQUFPLElBQUksQ0FBQyxXQUFXLENBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxJQUFJLENBQUMsdUJBQXVCLENBQUMsWUFBWSxDQUFDLENBQUM7SUFDbkYsQ0FBQztJQUVELE9BQU8sQ0FBQyxDQUFhO1FBQ25CLE9BQU8sQ0FBQyxDQUFDLENBQUMsT0FBTyxHQUFHLElBQUksQ0FBQyxHQUFHLEVBQUUsQ0FBQyxDQUFDO0lBQ2xDLENBQUM7SUFFRCxzQkFBc0IsQ0FBQyxPQUFlO1FBQ3BDLE1BQU0sUUFBUSxHQUFHLE9BQU8sR0FBRyxJQUFJLENBQUMsR0FBRyxFQUFFLENBQUM7UUFDdEMsT0FBTyxRQUFRLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUNyQyxDQUFDO0lBRUQsK0JBQStCO0lBRS9CLFlBQVksQ0FBQyxLQUFpQjtRQUM1QixNQUFNLE9BQU8sR0FBRyxJQUFJLENBQUMsd0JBQXdCLENBQUMsS0FBSyxDQUFDLENBQUM7UUFDckQsSUFBSSxDQUFDLGFBQWEsQ0FBQyxnQkFBZ0IsQ0FBQyxPQUFPLEVBQUUsS0FBSyxDQUFDLGNBQWMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQ3hFLENBQUM7SUFHRCxVQUFVLENBQUMsS0FBaUI7UUFDMUIsSUFBSSxDQUFDLGFBQWEsQ0FBQyxjQUFjLENBQUMsS0FBSyxDQUFDLGNBQWMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQzdELENBQUM7SUFHRCxXQUFXLENBQUMsS0FBaUI7UUFDM0IsSUFBSSxDQUFDLGFBQWEsQ0FBQyxlQUFlLENBQUMsS0FBSyxDQUFDLGNBQWMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQzlELENBQUM7SUFFTyx3QkFBd0IsQ0FBQyxLQUFpQjtRQUNoRCxJQUFJLE9BQU8sR0FBRyxLQUFLLENBQUMsTUFBcUIsQ0FBQztRQUMxQyxJQUFJLFVBQVUsR0FBWSxDQUFDLENBQUM7UUFDNUIsT0FBTyxDQUFDLE9BQU8sQ0FBQyxTQUFTLENBQUMsUUFBUSxDQUFDLFFBQVEsQ0FBQyxJQUFJLFVBQVUsR0FBRyxDQUFDLEVBQUUsQ0FBQztZQUMvRCxPQUFPLEdBQUcsT0FBTyxDQUFDLGFBQTRCLENBQUM7WUFDL0MsVUFBVSxFQUFFLENBQUM7UUFDZixDQUFDO1FBRUQsT0FBTyxRQUFRLENBQUMsT0FBTyxDQUFDLFlBQVksQ0FBQyxlQUFlLENBQUMsSUFBSSxHQUFHLENBQUMsQ0FBQztJQUNoRSxDQUFDOytHQS9GVSxlQUFlO21HQUFmLGVBQWUsMFNDcEI1QiwwMERBbUNNLHlwRkRuQk0sT0FBTyxvRkFBRSxPQUFPLHNFQUFFLFNBQVM7OzRGQUkxQixlQUFlO2tCQVAzQixTQUFTOytCQUNFLFFBQVEsY0FDTixJQUFJLFdBQ1AsQ0FBQyxPQUFPLEVBQUUsT0FBTyxFQUFFLFNBQVMsQ0FBQztrRkFNN0IsUUFBUTtzQkFBaEIsS0FBSztnQkFDRyxRQUFRO3NCQUFoQixLQUFLO2dCQUNHLFFBQVE7c0JBQWhCLEtBQUs7Z0JBbUVOLFlBQVk7c0JBRFgsWUFBWTt1QkFBQyxZQUFZLEVBQUUsQ0FBQyxRQUFRLENBQUM7Z0JBT3RDLFVBQVU7c0JBRFQsWUFBWTt1QkFBQyxVQUFVLEVBQUUsQ0FBQyxRQUFRLENBQUM7Z0JBTXBDLFdBQVc7c0JBRFYsWUFBWTt1QkFBQyxXQUFXLEVBQUUsQ0FBQyxRQUFRLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBBc3luY1BpcGUsIE5nQ2xhc3MsIE5nU3R5bGUgfSBmcm9tICdAYW5ndWxhci9jb21tb24nO1xyXG5pbXBvcnQgeyBDb21wb25lbnQsIEhvc3RMaXN0ZW5lciwgSW5wdXQsIFNpbXBsZUNoYW5nZXMgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcclxuaW1wb3J0IHsgVG9hc3RNb2RlbCwgVG9hc3R5U2VydmljZSB9IGZyb20gJy4uL3RvYXN0eS5zZXJ2aWNlJztcclxuXHJcbmVudW0gVG9hc3R5Q29udGFpbmVyUG9zaXRpb24ge1xyXG4gIFRPUF9MRUZUID0gJ3RvcC1sZWZ0JyxcclxuICBUT1AgPSAndG9wJyxcclxuICBUT1BfUklHSFQgPSAndG9wLXJpZ2h0JyxcclxuICBCT1RUT01fTEVGVCA9ICdib3R0b20tbGVmdCcsXHJcbiAgQk9UVE9NID0gJ2JvdHRvbScsXHJcbiAgQk9UVE9NX1JJR0hUID0gJ2JvdHRvbS1yaWdodCdcclxufVxyXG5cclxuQENvbXBvbmVudCh7XHJcbiAgc2VsZWN0b3I6ICd0b2FzdHknLFxyXG4gIHN0YW5kYWxvbmU6IHRydWUsXHJcbiAgaW1wb3J0czogW05nQ2xhc3MsIE5nU3R5bGUsIEFzeW5jUGlwZV0sXHJcbiAgdGVtcGxhdGVVcmw6ICcuL3RvYXN0eS5jb21wb25lbnQuaHRtbCcsXHJcbiAgc3R5bGVVcmw6ICcuL3RvYXN0eS5jb21wb25lbnQuY3NzJ1xyXG59KVxyXG5leHBvcnQgY2xhc3MgVG9hc3R5Q29tcG9uZW50IHtcclxuXHJcbiAgQElucHV0KCkgcG9zaXRpb246IHN0cmluZyA9IFRvYXN0eUNvbnRhaW5lclBvc2l0aW9uLkJPVFRPTV9SSUdIVDtcclxuICBASW5wdXQoKSBkdXJhdGlvbjogbnVtYmVyID0gdGhpcy5fdG9hc3RTZXJ2aWNlLmdldERlZmF1bHREdXJhdGlvbigpO1xyXG4gIEBJbnB1dCgpIGNhcGFjaXR5OiBudW1iZXIgPSB0aGlzLl90b2FzdFNlcnZpY2UuZ2V0Q2FwYWNpdHkoKTtcclxuXHJcbiAgcHJvdGVjdGVkIHRvYXN0cyQgPSB0aGlzLl90b2FzdFNlcnZpY2UubmV3VG9hc3QkO1xyXG5cclxuICBwcml2YXRlIHJlYWRvbmx5IHBvc2l0aW9uTWFwOiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmdbXT4gPSB7XHJcbiAgICAndG9wLWxlZnQnOiBbJ3RvcCcsICdsZWZ0J10sXHJcbiAgICAndG9wJzogWyd0b3AnLCAnY2VudGVyJ10sXHJcbiAgICAndG9wLXJpZ2h0JzogWyd0b3AnLCAncmlnaHQnXSxcclxuICAgICdib3R0b20tbGVmdCc6IFsnYm90dG9tJywgJ2xlZnQnXSxcclxuICAgICdib3R0b20nOiBbJ2JvdHRvbScsICdjZW50ZXInXSxcclxuICAgICdib3R0b20tcmlnaHQnOiBbJ2JvdHRvbScsICdyaWdodCddLFxyXG4gIH07XHJcbiAgY29uc3RydWN0b3IocHJpdmF0ZSBfdG9hc3RTZXJ2aWNlOiBUb2FzdHlTZXJ2aWNlKSB7XHJcblxyXG4gIH1cclxuXHJcbiAgbmdPbkluaXQoKTogdm9pZCB7XHJcbiAgICAvLyBTdWJzY3JpYmUgdG8gdGhlIHRvYXN0IHNlcnZpY2UgdG8gcmVjZWl2ZSBuZXcgdG9hc3RzXHJcbiAgICAvLyB0aGlzLl90b2FzdFNlcnZpY2UubmV3VG9hc3QkLnN1YnNjcmliZSh0ID0+IHtcclxuICAgIC8vICAgaWYgKHQpIHtcclxuICAgIC8vICAgICAvLyBjb25zb2xlLmxvZyh0KTtcclxuICAgIC8vICAgfVxyXG4gICAgLy8gfSk7XHJcblxyXG4gICAgdGhpcy5fdG9hc3RTZXJ2aWNlLmRlbGV0ZVRvYXN0JC5zdWJzY3JpYmUodCA9PiB7XHJcbiAgICAgIGlmICh0KSB7XHJcbiAgICAgICAgLy8gd2UgZG9udCBuZWVkIHRvIGRlbGV0ZSB0b2FzdCwgYmVjYXVzZSBpbnRlcm5hbGx5IGluIHRoZSBzZXJ2aWNlIHRoZSB0b2FzdCBoYXMgYmVlbiBkZWxldGVkIGFuZCBpbiBmdXR1cmUgdG9hc3RzLCBvbmx5IGxpdmUgdG9hc3RzIHdpbGwgYmUgcmVjZWl2ZWQgZnJvbSB0aGUgc2VydmljZVxyXG4gICAgICAgIC8vIGNvbnNvbGUubG9nKHQpO1xyXG4gICAgICB9XHJcbiAgICB9KTtcclxuXHJcbiAgICB0aGlzLl90b2FzdFNlcnZpY2UudXBkYXRlVG9hc3QkLnN1YnNjcmliZSh0ID0+IHtcclxuICAgICAgaWYgKHQpIHtcclxuICAgICAgICAvLyBjb25zb2xlLmxvZyh0KTtcclxuICAgICAgfVxyXG4gICAgfSlcclxuICB9XHJcblxyXG4gIG5nT25DaGFuZ2VzKGNoYW5nZXM6IFNpbXBsZUNoYW5nZXMpOiB2b2lkIHtcclxuICAgIGlmIChjaGFuZ2VzWydkdXJhdGlvbiddKSB7XHJcbiAgICAgIHRoaXMuX3RvYXN0U2VydmljZS5zZXREZWZhdWx0RHVyYXRpb24odGhpcy5kdXJhdGlvbik7XHJcbiAgICB9XHJcbiAgICBpZiAoY2hhbmdlc1snY2FwYWNpdHknXSkge1xyXG4gICAgICB0aGlzLl90b2FzdFNlcnZpY2Uuc2V0Q2FwYWNpdHkoY2hhbmdlc1snY2FwYWNpdHknXS5jdXJyZW50VmFsdWUpO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcblxyXG4gIGNsb3NlVG9hc3QoaWQ6IG51bWJlcik6IHZvaWQge1xyXG4gICAgdGhpcy5fdG9hc3RTZXJ2aWNlLmNsb3NlVG9hc3QoaWQpO1xyXG4gIH1cclxuXHJcbiAgY29udGFpbmVyQ2xhc3MoKTogc3RyaW5nW10ge1xyXG4gICAgcmV0dXJuIHRoaXMucG9zaXRpb25NYXBbdGhpcy5wb3NpdGlvbl0gPz8gW1RvYXN0eUNvbnRhaW5lclBvc2l0aW9uLkJPVFRPTV9SSUdIVF07XHJcbiAgfVxyXG5cclxuICBleHBpcmVzKHQ6IFRvYXN0TW9kZWwpOiBib29sZWFuIHtcclxuICAgIHJldHVybiAodC5leHBpcmVzIDwgRGF0ZS5ub3coKSk7XHJcbiAgfVxyXG5cclxuICBnZXREdXJhdGlvblVudGlsRXhwaXJlKGV4cGlyZXM6IG51bWJlcik6IG51bWJlciB7XHJcbiAgICBjb25zdCBkdXJhdGlvbiA9IGV4cGlyZXMgLSBEYXRlLm5vdygpO1xyXG4gICAgcmV0dXJuIGR1cmF0aW9uID4gMCA/IGR1cmF0aW9uIDogMDtcclxuICB9XHJcblxyXG4gIC8vIFN3aXBlIHRvIGNsb3NlIGZ1bmN0aW9uYWxpdHlcclxuICBASG9zdExpc3RlbmVyKCd0b3VjaHN0YXJ0JywgWyckZXZlbnQnXSlcclxuICBvblRvdWNoU3RhcnQoZXZlbnQ6IFRvdWNoRXZlbnQpIHtcclxuICAgIGNvbnN0IHRvYXN0aWQgPSB0aGlzLmxvY2FsaXplVG9hc3RJZEZyb21Ub3VjaChldmVudCk7XHJcbiAgICB0aGlzLl90b2FzdFNlcnZpY2UudXBkYXRlVG91Y2hTdGFydCh0b2FzdGlkLCBldmVudC5jaGFuZ2VkVG91Y2hlc1swXSk7XHJcbiAgfVxyXG5cclxuICBASG9zdExpc3RlbmVyKCd0b3VjaGVuZCcsIFsnJGV2ZW50J10pXHJcbiAgb25Ub3VjaEVuZChldmVudDogVG91Y2hFdmVudCkge1xyXG4gICAgdGhpcy5fdG9hc3RTZXJ2aWNlLnVwZGF0ZVRvdWNoRW5kKGV2ZW50LmNoYW5nZWRUb3VjaGVzWzBdKTtcclxuICB9XHJcblxyXG4gIEBIb3N0TGlzdGVuZXIoJ3RvdWNobW92ZScsIFsnJGV2ZW50J10pXHJcbiAgb25Ub3VjaE1vdmUoZXZlbnQ6IFRvdWNoRXZlbnQpIHtcclxuICAgIHRoaXMuX3RvYXN0U2VydmljZS51cGRhdGVUb3VjaE1vdmUoZXZlbnQuY2hhbmdlZFRvdWNoZXNbMF0pO1xyXG4gIH1cclxuXHJcbiAgcHJpdmF0ZSBsb2NhbGl6ZVRvYXN0SWRGcm9tVG91Y2goZXZlbnQ6IFRvdWNoRXZlbnQpOiBudW1iZXIge1xyXG4gICAgbGV0IGN1cnJlbnQgPSBldmVudC50YXJnZXQgYXMgSFRNTEVsZW1lbnQ7XHJcbiAgICBsZXQgbWF4bmVzdGluZyA6IG51bWJlciA9IDQ7XHJcbiAgICB3aGlsZSAoIWN1cnJlbnQuY2xhc3NMaXN0LmNvbnRhaW5zKCd0b2FzdHknKSAmJiBtYXhuZXN0aW5nID4gMCkge1xyXG4gICAgICBjdXJyZW50ID0gY3VycmVudC5wYXJlbnRFbGVtZW50IGFzIEhUTUxFbGVtZW50O1xyXG4gICAgICBtYXhuZXN0aW5nLS07XHJcbiAgICB9XHJcblxyXG4gICAgcmV0dXJuIHBhcnNlSW50KGN1cnJlbnQuZ2V0QXR0cmlidXRlKCdkYXRhLXRvYXN0LWlkJykgfHwgJzAnKTtcclxuICB9XHJcblxyXG59XHJcbiIsIjxkaXYgY2xhc3M9XCJ0b2FzdHktY29udGFpbmVyXCIgW25nQ2xhc3NdPVwiY29udGFpbmVyQ2xhc3MoKVwiPlxyXG4gICAgQGZvciAoaXRlbSBvZiB0b2FzdHMkIHwgYXN5bmM7IHRyYWNrIGl0ZW0uaWQpIHtcclxuICAgIDxkaXYgY2xhc3M9XCJ0b2FzdHktd3JhcHBlclwiIFtzdHlsZS50cmFuc2Zvcm1dPVwiJ3RyYW5zbGF0ZVgoJyArIChpdGVtLmdlc3R1cmU/Lm9mZnNldFggfHwgMCkgKyAncHgpJ1wiXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgW3N0eWxlLnRyYW5zaXRpb25dPVwiaXRlbS5nZXN0dXJlID8gJ25vbmUnIDogJ3RyYW5zZm9ybSAwLjNzIGVhc2UnXCI+XHJcbiAgICAgICAgPGRpdiBjbGFzcz1cInRvYXN0eVwiIFthdHRyLmRhdGEtdG9hc3QtaWRdPVwiaXRlbS5pZFwiIFtuZ0NsYXNzXT1cIml0ZW0udHlwZVwiIFtjbGFzcy5mYWRlb3V0XT1cImV4cGlyZXMoaXRlbSlcIlxyXG4gICAgICAgICAgICBbbmdTdHlsZV09XCJpdGVtLmNvbmZpZz8uY3VzdG9tU3R5bGVcIj5cclxuICAgICAgICAgICAgQGlmIChpdGVtLmljb24pIHtcclxuICAgICAgICAgICAgPGRpdiBjbGFzcz1cInRvYXN0eS1pY29uXCI+e3tpdGVtLmljb259fTwvZGl2PlxyXG4gICAgICAgICAgICB9IEBlbHNlIGlmIChpdGVtLmNvbmZpZz8ubG9hZGluZyl7XHJcbiAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJ0b2FzdHktbG9hZGluZ1wiPjwvZGl2PlxyXG4gICAgICAgICAgICB9IEBlbHNlIHtcclxuICAgICAgICAgICAgPGRpdiBjbGFzcz1cInRvYXN0eS1ub2ljb25cIj48L2Rpdj5cclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICA8ZGl2IGNsYXNzPVwidG9hc3R5LWNvbnRlbnRcIj5cclxuICAgICAgICAgICAgICAgIEBpZiAoaXRlbS50aXRsZSkge1xyXG4gICAgICAgICAgICAgICAgPGRpdiBjbGFzcz1cInRvYXN0eS1oZWFkZXJcIj5cclxuICAgICAgICAgICAgICAgICAgICA8c3Ryb25nIGNsYXNzPVwidG9hc3R5LXRpdGxlXCI+e3tpdGVtLnRpdGxlfX08L3N0cm9uZz5cclxuICAgICAgICAgICAgICAgICAgICA8IS0tIDxzbWFsbCBjbGFzcz1cInRvYXN0eS10aW1lXCI+e3tpdGVtLnRpbWVzdGFtcH19PC9zbWFsbD4gLS0+XHJcbiAgICAgICAgICAgICAgICA8L2Rpdj5cclxuICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgIEBpZiAoaXRlbS5jb25maWc/LmVuYWJsZUh0bWwpIHtcclxuICAgICAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJ0b2FzdHktYm9keVwiIFtpbm5lckhUTUxdPVwiaXRlbS5tZXNzYWdlXCI+PC9kaXY+XHJcbiAgICAgICAgICAgICAgICB9IEBlbHNlIHtcclxuICAgICAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJ0b2FzdHktYm9keVwiPnt7aXRlbS5tZXNzYWdlfX08L2Rpdj5cclxuICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgPC9kaXY+XHJcbiAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJ0b2FzdHktY2xvc2VcIj5cclxuICAgICAgICAgICAgICAgIDxidXR0b24gdHlwZT1cImJ1dHRvblwiIGNsYXNzPVwidG9hc3R5LWNsb3NlXCIgKGNsaWNrKT1cImNsb3NlVG9hc3QoaXRlbS5pZClcIj4mdGltZXM7PC9idXR0b24+XHJcbiAgICAgICAgICAgIDwvZGl2PlxyXG4gICAgICAgICAgICBAaWYgKGl0ZW0uY29uZmlnPy5wcm9ncmVzc0Jhcikge1xyXG4gICAgICAgICAgICAgICAgPGRpdiBjbGFzcz1cInRvYXN0eS1wcm9ncmVzc1wiIFtjbGFzcy5hbmltYXRlXT1cIml0ZW0uYW5pbWF0ZVBiYXJcIiBbc3R5bGUudHJhbnNpdGlvbi1kdXJhdGlvbi5tc109XCJpdGVtLmR1cmF0aW9uXCI+PC9kaXY+XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICA8L2Rpdj5cclxuICAgIDwvZGl2PlxyXG4gICAgfVxyXG48L2Rpdj4iXX0=