UNPKG

@doku-dev/doku-fragment

Version:

A new Angular UI library that moving away from Bootstrap and built from scratch.

293 lines 58.2 kB
import { CommonModule } from '@angular/common'; import { ChangeDetectionStrategy, Component, HostBinding, Inject, LOCALE_ID, Optional, ViewEncapsulation, } from '@angular/core'; import { FormsModule } from '@angular/forms'; import { Subject, distinctUntilChanged, filter, map, skip, takeUntil } from 'rxjs'; import { DokuBreakpoint } from '../../breakpoint'; import { DokuFormFieldModule } from '../../form-field'; import { DokuSelectModule } from '../../select'; import { DokuTypographyModule } from '../../typography'; import { CalendarUtil } from './calendar.util'; import { DokuDatePickerBaseProps } from './date-picker-base-props.component'; import { DOKU_DATE_PICKER_STRICT_TIME } from './date-picker.token'; import * as i0 from "@angular/core"; import * as i1 from "@angular/common"; import * as i2 from "../../select/select.component"; import * as i3 from "../../form-field/form-field.component"; import * as i4 from "../../typography/typography.component"; export class DokuDatePickerBase extends DokuDatePickerBaseProps { get activeCalendar() { // Always set the date to 1st so that it doesn't break while navigating to month/year // because of different total days. return new Date(this._activeCalendar.getFullYear(), this._activeCalendar.getMonth(), 1); } set activeCalendar(date) { this._activeCalendar = date; } get calendarHeaders() { return this.calendars.map((_, idx) => { const date = new Date(this.activeCalendar); date.setMonth(date.getMonth() + idx); const month = date.toLocaleString(this.localeId, { month: 'long' }); const year = date.getFullYear(); return `${month} ${year}`; }); } constructor(localeId, ngZone, useStrictTime) { super(); this.localeId = localeId; this.ngZone = ngZone; this.useStrictTime = useStrictTime; this.classes = 'd-date-picker-base'; this.calendars = []; this._activeCalendar = new Date(); this.canNavigateToPreviousMonth = false; this.canNavigateToNextMonth = false; this.destroy$ = new Subject(); } get monthSelectOptions() { return CalendarUtil.generateMonthSelectOptions({ locale: this.localeId, minDate: this.minDate, maxDate: this.maxDate, activeYear: parseInt(this.activeYear), }); } get yearSelectOptions() { return CalendarUtil.generateYearSelectOptions({ activeYear: parseInt(this.activeYear), minDate: this.minDate, maxDate: this.maxDate, }); } get weekdays() { return CalendarUtil.generateWeekdays({ locale: this.localeId }); } get activeMonth() { return this.activeCalendar.getMonth().toString(); } get activeYear() { return this.activeCalendar.getFullYear().toString(); } get isMobileScreen() { return window.matchMedia(DokuBreakpoint.mobile).matches; } ngOnInit() { this.activeCalendar = this.value?.start || new Date(); this.generateCalendar(); this.notifyChange$ .pipe(filter((change) => change === 'value' || change === 'minDate' || change === 'maxDate'), map(() => this.value), distinctUntilChanged((prev, current) => JSON.stringify(prev) === JSON.stringify(current)), skip(1), takeUntil(this.destroy$)) .subscribe((value) => { this.handleDateState(); this.valueChange.emit(value); }); this.notifyChange$ .pipe(filter((change) => change === 'minDate' || change === 'maxDate'), map(() => ({ minDate: this.minDate, maxDate: this.maxDate })), distinctUntilChanged((prev, current) => JSON.stringify(prev) === JSON.stringify(current)), takeUntil(this.destroy$)) .subscribe(() => { this.handleDateState(); }); } ngOnDestroy() { this.destroy$.next(true); this.destroy$.complete(); } navigateTo(date) { const comingDate = new Date(date); if (this.minDate) { const valid = CalendarUtil.isValidMinMonth(this.minDate, comingDate); if (!valid) return; } if (this.maxDate) { const valid = CalendarUtil.isValidMaxMonth(this.maxDate, comingDate); if (!valid) return; } this.activeCalendar = comingDate; this.generateCalendar(); } navigateToPreviousMonth() { const date = new Date(this.activeCalendar); date.setMonth(date.getMonth() - 1); this.navigateTo(date); } navigateToNextMonth() { const date = new Date(this.activeCalendar); date.setMonth(date.getMonth() + 1); this.navigateTo(date); } onMonthChange(value) { if (Array.isArray(value)) return; const date = new Date(this.activeCalendar); date.setMonth(parseInt(value)); this.navigateTo(date); } onYearChange(value) { if (Array.isArray(value)) return; const date = new Date(this.activeCalendar); date.setFullYear(parseInt(value)); this.navigateTo(date); } onSelectDate(date) { if (!date || date.isDisabled || this.disabled) return; if (this.useDateRange) { this.handleSelectDateRange(date); } else { this.value = this.handleStrictTime(date.day, this.value.start); } } onDayMouseEnter(date) { if (!this.useDateRange) return; this.ngZone.runOutsideAngular(() => { if (!this.value?.start || !date) return; const dateItems = this.calendars.reduce((prev, current) => [...prev, ...current.dates], []); if (date.day > this.value.start && !this.value.end) { const hoveredDay = dateItems.filter((item) => item && this.value?.start && item.day > this.value.start && item.day <= date.day); hoveredDay.forEach((item) => { if (item && !item.isDisabled) item.isSelectedRange = true; }); } }); } onDayMouseLeave(date) { if (!this.useDateRange) return; this.ngZone.runOutsideAngular(() => { if (!this.value?.start || !date) return; const dateItems = this.calendars.reduce((prev, current) => [...prev, ...current.dates], []); if (!this.value.end) { dateItems.forEach((item) => { if (item) item.isSelectedRange = false; }); } }); } handleSelectDateRange(date) { let startDate = this.value?.start || date.day; let endDate = this.value?.end || null; if (this.value?.start && date.day < this.value.start) { startDate = date.day; } if (this.value?.start && date.day >= this.value.start) { endDate = date.day; } if (this.value?.start && this.value.end) { startDate = date.day; endDate = null; } this.value = { start: startDate, end: endDate }; } generateDates(props) { const dates = CalendarUtil.generateDates(props).map((date) => ({ day: date })); return this.handleOutsideDays(dates); } handleOutsideDays(dates) { const firstDate = dates[0].day.getDay(); const numberOfEmptyDates = firstDate === 0 ? 6 : firstDate - 1; // Add empty date items as null to act as dates for previous month. const emptyPreviousDates = Array.from({ length: numberOfEmptyDates }).map(() => null); return [...emptyPreviousDates, ...dates]; } generateActiveMonthDates() { return this.generateDates({ month: this.activeCalendar.getMonth(), year: this.activeCalendar.getFullYear(), }); } generateNextMonthDates() { return this.generateDates({ month: this.activeCalendar.getMonth() + 1, year: this.activeCalendar.getFullYear(), }); } validateMonthNavigation() { if (this.minDate) { const date = new Date(this.activeCalendar); date.setMonth(date.getMonth() - 1); this.canNavigateToPreviousMonth = CalendarUtil.isValidMinMonth(this.minDate, date); } else { this.canNavigateToPreviousMonth = true; } if (this.maxDate) { const date = new Date(this.activeCalendar); date.setMonth(date.getMonth() + 1); this.canNavigateToNextMonth = CalendarUtil.isValidMaxMonth(this.maxDate, date); } else { this.canNavigateToNextMonth = true; } } handleDateState() { this.calendars.forEach((calendar) => { calendar.dates.forEach((dateItem) => { if (!dateItem) return; dateItem.isSelectedRange = false; dateItem.isSelected = CalendarUtil.isSameDate(dateItem.day, this.value?.start); if (this.useDateRange && !dateItem.isSelected && this.value?.end) { dateItem.isSelected = CalendarUtil.isSameDate(dateItem.day, this.value.end); } if (this.useDateRange && this.value?.start && this.value.end && !dateItem.isSelected) { const isOnRange = dateItem.day > this.value.start && dateItem.day < this.value.end; dateItem.isSelectedRange = isOnRange; } dateItem.isDisabled = CalendarUtil.isInvalidMinOrMaxDate(dateItem.day, this.minDate, this.maxDate, { useStrictTime: this.useStrictTime }); }); }); } generateCalendar() { this.calendars = []; this.calendars.push({ dates: this.generateActiveMonthDates() }); if (this.useDateRange && !this.isMobileScreen) { this.calendars.push({ dates: this.generateNextMonthDates() }); } this.validateMonthNavigation(); this.handleDateState(); } handleStrictTime(date, time) { if (!this.useStrictTime) return date; if (!time) { return this.handleReturnMinOrMaxDate(date); } const newDate = new Date(date); newDate.setHours(time.getHours(), time.getMinutes(), time.getSeconds(), time.getMilliseconds()); return this.handleReturnMinOrMaxDate(newDate); } handleReturnMinOrMaxDate(date) { if (this.minDate && date < this.minDate) { return this.minDate; } if (this.maxDate && date > this.maxDate) { return this.maxDate; } return date; } } DokuDatePickerBase.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: DokuDatePickerBase, deps: [{ token: LOCALE_ID }, { token: i0.NgZone }, { token: DOKU_DATE_PICKER_STRICT_TIME, optional: true }], target: i0.ɵɵFactoryTarget.Component }); DokuDatePickerBase.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.9", type: DokuDatePickerBase, isStandalone: true, selector: "doku-date-picker-base", host: { properties: { "class": "this.classes" } }, exportAs: ["dokuDatePickerBase"], usesInheritance: true, ngImport: i0, template: "<div class=\"d-date-picker-container\" [class.d-date-range]=\"useDateRange\">\n <div class=\"d-date-picker-header\">\n <span\n class=\"d-date-picker-arrow\"\n [class.disabled]=\"!canNavigateToPreviousMonth\"\n (click)=\"navigateToPreviousMonth()\"\n >\n <ng-container [ngTemplateOutlet]=\"leftArrowIcon\"></ng-container>\n </span>\n <div class=\"d-date-picker-header-content\">\n <ng-container *ngIf=\"!useDateRange\">\n <doku-form-field>\n <doku-select\n [items]=\"monthSelectOptions\"\n [value]=\"activeMonth\"\n (valueChange)=\"onMonthChange($event)\"\n portalClass=\"d-date-picker-month-selector\"\n ></doku-select>\n </doku-form-field>\n <doku-form-field>\n <doku-select\n [items]=\"yearSelectOptions\"\n [value]=\"activeYear\"\n (valueChange)=\"onYearChange($event)\"\n portalClass=\"d-date-picker-year-selector\"\n ></doku-select>\n </doku-form-field>\n </ng-container>\n <ng-container *ngIf=\"useDateRange\">\n <div *ngFor=\"let headerText of calendarHeaders\" doku-typography class=\"header-item\">\n {{ headerText }}\n </div>\n </ng-container>\n </div>\n <span\n class=\"d-date-picker-arrow\"\n [class.disabled]=\"!canNavigateToNextMonth\"\n (click)=\"navigateToNextMonth()\"\n >\n <ng-container [ngTemplateOutlet]=\"rightArrowIcon\"></ng-container>\n </span>\n </div>\n\n <div class=\"d-date-picker-body\">\n <div class=\"d-date-picker-calendar\" *ngFor=\"let calendar of calendars\">\n <div class=\"d-date-picker-calendar-content\">\n <div class=\"d-date-picker-calendar-content-item\">\n <div class=\"d-date-picker-weekdays\">\n <div class=\"d-date-picker-weekdays-item\" *ngFor=\"let label of weekdays\">\n {{ label }}\n </div>\n </div>\n </div>\n </div>\n <div class=\"d-date-picker-calendar-content\">\n <div class=\"d-date-picker-calendar-content-item\">\n <div class=\"d-date-picker-days\">\n <div\n #day\n class=\"d-date-picker-day\"\n *ngFor=\"let date of calendar.dates\"\n [class.d-date-picker-selected]=\"date?.isSelected\"\n [class.d-date-picker-disabled]=\"date?.isDisabled\"\n [class.d-date-picker-selected-range]=\"date?.isSelectedRange\"\n (click)=\"!!date && onSelectDate(date)\"\n (mouseenter)=\"onDayMouseEnter(date)\"\n (mouseleave)=\"onDayMouseLeave(date)\"\n >\n <ng-container *ngIf=\"date\">{{ date.day | date : \"d\" }}</ng-container>\n </div>\n </div>\n </div>\n </div>\n </div>\n </div>\n\n <div class=\"d-date-picker-footer\">\n <ng-content select=\"[doku-date-picker-footer]\"></ng-content>\n </div>\n</div>\n\n<ng-template #leftArrowIcon>\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"18\" height=\"18\" viewBox=\"0 0 18 18\" fill=\"none\">\n <g clip-path=\"url(#clip0_488_16768)\">\n <path\n d=\"M13.1324 2.9025L11.7974 1.575L4.37988 9L11.8049 16.425L13.1324 15.0975L7.03488 9L13.1324 2.9025Z\"\n fill=\"currentColor\"\n />\n </g>\n <defs>\n <clipPath id=\"clip0_488_16768\">\n <rect width=\"18\" height=\"18\" fill=\"white\" />\n </clipPath>\n </defs>\n </svg>\n</ng-template>\n\n<ng-template #rightArrowIcon>\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"18\" height=\"18\" viewBox=\"0 0 18 18\" fill=\"none\">\n <g clip-path=\"url(#clip0_488_16769)\">\n <path\n d=\"M4.86743 15.0975L6.19493 16.425L13.6199 9L6.19493 1.575L4.86743 2.9025L10.9649 9L4.86743 15.0975Z\"\n fill=\"currentColor\"\n />\n </g>\n <defs>\n <clipPath id=\"clip0_488_16769\">\n <rect width=\"18\" height=\"18\" fill=\"white\" />\n </clipPath>\n </defs>\n </svg>\n</ng-template>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "pipe", type: i1.DatePipe, name: "date" }, { kind: "ngmodule", type: FormsModule }, { kind: "ngmodule", type: DokuSelectModule }, { kind: "component", type: i2.DokuSelect, selector: "doku-select", inputs: ["items", "bindLabel", "bindValue", "value", "placeholder", "portalClass", "multiple", "truncateLabel", "arrowPlacement", "disabled", "readonly", "searchable", "isAsync", "searchMatcherFn", "clearable"], outputs: ["valueChange", "search"], exportAs: ["dokuSelect"] }, { kind: "ngmodule", type: DokuFormFieldModule }, { kind: "component", type: i3.DokuFormField, selector: "doku-form-field", inputs: ["showSuccessBehavior", "isErrorState", "isSuccessState"], exportAs: ["dokuFormField"] }, { kind: "ngmodule", type: DokuTypographyModule }, { kind: "component", type: i4.DokuTypography, selector: "[doku-typography]", inputs: ["variant"], exportAs: ["dokuTypography"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: DokuDatePickerBase, decorators: [{ type: Component, args: [{ selector: 'doku-date-picker-base', exportAs: 'dokuDatePickerBase', standalone: true, imports: [CommonModule, FormsModule, DokuSelectModule, DokuFormFieldModule, DokuTypographyModule], encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"d-date-picker-container\" [class.d-date-range]=\"useDateRange\">\n <div class=\"d-date-picker-header\">\n <span\n class=\"d-date-picker-arrow\"\n [class.disabled]=\"!canNavigateToPreviousMonth\"\n (click)=\"navigateToPreviousMonth()\"\n >\n <ng-container [ngTemplateOutlet]=\"leftArrowIcon\"></ng-container>\n </span>\n <div class=\"d-date-picker-header-content\">\n <ng-container *ngIf=\"!useDateRange\">\n <doku-form-field>\n <doku-select\n [items]=\"monthSelectOptions\"\n [value]=\"activeMonth\"\n (valueChange)=\"onMonthChange($event)\"\n portalClass=\"d-date-picker-month-selector\"\n ></doku-select>\n </doku-form-field>\n <doku-form-field>\n <doku-select\n [items]=\"yearSelectOptions\"\n [value]=\"activeYear\"\n (valueChange)=\"onYearChange($event)\"\n portalClass=\"d-date-picker-year-selector\"\n ></doku-select>\n </doku-form-field>\n </ng-container>\n <ng-container *ngIf=\"useDateRange\">\n <div *ngFor=\"let headerText of calendarHeaders\" doku-typography class=\"header-item\">\n {{ headerText }}\n </div>\n </ng-container>\n </div>\n <span\n class=\"d-date-picker-arrow\"\n [class.disabled]=\"!canNavigateToNextMonth\"\n (click)=\"navigateToNextMonth()\"\n >\n <ng-container [ngTemplateOutlet]=\"rightArrowIcon\"></ng-container>\n </span>\n </div>\n\n <div class=\"d-date-picker-body\">\n <div class=\"d-date-picker-calendar\" *ngFor=\"let calendar of calendars\">\n <div class=\"d-date-picker-calendar-content\">\n <div class=\"d-date-picker-calendar-content-item\">\n <div class=\"d-date-picker-weekdays\">\n <div class=\"d-date-picker-weekdays-item\" *ngFor=\"let label of weekdays\">\n {{ label }}\n </div>\n </div>\n </div>\n </div>\n <div class=\"d-date-picker-calendar-content\">\n <div class=\"d-date-picker-calendar-content-item\">\n <div class=\"d-date-picker-days\">\n <div\n #day\n class=\"d-date-picker-day\"\n *ngFor=\"let date of calendar.dates\"\n [class.d-date-picker-selected]=\"date?.isSelected\"\n [class.d-date-picker-disabled]=\"date?.isDisabled\"\n [class.d-date-picker-selected-range]=\"date?.isSelectedRange\"\n (click)=\"!!date && onSelectDate(date)\"\n (mouseenter)=\"onDayMouseEnter(date)\"\n (mouseleave)=\"onDayMouseLeave(date)\"\n >\n <ng-container *ngIf=\"date\">{{ date.day | date : \"d\" }}</ng-container>\n </div>\n </div>\n </div>\n </div>\n </div>\n </div>\n\n <div class=\"d-date-picker-footer\">\n <ng-content select=\"[doku-date-picker-footer]\"></ng-content>\n </div>\n</div>\n\n<ng-template #leftArrowIcon>\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"18\" height=\"18\" viewBox=\"0 0 18 18\" fill=\"none\">\n <g clip-path=\"url(#clip0_488_16768)\">\n <path\n d=\"M13.1324 2.9025L11.7974 1.575L4.37988 9L11.8049 16.425L13.1324 15.0975L7.03488 9L13.1324 2.9025Z\"\n fill=\"currentColor\"\n />\n </g>\n <defs>\n <clipPath id=\"clip0_488_16768\">\n <rect width=\"18\" height=\"18\" fill=\"white\" />\n </clipPath>\n </defs>\n </svg>\n</ng-template>\n\n<ng-template #rightArrowIcon>\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"18\" height=\"18\" viewBox=\"0 0 18 18\" fill=\"none\">\n <g clip-path=\"url(#clip0_488_16769)\">\n <path\n d=\"M4.86743 15.0975L6.19493 16.425L13.6199 9L6.19493 1.575L4.86743 2.9025L10.9649 9L4.86743 15.0975Z\"\n fill=\"currentColor\"\n />\n </g>\n <defs>\n <clipPath id=\"clip0_488_16769\">\n <rect width=\"18\" height=\"18\" fill=\"white\" />\n </clipPath>\n </defs>\n </svg>\n</ng-template>\n" }] }], ctorParameters: function () { return [{ type: undefined, decorators: [{ type: Inject, args: [LOCALE_ID] }] }, { type: i0.NgZone }, { type: undefined, decorators: [{ type: Optional }, { type: Inject, args: [DOKU_DATE_PICKER_STRICT_TIME] }] }]; }, propDecorators: { classes: [{ type: HostBinding, args: ['class'] }] } }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGF0ZS1waWNrZXItYmFzZS5jb21wb25lbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi8uLi9wcm9qZWN0cy9kb2t1LWZyYWdtZW50L3NyYy9saWIvZGF0ZS1waWNrZXIvYmFzZS9kYXRlLXBpY2tlci1iYXNlLmNvbXBvbmVudC50cyIsIi4uLy4uLy4uLy4uLy4uLy4uLy4uL3Byb2plY3RzL2Rva3UtZnJhZ21lbnQvc3JjL2xpYi9kYXRlLXBpY2tlci9iYXNlL2RhdGUtcGlja2VyLWJhc2UuY29tcG9uZW50Lmh0bWwiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFlBQVksRUFBVyxNQUFNLGlCQUFpQixDQUFDO0FBQ3hELE9BQU8sRUFDTCx1QkFBdUIsRUFDdkIsU0FBUyxFQUNULFdBQVcsRUFDWCxNQUFNLEVBQ04sU0FBUyxFQUlULFFBQVEsRUFDUixpQkFBaUIsR0FDbEIsTUFBTSxlQUFlLENBQUM7QUFDdkIsT0FBTyxFQUFFLFdBQVcsRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBQzdDLE9BQU8sRUFBRSxPQUFPLEVBQUUsb0JBQW9CLEVBQUUsTUFBTSxFQUFFLEdBQUcsRUFBRSxJQUFJLEVBQUUsU0FBUyxFQUFFLE1BQU0sTUFBTSxDQUFDO0FBQ25GLE9BQU8sRUFBRSxjQUFjLEVBQUUsTUFBTSxrQkFBa0IsQ0FBQztBQUNsRCxPQUFPLEVBQUUsbUJBQW1CLEVBQUUsTUFBTSxrQkFBa0IsQ0FBQztBQUN2RCxPQUFPLEVBQUUsZ0JBQWdCLEVBQXdCLE1BQU0sY0FBYyxDQUFDO0FBQ3RFLE9BQU8sRUFBRSxvQkFBb0IsRUFBRSxNQUFNLGtCQUFrQixDQUFDO0FBQ3hELE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQztBQUMvQyxPQUFPLEVBQUUsdUJBQXVCLEVBQUUsTUFBTSxvQ0FBb0MsQ0FBQztBQUM3RSxPQUFPLEVBQUUsNEJBQTRCLEVBQUUsTUFBTSxxQkFBcUIsQ0FB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QXdCLENBQUMsSUFBVTtRQUN6QyxJQUFJLElBQUksQ0FBQyxPQUFPLElBQUksSUFBSSxHQUFHLElBQUksQ0FBQyxPQUFPLEVBQUU7WUFDdkMsT0FBTyxJQUFJLENBQUMsT0FBTyxDQUFDO1NBQ3JCO1FBRUQsSUFBSSxJQUFJLENBQUMsT0FBTyxJQUFJLElBQUksR0FBRyxJQUFJLENBQUMsT0FBTyxFQUFFO1lBQ3ZDLE9BQU8sSUFBSSxDQUFDLE9BQU8sQ0FBQztTQUNyQjtRQUVELE9BQU8sSUFBSSxDQUFDO0lBQ2QsQ0FBQzs7K0dBdlVVLGtCQUFrQixrQkFnQ25CLFNBQVMsbUNBRUcsNEJBQTRCO21HQWxDdkMsa0JBQWtCLDZMQzlDL0IsMitIQWdIQSwyQ0R2RVksWUFBWSx5ZEFBRSxXQUFXLDhCQUFFLGdCQUFnQixxWEFBRSxtQkFBbUIsME1BQUUsb0JBQW9COzJGQUtyRixrQkFBa0I7a0JBVDlCLFNBQVM7K0JBQ0UsdUJBQXVCLFlBQ3ZCLG9CQUFvQixjQUNsQixJQUFJLFdBQ1AsQ0FBQyxZQUFZLEVBQUUsV0FBVyxFQUFFLGdCQUFnQixFQUFFLG1CQUFtQixFQUFFLG9CQUFvQixDQUFDLGlCQUNsRixpQkFBaUIsQ0FBQyxJQUFJLG1CQUNwQix1QkFBdUIsQ0FBQyxNQUFNOzswQkFtQzVDLE1BQU07MkJBQUMsU0FBUzs7MEJBRWhCLFFBQVE7OzBCQUFJLE1BQU07MkJBQUMsNEJBQTRCOzRDQWhDL0IsT0FBTztzQkFEekIsV0FBVzt1QkFBQyxPQUFPIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgQ29tbW9uTW9kdWxlLCBOZ0NsYXNzIH0gZnJvbSAnQGFuZ3VsYXIvY29tbW9uJztcbmltcG9ydCB7XG4gIENoYW5nZURldGVjdGlvblN0cmF0ZWd5LFxuICBDb21wb25lbnQsXG4gIEhvc3RCaW5kaW5nLFxuICBJbmplY3QsXG4gIExPQ0FMRV9JRCxcbiAgTmdab25lLFxuICBPbkRlc3Ryb3ksXG4gIE9uSW5pdCxcbiAgT3B0aW9uYWwsXG4gIFZpZXdFbmNhcHN1bGF0aW9uLFxufSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IEZvcm1zTW9kdWxlIH0gZnJvbSAnQGFuZ3VsYXIvZm9ybXMnO1xuaW1wb3J0IHsgU3ViamVjdCwgZGlzdGluY3RVbnRpbENoYW5nZWQsIGZpbHRlciwgbWFwLCBza2lwLCB0YWtlVW50aWwgfSBmcm9tICdyeGpzJztcbmltcG9ydCB7IERva3VCcmVha3BvaW50IH0gZnJvbSAnLi4vLi4vYnJlYWtwb2ludCc7XG5pbXBvcnQgeyBEb2t1Rm9ybUZpZWxkTW9kdWxlIH0gZnJvbSAnLi4vLi4vZm9ybS1maWVsZCc7XG5pbXBvcnQgeyBEb2t1U2VsZWN0TW9kdWxlLCBEb2t1U2VsZWN0T3B0aW9uSXRlbSB9IGZyb20gJy4uLy4uL3NlbGVjdCc7XG5pbXBvcnQgeyBEb2t1VHlwb2dyYXBoeU1vZHVsZSB9IGZyb20gJy4uLy4uL3R5cG9ncmFwaHknO1xuaW1wb3J0IHsgQ2FsZW5kYXJVdGlsIH0gZnJvbSAnLi9jYWxlbmRhci51dGlsJztcbmltcG9ydCB7IERva3VEYXRlUGlja2VyQmFzZVByb3BzIH0gZnJvbSAnLi9kYXRlLXBpY2tlci1iYXNlLXByb3BzLmNvbXBvbmVudCc7XG5pbXBvcnQgeyBET0tVX0RBVEVfUElDS0VSX1NUUklDVF9USU1FIH0gZnJvbSAnLi9kYXRlLXBpY2tlci50b2tlbic7XG5cbmludGVyZmFjZSBDYWxlbmRhckl0ZW0ge1xuICBkYXRlczogKERhdGVJdGVtIHwgbnVsbClbXTtcbn1cblxuaW50ZXJmYWNlIERhdGVJdGVtIHtcbiAgZGF5OiBEYXRlO1xuICBpc1NlbGVjdGVkPzogYm9vbGVhbjtcbiAgLyoqXG4gICAqIE9ubHkgYXZhaWxhYmxlIHdoZW4gYHVzZURhdGVSYW5nZWAgaXMgdHJ1ZS5cbiAgICovXG4gIGlzU2VsZWN0ZWRSYW5nZT86IGJvb2xlYW47XG4gIGlzRGlzYWJsZWQ/OiBib29sZWFuO1xufVxuXG5AQ29tcG9uZW50KHtcbiAgc2VsZWN0b3I6ICdkb2t1LWRhdGUtcGlja2VyLWJhc2UnLFxuICBleHBvcnRBczogJ2Rva3VEYXRlUGlja2VyQmFzZScsXG4gIHN0YW5kYWxvbmU6IHRydWUsXG4gIGltcG9ydHM6IFtDb21tb25Nb2R1bGUsIEZvcm1zTW9kdWxlLCBEb2t1U2VsZWN0TW9kdWxlLCBEb2t1Rm9ybUZpZWxkTW9kdWxlLCBEb2t1VHlwb2dyYXBoeU1vZHVsZV0sXG4gIGVuY2Fwc3VsYXRpb246IFZpZXdFbmNhcHN1bGF0aW9uLk5vbmUsXG4gIGNoYW5nZURldGVjdGlvbjogQ2hhbmdlRGV0ZWN0aW9uU3RyYXRlZ3kuT25QdXNoLFxuICB0ZW1wbGF0ZVVybDogJy4vZGF0ZS1waWNrZXItYmFzZS5jb21wb25lbnQuaHRtbCcsXG59KVxuZXhwb3J0IGNsYXNzIERva3VEYXRlUGlja2VyQmFzZSBleHRlbmRzIERva3VEYXRlUGlja2VyQmFzZVByb3BzIGltcGxlbWVudHMgT25Jbml0LCBPbkRlc3Ryb3kge1xuICBASG9zdEJpbmRpbmcoJ2NsYXNzJylcbiAgcHJvdGVjdGVkIHJlYWRvbmx5IGNsYXNzZXM6IE5nQ2xhc3NbJ25nQ2xhc3MnXSA9ICdkLWRhdGUtcGlja2VyLWJhc2UnO1xuXG4gIHByb3RlY3RlZCBjYWxlbmRhcnM6IENhbGVuZGFySXRlbVtdID0gW107XG5cbiAgcHJpdmF0ZSBnZXQgYWN0aXZlQ2FsZW5kYXIoKTogRGF0ZSB7XG4gICAgLy8gQWx3YXlzIHNldCB0aGUgZGF0ZSB0byAxc3Qgc28gdGhhdCBpdCBkb2Vzbid0IGJyZWFrIHdoaWxlIG5hdmlnYXRpbmcgdG8gbW9udGgveWVhclxuICAgIC8vIGJlY2F1c2Ugb2YgZGlmZmVyZW50IHRvdGFsIGRheXMuXG4gICAgcmV0dXJuIG5ldyBEYXRlKHRoaXMuX2FjdGl2ZUNhbGVuZGFyLmdldEZ1bGxZZWFyKCksIHRoaXMuX2FjdGl2ZUNhbGVuZGFyLmdldE1vbnRoKCksIDEpO1xuICB9XG4gIHByaXZhdGUgc2V0IGFjdGl2ZUNhbGVuZGFyKGRhdGU6IERhdGUpIHtcbiAgICB0aGlzLl9hY3RpdmVDYWxlbmRhciA9IGRhdGU7XG4gIH1cbiAgcHJpdmF0ZSBfYWN0aXZlQ2FsZW5kYXI6IERhdGUgPSBuZXcgRGF0ZSgpO1xuXG4gIHByb3RlY3RlZCBnZXQgY2FsZW5kYXJIZWFkZXJzKCk6IHN0cmluZ1tdIHtcbiAgICByZXR1cm4gdGhpcy5jYWxlbmRhcnMubWFwKChfLCBpZHgpID0+IHtcbiAgICAgIGNvbnN0IGRhdGUgPSBuZXcgRGF0ZSh0aGlzLmFjdGl2ZUNhbGVuZGFyKTtcbiAgICAgIGRhdGUuc2V0TW9udGgoZGF0ZS5nZXRNb250aCgpICsgaWR4KTtcbiAgICAgIGNvbnN0IG1vbnRoID0gZGF0ZS50b0xvY2FsZVN0cmluZyh0aGlzLmxvY2FsZUlkLCB7IG1vbnRoOiAnbG9uZycgfSk7XG4gICAgICBjb25zdCB5ZWFyID0gZGF0ZS5nZXRGdWxsWWVhcigpO1xuICAgICAgcmV0dXJuIGAke21vbnRofSAke3llYXJ9YDtcbiAgICB9KTtcbiAgfVxuXG4gIHByb3RlY3RlZCBjYW5OYXZpZ2F0ZVRvUHJldmlvdXNNb250aCA9IGZhbHNlO1xuICBwcm90ZWN0ZWQgY2FuTmF2aWdhdGVUb05leHRNb250aCA9IGZhbHNlO1xuXG4gIHByb3RlY3RlZCBkZXN0cm95JCA9IG5ldyBTdWJqZWN0KCk7XG5cbiAgY29uc3RydWN0b3IoXG4gICAgQEluamVjdChMT0NBTEVfSUQpIHByb3RlY3RlZCBsb2NhbGVJZDogc3RyaW5nLFxuICAgIHByaXZhdGUgbmdab25lOiBOZ1pvbmUsXG4gICAgQE9wdGlvbmFsKCkgQEluamVjdChET0tVX0RBVEVfUElDS0VSX1NUUklDVF9USU1FKSBwcml2YXRlIHVzZVN0cmljdFRpbWU6IGJvb2xlYW5cbiAgKSB7XG4gICAgc3VwZXIoKTtcbiAgfVxuXG4gIHByb3RlY3RlZCBnZXQgbW9udGhTZWxlY3RPcHRpb25zKCk6IERva3VTZWxlY3RPcHRpb25JdGVtW10ge1xuICAgIHJldHVybiBDYWxlbmRhclV0aWwuZ2VuZXJhdGVNb250aFNlbGVjdE9wdGlvbnMoe1xuICAgICAgbG9jYWxlOiB0aGlzLmxvY2FsZUlkLFxuICAgICAgbWluRGF0ZTogdGhpcy5taW5EYXRlLFxuICAgICAgbWF4RGF0ZTogdGhpcy5tYXhEYXRlLFxuICAgICAgYWN0aXZlWWVhcjogcGFyc2VJbnQodGhpcy5hY3RpdmVZZWFyKSxcbiAgICB9KTtcbiAgfVxuXG4gIHByb3RlY3RlZCBnZXQgeWVhclNlbGVjdE9wdGlvbnMoKTogRG9rdVNlbGVjdE9wdGlvbkl0ZW1bXSB7XG4gICAgcmV0dXJuIENhbGVuZGFyVXRpbC5nZW5lcmF0ZVllYXJTZWxlY3RPcHRpb25zKHtcbiAgICAgIGFjdGl2ZVllYXI6IHBhcnNlSW50KHRoaXMuYWN0aXZlWWVhciksXG4gICAgICBtaW5EYXRlOiB0aGlzLm1pbkRhdGUsXG4gICAgICBtYXhEYXRlOiB0aGlzLm1heERhdGUsXG4gICAgfSk7XG4gIH1cblxuICBwcm90ZWN0ZWQgZ2V0IHdlZWtkYXlzKCk6IHN0cmluZ1tdIHtcbiAgICByZXR1cm4gQ2FsZW5kYXJVdGlsLmdlbmVyYXRlV2Vla2RheXMoeyBsb2NhbGU6IHRoaXMubG9jYWxlSWQgfSk7XG4gIH1cblxuICBwcm90ZWN0ZWQgZ2V0IGFjdGl2ZU1vbnRoKCk6IHN0cmluZyB7XG4gICAgcmV0dXJuIHRoaXMuYWN0aXZlQ2FsZW5kYXIuZ2V0TW9udGgoKS50b1N0cmluZygpO1xuICB9XG5cbiAgcHJvdGVjdGVkIGdldCBhY3RpdmVZZWFyKCk6IHN0cmluZyB7XG4gICAgcmV0dXJuIHRoaXMuYWN0aXZlQ2FsZW5kYXIuZ2V0RnVsbFllYXIoKS50b1N0cmluZygpO1xuICB9XG5cbiAgcHJpdmF0ZSBnZXQgaXNNb2JpbGVTY3JlZW4oKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIHdpbmRvdy5tYXRjaE1lZGlhKERva3VCcmVha3BvaW50Lm1vYmlsZSkubWF0Y2hlcztcbiAgfVxuXG4gIG5nT25Jbml0KCk6IHZvaWQge1xuICAgIHRoaXMuYWN0aXZlQ2FsZW5kYXIgPSB0aGlzLnZhbHVlPy5zdGFydCB8fCBuZXcgRGF0ZSgpO1xuICAgIHRoaXMuZ2VuZXJhdGVDYWxlbmRhcigpO1xuXG4gICAgdGhpcy5ub3RpZnlDaGFuZ2UkXG4gICAgICAucGlwZShcbiAgICAgICAgZmlsdGVyKChjaGFuZ2UpID0+IGNoYW5nZSA9PT0gJ3ZhbHVlJyB8fCBjaGFuZ2UgPT09ICdtaW5EYXRlJyB8fCBjaGFuZ2UgPT09ICdtYXhEYXRlJyksXG4gICAgICAgIG1hcCgoKSA9PiB0aGlzLnZhbHVlKSxcbiAgICAgICAgZGlzdGluY3RVbnRpbENoYW5nZWQoKHByZXYsIGN1cnJlbnQpID0+IEpTT04uc3RyaW5naWZ5KHByZXYpID09PSBKU09OLnN0cmluZ2lmeShjdXJyZW50KSksXG4gICAgICAgIHNraXAoMSksXG4gICAgICAgIHRha2VVbnRpbCh0aGlzLmRlc3Ryb3kkKVxuICAgICAgKVxuICAgICAgLnN1YnNjcmliZSgodmFsdWUpID0+IHtcbiAgICAgICAgdGhpcy5oYW5kbGVEYXRlU3RhdGUoKTtcbiAgICAgICAgdGhpcy52YWx1ZUNoYW5nZS5lbWl0KHZhbHVlKTtcbiAgICAgIH0pO1xuXG4gICAgdGhpcy5ub3RpZnlDaGFuZ2UkXG4gICAgICAucGlwZShcbiAgICAgICAgZmlsdGVyKChjaGFuZ2UpID0+IGNoYW5nZSA9PT0gJ21pbkRhdGUnIHx8IGNoYW5nZSA9PT0gJ21heERhdGUnKSxcbiAgICAgICAgbWFwKCgpID0+ICh7IG1pbkRhdGU6IHRoaXMubWluRGF0ZSwgbWF4RGF0ZTogdGhpcy5tYXhEYXRlIH0pKSxcbiAgICAgICAgZGlzdGluY3RVbnRpbENoYW5nZWQoKHByZXYsIGN1cnJlbnQpID0+IEpTT04uc3RyaW5naWZ5KHByZXYpID09PSBKU09OLnN0cmluZ2lmeShjdXJyZW50KSksXG4gICAgICAgIHRha2VVbnRpbCh0aGlzLmRlc3Ryb3kkKVxuICAgICAgKVxuICAgICAgLnN1YnNjcmliZSgoKSA9PiB7XG4gICAgICAgIHRoaXMuaGFuZGxlRGF0ZVN0YXRlKCk7XG4gICAgICB9KTtcbiAgfVxuXG4gIG5nT25EZXN0cm95KCk6IHZvaWQge1xuICAgIHRoaXMuZGVzdHJveSQubmV4dCh0cnVlKTtcbiAgICB0aGlzLmRlc3Ryb3kkLmNvbXBsZXRlKCk7XG4gIH1cblxuICBuYXZpZ2F0ZVRvKGRhdGU6IERhdGUgfCBzdHJpbmcpIHtcbiAgICBjb25zdCBjb21pbmdEYXRlID0gbmV3IERhdGUoZGF0ZSk7XG5cbiAgICBpZiAodGhpcy5taW5EYXRlKSB7XG4gICAgICBjb25zdCB2YWxpZCA9IENhbGVuZGFyVXRpbC5pc1ZhbGlkTWluTW9udGgodGhpcy5taW5EYXRlLCBjb21pbmdEYXRlKTtcbiAgICAgIGlmICghdmFsaWQpIHJldHVybjtcbiAgICB9XG5cbiAgICBpZiAodGhpcy5tYXhEYXRlKSB7XG4gICAgICBjb25zdCB2YWxpZCA9IENhbGVuZGFyVXRpbC5pc1ZhbGlkTWF4TW9udGgodGhpcy5tYXhEYXRlLCBjb21pbmdEYXRlKTtcbiAgICAgIGlmICghdmFsaWQpIHJldHVybjtcbiAgICB9XG5cbiAgICB0aGlzLmFjdGl2ZUNhbGVuZGFyID0gY29taW5nRGF0ZTtcbiAgICB0aGlzLmdlbmVyYXRlQ2FsZW5kYXIoKTtcbiAgfVxuXG4gIHByb3RlY3RlZCBuYXZpZ2F0ZVRvUHJldmlvdXNNb250aCgpIHtcbiAgICBjb25zdCBkYXRlID0gbmV3IERhdGUodGhpcy5hY3RpdmVDYWxlbmRhcik7XG4gICAgZGF0ZS5zZXRNb250aChkYXRlLmdldE1vbnRoKCkgLSAxKTtcbiAgICB0aGlzLm5hdmlnYXRlVG8oZGF0ZSk7XG4gIH1cblxuICBwcm90ZWN0ZWQgbmF2aWdhdGVUb05leHRNb250aCgpIHtcbiAgICBjb25zdCBkYXRlID0gbmV3IERhdGUodGhpcy5hY3RpdmVDYWxlbmRhcik7XG4gICAgZGF0ZS5zZXRNb250aChkYXRlLmdldE1vbnRoKCkgKyAxKTtcbiAgICB0aGlzLm5hdmlnYXRlVG8oZGF0ZSk7XG4gIH1cblxuICBwcm90ZWN0ZWQgb25Nb250aENoYW5nZSh2YWx1ZTogc3RyaW5nIHwgc3RyaW5nW10pIHtcbiAgICBpZiAoQXJyYXkuaXNBcnJheSh2YWx1ZSkpIHJldHVybjtcbiAgICBjb25zdCBkYXRlID0gbmV3IERhdGUodGhpcy5hY3RpdmVDYWxlbmRhcik7XG4gICAgZGF0ZS5zZXRNb250aChwYXJzZUludCh2YWx1ZSkpO1xuICAgIHRoaXMubmF2aWdhdGVUbyhkYXRlKTtcbiAgfVxuXG4gIHByb3RlY3RlZCBvblllYXJDaGFuZ2UodmFsdWU6IHN0cmluZyB8IHN0cmluZ1tdKSB7XG4gICAgaWYgKEFycmF5LmlzQXJyYXkodmFsdWUpKSByZXR1cm47XG4gICAgY29uc3QgZGF0ZSA9IG5ldyBEYXRlKHRoaXMuYWN0aXZlQ2FsZW5kYXIpO1xuICAgIGRhdGUuc2V0RnVsbFllYXIocGFyc2VJbnQodmFsdWUpKTtcbiAgICB0aGlzLm5hdmlnYXRlVG8oZGF0ZSk7XG4gIH1cblxuICBwcm90ZWN0ZWQgb25TZWxlY3REYXRlKGRhdGU6IERhdGVJdGVtKSB7XG4gICAgaWYgKCFkYXRlIHx8IGRhdGUuaXNEaXNhYmxlZCB8fCB0aGlzLmRpc2FibGVkKSByZXR1cm47XG5cbiAgICBpZiAodGhpcy51c2VEYXRlUmFuZ2UpIHtcbiAgICAgIHRoaXMuaGFuZGxlU2VsZWN0RGF0ZVJhbmdlKGRhdGUpO1xuICAgIH0gZWxzZSB7XG4gICAgICB0aGlzLnZhbHVlID0gdGhpcy5oYW5kbGVTdHJpY3RUaW1lKGRhdGUuZGF5LCB0aGlzLnZhbHVlLnN0YXJ0KTtcbiAgICB9XG4gIH1cblxuICBwcm90ZWN0ZWQgb25EYXlNb3VzZUVudGVyKGRhdGU/OiBEYXRlSXRlbSB8IG51bGwpIHtcbiAgICBpZiAoIXRoaXMudXNlRGF0ZVJhbmdlKSByZXR1cm47XG4gICAgdGhpcy5uZ1pvbmUucnVuT3V0c2lkZUFuZ3VsYXIoKCkgPT4ge1xuICAgICAgaWYgKCF0aGlzLnZhbHVlPy5zdGFydCB8fCAhZGF0ZSkgcmV0dXJuO1xuXG4gICAgICBjb25zdCBkYXRlSXRlbXMgPSB0aGlzLmNhbGVuZGFycy5yZWR1Y2UoXG4gICAgICAgIChwcmV2LCBjdXJyZW50KSA9PiBbLi4ucHJldiwgLi4uY3VycmVudC5kYXRlc10sXG4gICAgICAgIDxDYWxlbmRhckl0ZW1bJ2RhdGVzJ10+W11cbiAgICAgICk7XG5cbiAgICAgIGlmIChkYXRlLmRheSA+IHRoaXMudmFsdWUuc3RhcnQgJiYgIXRoaXMudmFsdWUuZW5kKSB7XG4gICAgICAgIGNvbnN0IGhvdmVyZWREYXkgPSBkYXRlSXRlbXMuZmlsdGVyKFxuICAgICAgICAgIChpdGVtKSA9PiBpdGVtICYmIHRoaXMudmFsdWU/LnN0YXJ0ICYmIGl0ZW0uZGF5ID4gdGhpcy52YWx1ZS5zdGFydCAmJiBpdGVtLmRheSA8PSBkYXRlLmRheVxuICAgICAgICApO1xuXG4gICAgICAgIGhvdmVyZWREYXkuZm9yRWFjaCgoaXRlbSkgPT4ge1xuICAgICAgICAgIGlmIChpdGVtICYmICFpdGVtLmlzRGlzYWJsZWQpIGl0ZW0uaXNTZWxlY3RlZFJhbmdlID0gdHJ1ZTtcbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgfSk7XG4gIH1cblxuICBwcm90ZWN0ZWQgb25EYXlNb3VzZUxlYXZlKGRhdGU/OiBEYXRlSXRlbSB8IG51bGwpIHtcbiAgICBpZiAoIXRoaXMudXNlRGF0ZVJhbmdlKSByZXR1cm47XG4gICAgdGhpcy5uZ1pvbmUucnVuT3V0c2lkZUFuZ3VsYXIoKCkgPT4ge1xuICAgICAgaWYgKCF0aGlzLnZhbHVlPy5zdGFydCB8fCAhZGF0ZSkgcmV0dXJuO1xuXG4gICAgICBjb25zdCBkYXRlSXRlbXMgPSB0aGlzLmNhbGVuZGFycy5yZWR1Y2UoXG4gICAgICAgIChwcmV2LCBjdXJyZW50KSA9PiBbLi4ucHJldiwgLi4uY3VycmVudC5kYXRlc10sXG4gICAgICAgIDxDYWxlbmRhckl0ZW1bJ2RhdGVzJ10+W11cbiAgICAgICk7XG5cbiAgICAgIGlmICghdGhpcy52YWx1ZS5lbmQpIHtcbiAgICAgICAgZGF0ZUl0ZW1zLmZvckVhY2goKGl0ZW0pID0+IHtcbiAgICAgICAgICBpZiAoaXRlbSkgaXRlbS5pc1NlbGVjdGVkUmFuZ2UgPSBmYWxzZTtcbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgfSk7XG4gIH1cblxuICBwcml2YXRlIGhhbmRsZVNlbGVjdERhdGVSYW5nZShkYXRlOiBEYXRlSXRlbSkge1xuICAgIGxldCBzdGFydERhdGUgPSB0aGlzLnZhbHVlPy5zdGFydCB8fCBkYXRlLmRheTtcbiAgICBsZXQgZW5kRGF0ZSA9IHRoaXMudmFsdWU/LmVuZCB8fCBudWxsO1xuXG4gICAgaWYgKHRoaXMudmFsdWU/LnN0YXJ0ICYmIGRhdGUuZGF5IDwgdGhpcy52YWx1ZS5zdGFydCkge1xuICAgICAgc3RhcnREYXRlID0gZGF0ZS5kYXk7XG4gICAgfVxuXG4gICAgaWYgKHRoaXMudmFsdWU/LnN0YXJ0ICYmIGRhdGUuZGF5ID49IHRoaXMudmFsdWUuc3RhcnQpIHtcbiAgICAgIGVuZERhdGUgPSBkYXRlLmRheTtcbiAgICB9XG5cbiAgICBpZiAodGhpcy52YWx1ZT8uc3RhcnQgJiYgdGhpcy52YWx1ZS5lbmQpIHtcbiAgICAgIHN0YXJ0RGF0ZSA9IGRhdGUuZGF5O1xuICAgICAgZW5kRGF0ZSA9IG51bGw7XG4gICAgfVxuXG4gICAgdGhpcy52YWx1ZSA9IHsgc3RhcnQ6IHN0YXJ0RGF0ZSwgZW5kOiBlbmREYXRlIH07XG4gIH1cblxuICBwcml2YXRlIGdlbmVyYXRlRGF0ZXMocHJvcHM6IHsgbW9udGg6IG51bWJlcjsgeWVhcjogbnVtYmVyIH0pOiAoRGF0ZUl0ZW0gfCBudWxsKVtdIHtcbiAgICBjb25zdCBkYXRlcyA9IENhbGVuZGFyVXRpbC5nZW5lcmF0ZURhdGVzKHByb3BzKS5tYXAoKGRhdGUpID0+IDxEYXRlSXRlbT57IGRheTogZGF0ZSB9KTtcbiAgICByZXR1cm4gdGhpcy5oYW5kbGVPdXRzaWRlRGF5cyhkYXRlcyk7XG4gIH1cblxuICBwcml2YXRlIGhhbmRsZU91dHNpZGVEYXlzKGRhdGVzOiBEYXRlSXRlbVtdKTogKERhdGVJdGVtIHwgbnVsbClbXSB7XG4gICAgY29uc3QgZmlyc3REYXRlID0gZGF0ZXNbMF0uZGF5LmdldERheSgpO1xuICAgIGNvbnN0IG51bWJlck9mRW1wdHlEYXRlcyA9IGZpcnN0RGF0ZSA9PT0gMCA/IDYgOiBmaXJzdERhdGUgLSAxO1xuICAgIC8vIEFkZCBlbXB0eSBkYXRlIGl0ZW1zIGFzIG51bGwgdG8gYWN0IGFzIGRhdGVzIGZvciBwcmV2aW91cyBtb250aC5cbiAgICBjb25zdCBlbXB0eVByZXZpb3VzRGF0ZXMgPSBBcnJheS5mcm9tKHsgbGVuZ3RoOiBudW1iZXJPZkVtcHR5RGF0ZXMgfSkubWFwKCgpID0+IG51bGwpO1xuICAgIHJldHVybiBbLi4uZW1wdHlQcmV2aW91c0RhdGVzLCAuLi5kYXRlc107XG4gIH1cblxuICBwcml2YXRlIGdlbmVyYXRlQWN0aXZlTW9udGhEYXRlcygpIHtcbiAgICByZXR1cm4gdGhpcy5nZW5lcmF0ZURhdGVzKHtcbiAgICAgIG1vbnRoOiB0aGlzLmFjdGl2ZUNhbGVuZGFyLmdldE1vbnRoKCksXG4gICAgICB5ZWFyOiB0aGlzLmFjdGl2ZUNhbGVuZGFyLmdldEZ1bGxZZWFyKCksXG4gICAgfSk7XG4gIH1cblxuICBwcml2YXRlIGdlbmVyYXRlTmV4dE1vbnRoRGF0ZXMoKSB7XG4gICAgcmV0dXJuIHRoaXMuZ2VuZXJhdGVEYXRlcyh7XG4gICAgICBtb250aDogdGhpcy5hY3RpdmVDYWxlbmRhci5nZXRNb250aCgpICsgMSxcbiAgICAgIHllYXI6IHRoaXMuYWN0aXZlQ2FsZW5kYXIuZ2V0RnVsbFllYXIoKSxcbiAgICB9KTtcbiAgfVxuXG4gIHByaXZhdGUgdmFsaWRhdGVNb250aE5hdmlnYXRpb24oKSB7XG4gICAgaWYgKHRoaXMubWluRGF0ZSkge1xuICAgICAgY29uc3QgZGF0ZSA9IG5ldyBEYXRlKHRoaXMuYWN0aXZlQ2FsZW5kYXIpO1xuICAgICAgZGF0ZS5zZXRNb250aChkYXRlLmdldE1vbnRoKCkgLSAxKTtcbiAgICAgIHRoaXMuY2FuTmF2aWdhdGVUb1ByZXZpb3VzTW9udGggPSBDYWxlbmRhclV0aWwuaXNWYWxpZE1pbk1vbnRoKHRoaXMubWluRGF0ZSwgZGF0ZSk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHRoaXMuY2FuTmF2aWdhdGVUb1ByZXZpb3VzTW9udGggPSB0cnVlO1xuICAgIH1cblxuICAgIGlmICh0aGlzLm1heERhdGUpIHtcbiAgICAgIGNvbnN0IGRhdGUgPSBuZXcgRGF0ZSh0aGlzLmFjdGl2ZUNhbGVuZGFyKTtcbiAgICAgIGRhdGUuc2V0TW9udGgoZGF0ZS5nZXRNb250aCgpICsgMSk7XG4gICAgICB0aGlzLmNhbk5hdmlnYXRlVG9OZXh0TW9udGggPSBDYWxlbmRhclV0aWwuaXNWY