lucy-calendar
Version:
LucyCalendar is a powerful and flexible date picker library for Angular applications, specifically designed for Ethiopian dates. It provides a user-friendly interface for selecting dates and supports various customization options to fit your needs.
251 lines • 50.1 kB
JavaScript
import { CommonModule } from '@angular/common';
import { Component, Input, HostListener, Output, EventEmitter } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { isEthiopianLeapYear, toEthiopian, toGregorian } from './date-convertor';
import { DropdownComponent } from './custom-dropdown/custom-dropdown.component';
import * as i0 from "@angular/core";
import * as i1 from "@angular/common";
export class LucyCalendarComponent {
ngOnChanges(changes) {
// if (changes['value'] && !changes['value'].firstChange) {
// this.value = changes['value'].currentValue;
// this.parseDate();
// // this.valueChange.emit(this.value);
// this.dateValue = toGregorian({ year: this.selectedYear, month: this.selectedMonth, day: this.selectedDay });
// this.emitChange();
// }
// else
if (changes['dateValue'] && !changes['dateValue'].firstChange && changes['dateValue'].currentValue?.getTime() !== this.dateValue?.getTime()) {
this.dateValue = changes['dateValue'].currentValue;
if (this.dateValue === null)
return;
const et = toEthiopian(this.dateValue);
this.selectedYear = et.year;
this.selectedMonth = et.month;
this.selectedDay = et.day;
// this.dateValueChange.emit(this.dateValue);
// this.value = this.formatDate();
this.emitChange();
}
}
ngOnInit() {
if (this.dateValue) {
this.selectedYear = this.dateValue.getFullYear();
this.selectedMonth = this.dateValue.getMonth();
this.selectedDay = this.dateValue.getDate();
}
// if (this.value) {
// this.parseDate();
// }
// if (this.selectedDay !== 0) {
// this.selectDate(this.selectedDay);
// } else {
// this.value = '';
// }
this.filteredMonths = this.availableMonths.filter(m => !this.isMonthOptionDisabled(m));
this.filteredYears = this.availableYears.filter(y => !this.isYearOptionDisabled(y));
}
label = 'Select Date';
// @Input() value: string | null = null; // New input for value
valueChange = new EventEmitter(); // Output event emitter for value
dateValue = null;
dateValueChange = new EventEmitter(); // Output event emitter for grValue
placeholder = null;
min = null;
max = null;
dateFormat = 'DD/MM/YYYY'; // New input for date format
// @Input() disabled: boolean = false; // New input for disabled state
// @Input() readonly: boolean = true; // New input for readonly state
calendarVisible = false;
currentDate = new Date();
selectedYear = toEthiopian(this.currentDate).year; // Start with 2015 (Ethiopian year 2008)
selectedMonth = 1; // Start with Meskerem (January in Ethiopian calendar)
selectedDay = 0;
monthNames = [
"መስከረም", "ጥቅምት", "ህዳር", "ታህሳስ", "ጥር", "የካቲት",
"መጋቢት", "ሚይዚያ", "ግንቦት", "ሰኔ", "ሐምሌ", "ነሐሴ", "ጳጉሜ"
];
dayNames = ["እሁድ", "ሰኞ", "ማክሰኞ", "ረቡዕ", "ሐሙስ", "ዓርብ", "ቅዳሜ"];
availableYears = Array.from({ length: 101 }, (_, i) => this.currentDate.getFullYear() - 50 + i);
filteredYears = this.availableYears.filter(y => !this.isYearOptionDisabled(y));
availableMonths = Array.from({ length: 13 }, (_, i) => i + 1);
filteredMonths = this.availableMonths.filter(month => !this.isMonthOptionDisabled(month));
refreshMonthOptions() {
this.filteredMonths = this.availableMonths.filter(month => !this.isMonthOptionDisabled(month));
}
;
refreshYearOptions() {
this.filteredYears = this.availableYears.filter(y => !this.isYearOptionDisabled(y));
}
emitChange() {
this.dateValueChange.emit(this.dateValue); // Emit the new date value
// this.valueChange.emit(this.value);
}
toggleCalendar() {
this.calendarVisible = !this.calendarVisible;
if (this.dateValue) {
const et = toEthiopian(this.dateValue);
this.selectedYear = et.year;
this.selectedMonth = et.month;
this.selectedDay = et.day;
}
// if (this.value) {
// this.parseDate();
// }
}
monthDisplay = (month) => this.monthNames[month - 1]; /* Month numbers are 1-indexed so adjust for array (0-indexed)*/
selectMonthYear(month, year) {
this.selectedMonth = month;
this.selectedYear = year;
this.dateValue = toGregorian({ year, month, day: 1 });
// this.value = this.formatDate();
this.emitChange();
}
onMonthChanges(month) {
this.selectMonthYear(month, this.selectedYear);
this.refreshYearOptions();
}
onYearChanges(year) {
this.selectMonthYear(this.selectedMonth, year);
this.refreshMonthOptions();
}
prevMonth() {
this.selectedMonth = (this.selectedMonth - 1 + 13) % 13 || 13;
this.dateValue = toGregorian({ year: this.selectedYear, month: this.selectedMonth, day: 1 });
// this.value = this.formatDate();
this.emitChange();
}
nextMonth() {
this.selectedMonth = (this.selectedMonth + 1) % 13 || 13;
this.dateValue = toGregorian({ year: this.selectedYear, month: this.selectedMonth, day: 1 });
// this.value = this.formatDate();
this.emitChange();
}
getLeadingEmptyDays() {
const firstDay = toGregorian({ year: this.selectedYear, month: this.selectedMonth, day: 1 });
return Array(firstDay.getDay()).fill(null);
}
get daysInMonth() {
const daysInEthiopianMonth = this.selectedMonth === 13 ? (isEthiopianLeapYear(this.selectedYear) ? 6 : 5) : 30; // Pagumē has 6 days in a leap year
return Array.from({ length: daysInEthiopianMonth }, (_, i) => i + 1);
}
selectDate(day) {
this.selectedDay = day;
this.dateValue = toGregorian({ year: this.selectedYear, month: this.selectedMonth, day: day });
// this.value = this.formatDate();
this.calendarVisible = false;
this.emitChange();
}
clearDate() {
// if (this.disabled) return; // Prevent clearing date if disabled
this.dateValue = null;
// this.value = null;
this.selectedDay = 0;
this.calendarVisible = false;
this.emitChange();
}
selectToday() {
const today = toEthiopian(new Date());
this.selectedYear = today.year;
this.selectedMonth = today.month;
this.selectedDay = today.day;
this.selectDate(today.day);
}
isDayDisabled(day) {
if (this.max === null)
return false;
const date = toGregorian({ year: this.selectedYear, month: this.selectedMonth, day: day });
return date > this.max;
}
isNextMonthDisabled() {
if (this.max === null)
return false;
const nextMonthDate = toGregorian({ year: this.selectedYear, month: this.selectedMonth + 1, day: 1 });
return nextMonthDate > this.max;
}
isPrevMonthDisabled() {
if (this.min === null)
return false;
const prevMonthDate = toGregorian({ year: this.selectedYear, month: this.selectedMonth - 1, day: 1 });
return prevMonthDate < this.min;
}
isMonthOptionDisabled(monthIndex) {
const monthDate = toGregorian({ year: this.selectedYear, month: monthIndex, day: 1 });
return (this.max !== null && (monthDate > this.max || (this.selectedYear === this.max.getFullYear() && monthIndex > this.max.getMonth())))
|| (this.min !== null && (monthDate < this.min || (this.selectedYear === this.min.getFullYear() && monthIndex < this.min.getMonth())));
}
isYearOptionDisabled(year) {
const yearDate = toGregorian({ year: year, month: 1, day: 1 });
return (this.max !== null && yearDate > this.max) || (this.min !== null && yearDate < this.min);
}
formatDate() {
const formattedMonth = this.padZero(this.selectedMonth);
const formattedDay = this.padZero(this.selectedDay);
return this.dateFormat
.replace(/YYYY/i, this.selectedYear.toString())
.replace(/MM/i, formattedMonth)
.replace(/dd/i, formattedDay);
}
// parseDate() {
// if (!this.value || !this.dateFormat) return;
// // Detect separator from dateFormat (supports /, -, ., and others)
// const separator = this.dateFormat.match(/[^a-zA-Z0-9]/)?.[0] || '/';
// const dateParts = this.value.split(separator).map(Number);
// const formatParts = this.dateFormat.split(separator);
// if (dateParts.length !== formatParts.length) {
// console.error('Date format mismatch');
// return;
// }
// formatParts.forEach((part, index) => {
// const partType = part.toUpperCase()[0];
// switch (partType) {
// case 'Y':
// this.selectedYear = dateParts[index];
// break;
// case 'M':
// this.selectedMonth = dateParts[index];
// break;
// case 'D':
// this.selectedDay = dateParts[index];
// break;
// }
// });
// }
padZero(num) {
return num.toString().padStart(2, '0');
}
onClickOutside(event) {
const target = event.target;
if (!target.closest('.relative') && !target.closest('lucy-calendar') && !target.classList.contains('calendar-icon') && !target.classList.contains('lucy-host')) {
this.calendarVisible = false;
}
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: LucyCalendarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: LucyCalendarComponent, isStandalone: true, selector: "lucy-calendar", inputs: { label: "label", dateValue: "dateValue", placeholder: "placeholder", min: "min", max: "max", dateFormat: "dateFormat", calendarVisible: "calendarVisible" }, outputs: { valueChange: "valueChange", dateValueChange: "dateValueChange" }, host: { listeners: { "document:click": "onClickOutside($event)" } }, usesOnChanges: true, ngImport: i0, template: "<div class=\"relative\">\r\n <!-- <lucy-date [label]=\"label\" [placeholder]=\"placeholder\" [dateFormat]=\"dateFormat\" [selectedDay]=\"selectedDay\"\r\n [readonly]=\"readonly\" [disabled]=\"disabled\" [dateFormat]=\"dateFormat\"></lucy-date> -->\r\n <!-- Calendar Dropdown -->\r\n <div id=\"calendar\" class=\"absolute mt-1 w-auto bg-white border border-gray-300 rounded-lg shadow-lg p-4 z-10\"\r\n [ngClass]=\"{'hidden': !calendarVisible}\">\r\n <div class=\"flex justify-between items-center mb-2\">\r\n <button (click)=\"prevMonth()\"\r\n class=\"text-gray-500 hover:text-gray-700 disabled:text-gray-300 disabled:cursor-not-allowed\"\r\n [disabled]=\"isPrevMonthDisabled()\">\r\n <svg class=\"h-6 w-6 text-gray-500 hover:text-gray-700 disabled:text-gray-300\" fill=\"none\" stroke=\"currentColor\"\r\n viewBox=\"0 0 24 24\" xmlns=\"http://www.w3.org/2000/svg\">\r\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M15 19l-7-7 7-7\"></path>\r\n </svg>\r\n </button>\r\n <!-- (click)=\"toggleMonthYearSelection()\" -->\r\n <button class=\"font-medium text-gray-700\">\r\n {{ monthNames[selectedMonth - 1] }} {{ selectedYear }}\r\n </button>\r\n <button (click)=\"nextMonth()\"\r\n class=\"text-gray-500 hover:text-gray-700 disabled:text-gray-300 disabled:cursor-not-allowed\"\r\n [disabled]=\"isNextMonthDisabled()\">\r\n <svg class=\"h-6 w-6 text-gray-500 hover:text-gray-700 disabled:text-gray-300\" fill=\"none\" stroke=\"currentColor\"\r\n viewBox=\"0 0 24 24\" xmlns=\"http://www.w3.org/2000/svg\">\r\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M9 5l7 7-7 7\"></path>\r\n </svg>\r\n </button>\r\n </div>\r\n\r\n <div class=\"grid grid-cols-2 gap-2\">\r\n <lucy-dropdown [options]=\"filteredMonths\" [selected]=\"selectedMonth\" (selectedChange)=\"onMonthChanges($event)\"\r\n [displayFn]=\"monthDisplay\">\r\n </lucy-dropdown>\r\n <lucy-dropdown [options]=\"filteredYears\" [selected]=\"selectedYear\"\r\n (selectedChange)=\"onYearChanges($event)\"></lucy-dropdown>\r\n </div>\r\n\r\n <!-- Days of the Month -->\r\n <div class=\"grid grid-cols-7 gap-1 text-center text-sm\">\r\n <div *ngFor=\"let dayName of dayNames\" class=\"text-gray-500\">{{ dayName }}</div>\r\n </div>\r\n\r\n <div class=\"grid grid-cols-7 gap-1 text-center text-sm pt-2\">\r\n <div *ngFor=\"let empty of getLeadingEmptyDays()\"></div>\r\n <button *ngFor=\"let day of daysInMonth\" class=\"py-1 rounded hover:bg-indigo-100 focus:bg-indigo-200\"\r\n [ngClass]=\"{'bg-blue-200': day === selectedDay, 'bg-gray-200 text-gray-400 cursor-not-allowed': isDayDisabled(day)}\"\r\n [disabled]=\"isDayDisabled(day)\" (click)=\"selectDate(day)\">\r\n {{ day }}\r\n </button>\r\n </div>\r\n\r\n <div class=\"flex justify-between mt-2\">\r\n <button (click)=\"clearDate()\"\r\n class=\"px-2 py-1 border border-red-500 text-red-500 rounded text-xs hover:bg-red-100\">Clear</button>\r\n <button (click)=\"selectToday()\"\r\n class=\"px-2 py-1 border border-blue-500 text-blue-500 rounded text-xs hover:bg-blue-100\">Today</button>\r\n </div>\r\n </div>\r\n</div>", styles: [""], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "ngmodule", type: FormsModule }, { kind: "component", type: DropdownComponent, selector: "lucy-dropdown", inputs: ["options", "selected", "displayFn"], outputs: ["selectedChange"] }] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: LucyCalendarComponent, decorators: [{
type: Component,
args: [{ selector: 'lucy-calendar', standalone: true, imports: [CommonModule, FormsModule, DropdownComponent], template: "<div class=\"relative\">\r\n <!-- <lucy-date [label]=\"label\" [placeholder]=\"placeholder\" [dateFormat]=\"dateFormat\" [selectedDay]=\"selectedDay\"\r\n [readonly]=\"readonly\" [disabled]=\"disabled\" [dateFormat]=\"dateFormat\"></lucy-date> -->\r\n <!-- Calendar Dropdown -->\r\n <div id=\"calendar\" class=\"absolute mt-1 w-auto bg-white border border-gray-300 rounded-lg shadow-lg p-4 z-10\"\r\n [ngClass]=\"{'hidden': !calendarVisible}\">\r\n <div class=\"flex justify-between items-center mb-2\">\r\n <button (click)=\"prevMonth()\"\r\n class=\"text-gray-500 hover:text-gray-700 disabled:text-gray-300 disabled:cursor-not-allowed\"\r\n [disabled]=\"isPrevMonthDisabled()\">\r\n <svg class=\"h-6 w-6 text-gray-500 hover:text-gray-700 disabled:text-gray-300\" fill=\"none\" stroke=\"currentColor\"\r\n viewBox=\"0 0 24 24\" xmlns=\"http://www.w3.org/2000/svg\">\r\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M15 19l-7-7 7-7\"></path>\r\n </svg>\r\n </button>\r\n <!-- (click)=\"toggleMonthYearSelection()\" -->\r\n <button class=\"font-medium text-gray-700\">\r\n {{ monthNames[selectedMonth - 1] }} {{ selectedYear }}\r\n </button>\r\n <button (click)=\"nextMonth()\"\r\n class=\"text-gray-500 hover:text-gray-700 disabled:text-gray-300 disabled:cursor-not-allowed\"\r\n [disabled]=\"isNextMonthDisabled()\">\r\n <svg class=\"h-6 w-6 text-gray-500 hover:text-gray-700 disabled:text-gray-300\" fill=\"none\" stroke=\"currentColor\"\r\n viewBox=\"0 0 24 24\" xmlns=\"http://www.w3.org/2000/svg\">\r\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M9 5l7 7-7 7\"></path>\r\n </svg>\r\n </button>\r\n </div>\r\n\r\n <div class=\"grid grid-cols-2 gap-2\">\r\n <lucy-dropdown [options]=\"filteredMonths\" [selected]=\"selectedMonth\" (selectedChange)=\"onMonthChanges($event)\"\r\n [displayFn]=\"monthDisplay\">\r\n </lucy-dropdown>\r\n <lucy-dropdown [options]=\"filteredYears\" [selected]=\"selectedYear\"\r\n (selectedChange)=\"onYearChanges($event)\"></lucy-dropdown>\r\n </div>\r\n\r\n <!-- Days of the Month -->\r\n <div class=\"grid grid-cols-7 gap-1 text-center text-sm\">\r\n <div *ngFor=\"let dayName of dayNames\" class=\"text-gray-500\">{{ dayName }}</div>\r\n </div>\r\n\r\n <div class=\"grid grid-cols-7 gap-1 text-center text-sm pt-2\">\r\n <div *ngFor=\"let empty of getLeadingEmptyDays()\"></div>\r\n <button *ngFor=\"let day of daysInMonth\" class=\"py-1 rounded hover:bg-indigo-100 focus:bg-indigo-200\"\r\n [ngClass]=\"{'bg-blue-200': day === selectedDay, 'bg-gray-200 text-gray-400 cursor-not-allowed': isDayDisabled(day)}\"\r\n [disabled]=\"isDayDisabled(day)\" (click)=\"selectDate(day)\">\r\n {{ day }}\r\n </button>\r\n </div>\r\n\r\n <div class=\"flex justify-between mt-2\">\r\n <button (click)=\"clearDate()\"\r\n class=\"px-2 py-1 border border-red-500 text-red-500 rounded text-xs hover:bg-red-100\">Clear</button>\r\n <button (click)=\"selectToday()\"\r\n class=\"px-2 py-1 border border-blue-500 text-blue-500 rounded text-xs hover:bg-blue-100\">Today</button>\r\n </div>\r\n </div>\r\n</div>" }]
}], propDecorators: { label: [{
type: Input
}], valueChange: [{
type: Output
}], dateValue: [{
type: Input
}], dateValueChange: [{
type: Output
}], placeholder: [{
type: Input
}], min: [{
type: Input
}], max: [{
type: Input
}], dateFormat: [{
type: Input
}], calendarVisible: [{
type: Input
}], onClickOutside: [{
type: HostListener,
args: ['document:click', ['$event']]
}] } });
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibHVjeS1jYWxlbmRhci5jb21wb25lbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9wcm9qZWN0cy9sdWN5LWNhbGVuZGFyL3NyYy9saWIvbHVjeS1jYWxlbmRhci5jb21wb25lbnQudHMiLCIuLi8uLi8uLi8uLi9wcm9qZWN0cy9sdWN5LWNhbGVuZGFyL3NyYy9saWIvbHVjeS1jYWxlbmRhci5jb21wb25lbnQuaHRtbCJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFDL0MsT0FBTyxFQUFFLFNBQVMsRUFBRSxLQUFLLEVBQVUsWUFBWSxFQUFFLE1BQU0sRUFBRSxZQUFZLEVBQTRCLE1BQU0sZUFBZSxDQUFDO0FBQ3ZILE9BQU8sRUFBRSxXQUFXLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUM3QyxPQUFPLEVBQUUsbUJBQW1CLEVBQUUsV0FBVyxFQUFFLFdBQVcsRUFBRSxNQUFNLGtCQUFrQixDQUFDO0FBQ2pGLE9BQU8sRUFBRSxpQkFBaUIsRUFBRSxNQUFNLDZDQUE2QyxDQUFDOzs7QUFVaEYsTUFBTSxPQUFPLHFCQUFxQjtJQUNoQyxXQUFXLENBQUMsT0FBc0I7UUFDaEMsMkRBQTJEO1FBQzNELGdEQUFnRDtRQUNoRCxzQkFBc0I7UUFDdEIsMENBQTBDO1FBQzFDLGlIQUFpSDtRQUNqSCx1QkFBdUI7UUFDdkIsSUFBSTtRQUNKLFFBQVE7UUFDUixJQUFJLE9BQU8sQ0FBQyxXQUFXLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxXQUFXLENBQUMsQ0FBQyxXQUFXLElBQUksT0FBTyxDQUFDLFdBQVcsQ0FBQyxDQUFDLFlBQVksRUFBRSxPQUFPLEVBQUUsS0FBSyxJQUFJLENBQUMsU0FBUyxFQUFFLE9BQU8sRUFBRSxFQUFFLENBQUM7WUFDNUksSUFBSSxDQUFDLFNBQVMsR0FBRyxPQUFPLENBQUMsV0FBVyxDQUFDLENBQUMsWUFBWSxDQUFDO1lBQ25E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aUJBQWlCOzs0RkFJM0MscUJBQXFCO2tCQVBqQyxTQUFTOytCQUNFLGVBQWUsY0FDYixJQUFJLFdBQ1AsQ0FBQyxZQUFZLEVBQUUsV0FBVyxFQUFFLGlCQUFpQixDQUFDOzhCQTRDOUMsS0FBSztzQkFBYixLQUFLO2dCQUVJLFdBQVc7c0JBQXBCLE1BQU07Z0JBQ0UsU0FBUztzQkFBakIsS0FBSztnQkFDSSxlQUFlO3NCQUF4QixNQUFNO2dCQUVFLFdBQVc7c0JBQW5CLEtBQUs7Z0JBQ0csR0FBRztzQkFBWCxLQUFLO2dCQUNHLEdBQUc7c0JBQVgsS0FBSztnQkFDRyxVQUFVO3NCQUFsQixLQUFLO2dCQUlHLGVBQWU7c0JBQXZCLEtBQUs7Z0JBMkxOLGNBQWM7c0JBRGIsWUFBWTt1QkFBQyxnQkFBZ0IsRUFBRSxDQUFDLFFBQVEsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IENvbW1vbk1vZHVsZSB9IGZyb20gJ0Bhbmd1bGFyL2NvbW1vbic7XHJcbmltcG9ydCB7IENvbXBvbmVudCwgSW5wdXQsIE9uSW5pdCwgSG9zdExpc3RlbmVyLCBPdXRwdXQsIEV2ZW50RW1pdHRlciwgT25DaGFuZ2VzLCBTaW1wbGVDaGFuZ2VzIH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XHJcbmltcG9ydCB7IEZvcm1zTW9kdWxlIH0gZnJvbSAnQGFuZ3VsYXIvZm9ybXMnO1xyXG5pbXBvcnQgeyBpc0V0aGlvcGlhbkxlYXBZZWFyLCB0b0V0aGlvcGlhbiwgdG9HcmVnb3JpYW4gfSBmcm9tICcuL2RhdGUtY29udmVydG9yJztcclxuaW1wb3J0IHsgRHJvcGRvd25Db21wb25lbnQgfSBmcm9tICcuL2N1c3RvbS1kcm9wZG93bi9jdXN0b20tZHJvcGRvd24uY29tcG9uZW50JztcclxuaW1wb3J0IHsgTHVjeURhdGVDb21wb25lbnQgfSBmcm9tICcuL2x1Y3ktZGF0ZS9sdWN5LWRhdGUuY29tcG9uZW50JztcclxuXHJcbkBDb21wb25lbnQoe1xyXG4gIHNlbGVjdG9yOiAnbHVjeS1jYWxlbmRhcicsXHJcbiAgc3RhbmRhbG9uZTogdHJ1ZSxcclxuICBpbXBvcnRzOiBbQ29tbW9uTW9kdWxlLCBGb3Jtc01vZHVsZSwgRHJvcGRvd25Db21wb25lbnRdLFxyXG4gIHRlbXBsYXRlVXJsOiAnLi9sdWN5LWNhbGVuZGFyLmNvbXBvbmVudC5odG1sJyxcclxuICBzdHlsZVVybDogJy4vbHVjeS1jYWxlbmRhci5jb21wb25lbnQuY3NzJ1xyXG59KVxyXG5leHBvcnQgY2xhc3MgTHVjeUNhbGVuZGFyQ29tcG9uZW50IGltcGxlbWVudHMgT25Jbml0LCBPbkNoYW5nZXMge1xyXG4gIG5nT25DaGFuZ2VzKGNoYW5nZXM6IFNpbXBsZUNoYW5nZXMpOiB2b2lkIHtcclxuICAgIC8vIGlmIChjaGFuZ2VzWyd2YWx1ZSddICYmICFjaGFuZ2VzWyd2YWx1ZSddLmZpcnN0Q2hhbmdlKSB7XHJcbiAgICAvLyAgIHRoaXMudmFsdWUgPSBjaGFuZ2VzWyd2YWx1ZSddLmN1cnJlbnRWYWx1ZTtcclxuICAgIC8vICAgdGhpcy5wYXJzZURhdGUoKTtcclxuICAgIC8vICAgLy8gdGhpcy52YWx1ZUNoYW5nZS5lbWl0KHRoaXMudmFsdWUpO1xyXG4gICAgLy8gICB0aGlzLmRhdGVWYWx1ZSA9IHRvR3JlZ29yaWFuKHsgeWVhcjogdGhpcy5zZWxlY3RlZFllYXIsIG1vbnRoOiB0aGlzLnNlbGVjdGVkTW9udGgsIGRheTogdGhpcy5zZWxlY3RlZERheSB9KTtcclxuICAgIC8vICAgdGhpcy5lbWl0Q2hhbmdlKCk7XHJcbiAgICAvLyB9XHJcbiAgICAvLyBlbHNlIFxyXG4gICAgaWYgKGNoYW5nZXNbJ2RhdGVWYWx1ZSddICYmICFjaGFuZ2VzWydkYXRlVmFsdWUnXS5maXJzdENoYW5nZSAmJiBjaGFuZ2VzWydkYXRlVmFsdWUnXS5jdXJyZW50VmFsdWU/LmdldFRpbWUoKSAhPT0gdGhpcy5kYXRlVmFsdWU/LmdldFRpbWUoKSkge1xyXG4gICAgICB0aGlzLmRhdGVWYWx1ZSA9IGNoYW5nZXNbJ2RhdGVWYWx1ZSddLmN1cnJlbnRWYWx1ZTtcclxuICAgICAgaWYgKHRoaXMuZGF0ZVZhbHVlID09PSBudWxsKVxyXG4gICAgICAgIHJldHVybjtcclxuICAgICAgY29uc3QgZXQgPSB0b0V0aGlvcGlhbih0aGlzLmRhdGVWYWx1ZSk7XHJcbiAgICAgIHRoaXMuc2VsZWN0ZWRZZWFyID0gZXQueWVhcjtcclxuICAgICAgdGhpcy5zZWxlY3RlZE1vbnRoID0gZXQubW9udGg7XHJcbiAgICAgIHRoaXMuc2VsZWN0ZWREYXkgPSBldC5kYXk7XHJcbiAgICAgIC8vIHRoaXMuZGF0ZVZhbHVlQ2hhbmdlLmVtaXQodGhpcy5kYXRlVmFsdWUpO1xyXG4gICAgICAvLyB0aGlzLnZhbHVlID0gdGhpcy5mb3JtYXREYXRlKCk7XHJcbiAgICAgIHRoaXMuZW1pdENoYW5nZSgpO1xyXG4gICAgfVxyXG4gIH1cclxuICBuZ09uSW5pdCgpOiB2b2lkIHtcclxuICAgIGlmICh0aGlzLmRhdGVWYWx1ZSkge1xyXG4gICAgICB0aGlzLnNlbGVjdGVkWWVhciA9IHRoaXMuZGF0ZVZhbHVlLmdldEZ1bGxZZWFyKCk7XHJcbiAgICAgIHRoaXMuc2VsZWN0ZWRNb250aCA9IHRoaXMuZGF0ZVZhbHVlLmdldE1vbnRoKCk7XHJcbiAgICAgIHRoaXMuc2VsZWN0ZWREYXkgPSB0aGlzLmRhdGVWYWx1ZS5nZXREYXRlKCk7XHJcbiAgICB9XHJcbiAgICAvLyBpZiAodGhpcy52YWx1ZSkge1xyXG4gICAgLy8gICB0aGlzLnBhcnNlRGF0ZSgpO1xyXG4gICAgLy8gfVxyXG4gICAgLy8gaWYgKHRoaXMuc2VsZWN0ZWREYXkgIT09IDApIHtcclxuICAgIC8vICAgdGhpcy5zZWxlY3REYXRlKHRoaXMuc2VsZWN0ZWREYXkpO1xyXG4gICAgLy8gfSBlbHNlIHtcclxuICAgIC8vICAgdGhpcy52YWx1ZSA9ICcnO1xyXG4gICAgLy8gfVxyXG4gICAgdGhpcy5maWx0ZXJlZE1vbnRocyA9IHRoaXMuYXZhaWxhYmxlTW9udGhzLmZpbHRlcihtID0+ICF0aGlzLmlzTW9udGhPcHRpb25EaXNhYmxlZChtKSk7XHJcbiAgICB0aGlzLmZpbHRlcmVkWWVhcnMgPSB0aGlzLmF2YWlsYWJsZVllYXJzLmZpbHRlcih5ID0+ICF0aGlzLmlzWWVhck9wdGlvbkRpc2FibGVkKHkpKTtcclxuICB9XHJcbiAgQElucHV0KCkgbGFiZWw6IHN0cmluZyA9ICdTZWxlY3QgRGF0ZSc7XHJcbiAgLy8gQElucHV0KCkgdmFsdWU6IHN0cmluZyB8IG51bGwgPSBudWxsOyAvLyBOZXcgaW5wdXQgZm9yIHZhbHVlXHJcbiAgQE91dHB1dCgpIHZhbHVlQ2hhbmdlOiBFdmVudEVtaXR0ZXI8c3RyaW5nIHwgbnVsbD4gPSBuZXcgRXZlbnRFbWl0dGVyPHN0cmluZyB8IG51bGw+KCk7IC8vIE91dHB1dCBldmVudCBlbWl0dGVyIGZvciB2YWx1ZVxyXG4gIEBJbnB1dCgpIGRhdGVWYWx1ZTogRGF0ZSB8IG51bGwgPSBudWxsO1xyXG4gIEBPdXRwdXQoKSBkYXRlVmFsdWVDaGFuZ2U6IEV2ZW50RW1pdHRlcjxEYXRlIHwgbnVsbD4gPSBuZXcgRXZlbnRFbWl0dGVyPERhdGUgfCBudWxsPigpOyAvLyBPdXRwdXQgZXZlbnQgZW1pdHRlciBmb3IgZ3JWYWx1ZVxyXG5cclxuICBASW5wdXQoKSBwbGFjZWhvbGRlcjogc3RyaW5nIHwgbnVsbCA9IG51bGw7XHJcbiAgQElucHV0KCkgbWluOiBEYXRlIHwgbnVsbCA9IG51bGw7XHJcbiAgQElucHV0KCkgbWF4OiBEYXRlIHwgbnVsbCA9IG51bGw7XHJcbiAgQElucHV0KCkgZGF0ZUZvcm1hdDogc3RyaW5nID0gJ0REL01NL1lZWVknOyAvLyBOZXcgaW5wdXQgZm9yIGRhdGUgZm9ybWF0XHJcbiAgLy8gQElucHV0KCkgZGlzYWJsZWQ6IGJvb2xlYW4gPSBmYWxzZTsgLy8gTmV3IGlucHV0IGZvciBkaXNhYmxlZCBzdGF0ZVxyXG4gIC8vIEBJbnB1dCgpIHJlYWRvbmx5OiBib29sZWFuID0gdHJ1ZTsgLy8gTmV3IGlucHV0IGZvciByZWFkb25seSBzdGF0ZVxyXG5cclxuICBASW5wdXQoKSBjYWxlbmRhclZpc2libGU6IGJvb2xlYW4gPSBmYWxzZTtcclxuXHJcbiAgY3VycmVudERhdGU6IERhdGUgPSBuZXcgRGF0ZSgpO1xyXG4gIHNlbGVjdGVkWWVhcjogbnVtYmVyID0gdG9FdGhpb3BpYW4odGhpcy5jdXJyZW50RGF0ZSkueWVhcjsgLy8gU3RhcnQgd2l0aCAyMDE1IChFdGhpb3BpYW4geWVhciAyMDA4KVxyXG4gIHNlbGVjdGVkTW9udGg6IG51bWJlciA9IDE7IC8vIFN0YXJ0IHdpdGggTWVza2VyZW0gKEphbnVhcnkgaW4gRXRoaW9waWFuIGNhbGVuZGFyKVxyXG4gIHNlbGVjdGVkRGF5OiBudW1iZXIgPSAwO1xyXG4gIG1vbnRoTmFtZXM6IHN0cmluZ1tdID0gW1xyXG4gICAgXCLhiJjhiLXhiqjhiKjhiJ1cIiwgXCLhjKXhiYXhiJ3hibVcIiwgXCLhiIXhi7PhiK1cIiwgXCLhibPhiIXhiLPhiLVcIiwgXCLhjKXhiK1cIiwgXCLhi6jhiqvhibLhibVcIixcclxuICAgIFwi4YiY4YyL4Ymi4Ym1XCIsIFwi4Yia4Yut4Yua4YurXCIsIFwi4YyN4YqV4Ymm4Ym1XCIsIFwi4Yiw4YqUXCIsIFwi4YiQ4Yid4YiMXCIsIFwi4YqQ4YiQ4Yi0XCIsIFwi4Yyz4YyJ4YicXCJcclxuICBdO1xyXG4gIGRheU5hbWVzOiBzdHJpbmdbXSA9IFtcIuGKpeGIgeGLtVwiLCBcIuGIsOGKnlwiLCBcIuGIm+GKreGIsOGKnlwiLCBcIuGIqOGJoeGLlVwiLCBcIuGIkOGImeGItVwiLCBcIuGLk+GIreGJpVwiLCBcIuGJheGLs+GInFwiXTtcclxuXHJcbiAgYXZhaWxhYmxlWWVhcnM6IG51bWJlcltdID0gQXJyYXkuZnJvbSh7IGxlbmd0aDogMTAxIH0sIChfLCBpKSA9PiB0aGlzLmN1cnJlbnREYXRlLmdldEZ1bGxZZWFyKCkgLSA1MCArIGkpO1xyXG4gIGZpbHRlcmVkWWVhcnMgPSB0aGlzLmF2YWlsYWJsZVllYXJzLmZpbHRlcih5ID0+ICF0aGlzLmlzWWVhck9wdGlvbkRpc2FibGVkKHkpKTtcclxuICBhdmFpbGFibGVNb250aHMgPSBBcnJheS5mcm9tKHsgbGVuZ3RoOiAxMyB9LCAoXywgaSkgPT4gaSArIDEpO1xyXG4gIGZpbHRlcmVkTW9udGhzID0gdGhpcy5hdmFpbGFibGVNb250aHMuZmlsdGVyKG1vbnRoID0+ICF0aGlzLmlzTW9udGhPcHRpb25EaXNhYmxlZChtb250aCkpO1xyXG5cclxuXHJcbiAgcmVmcmVzaE1vbnRoT3B0aW9ucygpIHtcclxuICAgIHRoaXMuZmlsdGVyZWRNb250aHMgPSB0aGlzLmF2YWlsYWJsZU1vbnRocy5maWx0ZXIobW9udGggPT4gIXRoaXMuaXNNb250aE9wdGlvbkRpc2FibGVkKG1vbnRoKSk7XHJcbiAgfTtcclxuICByZWZyZXNoWWVhck9wdGlvbnMoKTogdm9pZCB7XHJcbiAgICB0aGlzLmZpbHRlcmVkWWVhcnMgPSB0aGlzLmF2YWlsYWJsZVllYXJzLmZpbHRlcih5ID0+ICF0aGlzLmlzWWVhck9wdGlvbkRpc2FibGVkKHkpKTtcclxuICB9XHJcblxyXG4gIGVtaXRDaGFuZ2UoKSB7XHJcbiAgICB0aGlzLmRhdGVWYWx1ZUNoYW5nZS5lbWl0KHRoaXMuZGF0ZVZhbHVlKTsgLy8gRW1pdCB0aGUgbmV3IGRhdGUgdmFsdWVcclxuICAgIC8vIHRoaXMudmFsdWVDaGFuZ2UuZW1pdCh0aGlzLnZhbHVlKTtcclxuICB9XHJcblxyXG4gIHRvZ2dsZUNhbGVuZGFyKCkge1xyXG4gICAgdGhpcy5jYWxlbmRhclZpc2libGUgPSAhdGhpcy5jYWxlbmRhclZpc2libGU7XHJcbiAgICBpZiAodGhpcy5kYXRlVmFsdWUpIHtcclxuICAgICAgY29uc3QgZXQgPSB0b0V0aGlvcGlhbih0aGlzLmRhdGVWYWx1ZSk7XHJcbiAgICAgIHRoaXMuc2VsZWN0ZWRZZWFyID0gZXQueWVhcjtcclxuICAgICAgdGhpcy5zZWxlY3RlZE1vbnRoID0gZXQubW9udGg7XHJcbiAgICAgIHRoaXMuc2VsZWN0ZWREYXkgPSBldC5kYXk7XHJcbiAgICB9XHJcbiAgICAvLyBpZiAodGhpcy52YWx1ZSkge1xyXG4gICAgLy8gICB0aGlzLnBhcnNlRGF0ZSgpO1xyXG4gICAgLy8gfVxyXG4gIH1cclxuXHJcbiAgbW9udGhEaXNwbGF5ID0gKG1vbnRoOiBudW1iZXIpOiBzdHJpbmcgPT4gdGhpcy5tb250aE5hbWVzW21vbnRoIC0gMV07IC8qIE1vbnRoIG51bWJlcnMgYXJlIDEtaW5kZXhlZCBzbyBhZGp1c3QgZm9yIGFycmF5ICgwLWluZGV4ZWQpKi9cclxuXHJcbiAgc2VsZWN0TW9udGhZZWFyKG1vbnRoOiBudW1iZXIsIHllYXI6IG51bWJlcikge1xyXG4gICAgdGhpcy5zZWxlY3RlZE1vbnRoID0gbW9udGg7XHJcbiAgICB0aGlzLnNlbGVjdGVkWWVhciA9IHllYXI7XHJcbiAgICB0aGlzLmRhdGVWYWx1ZSA9IHRvR3JlZ29yaWFuKHsgeWVhciwgbW9udGgsIGRheTogMSB9KTtcclxuICAgIC8vIHRoaXMudmFsdWUgPSB0aGlzLmZvcm1hdERhdGUoKTtcclxuICAgIHRoaXMuZW1pdENoYW5nZSgpO1xyXG4gIH1cclxuXHJcbiAgb25Nb250aENoYW5nZXMobW9udGg6IG51bWJlcikge1xyXG4gICAgdGhpcy5zZWxlY3RNb250aFllYXIobW9udGgsIHRoaXMuc2VsZWN0ZWRZZWFyKTtcclxuICAgIHRoaXMucmVmcmVzaFllYXJPcHRpb25zKCk7XHJcbiAgfVxyXG5cclxuICBvblllYXJDaGFuZ2VzKHllYXI6IG51bWJlcikge1xyXG4gICAgdGhpcy5zZWxlY3RNb250aFllYXIodGhpcy5zZWxlY3RlZE1vbnRoLCB5ZWFyKTtcclxuICAgIHRoaXMucmVmcmVzaE1vbnRoT3B0aW9ucygpO1xyXG4gIH1cclxuXHJcbiAgcHJldk1vbnRoKCkge1xyXG4gICAgdGhpcy5zZWxlY3RlZE1vbnRoID0gKHRoaXMuc2VsZWN0ZWRNb250aCAtIDEgKyAxMykgJSAxMyB8fCAxMztcclxuICAgIHRoaXMuZGF0ZVZhbHVlID0gdG9HcmVnb3JpYW4oeyB5ZWFyOiB0aGlzLnNlbGVjdGVkWWVhciwgbW9udGg6IHRoaXMuc2VsZWN0ZWRNb250aCwgZGF5OiAxIH0pO1xyXG4gICAgLy8gdGhpcy52YWx1ZSA9IHRoaXMuZm9ybWF0RGF0ZSgpO1xyXG4gICAgdGhpcy5lbWl0Q2hhbmdlKClcclxuICB9XHJcblxyXG4gIG5leHRNb250aCgpIHtcclxuICAgIHRoaXMuc2VsZWN0ZWRNb250aCA9ICh0aGlzLnNlbGVjdGVkTW9udGggKyAxKSAlIDEzIHx8IDEzO1xyXG4gICAgdGhpcy5kYXRlVmFsdWUgPSB0b0dyZWdvcmlhbih7IHllYXI6IHRoaXMuc2VsZWN0ZWRZZWFyLCBtb250aDogdGhpcy5zZWxlY3RlZE1vbnRoLCBkYXk6IDEgfSk7XHJcbiAgICAvLyB0aGlzLnZhbHVlID0gdGhpcy5mb3JtYXREYXRlKCk7XHJcbiAgICB0aGlzLmVtaXRDaGFuZ2UoKTtcclxuICB9XHJcblxyXG4gIGdldExlYWRpbmdFbXB0eURheXMoKTogYW55W10ge1xyXG4gICAgY29uc3QgZmlyc3REYXkgPSB0b0dyZWdvcmlhbih7IHllYXI6IHRoaXMuc2VsZWN0ZWRZZWFyLCBtb250aDogdGhpcy5zZWxlY3RlZE1vbnRoLCBkYXk6IDEgfSk7XHJcbiAgICByZXR1cm4gQXJyYXkoZmlyc3REYXkuZ2V0RGF5KCkpLmZpbGwobnVsbCk7XHJcbiAgfVxyXG5cclxuICBnZXQgZGF5c0luTW9udGgoKTogbnVtYmVyW10ge1xyXG4gICAgY29uc3QgZGF5c0luRXRoaW9waWFuTW9udGggPSB0aGlzLnNlbGVjdGVkTW9udGggPT09IDEzID8gKGlzRXRoaW9waWFuTGVhcFllYXIodGhpcy5zZWxlY3RlZFllYXIpID8gNiA6IDUpIDogMzA7IC8vIFBhZ3VtxJMgaGFzIDYgZGF5cyBpbiBhIGxlYXAgeWVhclxyXG4gICAgcmV0dXJuIEFycmF5LmZyb20oeyBsZW5ndGg6IGRheXNJbkV0aGlvcGlhbk1vbnRoIH0sIChfLCBpKSA9PiBpICsgMSk7XHJcbiAgfVxyXG5cclxuICBzZWxlY3REYXRlKGRheTogbnVtYmVyKSB7XHJcbiAgICB0aGlzLnNlbGVjdGVkRGF5ID0gZGF5O1xyXG4gICAgdGhpcy5kYXRlVmFsdWUgPSB0b0dyZWdvcmlhbih7IHllYXI6IHRoaXMuc2VsZWN0ZWRZZWFyLCBtb250aDogdGhpcy5zZWxlY3RlZE1vbnRoLCBkYXk6IGRheSB9KTtcclxuICAgIC8vIHRoaXMudmFsdWUgPSB0aGlzLmZvcm1hdERhdGUoKTtcclxuICAgIHRoaXMuY2FsZW5kYXJWaXNpYmxlID0gZmFsc2U7XHJcbiAgICB0aGlzLmVtaXRDaGFuZ2UoKTtcclxuICB9XHJcblxyXG4gIGNsZWFyRGF0ZSgpIHtcclxuICAgIC8vIGlmICh0aGlzLmRpc2FibGVkKSByZXR1cm47IC8vIFByZXZlbnQgY2xlYXJpbmcgZGF0ZSBpZiBkaXNhYmxlZFxyXG4gICAgdGhpcy5kYXRlVmFsdWUgPSBudWxsO1xyXG4gICAgLy8gdGhpcy52YWx1ZSA9IG51bGw7XHJcbiAgICB0aGlzLnNlbGVjdGVkRGF5ID0gMDtcclxuICAgIHRoaXMuY2FsZW5kYXJWaXNpYmxlID0gZmFsc2U7XHJcbiAgICB0aGlzLmVtaXRDaGFuZ2UoKTtcclxuICB9XHJcblxyXG4gIHNlbGVjdFRvZGF5KCkge1xyXG4gICAgY29uc3QgdG9kYXkgPSB0b0V0aGlvcGlhbihuZXcgRGF0ZSgpKTtcclxuICAgIHRoaXMuc2VsZWN0ZWRZZWFyID0gdG9kYXkueWVhcjtcclxuICAgIHRoaXMuc2VsZWN0ZWRNb250aCA9IHRvZGF5Lm1vbnRoO1xyXG4gICAgdGhpcy5zZWxlY3RlZERheSA9IHRvZGF5LmRheTtcclxuICAgIHRoaXMuc2VsZWN0RGF0ZSh0b2RheS5kYXkpO1xyXG4gIH1cclxuXHJcbiAgaXNEYXlEaXNhYmxlZChkYXk6IG51bWJlcik6IGJvb2xlYW4ge1xyXG4gICAgaWYgKHRoaXMubWF4ID09PSBudWxsKVxyXG4gICAgICByZXR1cm4gZmFsc2U7XHJcbiAgICBjb25zdCBkYXRlID0gdG9HcmVnb3JpYW4oeyB5ZWFyOiB0aGlzLnNlbGVjdGVkWWVhciwgbW9udGg6IHRoaXMuc2VsZWN0ZWRNb250aCwgZGF5OiBkYXkgfSk7XHJcbiAgICByZXR1cm4gZGF0ZSA+IHRoaXMubWF4O1xyXG4gIH1cclxuXHJcbiAgaXNOZXh0TW9udGhEaXNhYmxlZCgpOiBib29sZWFuIHtcclxuICAgIGlmICh0aGlzLm1heCA9PT0gbnVsbClcclxuICAgICAgcmV0dXJuIGZhbHNlO1xyXG4gICAgY29uc3QgbmV4dE1vbnRoRGF0ZSA9IHRvR3JlZ29yaWFuKHsgeWVhcjogdGhpcy5zZWxlY3RlZFllYXIsIG1vbnRoOiB0aGlzLnNlbGVjdGVkTW9udGggKyAxLCBkYXk6IDEgfSk7XHJcbiAgICByZXR1cm4gbmV4dE1vbnRoRGF0ZSA+IHRoaXMubWF4O1xyXG4gIH1cclxuXHJcbiAgaXNQcmV2TW9udGhEaXNhYmxlZCgpOiBib29sZWFuIHtcclxuICAgIGlmICh0aGlzLm1pbiA9PT0gbnVsbClcclxuICAgICAgcmV0dXJuIGZhbHNlO1xyXG4gICAgY29uc3QgcHJldk1vbnRoRGF0ZSA9IHRvR3JlZ29yaWFuKHsgeWVhcjogdGhpcy5zZWxlY3RlZFllYXIsIG1vbnRoOiB0aGlzLnNlbGVjdGVkTW9udGggLSAxLCBkYXk6IDEgfSk7XHJcbiAgICByZXR1cm4gcHJldk1vbnRoRGF0ZSA8IHRoaXMubWluO1xyXG4gIH1cclxuXHJcbiAgaXNNb250aE9wdGlvbkRpc2FibGVkKG1vbnRoSW5kZXg6IG51bWJlcik6IGJvb2xlYW4ge1xyXG4gICAgY29uc3QgbW9udGhEYXRlID0gdG9HcmVnb3JpYW4oeyB5ZWFyOiB0aGlzLnNlbGVjdGVkWWVhciwgbW9udGg6IG1vbnRoSW5kZXgsIGRheTogMSB9KTtcclxuICAgIHJldHVybiAodGhpcy5tYXggIT09IG51bGwgJiYgKG1vbnRoRGF0ZSA+IHRoaXMubWF4IHx8ICh0aGlzLnNlbGVjdGVkWWVhciA9PT0gdGhpcy5tYXguZ2V0RnVsbFllYXIoKSAmJiBtb250aEluZGV4ID4gdGhpcy5tYXguZ2V0TW9udGgoKSkpKVxyXG4gICAgICB8fCAodGhpcy5taW4gIT09IG51bGwgJiYgKG1vbnRoRGF0ZSA8IHRoaXMubWluIHx8ICh0aGlzLnNlbGVjdGVkWWVhciA9PT0gdGhpcy5taW4uZ2V0RnVsbFllYXIoKSAmJiBtb250aEluZGV4IDwgdGhpcy5taW4uZ2V0TW9udGgoKSkpKTtcclxuICB9XHJcblxyXG4gIGlzWWVhck9wdGlvbkRpc2FibGVkKHllYXI6IG51bWJlcik6IGJvb2xlYW4ge1xyXG4gICAgY29uc3QgeWVhckRhdGUgPSB0b0dyZWdvcmlhbih7IHllYXI6IHllYXIsIG1vbnRoOiAxLCBkYXk6IDEgfSk7XHJcbiAgICByZXR1cm4gKHRoaXMubWF4ICE9PSBudWxsICYmIHllYXJEYXRlID4gdGhpcy5tYXgpIHx8ICh0aGlzLm1pbiAhPT0gbnVsbCAmJiB5ZWFyRGF0ZSA8IHRoaXMubWluKTtcclxuICB9XHJcblxyXG4gIGZvcm1hdERhdGUoKTogc3RyaW5nIHtcclxuICAgIGNvbnN0IGZvcm1hdHRlZE1vbnRoID0gdGhpcy5wYWRaZXJvKHRoaXMuc2VsZWN0ZWRNb250aCk7XHJcbiAgICBjb25zdCBmb3JtYXR0ZWREYXkgPSB0aGlzLnBhZFplcm8odGhpcy5zZWxlY3RlZERheSk7XHJcbiAgICByZXR1cm4gdGhpcy5kYXRlRm9ybWF0XHJcbiAgICAgIC5yZXBsYWNlKC9ZWVlZL2ksIHRoaXMuc2VsZWN0ZWRZZWFyLnRvU3RyaW5nKCkpXHJcbiAgICAgIC5yZXBsYWNlKC9NTS9pLCBmb3JtYXR0ZWRNb250aClcclxuICAgICAgLnJlcGxhY2UoL2RkL2ksIGZvcm1hdHRlZERheSk7XHJcbiAgfVxyXG5cclxuICAvLyBwYXJzZURhdGUoKSB7XHJcbiAgLy8gICBpZiAoIXRoaXMudmFsdWUgfHwgIXRoaXMuZGF0ZUZvcm1hdCkgcmV0dXJuO1xyXG5cclxuICAvLyAgIC8vIERldGVjdCBzZXBhcmF0b3IgZnJvbSBkYXRlRm9ybWF0IChzdXBwb3J0cyAvLCAtLCAuLCBhbmQgb3RoZXJzKVxyXG4gIC8vICAgY29uc3Qgc2VwYXJhdG9yID0gdGhpcy5kYXRlRm9ybWF0Lm1hdGNoKC9bXmEtekEtWjAtOV0vKT8uWzBdIHx8ICcvJztcclxuICAvLyAgIGNvbnN0IGRhdGVQYXJ0cyA9IHRoaXMudmFsdWUuc3BsaXQoc2VwYXJhdG9yKS5tYXAoTnVtYmVyKTtcclxuICAvLyAgIGNvbnN0IGZvcm1hdFBhcnRzID0gdGhpcy5kYXRlRm9ybWF0LnNwbGl0KHNlcGFyYXRvcik7XHJcblxyXG4gIC8vICAgaWYgKGRhdGVQYXJ0cy5sZW5ndGggIT09IGZvcm1hdFBhcnRzLmxlbmd0aCkge1xyXG4gIC8vICAgICBjb25zb2xlLmVycm9yKCdEYXRlIGZvcm1hdCBtaXNtYXRjaCcpO1xyXG4gIC8vICAgICByZXR1cm47XHJcbiAgLy8gICB9XHJcblxyXG4gIC8vICAgZm9ybWF0UGFydHMuZm9yRWFjaCgocGFydCwgaW5kZXgpID0+IHtcclxuICAvLyAgICAgY29uc3QgcGFydFR5cGUgPSBwYXJ0LnRvVXBwZXJDYXNlKClbMF07XHJcbiAgLy8gICAgIHN3aXRjaCAocGFydFR5cGUpIHtcclxuICAvLyAgICAgICBjYXNlICdZJzpcclxuICAvLyAgICAgICAgIHRoaXMuc2VsZWN0ZWRZZWFyID0gZGF0ZVBhcnRzW2luZGV4XTtcclxuICAvLyAgICAgICAgIGJyZWFrO1xyXG4gIC8vICAgICAgIGNhc2UgJ00nOlxyXG4gIC8vICAgICAgICAgdGhpcy5zZWxlY3RlZE1vbnRoID0gZGF0ZVBhcnRzW2luZGV4XTtcclxuICAvLyAgICAgICAgIGJyZWFrO1xyXG4gIC8vICAgICAgIGNhc2UgJ0QnOlxyXG4gIC8vICAgICAgICAgdGhpcy5zZWxlY3RlZERheSA9IGRhdGVQYXJ0c1tpbmRleF07XHJcbiAgLy8gICAgICAgICBicmVhaztcclxuICAvLyAgICAgfVxyXG4gIC8vICAgfSk7XHJcbiAgLy8gfVxyXG5cclxuICBwYWRaZXJvKG51bTogbnVtYmVyKTogc3RyaW5nIHtcclxuICAgIHJldHVybiBudW0udG9TdHJpbmcoKS5wYWRTdGFydCgyLCAnMCcpO1xyXG4gIH1cclxuXHJcbiAgQEhvc3RMaXN0ZW5lcignZG9jdW1lbnQ6Y2xpY2snLCBbJyRldmVudCddKVxyXG4gIG9uQ2xpY2tPdXRzaWRlKGV2ZW50OiBNb3VzZUV2ZW50KSB7XHJcbiAgICBjb25zdCB0YXJnZXQgPSBldmVudC50YXJnZXQgYXMgSFRNTEVsZW1lbnQ7XHJcbiAgICBpZiAoIXRhcmdldC5jbG9zZXN0KCcucmVsYXRpdmUnKSAmJiAhdGFyZ2V0LmNsb3Nlc3QoJ2x1Y3ktY2FsZW5kYXInKSAmJiAhdGFyZ2V0LmNsYXNzTGlzdC5jb250YWlucygnY2FsZW5kYXItaWNvbicpICYmICF0YXJnZXQuY2xhc3NMaXN0LmNvbnRhaW5zKCdsdWN5LWhvc3QnKSkge1xyXG4gICAgICB0aGlzLmNhbGVuZGFyVmlzaWJsZSA9IGZhbHNlO1xyXG4gICAgfVxyXG4gIH1cclxufVxyXG4iLCI8ZGl2IGNsYXNzPVwicmVsYXRpdmVcIj5cclxuICA8IS0tIDxsdWN5LWRhdGUgW2xhYmVsXT1cImxhYmVsXCIgW3BsYWNlaG9sZGVyXT1cInBsYWNlaG9sZGVyXCIgW2RhdGVGb3JtYXRdPVwiZGF0ZUZvcm1hdFwiIFtzZWxlY3RlZERheV09XCJzZWxlY3RlZERheVwiXHJcbiAgICBbcmVhZG9ubHldPVwicmVhZG9ubHlcIiBbZGlzYWJsZWRdPVwiZGlzYWJsZWRcIiBbZGF0ZUZvcm1hdF09XCJkYXRlRm9ybWF0XCI+PC9sdWN5LWRhdGU+IC0tPlxyXG4gIDwhLS0gQ2FsZW5kYXIgRHJvcGRvd24gLS0+XHJcbiAgPGRpdiBpZD1cImNhbGVuZGFyXCIgY2xhc3M9XCJhYnNvbHV0ZSBtdC0xIHctYXV0byBiZy13aGl0ZSBib3JkZXIgYm9yZGVyLWdyYXktMzAwIHJvdW5kZWQtbGcgc2hhZG93LWxnIHAtNCB6LTEwXCJcclxuICAgIFtuZ0NsYXNzXT1cInsnaGlkZGVuJzogIWNhbGVuZGFyVmlzaWJsZX1cIj5cclxuICAgIDxkaXYgY2xhc3M9XCJmbGV4IGp1c3RpZnktYmV0d2VlbiBpdGVtcy1jZW50ZXIgbWItMlwiPlxyXG4gICAgICA8YnV0dG9uIChjbGljayk9XCJwcmV2TW9udGgoKVwiXHJcbiAgICAgICAgY2xhc3M9XCJ0ZXh0LWdyYXktNTAwIGhvdmVyOnRleHQtZ3JheS03MDAgZGlzYWJsZWQ6dGV4dC1ncmF5LTMwMCBkaXNhYmxlZDpjdXJzb3Itbm90LWFsbG93ZWRcIlxyXG4gICAgICAgIFtkaXNhYmxlZF09XCJpc1ByZXZNb250aERpc2FibGVkKClcIj5cclxuICAgICAgICA8c3ZnIGNsYXNzPVwiaC02IHctNiB0ZXh0LWdyYXktNTAwIGhvdmVyOnRleHQtZ3JheS03MDAgZGlzYWJsZWQ6dGV4dC1ncmF5LTMwMFwiIGZpbGw9XCJub25lXCIgc3Ryb2tlPVwiY3VycmVudENvbG9yXCJcclxuICAgICAgICAgIHZpZXdCb3g9XCIwIDAgMjQgMjRcIiB4bWxucz1cImh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnXCI+XHJcbiAgICAgICAgICA8cGF0aCBzdHJva2UtbGluZWNhcD1cInJvdW5kXCIgc3Ryb2tlLWxpbmVqb2luPVwicm91bmRcIiBzdHJva2Utd2lkdGg9XCIyXCIgZD1cIk0xNSAxOWwtNy03IDctN1wiPjwvcGF0aD5cclxuICAgICAgICA8L3N2Zz5cclxuICAgICAgPC9idXR0b24+XHJcbiAgICAgIDwhLS0gKGNsaWNrKT1cInRvZ2dsZU1vbnRoWWVhclNlbGVjdGlvbigpXCIgLS0+XHJcbiAgICAgIDxidXR0b24gY2xhc3M9XCJmb250LW1lZGl1bSB0ZXh0LWdyYXktNzAwXCI+XHJcbiAgICAgICAge3sgbW9udGhOYW1lc1tzZWxlY3RlZE1vbnRoIC0gMV0gfX0ge3sgc2VsZWN0ZWRZZWFyIH19XHJcbiAgICAgIDwvYnV0dG9uPlxyXG4gICAgICA8YnV0dG9uIChjbGljayk9XCJuZXh0TW9udGgoKVwiXHJcbiAgICAgICAgY2xhc3M9XCJ0ZXh0LWdyYXktNTAwIGhvdmVyOnRleHQtZ3JheS03MDAgZGlzYWJsZWQ6dGV4dC1ncmF5LTMwMCBkaXNhYmxlZDpjdXJzb3Itbm90LWFsbG93ZWRcIlxyXG4gICAgICAgIFtkaXNhYmxlZF09XCJpc05leHRNb250aERpc2FibGVkKClcIj5cclxuICAgICAgICA8c3ZnIGNsYXNzPVwiaC02IHctNiB0ZXh0LWdyYXktNTAwIGhvdmVyOnRleHQtZ3JheS03MDAgZGlzYWJsZWQ6dGV4dC1ncmF5LTMwMFwiIGZpbGw9XCJub25lXCIgc3Ryb2tlPVwiY3VycmVudENvbG9yXCJcclxuICAgICAgICAgIHZpZXdCb3g9XCIwIDAgMjQgMjRcIiB4bWxucz1cImh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnXCI+XHJcbiAgICAgICAgICA8cGF0aCBzdHJva2UtbGluZWNhcD1cInJvdW5kXCIgc3Ryb2tlLWxpbmVqb2luPVwicm91bmRcIiBzdHJva2Utd2lkdGg9XCIyXCIgZD1cIk05IDVsNyA3LTcgN1wiPjwvcGF0aD5cclxuICAgICAgICA8L3N2Zz5cclxuICAgICAgPC9idXR0b24+XHJcbiAgICA8L2Rpdj5cclxuXHJcbiAgICA8ZGl2IGNsYXNzPVwiZ3JpZCBncmlkLWNvbHMtMiBnYXAtMlwiPlxyXG4gICAgICA8bHVjeS1kcm9wZG93biBbb3B0aW9uc109XCJmaWx0ZXJlZE1vbnRoc1wiIFtzZWxlY3RlZF09XCJzZWxlY3RlZE1vbnRoXCIgKHNlbGVjdGVkQ2hhbmdlKT1cIm9uTW9udGhDaGFuZ2VzKCRldmVudClcIlxyXG4gICAgICAgIFtkaXNwbGF5Rm5dPVwibW9udGhEaXNwbGF5XCI+XHJcbiAgICAgIDwvbHVjeS1kcm9wZG93bj5cclxuICAgICAgPGx1Y3ktZHJvcGRvd24gW29wdGlvbnNdPVwiZmlsdGVyZWRZZWFyc1wiIFtzZWxlY3RlZF09XCJzZWxlY3RlZFllYXJcIlxyXG4gICAgICAgIChzZWxlY3RlZENoYW5nZSk9XCJvblllYXJDaGFuZ2VzKCRldmVudClcIj48L2x1Y3ktZHJvcGRvd24+XHJcbiAgICA8L2Rpdj5cclxuXHJcbiAgICA8IS0tIERheXMgb2YgdGhlIE1vbnRoIC0tPlxyXG4gICAgPGRpdiBjbGFzcz1cImdyaWQgZ3JpZC1jb2xzLTcgZ2FwLTEgdGV4dC1jZW50ZXIgdGV4dC1zbVwiPlxyXG4gICAgICA8ZGl2ICpuZ0Zvcj1cImxldCBkYXlOYW1lIG9mIGRheU5hbWVzXCIgY2xhc3M9XCJ0ZXh0LWdyYXktNTAwXCI+e3sgZGF5TmFtZSB9fTwvZGl2PlxyXG4gICAgPC9kaXY+XHJcblxyXG4gICAgPGRpdiBjbGFzcz1cImdyaWQgZ3JpZC1jb2xzLTcgZ2FwLTEgdGV4dC1jZW50ZXIgdGV4dC1zbSBwdC0yXCI+XHJcbiAgICAgIDxkaXYgKm5nRm9yPVwibGV0IGVtcHR5IG9mIGdldExlYWRpbmdFbXB0eURheXMoKVwiPjwvZGl2PlxyXG4gICAgICA8YnV0dG9uICpuZ0Zvcj1cImxldCBkYXkgb2YgZGF5c0luTW9udGhcIiBjbGFzcz1cInB5LTEgcm91bmRlZCBob3ZlcjpiZy1pbmRpZ28tMTAwIGZvY3VzOmJnLWluZGlnby0yMDBcIlxyXG4gICAgICAgIFtuZ0NsYXNzXT1cInsnYmctYmx1ZS0yMDAnOiBkYXkgPT09IHNlbGVjdGVkRGF5LCAnYmctZ3JheS0yMDAgdGV4dC1ncmF5LTQwMCBjdXJzb3Itbm90LWFsbG93ZWQnOiBpc0RheURpc2FibGVkKGRheSl9XCJcclxuICAgICAgICBbZGlzYWJsZWRdPVwiaXNEYXlEaXNhYmxlZChkYXkpXCIgKGNsaWNrKT1cInNlbGVjdERhdGUoZGF5KVwiPlxyXG4gICAgICAgIHt7IGRheSB9fVxyXG4gICAgICA8L2J1dHRvbj5cclxuICAgIDwvZGl2PlxyXG5cclxuICAgIDxkaXYgY2xhc3M9XCJmbGV4IGp1c3RpZnktYmV0d2VlbiBtdC0yXCI+XHJcbiAgICAgIDxidXR0b24gKGNsaWNrKT1cImNsZWFyRGF0ZSgpXCJcclxuICAgICAgICBjbGFzcz1cInB4LTIgcHktMSBib3JkZXIgYm9yZGVyLXJlZC01MDAgdGV4dC1yZWQtNTAwIHJvdW5kZWQgdGV4dC14cyBob3ZlcjpiZy1yZWQtMTAwXCI+Q2xlYXI8L2J1dHRvbj5cclxuICAgICAgPGJ1dHRvbiAoY2xpY2spPVwic2VsZWN0VG9kYXkoKVwiXHJcbiAgICAgICAgY2xhc3M9XCJweC0yIHB5LTEgYm9yZGVyIGJvcmRlci1ibHVlLTUwMCB0ZXh0LWJsdWUtNTAwIHJvdW5kZWQgdGV4dC14cyBob3ZlcjpiZy1ibHVlLTEwMFwiPlRvZGF5PC9idXR0b24+XHJcbiAgICA8L2Rpdj5cclxuICA8L2Rpdj5cclxuPC9kaXY+Il19