ng-toast-notify
Version:
Lightweight and flexible toast notifications for Angular
203 lines • 30.6 kB
JavaScript
import { Injectable } from '@angular/core';
import { BehaviorSubject } from 'rxjs/internal/BehaviorSubject';
import * as i0 from "@angular/core";
import * as i1 from "./toastysound.service";
class Queue {
constructor(capacity = Infinity) {
this.capacity = capacity;
this.storage = [];
}
setCapacity(c) {
this.capacity = c;
}
getCapacity() { return this.capacity; }
enqueue(item) {
if (this.size() >= this.capacity) {
throw Error('Toasty queue has reached max capacity, you cannot add more items.');
}
this.storage.push(item);
}
dequeue() {
return this.storage.shift();
}
size() {
return this.storage.length;
}
getElements() {
return this.storage;
}
removeId(id) {
const index = this.storage.findIndex(item => item.id === id);
if (index !== -1) {
const [removed] = this.storage.splice(index, 1);
return removed;
}
return undefined;
}
}
export var ToastType;
(function (ToastType) {
ToastType["Basic"] = "basic";
ToastType["Success"] = "success";
ToastType["Error"] = "error";
ToastType["Info"] = "info";
ToastType["Warning"] = "warning";
ToastType["Custom"] = "custom";
})(ToastType || (ToastType = {}));
export class ToastyService {
constructor(_toastySoundService) {
this._toastySoundService = _toastySoundService;
this.TOASTY_SERVICE_CONFIG = {
capacity: 10,
duration: 5000,
messages: {
now: 'just now',
seconds: '{0} seconds ago',
minutes: '{0} minutes ago'
},
threshold_offsetX: 170
};
this.queue = new Queue(this.TOASTY_SERVICE_CONFIG.capacity);
this.counter = 0;
this.newToastBehaviorSubject = new BehaviorSubject([]);
this.newToast$ = this.newToastBehaviorSubject.asObservable();
this.deleteToastBehaviorSubject = new BehaviorSubject(undefined);
this.deleteToast$ = this.deleteToastBehaviorSubject.asObservable();
this.updateToastBehaviorSubject = new BehaviorSubject(undefined);
this.updateToast$ = this.updateToastBehaviorSubject.asObservable();
}
setDefaultDuration(d) { this.TOASTY_SERVICE_CONFIG.duration = d; }
getDefaultDuration() { return this.TOASTY_SERVICE_CONFIG.duration; }
setCapacity(c) { this.TOASTY_SERVICE_CONFIG.capacity = c; this.queue.setCapacity(c); }
getCapacity() { return this.queue.getCapacity(); }
showToast(title, message, toastConfig, isPromise) {
this.counter++;
// if sticky is true duration is infinity else use the provided duration or the default one
const duration = toastConfig?.sticky ? Infinity : (toastConfig?.duration ?? this.TOASTY_SERVICE_CONFIG.duration);
const toast = {
id: this.counter,
title: title,
message: message,
type: toastConfig?.type ?? ToastType.Basic,
timestamp: Date.now(),
duration: duration,
expires: isPromise ? Infinity : Date.now() + duration,
config: toastConfig,
get icon() {
if (toastConfig?.type == ToastType.Success)
return "✅";
if (toastConfig?.type == ToastType.Info)
return "ℹ️";
if (toastConfig?.type == ToastType.Warning)
return "⚠️";
if (toastConfig?.type == ToastType.Error)
return "❌";
return "";
}
};
this.queue.enqueue(toast);
this.newToastBehaviorSubject.next([...this.queue.getElements()]);
if (toast.config?.beep) {
this._toastySoundService.notify();
}
// if sticky progress bar is not animated and toast will not expire
if (!toast.config?.sticky) {
if (toast.config?.progressBar) {
setTimeout(() => {
this.updateToast(toast.id, { animatePbar: true });
}, 100);
}
if (!isPromise) {
setTimeout(() => {
this.removeToast(toast.id);
}, duration + 5);
}
}
return this.counter;
}
showToastPromise(title, promise, config) {
const idtoast = this.showToast(title, promise.loading, { ...config, loading: true }, true);
const duration = config?.duration ?? this.TOASTY_SERVICE_CONFIG.duration;
promise.promise
.then((result) => {
const successMessage = typeof promise.success === 'function'
? promise.success(result)
: promise.success;
this.updateToast(idtoast, {
message: successMessage,
type: ToastType.Success,
expires: Date.now() + duration,
config: { loading: false }
});
})
.catch((err) => {
const errorMessage = typeof promise.error === 'function'
? promise.error(err)
: promise.error;
this.updateToast(idtoast, {
message: errorMessage,
type: ToastType.Error,
expires: Date.now() + duration,
config: { loading: false }
});
})
.finally(() => {
if (!config?.sticky)
setTimeout(() => this.removeToast(idtoast), duration);
});
}
removeToast(id) {
this.newToastBehaviorSubject.next([...this.queue.getElements()]); // Trigger re-render to start exit animation
setTimeout(() => { const t = this.queue.removeId(id); this.newToastBehaviorSubject.next([...this.queue.getElements()]); }, 500); // Wait for animation to finish before removing from queue
}
closeToast(id) {
const t = this.queue.removeId(id);
this.newToastBehaviorSubject.next([...this.queue.getElements()]);
}
updateTouchStart(id, touch) {
const gesture = { date: Date.now(), touchStart: touch };
this.updateToast(id, { gesture: gesture });
}
// Loops through the toasts to find which one was touched and updates its touchEnd
updateTouchEnd(touch) {
const toasts = this.queue.getElements().forEach(t => {
if (t.gesture) {
const deltaY = Math.abs(touch.clientY - t.gesture.touchStart.clientY);
const deltaX = Math.abs(touch.clientX - t.gesture.touchStart.clientX);
const deltaTime = Date.now() - t.gesture.date;
if (deltaTime < 500 && deltaX > this.TOASTY_SERVICE_CONFIG.threshold_offsetX) {
this.closeToast(t.id);
}
else {
t.gesture = undefined; // Reset gesture if not swiped
}
}
});
}
updateTouchMove(touch) {
const toasts = this.queue.getElements();
toasts.forEach(t => {
if (t.gesture) {
const deltaX = touch.clientX - t.gesture.touchStart.clientX;
t.gesture.offsetX = deltaX; // Store the offset for potential use in UI updates
}
});
}
updateToast(id, newData) {
const toasts = this.queue.getElements();
const index = toasts.findIndex(t => t.id === id);
if (index !== -1) {
toasts[index] = { ...toasts[index], ...newData };
this.newToastBehaviorSubject.next([...toasts]);
}
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: ToastyService, deps: [{ token: i1.ToastysoundService }], target: i0.ɵɵFactoryTarget.Injectable }); }
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: ToastyService, providedIn: 'root' }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: ToastyService, decorators: [{
type: Injectable,
args: [{
providedIn: 'root'
}]
}], ctorParameters: () => [{ type: i1.ToastysoundService }] });
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidG9hc3R5LnNlcnZpY2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9wcm9qZWN0cy9uZy10b2FzdC1ub3RpZnkvc3JjL2xpYi90b2FzdHkuc2VydmljZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBQzNDLE9BQU8sRUFBRSxlQUFlLEVBQUUsTUFBTSwrQkFBK0IsQ0FBQzs7O0FBb0JoRSxNQUFNLEtBQUs7SUFHVCxZQUFvQixXQUFtQixRQUFRO1FBQTNCLGFBQVEsR0FBUixRQUFRLENBQW1CO1FBRnZDLFlBQU8sR0FBUSxFQUFFLENBQUM7SUFHMUIsQ0FBQztJQUVELFdBQVcsQ0FBQyxDQUFTO1FBQ25CLElBQUksQ0FBQyxRQUFRLEdBQUcsQ0FBQyxDQUFDO0lBQ3BCLENBQUM7SUFDRCxXQUFXLEtBQUssT0FBTyxJQUFJLENBQUMsUUFBUSxDQUFDLENBQUMsQ0FBQztJQUV2QyxPQUFPLENBQUMsSUFBTztRQUNiLElBQUksSUFBSSxDQUFDLElBQUksRUFBRSxJQUFJLElBQUksQ0FBQyxRQUFRLEVBQUUsQ0FBQztZQUNqQyxNQUFNLEtBQUssQ0FBQyxtRUFBbUUsQ0FBQyxDQUFDO1FBQ25GLENBQUM7UUFDRCxJQUFJLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQztJQUMxQixDQUFDO0lBQ0QsT0FBTztRQUNMLE9BQU8sSUFBSSxDQUFDLE9BQU8sQ0FBQyxLQUFLLEVBQUUsQ0FBQztJQUM5QixDQUFDO0lBQ0QsSUFBSTtRQUNGLE9BQU8sSUFBSSxDQUFDLE9BQU8sQ0FBQyxNQUFNLENBQUM7SUFDN0IsQ0FBQztJQUNELFdBQVc7UUFDVCxPQUFPLElBQUksQ0FBQyxPQUFPLENBQUM7SUFDdEIsQ0FBQztJQUNELFFBQVEsQ0FBQyxFQUFVO1FBQ2pCLE1BQU0sS0FBSyxHQUFHLElBQUksQ0FBQyxPQUFPLENBQUMsU0FBUyxDQUFD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QUFDO1lBQ2pELElBQUksQ0FBQyx1QkFBdUIsQ0FBQyxJQUFJLENBQUMsQ0FBQyxHQUFHLE1BQU0sQ0FBQyxDQUFDLENBQUM7UUFDakQsQ0FBQztJQUNILENBQUM7K0dBbExVLGFBQWE7bUhBQWIsYUFBYSxjQUZaLE1BQU07OzRGQUVQLGFBQWE7a0JBSHpCLFVBQVU7bUJBQUM7b0JBQ1YsVUFBVSxFQUFFLE1BQU07aUJBQ25CIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgSW5qZWN0YWJsZSB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xyXG5pbXBvcnQgeyBCZWhhdmlvclN1YmplY3QgfSBmcm9tICdyeGpzL2ludGVybmFsL0JlaGF2aW9yU3ViamVjdCc7XHJcbmltcG9ydCB7IFRvYXN0eXNvdW5kU2VydmljZSB9IGZyb20gJy4vdG9hc3R5c291bmQuc2VydmljZSc7XHJcblxyXG5pbnRlcmZhY2UgSVNlcnZpY2VDb25maWcge1xyXG4gIGNhcGFjaXR5OiBudW1iZXI7XHJcbiAgZHVyYXRpb246IG51bWJlcjtcclxuICBtZXNzYWdlczogUmVjb3JkPHN0cmluZywgc3RyaW5nPjtcclxuICB0aHJlc2hvbGRfb2Zmc2V0WDogbnVtYmVyO1xyXG59XHJcblxyXG5pbnRlcmZhY2UgSVRvYXN0UXVldWU8VD4ge1xyXG4gIHNldENhcGFjaXR5KGM6IG51bWJlcik6IHZvaWQ7XHJcbiAgZ2V0Q2FwYWNpdHkoKTogbnVtYmVyO1xyXG4gIGVucXVldWUoaXRlbTogVCk6IHZvaWQ7XHJcbiAgZGVxdWV1ZSgpOiBUIHwgdW5kZWZpbmVkO1xyXG4gIHNpemUoKTogbnVtYmVyO1xyXG4gIGdldEVsZW1lbnRzKCk6IFRbXTtcclxuICByZW1vdmVJZChpZDogbnVtYmVyKTogVCB8IHVuZGVmaW5lZDtcclxufVxyXG5cclxuY2xhc3MgUXVldWU8VD4gaW1wbGVtZW50cyBJVG9hc3RRdWV1ZTxUPiB7XHJcbiAgcHJpdmF0ZSBzdG9yYWdlOiBUW10gPSBbXTtcclxuXHJcbiAgY29uc3RydWN0b3IocHJpdmF0ZSBjYXBhY2l0eTogbnVtYmVyID0gSW5maW5pdHkpIHtcclxuICB9XHJcblxyXG4gIHNldENhcGFjaXR5KGM6IG51bWJlcikge1xyXG4gICAgdGhpcy5jYXBhY2l0eSA9IGM7XHJcbiAgfVxyXG4gIGdldENhcGFjaXR5KCkgeyByZXR1cm4gdGhpcy5jYXBhY2l0eTsgfVxyXG5cclxuICBlbnF1ZXVlKGl0ZW06IFQpOiB2b2lkIHtcclxuICAgIGlmICh0aGlzLnNpemUoKSA+PSB0aGlzLmNhcGFjaXR5KSB7XHJcbiAgICAgIHRocm93IEVycm9yKCdUb2FzdHkgcXVldWUgaGFzIHJlYWNoZWQgbWF4IGNhcGFjaXR5LCB5b3UgY2Fubm90IGFkZCBtb3JlIGl0ZW1zLicpO1xyXG4gICAgfVxyXG4gICAgdGhpcy5zdG9yYWdlLnB1c2goaXRlbSk7XHJcbiAgfVxyXG4gIGRlcXVldWUoKTogVCB8IHVuZGVmaW5lZCB7XHJcbiAgICByZXR1cm4gdGhpcy5zdG9yYWdlLnNoaWZ0KCk7XHJcbiAgfVxyXG4gIHNpemUoKTogbnVtYmVyIHtcclxuICAgIHJldHVybiB0aGlzLnN0b3JhZ2UubGVuZ3RoO1xyXG4gIH1cclxuICBnZXRFbGVtZW50cygpOiBUW10ge1xyXG4gICAgcmV0dXJuIHRoaXMuc3RvcmFnZTtcclxuICB9XHJcbiAgcmVtb3ZlSWQoaWQ6IG51bWJlcik6IFQgfCB1bmRlZmluZWQge1xyXG4gICAgY29uc3QgaW5kZXggPSB0aGlzLnN0b3JhZ2UuZmluZEluZGV4KGl0ZW0gPT4gKGl0ZW0gYXMgYW55KS5pZCA9PT0gaWQpO1xyXG4gICAgaWYgKGluZGV4ICE9PSAtMSkge1xyXG4gICAgICBjb25zdCBbcmVtb3ZlZF0gPSB0aGlzLnN0b3JhZ2Uuc3BsaWNlKGluZGV4LCAxKTtcclxuICAgICAgcmV0dXJuIHJlbW92ZWQ7XHJcbiAgICB9XHJcbiAgICByZXR1cm4gdW5kZWZpbmVkO1xyXG4gIH1cclxufVxyXG5leHBvcnQgZW51bSBUb2FzdFR5cGUge1xyXG4gIEJhc2ljID0gJ2Jhc2ljJyxcclxuICBTdWNjZXNzID0gJ3N1Y2Nlc3MnLFxyXG4gIEVycm9yID0gJ2Vycm9yJyxcclxuICBJbmZvID0gJ2luZm8nLFxyXG4gIFdhcm5pbmcgPSAnd2FybmluZycsXHJcbiAgQ3VzdG9tID0gJ2N1c3RvbSdcclxufVxyXG5cclxuaW50ZXJmYWNlIFRvYXN0R2VzdHVyZSB7XHJcbiAgZGF0ZTogbnVtYmVyO1xyXG4gIHRvdWNoU3RhcnQ/OiBUb3VjaDtcclxuICB0b3VjaEVuZD86IFRvdWNoO1xyXG4gIG9mZnNldFg/OiBudW1iZXI7XHJcbn1cclxuXHJcbmV4cG9ydCBpbnRlcmZhY2UgVG9hc3RNb2RlbCB7XHJcbiAgaWQ6IG51bWJlcjtcclxuICB0aXRsZTogc3RyaW5nO1xyXG4gIG1lc3NhZ2U6IHN0cmluZztcclxuICB0eXBlOiBUb2FzdFR5cGU7XHJcbiAgdGltZXN0YW1wOiBudW1iZXI7XHJcbiAgZHVyYXRpb246IG51bWJlcjtcclxuICBleHBpcmVzOiBudW1iZXI7XHJcbiAgY29uZmlnPzogVG9hc3R5Q29uZmlnO1xyXG4gIGdldCBpY29uKCk6IHN0cmluZztcclxuXHJcbiAgZ2VzdHVyZT86IFRvYXN0R2VzdHVyZTtcclxuICBhbmltYXRlUGJhcj86IGJvb2xlYW47IC8vIFVzZWQgdG8gYW5pbWF0ZSB0aGUgcHJvZ3Jlc3MgYmFyXHJcbn1cclxuXHJcbmV4cG9ydCBpbnRlcmZhY2UgVG9hc3R5Q29uZmlnIHtcclxuICB0eXBlPzogVG9hc3RUeXBlO1xyXG4gIGR1cmF0aW9uPzogbnVtYmVyO1xyXG4gIHN0aWNreT86IGJvb2xlYW47XHJcbiAgZW5hYmxlSHRtbD86IGJvb2xlYW47XHJcbiAgY3VzdG9tU3R5bGU/OiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+O1xyXG4gIGxvYWRpbmc/OiBib29sZWFuO1xyXG4gIGJlZXA/OiBib29sZWFuO1xyXG4gIHByb2dyZXNzQmFyPzogYm9vbGVhbjtcclxufVxyXG5cclxuZXhwb3J0IGludGVyZmFjZSBUb2FzdHlQcm9taXNlPFQ+IHtcclxuICBwcm9taXNlOiBQcm9taXNlPFQ+O1xyXG4gIGxvYWRpbmc6IHN0cmluZztcclxuICBzdWNjZXNzOiBzdHJpbmcgfCAoKHJlc3VsdDogVCkgPT4gc3RyaW5nKTtcclxuICBlcnJvcjogc3RyaW5nIHwgKChlcnI6IGFueSkgPT4gc3RyaW5nKTtcclxufVxyXG5cclxuXHJcbkBJbmplY3RhYmxlKHtcclxuICBwcm92aWRlZEluOiAncm9vdCdcclxufSlcclxuZXhwb3J0IGNsYXNzIFRvYXN0eVNlcnZpY2Uge1xyXG5cclxuICBwcml2YXRlIFRPQVNUWV9TRVJWSUNFX0NPTkZJRzogSVNlcnZpY2VDb25maWcgPSB7XHJcbiAgICBjYXBhY2l0eTogMTAsXHJcbiAgICBkdXJhdGlvbjogNTAwMCxcclxuICAgIG1lc3NhZ2VzOiB7XHJcbiAgICAgIG5vdzogJ2p1c3Qgbm93JyxcclxuICAgICAgc2Vjb25kczogJ3swfSBzZWNvbmRzIGFnbycsXHJcbiAgICAgIG1pbnV0ZXM6ICd7MH0gbWludXRlcyBhZ28nXHJcbiAgICB9LFxyXG4gICAgdGhyZXNob2xkX29mZnNldFg6IDE3MFxyXG4gIH07XHJcblxyXG5cclxuICBwcml2YXRlIHF1ZXVlOiBJVG9hc3RRdWV1ZTxUb2FzdE1vZGVsPiA9IG5ldyBRdWV1ZTxUb2FzdE1vZGVsPih0aGlzLlRPQVNUWV9TRVJWSUNFX0NPTkZJRy5jYXBhY2l0eSk7XHJcbiAgcHJpdmF0ZSBjb3VudGVyOiBudW1iZXIgPSAwO1xyXG4gIHByaXZhdGUgbmV3VG9hc3RCZWhhdmlvclN1YmplY3QgPSBuZXcgQmVoYXZpb3JTdWJqZWN0PFRvYXN0TW9kZWxbXT4oW10pO1xyXG4gIHB1YmxpYyBuZXdUb2FzdCQgPSB0aGlzLm5ld1RvYXN0QmVoYXZpb3JTdWJqZWN0LmFzT2JzZXJ2YWJsZSgpO1xyXG4gIHByaXZhdGUgZGVsZXRlVG9hc3RCZWhhdmlvclN1YmplY3QgPSBuZXcgQmVoYXZpb3JTdWJqZWN0PFRvYXN0TW9kZWwgfCB1bmRlZmluZWQ+KHVuZGVmaW5lZCk7XHJcbiAgcHVibGljIGRlbGV0ZVRvYXN0JCA9IHRoaXMuZGVsZXRlVG9hc3RCZWhhdmlvclN1YmplY3QuYXNPYnNlcnZhYmxlKCk7XHJcbiAgcHJpdmF0ZSB1cGRhdGVUb2FzdEJlaGF2aW9yU3ViamVjdCA9IG5ldyBCZWhhdmlvclN1YmplY3Q8VG9hc3RNb2RlbCB8IHVuZGVmaW5lZD4odW5kZWZpbmVkKTtcclxuICBwdWJsaWMgdXBkYXRlVG9hc3QkID0gdGhpcy51cGRhdGVUb2FzdEJlaGF2aW9yU3ViamVjdC5hc09ic2VydmFibGUoKTtcclxuXHJcbiAgY29uc3RydWN0b3IocHJpdmF0ZSBfdG9hc3R5U291bmRTZXJ2aWNlOiBUb2FzdHlzb3VuZFNlcnZpY2UpIHtcclxuICB9XHJcblxyXG4gIHNldERlZmF1bHREdXJhdGlvbihkOiBudW1iZXIpOiB2b2lkIHsgdGhpcy5UT0FTVFlfU0VSVklDRV9DT05GSUcuZHVyYXRpb24gPSBkOyB9XHJcbiAgZ2V0RGVmYXVsdER1cmF0aW9uKCk6IG51bWJlciB7IHJldHVybiB0aGlzLlRPQVNUWV9TRVJWSUNFX0NPTkZJRy5kdXJhdGlvbjsgfVxyXG4gIHNldENhcGFjaXR5KGM6IG51bWJlcikgeyB0aGlzLlRPQVNUWV9TRVJWSUNFX0NPTkZJRy5jYXBhY2l0eSA9IGM7IHRoaXMucXVldWUuc2V0Q2FwYWNpdHkoYyk7IH1cclxuICBnZXRDYXBhY2l0eSgpOiBudW1iZXIgeyByZXR1cm4gdGhpcy5xdWV1ZS5nZXRDYXBhY2l0eSgpOyB9XHJcblxyXG4gIHNob3dUb2FzdCh0aXRsZTogc3RyaW5nLCBtZXNzYWdlOiBzdHJpbmcsIHRvYXN0Q29uZmlnPzogVG9hc3R5Q29uZmlnIHwgdW5kZWZpbmVkLCBpc1Byb21pc2U/OiBib29sZWFuKTogbnVtYmVyIHtcclxuICAgIHRoaXMuY291bnRlcisrO1xyXG5cclxuICAgIC8vIGlmIHN0aWNreSBpcyB0cnVlIGR1cmF0aW9uIGlzIGluZmluaXR5IGVsc2UgdXNlIHRoZSBwcm92aWRlZCBkdXJhdGlvbiBvciB0aGUgZGVmYXVsdCBvbmVcclxuICAgIGNvbnN0IGR1cmF0aW9uID0gdG9hc3RDb25maWc/LnN0aWNreSA/IEluZmluaXR5IDogKHRvYXN0Q29uZmlnPy5kdXJhdGlvbiA/PyB0aGlzLlRPQVNUWV9TRVJWSUNFX0NPTkZJRy5kdXJhdGlvbik7XHJcblxyXG4gICAgY29uc3QgdG9hc3Q6IFRvYXN0TW9kZWwgPSB7XHJcbiAgICAgIGlkOiB0aGlzLmNvdW50ZXIsXHJcbiAgICAgIHRpdGxlOiB0aXRsZSxcclxuICAgICAgbWVzc2FnZTogbWVzc2FnZSxcclxuICAgICAgdHlwZTogdG9hc3RDb25maWc/LnR5cGUgPz8gVG9hc3RUeXBlLkJhc2ljLFxyXG4gICAgICB0aW1lc3RhbXA6IERhdGUubm93KCksXHJcbiAgICAgIGR1cmF0aW9uOiBkdXJhdGlvbixcclxuICAgICAgZXhwaXJlczogaXNQcm9taXNlID8gSW5maW5pdHkgOiBEYXRlLm5vdygpICsgZHVyYXRpb24sXHJcbiAgICAgIGNvbmZpZzogdG9hc3RDb25maWcsXHJcbiAgICAgIGdldCBpY29uKCkge1xyXG4gICAgICAgIGlmICh0b2FzdENvbmZpZz8udHlwZSA9PSBUb2FzdFR5cGUuU3VjY2VzcylcclxuICAgICAgICAgIHJldHVybiBcIuKchVwiO1xyXG4gICAgICAgIGlmICh0b2FzdENvbmZpZz8udHlwZSA9PSBUb2FzdFR5cGUuSW5mbylcclxuICAgICAgICAgIHJldHVybiBcIuKEue+4j1wiO1xyXG4gICAgICAgIGlmICh0b2FzdENvbmZpZz8udHlwZSA9PSBUb2FzdFR5cGUuV2FybmluZylcclxuICAgICAgICAgIHJldHVybiBcIuKaoO+4j1wiO1xyXG4gICAgICAgIGlmICh0b2FzdENvbmZpZz8udHlwZSA9PSBUb2FzdFR5cGUuRXJyb3IpXHJcbiAgICAgICAgICByZXR1cm4gXCLinYxcIjtcclxuXHJcbiAgICAgICAgcmV0dXJuIFwiXCI7XHJcbiAgICAgIH1cclxuICAgIH07XHJcblxyXG4gICAgdGhpcy5xdWV1ZS5lbnF1ZXVlKHRvYXN0KTtcclxuXHJcbiAgICB0aGlzLm5ld1RvYXN0QmVoYXZpb3JTdWJqZWN0Lm5leHQoWy4uLnRoaXMucXVldWUuZ2V0RWxlbWVudHMoKV0pO1xyXG5cclxuICAgIGlmICh0b2FzdC5jb25maWc/LmJlZXApIHtcclxuICAgICAgdGhpcy5fdG9hc3R5U291bmRTZXJ2aWNlLm5vdGlmeSgpO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIGlmIHN0aWNreSBwcm9ncmVzcyBiYXIgaXMgbm90IGFuaW1hdGVkIGFuZCB0b2FzdCB3aWxsIG5vdCBleHBpcmVcclxuICAgIGlmICghdG9hc3QuY29uZmlnPy5zdGlja3kpIHtcclxuICAgICAgaWYgKHRvYXN0LmNvbmZpZz8ucHJvZ3Jlc3NCYXIpIHtcclxuICAgICAgICBzZXRUaW1lb3V0KCgpID0+IHtcclxuICAgICAgICAgIHRoaXMudXBkYXRlVG9hc3QodG9hc3QuaWQsIHsgYW5pbWF0ZVBiYXI6IHRydWUgfSk7XHJcbiAgICAgICAgfSwgMTAwKTtcclxuICAgICAgfVxyXG5cclxuICAgICAgaWYgKCFpc1Byb21pc2UpIHtcclxuICAgICAgICBzZXRUaW1lb3V0KCgpID0+IHtcclxuICAgICAgICAgIHRoaXMucmVtb3ZlVG9hc3QodG9hc3QuaWQpO1xyXG4gICAgICAgIH0sIGR1cmF0aW9uICsgNSk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICByZXR1cm4gdGhpcy5jb3VudGVyO1xyXG4gIH1cclxuXHJcbiAgc2hvd1RvYXN0UHJvbWlzZTxUPih0aXRsZTogc3RyaW5nLCBwcm9taXNlOiBUb2FzdHlQcm9taXNlPFQ+LCBjb25maWc/OiBUb2FzdHlDb25maWcpIHtcclxuICAgIGNvbnN0IGlkdG9hc3QgPSB0aGlzLnNob3dUb2FzdCh0aXRsZSwgcHJvbWlzZS5sb2FkaW5nLCB7IC4uLmNvbmZpZywgbG9hZGluZzogdHJ1ZSB9LCB0cnVlKTtcclxuICAgIGNvbnN0IGR1cmF0aW9uID0gY29uZmlnPy5kdXJhdGlvbiA/PyB0aGlzLlRPQVNUWV9TRVJWSUNFX0NPTkZJRy5kdXJhdGlvbjtcclxuXHJcbiAgICBwcm9taXNlLnByb21pc2VcclxuICAgICAgLnRoZW4oKHJlc3VsdCkgPT4ge1xyXG4gICAgICAgIGNvbnN0IHN1Y2Nlc3NNZXNzYWdlID1cclxuICAgICAgICAgIHR5cGVvZiBwcm9taXNlLnN1Y2Nlc3MgPT09ICdmdW5jdGlvbidcclxuICAgICAgICAgICAgPyBwcm9taXNlLnN1Y2Nlc3MocmVzdWx0KVxyXG4gICAgICAgICAgICA6IHByb21pc2Uuc3VjY2VzcztcclxuXHJcbiAgICAgICAgdGhpcy51cGRhdGVUb2FzdChpZHRvYXN0LCB7XHJcbiAgICAgICAgICBtZXNzYWdlOiBzdWNjZXNzTWVzc2FnZSxcclxuICAgICAgICAgIHR5cGU6IFRvYXN0VHlwZS5TdWNjZXNzLFxyXG4gICAgICAgICAgZXhwaXJlczogRGF0ZS5ub3coKSArIGR1cmF0aW9uLFxyXG4gICAgICAgICAgY29uZmlnOiB7IGxvYWRpbmc6IGZhbHNlIH1cclxuICAgICAgICB9KTtcclxuICAgICAgfSlcclxuICAgICAgLmNhdGNoKChlcnIpID0+IHtcclxuICAgICAgICBjb25zdCBlcnJvck1lc3NhZ2UgPVxyXG4gICAgICAgICAgdHlwZW9mIHByb21pc2UuZXJyb3IgPT09ICdmdW5jdGlvbidcclxuICAgICAgICAgICAgPyBwcm9taXNlLmVycm9yKGVycilcclxuICAgICAgICAgICAgOiBwcm9taXNlLmVycm9yO1xyXG5cclxuICAgICAgICB0aGlzLnVwZGF0ZVRvYXN0KGlkdG9hc3QsIHtcclxuICAgICAgICAgIG1lc3NhZ2U6IGVycm9yTWVzc2FnZSxcclxuICAgICAgICAgIHR5cGU6IFRvYXN0VHlwZS5FcnJvcixcclxuICAgICAgICAgIGV4cGlyZXM6IERhdGUubm93KCkgKyBkdXJhdGlvbixcclxuICAgICAgICAgIGNvbmZpZzogeyBsb2FkaW5nOiBmYWxzZSB9XHJcbiAgICAgICAgfSk7XHJcbiAgICAgIH0pXHJcbiAgICAgIC5maW5hbGx5KCgpID0+IHtcclxuICAgICAgICBpZiAoIWNvbmZpZz8uc3RpY2t5KVxyXG4gICAgICAgICAgc2V0VGltZW91dCgoKSA9PiB0aGlzLnJlbW92ZVRvYXN0KGlkdG9hc3QpLCBkdXJhdGlvbilcclxuICAgICAgICB9XHJcbiAgICAgICk7XHJcblxyXG4gIH1cclxuXHJcbiAgcmVtb3ZlVG9hc3QoaWQ6IG51bWJlcik6IHZvaWQge1xyXG4gICAgdGhpcy5uZXdUb2FzdEJlaGF2aW9yU3ViamVjdC5uZXh0KFsuLi50aGlzLnF1ZXVlLmdldEVsZW1lbnRzKCldKTsgLy8gVHJpZ2dlciByZS1yZW5kZXIgdG8gc3RhcnQgZXhpdCBhbmltYXRpb25cclxuICAgIHNldFRpbWVvdXQoKCkgPT4geyBjb25zdCB0ID0gdGhpcy5xdWV1ZS5yZW1vdmVJZChpZCk7IHRoaXMubmV3VG9hc3RCZWhhdmlvclN1YmplY3QubmV4dChbLi4udGhpcy5xdWV1ZS5nZXRFbGVtZW50cygpXSk7fSwgNTAwKTsgLy8gV2FpdCBmb3IgYW5pbWF0aW9uIHRvIGZpbmlzaCBiZWZvcmUgcmVtb3ZpbmcgZnJvbSBxdWV1ZVxyXG4gIH1cclxuXHJcbiAgY2xvc2VUb2FzdChpZDogbnVtYmVyKTogdm9pZCB7XHJcbiAgICBjb25zdCB0ID0gdGhpcy5xdWV1ZS5yZW1vdmVJZChpZCk7XHJcbiAgICB0aGlzLm5ld1RvYXN0QmVoYXZpb3JTdWJqZWN0Lm5leHQoWy4uLnRoaXMucXVldWUuZ2V0RWxlbWVudHMoKV0pO1xyXG4gIH1cclxuXHJcbiAgdXBkYXRlVG91Y2hTdGFydChpZDogbnVtYmVyLCB0b3VjaDogVG91Y2gpOiB2b2lkIHtcclxuICAgIGNvbnN0IGdlc3R1cmU6IFRvYXN0R2VzdHVyZSA9IHsgZGF0ZTogRGF0ZS5ub3coKSwgdG91Y2hTdGFydDogdG91Y2ggfTtcclxuICAgIHRoaXMudXBkYXRlVG9hc3QoaWQsIHsgZ2VzdHVyZTogZ2VzdHVyZSB9KTtcclxuICB9XHJcblxyXG4gIC8vIExvb3BzIHRocm91Z2ggdGhlIHRvYXN0cyB0byBmaW5kIHdoaWNoIG9uZSB3YXMgdG91Y2hlZCBhbmQgdXBkYXRlcyBpdHMgdG91Y2hFbmRcclxuICB1cGRhdGVUb3VjaEVuZCh0b3VjaDogVG91Y2gpOiB2b2lkIHtcclxuICAgIGNvbnN0IHRvYXN0cyA9IHRoaXMucXVldWUuZ2V0RWxlbWVudHMoKS5mb3JFYWNoKFxyXG4gICAgICB0ID0+IHtcclxuICAgICAgICBpZiAodC5nZXN0dXJlKSB7XHJcbiAgICAgICAgICBjb25zdCBkZWx0YVkgPSBNYXRoLmFicyh0b3VjaC5jbGllbnRZIC0gdC5nZXN0dXJlLnRvdWNoU3RhcnQhLmNsaWVudFkpO1xyXG4gICAgICAgICAgY29uc3QgZGVsdGFYID0gTWF0aC5hYnModG91Y2guY2xpZW50WCAtIHQuZ2VzdHVyZS50b3VjaFN0YXJ0IS5jbGllbnRYKTtcclxuICAgICAgICAgIGNvbnN0IGRlbHRhVGltZSA9IERhdGUubm93KCkgLSB0Lmdlc3R1cmUuZGF0ZTtcclxuXHJcbiAgICAgICAgICBpZiAoZGVsdGFUaW1lIDwgNTAwICYmIGRlbHRhWCA+IHRoaXMuVE9BU1RZX1NFUlZJQ0VfQ09ORklHLnRocmVzaG9sZF9vZmZzZXRYKSB7XHJcbiAgICAgICAgICAgIHRoaXMuY2xvc2VUb2FzdCh0LmlkKTtcclxuICAgICAgICAgIH1cclxuICAgICAgICAgIGVsc2Uge1xyXG4gICAgICAgICAgICB0Lmdlc3R1cmUgPSB1bmRlZmluZWQ7IC8vIFJlc2V0IGdlc3R1cmUgaWYgbm90IHN3aXBlZFxyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG4gICAgKVxyXG4gIH1cclxuXHJcbiAgdXBkYXRlVG91Y2hNb3ZlKHRvdWNoOiBUb3VjaCk6IHZvaWQge1xyXG4gICAgY29uc3QgdG9hc3RzID0gdGhpcy5xdWV1ZS5nZXRFbGVtZW50cygpO1xyXG4gICAgdG9hc3RzLmZvckVhY2godCA9PiB7XHJcbiAgICAgIGlmICh0Lmdlc3R1cmUpIHtcclxuICAgICAgICBjb25zdCBkZWx0YVggPSB0b3VjaC5jbGllbnRYIC0gdC5nZXN0dXJlLnRvdWNoU3RhcnQhLmNsaWVudFg7XHJcbiAgICAgICAgdC5nZXN0dXJlLm9mZnNldFggPSBkZWx0YVg7IC8vIFN0b3JlIHRoZSBvZmZzZXQgZm9yIHBvdGVudGlhbCB1c2UgaW4gVUkgdXBkYXRlc1xyXG4gICAgICB9XHJcbiAgICB9KTtcclxuICB9XHJcblxyXG4gIHByaXZhdGUgdXBkYXRlVG9hc3QoaWQ6IG51bWJlciwgbmV3RGF0YTogUGFydGlhbDxUb2FzdE1vZGVsPik6IHZvaWQge1xyXG4gICAgY29uc3QgdG9hc3RzID0gdGhpcy5xdWV1ZS5nZXRFbGVtZW50cygpO1xyXG4gICAgY29uc3QgaW5kZXggPSB0b2FzdHMuZmluZEluZGV4KHQgPT4gdC5pZCA9PT0gaWQpO1xyXG5cclxuICAgIGlmIChpbmRleCAhPT0gLTEpIHtcclxuICAgICAgdG9hc3RzW2luZGV4XSA9IHsgLi4udG9hc3RzW2luZGV4XSwgLi4ubmV3RGF0YSB9O1xyXG4gICAgICB0aGlzLm5ld1RvYXN0QmVoYXZpb3JTdWJqZWN0Lm5leHQoWy4uLnRvYXN0c10pO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbn1cclxuIl19