angular-nepali-datepicker
Version:
Simple Nepali datepicker component for angular applications
313 lines • 34.5 kB
JavaScript
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
import { Component, forwardRef, Input, ViewEncapsulation } from "@angular/core";
import * as NepaliDateConverter from "nepali-date";
import { NG_VALUE_ACCESSOR } from "@angular/forms";
import { daysMapping, monthsMapping } from "./mapping";
export class DatepickerComponent {
constructor() {
this.nepaliDateToday = { day: 0, month: 0, year: 0 };
this.currentNepaliDate = { day: 0, month: 0, year: 0 };
this.formattedDate = "";
this.currentDate = new Date();
this.years = [];
this.daysMapping = daysMapping;
this.monthsMapping = monthsMapping;
this.isOpen = false;
this.hideInput = false;
this.alwaysVisible = false;
this.language = "ne";
this.monthDisplayType = "default";
this.dayDisplayType = "default";
this.dateFormatter = (selectedDate) => {
/** @type {?} */
const dd = selectedDate.day < 10 ? "0" + selectedDate.day : selectedDate.day;
/** @type {?} */
const mm = selectedDate.month < 10 ? "0" + selectedDate.month : selectedDate.month;
return `${dd}/${mm}/${this.selectedDate.year}`;
};
this.propagateChange = (_) => { };
this.propagateTouch = (_) => { };
}
/**
* @return {?}
*/
ngOnInit() {
/** @type {?} */
const nepaliDateToday = new NepaliDateConverter(new Date());
this.nepaliDateToday = {
year: nepaliDateToday.getYear(),
month: nepaliDateToday.getMonth(),
day: nepaliDateToday.getDate()
};
this.setCurrentDate();
this.populateYears();
this.setCurrentMonthData();
}
/**
* @return {?}
*/
setCurrentDate() {
/** @type {?} */
let currentNepaliDate;
if (!this.selectedDate) {
currentNepaliDate = new NepaliDateConverter(this.currentDate);
}
else {
const { year, month, day } = this.selectedDate;
currentNepaliDate = new NepaliDateConverter(year, month, day);
this.currentDate = currentNepaliDate.getEnglishDate();
}
this.currentNepaliDate = {
year: currentNepaliDate.getYear(),
month: currentNepaliDate.getMonth(),
day: currentNepaliDate.getDate()
};
}
/**
* @return {?}
*/
populateYears() {
for (let i = 2001; i <= 2088; i++) {
this.years.push(i);
}
}
/**
* @return {?}
*/
resetCurrentMonthData() {
this.currentMonthData = {
0: [],
1: [],
2: [],
3: [],
4: [],
5: [],
6: []
};
}
/**
* @return {?}
*/
formatValue() {
if (this.selectedDate) {
this.formattedDate = this.dateFormatter(this.selectedDate);
}
}
/**
* @param {?} value
* @return {?}
*/
writeValue(value) {
if (value) {
this.selectedDate = value;
this.currentNepaliDate = value;
this.formatValue();
}
}
/**
* @return {?}
*/
registerOnTouched() { }
/**
* @param {?} fn
* @return {?}
*/
registerOnChange(fn) {
this.propagateChange = fn;
}
/**
* @return {?}
*/
setCurrentMonthData() {
this.resetCurrentMonthData();
// fill the currentMonthData with current date
/** @type {?} */
const day = this.currentDate.getDay();
this.currentMonthData[day] = [this.currentNepaliDate.day];
// fill the currentMonthData with day before the current date
this.setMonthDataBefore(day - 1, this.currentNepaliDate.day - 1);
// fill the currentMonthData with day after the current date
this.setMonthDataAfter(day + 1, this.currentNepaliDate.day + 1);
// we need some empty spaces in place so that the dates are shown in correct order
// eg if the 1st day starts on monday then we need 1 empty space for non existingn date on Sunday
this.createEmptySpaces();
}
/**
* @param {?} day
* @param {?} date
* @return {?}
*/
setMonthDataBefore(day, date) {
if (date >= 1) {
if (day < 0) {
day = 6;
}
this.currentMonthData[day] = [date, ...this.currentMonthData[day]];
this.setMonthDataBefore(--day, --date);
}
}
/**
* @param {?} day
* @param {?} date
* @return {?}
*/
setMonthDataAfter(day, date) {
/** @type {?} */
const nepaliDate = new NepaliDateConverter(this.currentNepaliDate.year, this.currentNepaliDate.month, date);
// only add the data if the current month matches
if (nepaliDate.getMonth() === this.currentNepaliDate.month) {
if (day > 6) {
day = 0;
}
this.currentMonthData[day] = [...this.currentMonthData[day], date];
this.setMonthDataAfter(++day, ++date);
}
}
/**
* @return {?}
*/
createEmptySpaces() {
// first find out which day has the 1st
// if its a Sunday, then don't do anything else add 1 space on each previous day
/** @type {?} */
let dayIndex = 0;
Object.values(this.currentMonthData).find((value, index) => {
if (value.includes(1)) {
dayIndex = index;
}
return value.includes(1);
});
if (dayIndex) {
for (dayIndex; dayIndex > 0; dayIndex--) {
/** @type {?} */
const monthData = this.currentMonthData[dayIndex - 1];
this.currentMonthData[dayIndex - 1] = [null, ...monthData];
}
}
}
/**
* @param {?} day
* @return {?}
*/
selectDate(day) {
this.selectedDate = Object.assign({}, this.currentNepaliDate, { day });
this.formatValue();
this.close();
this.propagateChange(this.selectedDate);
}
/**
* @param {?} year
* @return {?}
*/
selectYear(year) {
this.currentNepaliDate.year = +year;
/** @type {?} */
const newDate = new NepaliDateConverter(this.currentNepaliDate.year, this.currentNepaliDate.month, this.currentNepaliDate.day);
this.currentDate = newDate.getEnglishDate();
this.setCurrentMonthData();
}
/**
* @param {?} month
* @return {?}
*/
selectMonth(month) {
this.currentNepaliDate.month = this.monthsMapping[this.language][this.monthDisplayType].indexOf(month);
/** @type {?} */
const newDate = new NepaliDateConverter(this.currentNepaliDate.year, this.currentNepaliDate.month, this.currentNepaliDate.day);
this.currentDate = newDate.getEnglishDate();
this.setCurrentMonthData();
}
/**
* @return {?}
*/
toggleOpen() {
if (!this.alwaysVisible) {
this.isOpen = !this.isOpen;
}
}
/**
* @return {?}
*/
open() {
this.isOpen = true;
}
/**
* @return {?}
*/
close() {
this.isOpen = false;
this.setCurrentDate();
}
}
DatepickerComponent.decorators = [
{ type: Component, args: [{
selector: "np-datepicker",
template: "<input\r\n class=\"datepicker__input\"\r\n type=\"text\"\r\n [value]=\"formattedDate | toNp: language\"\r\n [ngClass]=\"inputClass\"\r\n #origin=\"cdkOverlayOrigin\"\r\n cdk-overlay-origin\r\n (focus)=\"open()\"\r\n (keydown)=\"$event.preventDefault()\"\r\n aria-hidden=\"true\"\r\n [hidden]=\"hideInput\">\r\n<ng-template\r\n cdk-connected-overlay\r\n cdkConnectedOverlayLockPosition\r\n cdkConnectedOverlayHasBackdrop\r\n cdkConnectedOverlayBackdropClass=\"cdk-overlay-transparent-backdrop\"\r\n [cdkConnectedOverlayOrigin]=\"origin\"\r\n [cdkConnectedOverlayOpen]=\"isOpen\"\r\n (backdropClick)=\"close()\"\r\n (detach)=\"close()\">\r\n <ng-container [ngTemplateOutlet]=\"dp\"></ng-container>\r\n</ng-template>\r\n\r\n<ng-container [ngTemplateOutlet]=\"dp\" *ngIf=\"alwaysVisible\"></ng-container>\r\n\r\n<ng-template #dp>\r\n <div class=\"datepicker__container\">\r\n <div class=\"datepicker__options-container\">\r\n <span class=\"datepicker__options-year-container\">\r\n <span>\r\n {{'Year' | toNp : language : 'word'}}:\r\n </span>\r\n <select (change)=\"selectYear($event.target.value)\">\r\n <option\r\n *ngFor=\"let year of years\"\r\n [value]=\"year\"\r\n [selected]=\"year === currentNepaliDate?.year\">\r\n {{year | toNp: language }}\r\n </option>\r\n </select>\r\n </span>\r\n <span class=\"datepicker__options-month-container\">\r\n <span>{{'Month' | toNp : language : 'word'}}: </span>\r\n <select (change)=\"selectMonth($event.target.value)\">\r\n <option\r\n *ngFor=\"let month of monthsMapping[language][monthDisplayType]; index as i\"\r\n [value]=\"month\"\r\n [selected]=\"i === currentNepaliDate?.month\">\r\n {{month}}\r\n </option>\r\n </select>\r\n </span>\r\n </div>\r\n <div class=\"datepicker__days-container\">\r\n <div class=\"datepicker__days\" *ngFor=\"let day of daysMapping[language][dayDisplayType]; index as i\">\r\n <div class=\"datepicker__weekday\">{{day}}</div>\r\n <div class=\"datepicker__date-container\" *ngFor=\"let date of currentMonthData[i]\">\r\n <div\r\n class=\"datepicker__date\"\r\n [class.datepicker__date--active]=\"\r\n date === selectedDate?.day &&\r\n currentNepaliDate.month === selectedDate?.month &&\r\n currentNepaliDate.year === selectedDate?.year\r\n \"\r\n [class.datepicker__date--current-day]=\"\r\n date === nepaliDateToday.day &&\r\n currentNepaliDate.month === nepaliDateToday.month &&\r\n currentNepaliDate.year === nepaliDateToday.year\r\n \"\r\n [class.datepicker__date--disabled]=\"!date\"\r\n (click)=\"selectDate(date)\">\r\n <span *ngIf=\"!date\"> </span>\r\n {{date | toNp: language }}\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n</ng-template>",
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => DatepickerComponent),
multi: true
}
],
encapsulation: ViewEncapsulation.None,
styles: [".cdk-global-overlay-wrapper,.cdk-overlay-container{pointer-events:none;top:0;left:0;height:100%;width:100%}.cdk-overlay-container{position:fixed;z-index:1000}.cdk-overlay-container:empty{display:none}.cdk-global-overlay-wrapper{display:flex;position:absolute;z-index:1000}.cdk-overlay-pane{position:absolute;pointer-events:auto;box-sizing:border-box;z-index:1000;display:flex;max-width:100%;max-height:100%}.cdk-overlay-backdrop{position:absolute;top:0;bottom:0;left:0;right:0;z-index:1000;pointer-events:auto;-webkit-tap-highlight-color:transparent;transition:opacity .4s cubic-bezier(.25,.8,.25,1);opacity:0}.cdk-overlay-backdrop.cdk-overlay-backdrop-showing{opacity:1}@media screen and (-ms-high-contrast:active){.cdk-overlay-backdrop.cdk-overlay-backdrop-showing{opacity:.6}}.cdk-overlay-dark-backdrop{background:rgba(0,0,0,.32)}.cdk-overlay-transparent-backdrop,.cdk-overlay-transparent-backdrop.cdk-overlay-backdrop-showing{opacity:0}.cdk-overlay-connected-position-bounding-box{position:absolute;z-index:1000;display:flex;flex-direction:column;min-width:1px;min-height:1px}.cdk-global-scrollblock{position:fixed;width:100%;overflow-y:scroll}.datepicker__input{display:block}.datepicker__container{--font-family:arial,sans-serif;--font-size:14px;--container-padding:8px 5px;--container-border-color:lightgray;--container-border:1px solid;--container-background-color:white;--select-height:24px;--option-margin:0 0 7px;--option-year-container-margin:0 10px 0;--days-size:40px;--weekday-margin:0 0 5px;--active-day-color:white;--active-day-background:#27a4f7;--hover-color:#27a4f7;--selected-color:#27a4f7;display:inline-block;font-family:\"arial, sans-serif\";font-family:var(--font-family);font-size:14px;font-size:var(--font-size);padding:8px 5px;padding:var(--container-padding);border:1px solid #d3d3d3;border:var(--container-border);border-color:var(--container-border-color);background-color:#fff;background-color:var(--container-background-color)}.datepicker__options-container{margin:0 0 7px;margin:var(--option-margin)}.datepicker__options-container select{height:24px;height:var(--select-height)}.datepicker__options-year-container{display:inline-block;margin:0 10px;margin:var(--option-year-container-margin)}.datepicker__days{display:inline-block;vertical-align:top;text-align:center;width:40px;width:var(--days-size)}.datepicker__weekday{margin:0 0 5px;margin:var(--weekday-margin);font-weight:700;text-align:center}.datepicker__date{width:40px;width:var(--days-size);height:40px;height:var(--days-size);line-height:40px;line-height:var(--days-size);cursor:pointer}.datepicker__date--active{color:#fff;color:var(--active-day-color);background:#27a4f7;background:var(--active-day-background)}.datepicker__date--current-day:not(.datepicker__date--active){color:#27a4f7;color:var(--selected-color);font-weight:700}.datepicker__date--disabled{pointer-events:none}.datepicker__date:hover:not(.datepicker__date--active){color:#27a4f7;color:var(--hover-color);transition:color .3s}"]
}] }
];
/** @nocollapse */
DatepickerComponent.ctorParameters = () => [];
DatepickerComponent.propDecorators = {
hideInput: [{ type: Input }],
alwaysVisible: [{ type: Input }],
inputClass: [{ type: Input }],
language: [{ type: Input }],
monthDisplayType: [{ type: Input }],
dayDisplayType: [{ type: Input }],
dateFormatter: [{ type: Input }]
};
if (false) {
/** @type {?} */
DatepickerComponent.prototype.nepaliDateToday;
/** @type {?} */
DatepickerComponent.prototype.currentNepaliDate;
/** @type {?} */
DatepickerComponent.prototype.selectedDate;
/** @type {?} */
DatepickerComponent.prototype.formattedDate;
/** @type {?} */
DatepickerComponent.prototype.currentDate;
/** @type {?} */
DatepickerComponent.prototype.displayDate;
/** @type {?} */
DatepickerComponent.prototype.years;
/** @type {?} */
DatepickerComponent.prototype.currentMonthData;
/** @type {?} */
DatepickerComponent.prototype.daysMapping;
/** @type {?} */
DatepickerComponent.prototype.monthsMapping;
/** @type {?} */
DatepickerComponent.prototype.isOpen;
/** @type {?} */
DatepickerComponent.prototype.hideInput;
/** @type {?} */
DatepickerComponent.prototype.alwaysVisible;
/** @type {?} */
DatepickerComponent.prototype.inputClass;
/** @type {?} */
DatepickerComponent.prototype.language;
/** @type {?} */
DatepickerComponent.prototype.monthDisplayType;
/** @type {?} */
DatepickerComponent.prototype.dayDisplayType;
/** @type {?} */
DatepickerComponent.prototype.dateFormatter;
/** @type {?} */
DatepickerComponent.prototype.propagateChange;
/** @type {?} */
DatepickerComponent.prototype.propagateTouch;
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGF0ZXBpY2tlci5jb21wb25lbnQuanMiLCJzb3VyY2VSb290Ijoibmc6Ly9hbmd1bGFyLW5lcGFsaS1kYXRlcGlja2VyLyIsInNvdXJjZXMiOlsibGliL2RhdGVwaWNrZXIvZGF0ZXBpY2tlci5jb21wb25lbnQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7OztBQUFBLE9BQU8sRUFDTCxTQUFTLEVBRVQsVUFBVSxFQUNWLEtBQUssRUFDTCxpQkFBaUIsRUFDbEIsTUFBTSxlQUFlLENBQUM7QUFDdkIsT0FBTyxLQUFLLG1CQUFtQixNQUFNLGFBQWEsQ0FBQztBQUNuRCxPQUFPLEVBQXdCLGlCQUFpQixFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFRekUsT0FBTyxFQUFFLFdBQVcsRUFBRSxhQUFhLEVBQUUsTUFBTSxXQUFXLENBQUM7QUFldkQsTUFBTSxPQUFPLG1CQUFtQjtJQThDOUI7UUE3Q0Esb0JBQWUsR0FBZSxFQUFFLEdBQUcsRUFBRSxDQUFDLEVBQUUsS0FBSyxFQUFFLENBQUMsRUFBRSxJQUFJLEVBQUUsQ0FBQyxFQUFFLENBQUM7UUFDNUQsc0JBQWlCLEdBQWUsRUFBRSxHQUFHLEVBQUUsQ0FBQyxFQUFFLEtBQUssRUFBRSxDQUFDLEVBQUUsSUFBSSxFQUFFLENBQUMsRUFBRSxDQUFDO1FBRTlELGtCQUFhLEdBQUcsRUFBRSxDQUFDO1FBQ25CLGdCQUFXLEdBQUcsSUFBSSxJQUFJLEVBQUUsQ0FBQztRQUl6QixVQUFLLEdBQWEsRUFBRSxDQUFDO1FBSXJCLGdCQUFXLEdBQWdCLFdBQVcsQ0FBQztRQUV2QyxrQkFBYSxHQUFpQixhQUFhLENBQUM7UUFFNUMsV0FBTSxHQUFHLEtBQUssQ0FBQztRQUdmLGNBQVMsR0FBRyxLQUFLLENBQUM7UUFHbEIsa0JBQWEsR0FBRyxLQUFLLENBQUM7UUFNdEIsYUFBUSxHQUFnQixJQUFJLENBQUM7UUFHN0IscUJBQWdCLEdBQW1DLFNBQVMsQ0FBQztRQUc3RCxtQkFBYyxHQUF3QixTQUFTLENBQUM7UUFHaEQs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QUE0Qzs7SUFFNUMscUNBQWU7O0lBRWYsd0NBQ2tCOztJQUVsQiw0Q0FDc0I7O0lBRXRCLHlDQUNtQjs7SUFFbkIsdUNBQzZCOztJQUU3QiwrQ0FDNkQ7O0lBRTdELDZDQUNnRDs7SUFFaEQsNENBT0U7O0lBeURGLDhDQUFpQzs7SUFFakMsNkNBQWdDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHtcclxuICBDb21wb25lbnQsXHJcbiAgT25Jbml0LFxyXG4gIGZvcndhcmRSZWYsXHJcbiAgSW5wdXQsXHJcbiAgVmlld0VuY2Fwc3VsYXRpb25cclxufSBmcm9tIFwiQGFuZ3VsYXIvY29yZVwiO1xyXG5pbXBvcnQgKiBhcyBOZXBhbGlEYXRlQ29udmVydGVyIGZyb20gXCJuZXBhbGktZGF0ZVwiO1xyXG5pbXBvcnQgeyBDb250cm9sVmFsdWVBY2Nlc3NvciwgTkdfVkFMVUVfQUNDRVNTT1IgfSBmcm9tIFwiQGFuZ3VsYXIvZm9ybXNcIjtcclxuaW1wb3J0IHtcclxuICBOZXBhbGlEYXRlLFxyXG4gIE1vbnRoRGF0YSxcclxuICBEYXlzTWFwcGluZyxcclxuICBNb250aE1hcHBpbmcsXHJcbiAgRGF0ZUZvcm1hdHRlclxyXG59IGZyb20gXCIuL3R5cGVzXCI7XHJcbmltcG9ydCB7IGRheXNNYXBwaW5nLCBtb250aHNNYXBwaW5nIH0gZnJvbSBcIi4vbWFwcGluZ1wiO1xyXG5cclxuQENvbXBvbmVudCh7XHJcbiAgc2VsZWN0b3I6IFwibnAtZGF0ZXBpY2tlclwiLFxyXG4gIHRlbXBsYXRlVXJsOiBcIi4vZGF0ZXBpY2tlci5jb21wb25lbnQuaHRtbFwiLFxyXG4gIHN0eWxlVXJsczogW1wiLi9kYXRlcGlja2VyLmNvbXBvbmVudC5zY3NzXCJdLFxyXG4gIHByb3ZpZGVyczogW1xyXG4gICAge1xyXG4gICAgICBwcm92aWRlOiBOR19WQUxVRV9BQ0NFU1NPUixcclxuICAgICAgdXNlRXhpc3Rpbmc6IGZvcndhcmRSZWYoKCkgPT4gRGF0ZXBpY2tlckNvbXBvbmVudCksXHJcbiAgICAgIG11bHRpOiB0cnVlXHJcbiAgICB9XHJcbiAgXSxcclxuICBlbmNhcHN1bGF0aW9uOiBWaWV3RW5jYXBzdWxhdGlvbi5Ob25lXHJcbn0pXHJcbmV4cG9ydCBjbGFzcyBEYXRlcGlja2VyQ29tcG9uZW50IGltcGxlbWVudHMgT25Jbml0LCBDb250cm9sVmFsdWVBY2Nlc3NvciB7XHJcbiAgbmVwYWxpRGF0ZVRvZGF5OiBOZXBhbGlEYXRlID0geyBkYXk6IDAsIG1vbnRoOiAwLCB5ZWFyOiAwIH07XHJcbiAgY3VycmVudE5lcGFsaURhdGU6IE5lcGFsaURhdGUgPSB7IGRheTogMCwgbW9udGg6IDAsIHllYXI6IDAgfTtcclxuICBzZWxlY3RlZERhdGU6IE5lcGFsaURhdGU7XHJcbiAgZm9ybWF0dGVkRGF0ZSA9IFwiXCI7XHJcbiAgY3VycmVudERhdGUgPSBuZXcgRGF0ZSgpO1xyXG5cclxuICBkaXNwbGF5RGF0ZTogc3RyaW5nO1xyXG5cclxuICB5ZWFyczogbnVtYmVyW10gPSBbXTtcclxuXHJcbiAgY3VycmVudE1vbnRoRGF0YTogTW9udGhEYXRhO1xyXG5cclxuICBkYXlzTWFwcGluZzogRGF5c01hcHBpbmcgPSBkYXlzTWFwcGluZztcclxuXHJcbiAgbW9udGhzTWFwcGluZzogTW9udGhNYXBwaW5nID0gbW9udGhzTWFwcGluZztcclxuXHJcbiAgaXNPcGVuID0gZmFsc2U7XHJcblxyXG4gIEBJbnB1dCgpXHJcbiAgaGlkZUlucHV0ID0gZmFsc2U7XHJcblxyXG4gIEBJbnB1dCgpXHJcbiAgYWx3YXlzVmlzaWJsZSA9IGZhbHNlO1xyXG5cclxuICBASW5wdXQoKVxyXG4gIGlucHV0Q2xhc3M6IHN0cmluZztcclxuXHJcbiAgQElucHV0KClcclxuICBsYW5ndWFnZTogXCJlblwiIHwgXCJuZVwiID0gXCJuZVwiO1xyXG5cclxuICBASW5wdXQoKVxyXG4gIG1vbnRoRGlzcGxheVR5cGU6IFwiZGVmYXVsdFwiIHwgXCJtb2Rlcm5cIiB8IFwic2hvcnRcIiA9IFwiZGVmYXVsdFwiO1xyXG5cclxuICBASW5wdXQoKVxyXG4gIGRheURpc3BsYXlUeXBlOiBcImRlZmF1bHRcIiB8IFwic2hvcnRcIiA9IFwiZGVmYXVsdFwiO1xyXG5cclxuICBASW5wdXQoKVxyXG4gIGRhdGVGb3JtYXR0ZXI6IERhdGVGb3JtYXR0ZXIgPSAoc2VsZWN0ZWREYXRlOiBOZXBhbGlEYXRlKSA9PiB7XHJcbiAgICBjb25zdCBkZCA9XHJcbiAgICAgIHNlbGVjdGVkRGF0ZS5kYXkgPCAxMCA/IFwiMFwiICsgc2VsZWN0ZWREYXRlLmRheSA6IHNlbGVjdGVkRGF0ZS5kYXk7XHJcbiAgICBjb25zdCBtbSA9XHJcbiAgICAgIHNlbGVjdGVkRGF0ZS5tb250aCA8IDEwID8gXCIwXCIgKyBzZWxlY3RlZERhdGUubW9udGggOiBzZWxlY3RlZERhdGUubW9udGg7XHJcbiAgICByZXR1cm4gYCR7ZGR9LyR7bW19LyR7dGhpcy5zZWxlY3RlZERhdGUueWVhcn1gO1xyXG4gIH07XHJcblxyXG4gIGNvbnN0cnVjdG9yKCkge31cclxuXHJcbiAgbmdPbkluaXQoKSB7XHJcbiAgICBjb25zdCBuZXBhbGlEYXRlVG9kYXkgPSBuZXcgTmVwYWxpRGF0ZUNvbnZlcnRlcihuZXcgRGF0ZSgpKTtcclxuICAgIHRoaXMubmVwYWxpRGF0ZVRvZGF5ID0ge1xyXG4gICAgICB5ZWFyOiBuZXBhbGlEYXRlVG9kYXkuZ2V0WWVhcigpLFxyXG4gICAgICBtb250aDogbmVwYWxpRGF0ZVRvZGF5LmdldE1vbnRoKCksXHJcbiAgICAgIGRheTogbmVwYWxpRGF0ZVRvZGF5LmdldERhdGUoKVxyXG4gICAgfTtcclxuXHJcbiAgICB0aGlzLnNldEN1cnJlbnREYXRlKCk7XHJcbiAgICB0aGlzLnBvcHVsYXRlWWVhcnMoKTtcclxuICAgIHRoaXMuc2V0Q3VycmVudE1vbnRoRGF0YSgpO1xyXG4gIH1cclxuXHJcbiAgc2V0Q3VycmVudERhdGUoKSB7XHJcbiAgICBsZXQgY3VycmVudE5lcGFsaURhdGU7XHJcbiAgICBpZiAoIXRoaXMuc2VsZWN0ZWREYXRlKSB7XHJcbiAgICAgIGN1cnJlbnROZXBhbGlEYXRlID0gbmV3IE5lcGFsaURhdGVDb252ZXJ0ZXIodGhpcy5jdXJyZW50RGF0ZSk7XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICBjb25zdCB7IHllYXIsIG1vbnRoLCBkYXkgfSA9IHRoaXMuc2VsZWN0ZWREYXRlO1xyXG4gICAgICBjdXJyZW50TmVwYWxpRGF0ZSA9IG5ldyBOZXBhbGlEYXRlQ29udmVydGVyKHllYXIsIG1vbnRoLCBkYXkpO1xyXG4gICAgICB0aGlzLmN1cnJlbnREYXRlID0gY3VycmVudE5lcGFsaURhdGUuZ2V0RW5nbGlzaERhdGUoKTtcclxuICAgIH1cclxuICAgIHRoaXMuY3VycmVudE5lcGFsaURhdGUgPSB7XHJcbiAgICAgIHllYXI6IGN1cnJlbnROZXBhbGlEYXRlLmdldFllYXIoKSxcclxuICAgICAgbW9udGg6IGN1cnJlbnROZXBhbGlEYXRlLmdldE1vbnRoKCksXHJcbiAgICAgIGRheTogY3VycmVudE5lcGFsaURhdGUuZ2V0RGF0ZSgpXHJcbiAgICB9O1xyXG4gIH1cclxuXHJcbiAgcG9wdWxhdGVZZWFycygpIHtcclxuICAgIGZvciAobGV0IGkgPSAyMDAxOyBpIDw9IDIwODg7IGkrKykge1xyXG4gICAgICB0aGlzLnllYXJzLnB1c2goaSk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICByZXNldEN1cnJlbnRNb250aERhdGEoKSB7XHJcbiAgICB0aGlzLmN1cnJlbnRNb250aERhdGEgPSB7XHJcbiAgICAgIDA6IFtdLFxyXG4gICAgICAxOiBbXSxcclxuICAgICAgMjogW10sXHJcbiAgICAgIDM6IFtdLFxyXG4gICAgICA0OiBbXSxcclxuICAgICAgNTogW10sXHJcbiAgICAgIDY6IFtdXHJcbiAgICB9O1xyXG4gIH1cclxuXHJcbiAgZm9ybWF0VmFsdWUoKSB7XHJcbiAgICBpZiAodGhpcy5zZWxlY3RlZERhdGUpIHtcclxuICAgICAgdGhpcy5mb3JtYXR0ZWREYXRlID0gdGhpcy5kYXRlRm9ybWF0dGVyKHRoaXMuc2VsZWN0ZWREYXRlKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIHByb3BhZ2F0ZUNoYW5nZSA9IChfOiBhbnkpID0+IHt9O1xyXG5cclxuICBwcm9wYWdhdGVUb3VjaCA9IChfOiBhbnkpID0+IHt9O1xyXG5cclxuICB3cml0ZVZhbHVlKHZhbHVlOiBhbnkpIHtcclxuICAgIGlmICh2YWx1ZSkge1xyXG4gICAgICB0aGlzLnNlbGVjdGVkRGF0ZSA9IHZhbHVlO1xyXG4gICAgICB0aGlzLmN1cnJlbnROZXBhbGlEYXRlID0gdmFsdWU7XHJcbiAgICAgIHRoaXMuZm9ybWF0VmFsdWUoKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIHJlZ2lzdGVyT25Ub3VjaGVkKCkge31cclxuXHJcbiAgcmVnaXN0ZXJPbkNoYW5nZShmbikge1xyXG4gICAgdGhpcy5wcm9wYWdhdGVDaGFuZ2UgPSBmbjtcclxuICB9XHJcblxyXG4gIHNldEN1cnJlbnRNb250aERhdGEoKSB7XHJcbiAgICB0aGlzLnJlc2V0Q3VycmVudE1vbnRoRGF0YSgpO1xyXG4gICAgLy8gZmlsbCB0aGUgY3VycmVudE1vbnRoRGF0YSB3aXRoIGN1cnJlbnQgZGF0ZVxyXG4gICAgY29uc3QgZGF5ID0gdGhpcy5jdXJyZW50RGF0ZS5nZXREYXkoKTtcclxuICAgIHRoaXMuY3VycmVudE1vbnRoRGF0YVtkYXldID0gW3RoaXMuY3VycmVudE5lcGFsaURhdGUuZGF5XTtcclxuXHJcbiAgICAvLyBmaWxsIHRoZSBjdXJyZW50TW9udGhEYXRhIHdpdGggZGF5IGJlZm9yZSB0aGUgY3VycmVudCBkYXRlXHJcbiAgICB0aGlzLnNldE1vbnRoRGF0YUJlZm9yZShkYXkgLSAxLCB0aGlzLmN1cnJlbnROZXBhbGlEYXRlLmRheSAtIDEpO1xyXG5cclxuICAgIC8vIGZpbGwgdGhlIGN1cnJlbnRNb250aERhdGEgd2l0aCBkYXkgYWZ0ZXIgdGhlIGN1cnJlbnQgZGF0ZVxyXG4gICAgdGhpcy5zZXRNb250aERhdGFBZnRlcihkYXkgKyAxLCB0aGlzLmN1cnJlbnROZXBhbGlEYXRlLmRheSArIDEpO1xyXG5cclxuICAgIC8vIHdlIG5lZWQgc29tZSBlbXB0eSBzcGFjZXMgaW4gcGxhY2Ugc28gdGhhdCB0aGUgZGF0ZXMgYXJlIHNob3duIGluIGNvcnJlY3Qgb3JkZXJcclxuICAgIC8vIGVnIGlmIHRoZSAxc3QgZGF5IHN0YXJ0cyBvbiBtb25kYXkgdGhlbiB3ZSBuZWVkIDEgZW1wdHkgc3BhY2UgZm9yIG5vbiBleGlzdGluZ24gZGF0ZSBvbiBTdW5kYXlcclxuICAgIHRoaXMuY3JlYXRlRW1wdHlTcGFjZXMoKTtcclxuICB9XHJcblxyXG4gIHNldE1vbnRoRGF0YUJlZm9yZShkYXksIGRhdGUpIHtcclxuICAgIGlmIChkYXRlID49IDEpIHtcclxuICAgICAgaWYgKGRheSA8IDApIHtcclxuICAgICAgICBkYXkgPSA2O1xyXG4gICAgICB9XHJcbiAgICAgIHRoaXMuY3VycmVudE1vbnRoRGF0YVtkYXldID0gW2RhdGUsIC4uLnRoaXMuY3VycmVudE1vbnRoRGF0YVtkYXldXTtcclxuICAgICAgdGhpcy5zZXRNb250aERhdGFCZWZvcmUoLS1kYXksIC0tZGF0ZSk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICBzZXRNb250aERhdGFBZnRlcihkYXksIGRhdGUpIHtcclxuICAgIGNvbnN0IG5lcGFsaURhdGUgPSBuZXcgTmVwYWxpRGF0ZUNvbnZlcnRlcihcclxuICAgICAgdGhpcy5jdXJyZW50TmVwYWxpRGF0ZS55ZWFyLFxyXG4gICAgICB0aGlzLmN1cnJlbnROZXBhbGlEYXRlLm1vbnRoLFxyXG4gICAgICBkYXRlXHJcbiAgICApO1xyXG4gICAgLy8gIG9ubHkgYWRkIHRoZSBkYXRhIGlmIHRoZSBjdXJyZW50IG1vbnRoIG1hdGNoZXNcclxuICAgIGlmIChuZXBhbGlEYXRlLmdldE1vbnRoKCkgPT09IHRoaXMuY3VycmVudE5lcGFsaURhdGUubW9udGgpIHtcclxuICAgICAgaWYgKGRheSA+IDYpIHtcclxuICAgICAgICBkYXkgPSAwO1xyXG4gICAgICB9XHJcbiAgICAgIHRoaXMuY3VycmVudE1vbnRoRGF0YVtkYXldID0gWy4uLnRoaXMuY3VycmVudE1vbnRoRGF0YVtkYXldLCBkYXRlXTtcclxuICAgICAgdGhpcy5zZXRNb250aERhdGFBZnRlcigrK2RheSwgKytkYXRlKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIGNyZWF0ZUVtcHR5U3BhY2VzKCkge1xyXG4gICAgLy8gZmlyc3QgZmluZCBvdXQgd2hpY2ggZGF5IGhhcyB0aGUgMXN0XHJcbiAgICAvLyAgaWYgaXRzIGEgU3VuZGF5LCB0aGVuIGRvbid0IGRvIGFueXRoaW5nIGVsc2UgYWRkIDEgc3BhY2Ugb24gZWFjaCBwcmV2aW91cyBkYXlcclxuICAgIGxldCBkYXlJbmRleCA9IDA7XHJcbiAgICBPYmplY3QudmFsdWVzKHRoaXMuY3VycmVudE1vbnRoRGF0YSkuZmluZCgodmFsdWUsIGluZGV4KSA9PiB7XHJcbiAgICAgIGlmICh2YWx1ZS5pbmNsdWRlcygxKSkge1xyXG4gICAgICAgIGRheUluZGV4ID0gaW5kZXg7XHJcbiAgICAgIH1cclxuICAgICAgcmV0dXJuIHZhbHVlLmluY2x1ZGVzKDEpO1xyXG4gICAgfSk7XHJcblxyXG4gICAgaWYgKGRheUluZGV4KSB7XHJcbiAgICAgIGZvciAoZGF5SW5kZXg7IGRheUluZGV4ID4gMDsgZGF5SW5kZXgtLSkge1xyXG4gICAgICAgIGNvbnN0IG1vbnRoRGF0YSA9IHRoaXMuY3VycmVudE1vbnRoRGF0YVtkYXlJbmRleCAtIDFdO1xyXG4gICAgICAgIHRoaXMuY3VycmVudE1vbnRoRGF0YVtkYXlJbmRleCAtIDFdID0gW251bGwsIC4uLm1vbnRoRGF0YV07XHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9XHJcblxyXG4gIHNlbGVjdERhdGUoZGF5OiBudW1iZXIpIHtcclxuICAgIHRoaXMuc2VsZWN0ZWREYXRlID0geyAuLi50aGlzLmN1cnJlbnROZXBhbGlEYXRlLCBkYXkgfTtcclxuICAgIHRoaXMuZm9ybWF0VmFsdWUoKTtcclxuICAgIHRoaXMuY2xvc2UoKTtcclxuICAgIHRoaXMucHJvcGFnYXRlQ2hhbmdlKHRoaXMuc2VsZWN0ZWREYXRlKTtcclxuICB9XHJcblxyXG4gIHNlbGVjdFllYXIoeWVhcjogc3RyaW5nKSB7XHJcbiAgICB0aGlzLmN1cnJlbnROZXBhbGlEYXRlLnllYXIgPSAreWVhcjtcclxuICAgIGNvbnN0IG5ld0RhdGUgPSBuZXcgTmVwYWxpRGF0ZUNvbnZlcnRlcihcclxuICAgICAgdGhpcy5jdXJyZW50TmVwYWxpRGF0ZS55ZWFyLFxyXG4gICAgICB0aGlzLmN1cnJlbnROZXBhbGlEYXRlLm1vbnRoLFxyXG4gICAgICB0aGlzLmN1cnJlbnROZXBhbGlEYXRlLmRheVxyXG4gICAgKTtcclxuICAgIHRoaXMuY3VycmVudERhdGUgPSBuZXdEYXRlLmdldEVuZ2xpc2hEYXRlKCk7XHJcbiAgICB0aGlzLnNldEN1cnJlbnRNb250aERhdGEoKTtcclxuICB9XHJcblxyXG4gIHNlbGVjdE1vbnRoKG1vbnRoOiBzdHJpbmcpIHtcclxuICAgIHRoaXMuY3VycmVudE5lcGFsaURhdGUubW9udGggPSB0aGlzLm1vbnRoc01hcHBpbmdbdGhpcy5sYW5ndWFnZV1bXHJcbiAgICAgIHRoaXMubW9udGhEaXNwbGF5VHlwZVxyXG4gICAgXS5pbmRleE9mKG1vbnRoKTtcclxuICAgIGNvbnN0IG5ld0RhdGUgPSBuZXcgTmVwYWxpRGF0ZUNvbnZlcnRlcihcclxuICAgICAgdGhpcy5jdXJyZW50TmVwYWxpRGF0ZS55ZWFyLFxyXG4gICAgICB0aGlzLmN1cnJlbnROZXBhbGlEYXRlLm1vbnRoLFxyXG4gICAgICB0aGlzLmN1cnJlbnROZXBhbGlEYXRlLmRheVxyXG4gICAgKTtcclxuICAgIHRoaXMuY3VycmVudERhdGUgPSBuZXdEYXRlLmdldEVuZ2xpc2hEYXRlKCk7XHJcbiAgICB0aGlzLnNldEN1cnJlbnRNb250aERhdGEoKTtcclxuICB9XHJcblxyXG4gIHRvZ2dsZU9wZW4oKSB7XHJcbiAgICBpZiAoIXRoaXMuYWx3YXlzVmlzaWJsZSkge1xyXG4gICAgICB0aGlzLmlzT3BlbiA9ICF0aGlzLmlzT3BlbjtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIG9wZW4oKSB7XHJcbiAgICB0aGlzLmlzT3BlbiA9IHRydWU7XHJcbiAgfVxyXG5cclxuICBjbG9zZSgpIHtcclxuICAgIHRoaXMuaXNPcGVuID0gZmFsc2U7XHJcbiAgICB0aGlzLnNldEN1cnJlbnREYXRlKCk7XHJcbiAgfVxyXG59XHJcbiJdfQ==