@eduardsson/ngx-daterange
Version:
Date-Range Selector for Angular
325 lines • 50.8 kB
JavaScript
import { Component, Input, Output, EventEmitter, HostListener, ViewEncapsulation } from "@angular/core";
import { FormGroup, FormControl } from "@angular/forms";
import { defaultDateRangePickerOptions } from "../../constants";
import * as momentNs from "moment";
const moment = momentNs;
let instanceCount = 0;
export class DateRangePickerComponent {
constructor() {
this.options = defaultDateRangePickerOptions;
this.controlName = "dateRange";
this.instanceId = null;
this.fromDate = null;
this.toDate = null;
this.rangeSelected = new EventEmitter();
this.range = "";
this.showCalendars = false;
if (!this.instanceId) {
// assign auto-id
this.instanceId = `dateRangePicker-${instanceCount++}`;
}
}
get enableApplyButton() {
return (!this.options.autoApply &&
!this.options.singleCalendar &&
this.fromDate !== null &&
this.toDate !== null);
}
handleClick(event) {
const target = event.target;
// close the DatePicker if clicking outside is not allowed
if (!this.options.clickOutsideAllowed) {
const containerElementClassRoot = "dateRangePicker";
let targetPathClassNames = [""];
if (event["path"]) {
targetPathClassNames = event["path"].map(obj => obj.className || "");
}
else {
try {
targetPathClassNames = event
.composedPath()
.map(item => item.className || "");
}
catch (error) {
console.warn("Edge sux");
}
}
const targetExistsInPath = targetPathClassNames.some(className => {
if (typeof className === "string") {
return className && className.includes(containerElementClassRoot);
}
return false;
});
if (!targetExistsInPath) {
this.toggleCalendarVisibility(false);
}
}
// Close the DatePicker if the target input was clicked
if (target.id === this.instanceId) {
this.toggleCalendarVisibility(!this.showCalendars);
}
}
ngOnInit() {
// ensure dates in options are valid
this.validateOptionDates();
// ensure input dates are within the min/max dates in options
this.validateInputDates();
if (this.options.preDefinedRanges &&
this.options.preDefinedRanges.length > 0) {
this.defaultRanges = this.validateAndAssignPredefinedRanges(this.options.preDefinedRanges);
}
// assign values not present in options with default values
const optionsKeys = Object.keys(this.options);
const defaultValuesKeys = Object.keys(defaultDateRangePickerOptions);
defaultValuesKeys.forEach((key) => {
if (!optionsKeys.includes(key)) {
this.options[key] = defaultDateRangePickerOptions[key];
}
});
// update calendar grid
this.updateCalendar();
// create parent form group if it doesn't exist
if (!this.parentFormGroup) {
this.parentFormGroup = new FormGroup({});
}
// add form control to parent form group
const value = this.formatRangeAsString();
const control = new FormControl(value, this.options.validators);
if (this.options.disabled) {
control.disable();
}
this.parentFormGroup.addControl(this.controlName, control);
// set value of control
this.setRange();
}
validateInputDates() {
if (this.fromDate &&
this.options.minDate &&
this.fromDate.isBefore(this.options.minDate, "date")) {
throw new RangeError("@Input fromDate is before the specified minDate in options");
}
if (this.toDate &&
this.options.maxDate &&
this.toDate.isAfter(this.options.maxDate, "date")) {
throw new RangeError("@Input toDate is after the specified maxDate in options");
}
}
validateOptionDates() {
// validate maxDate isn't before minDate or vice versa
if (this.options) {
if (this.options.minDate && this.options.maxDate) {
if (this.options.minDate.isAfter(this.options.maxDate, "date")) {
throw new RangeError("minDate specified in options is after the maxDate");
}
else if (this.options.maxDate.isBefore(this.options.minDate, "date")) {
throw new RangeError("maxDate specified in options is before the minDate");
}
}
}
}
// assists CSS to fix small positioning bug with From:/To: date text
checkChrome() {
return window["chrome"] ? "is-chrome" : "";
}
toggleCalendarVisibility(value) {
this.showCalendars = value !== null ? value : !this.showCalendars;
}
setFromToMonthYear(fromDate, toDate) {
const tempFromDate = fromDate || this.fromDate || this.options.startingFromDate || moment();
const tempToDate = toDate || this.toDate || this.options.startingToDate || moment();
this.fromMonth = tempFromDate.get("month");
this.fromYear = tempFromDate.get("year");
this.toMonth = tempToDate.get("month");
this.toYear = tempToDate.get("year");
}
updateCalendar() {
// get month and year to show calendar
this.setFromToMonthYear();
this.setRange();
}
// update from/to based on selection
dateChanged(changedData) {
const value = changedData.day;
const isLeft = changedData.isLeft;
if (isLeft) {
this.fromDate = value;
if (this.fromDate.isAfter(this.toDate, "date")) {
this.toDate = this.fromDate.clone();
}
}
else {
this.toDate = value;
if (this.toDate.isBefore(this.fromDate, "date")) {
this.fromDate = this.toDate.clone();
}
}
this.setFromToMonthYear(this.fromDate, this.toDate);
if (this.isAutoApply() &&
(this.options.singleCalendar || !isLeft) &&
this.fromDate) {
this.toggleCalendarVisibility(false);
this.setRange();
this.emitRangeSelected();
}
}
emitRangeSelected(data) {
if (!data) {
data = this.options.singleCalendar
? { start: this.fromDate }
: { start: this.fromDate, end: this.toDate };
}
this.rangeSelected.emit(data);
}
getMoment(value) {
return moment(value, this.options.format);
}
formatRangeAsString() {
let range = "";
if (this.options.singleCalendar && this.fromDate) {
range = this.fromDate.format(this.options.format);
}
else if (!this.options.singleCalendar && this.fromDate && this.toDate) {
range = `${this.fromDate.format(this.options.format)} - ${this.toDate.format(this.options.format)}`;
}
return range;
}
setRange() {
this.range = this.formatRangeAsString();
if (this.parentFormGroup) {
const control = this.parentFormGroup.get(this.controlName);
if (control) {
control.setValue(this.range);
control.updateValueAndValidity();
}
}
}
setDateFromInput(event, isLeft = false) {
const target = event.target;
try {
if (target.value) {
const day = this.getMoment(target.value);
if (!day.isBefore(this.options.minDate) &&
!day.isAfter(this.options.maxDate)) {
if (isLeft && !this.fromDate) {
this.fromDate = day;
}
if (!isLeft && !this.toDate) {
this.toDate = day;
}
this.dateChanged({
day,
isLeft
});
this.setFromToMonthYear(this.fromDate, this.toDate);
}
else {
// assume nothing - reset values
this.fromDate = null;
this.toDate = null;
target.value = "";
target.focus();
}
}
this.emitRangeSelected();
}
catch (e) {
console.error(e);
}
}
monthChanged(data) {
let temp;
if (data.isLeft) {
temp = moment([this.fromYear, this.fromMonth]).add(data.value, "months");
this.fromMonth = temp.get("month");
this.fromYear = temp.get("year");
}
else {
temp = moment([this.toYear, this.toMonth]).add(data.value, "months");
this.toMonth = temp.get("month");
this.toYear = temp.get("year");
}
}
yearChanged(data) {
let temp;
if (data.isLeft) {
temp = moment([this.fromYear, this.fromMonth]).add(data.value, "year");
this.fromMonth = temp.get("month");
this.fromYear = temp.get("year");
}
else {
temp = moment([this.toYear, this.toMonth]).add(data.value, "year");
this.toMonth = temp.get("month");
this.toYear = temp.get("year");
}
}
close(event) {
this.toggleCalendarVisibility(false);
event.stopPropagation();
}
reset(event) {
this.fromDate = null;
this.toDate = null;
this.setRange();
event.stopPropagation();
}
apply(event) {
this.toggleCalendarVisibility(false);
this.setRange();
this.emitRangeSelected();
event.stopPropagation();
}
applyPredefinedRange(event, definedDateRange) {
// adjust to/from month/year so calendar months and years match range
this.setFromToMonthYear(definedDateRange.value.start, definedDateRange.value.end);
this.fromDate = definedDateRange.value.start;
this.toDate = definedDateRange.value.end;
if (this.options.autoApply) {
this.apply(event);
}
}
validateAndAssignPredefinedRanges(ranges) {
return ranges.filter(range => {
if (range.value.start.isAfter(range.value.end, "date")) {
throw new RangeError(`Pre-defined range "${range.name}" start date cannot be after the end date for the range.`);
}
if (this.options.minDate &&
range.value.start.isBefore(this.options.minDate)) {
throw new RangeError(`Pre-defined range "${range.name}" start date is before the specified minDate in your options.`);
}
if (this.options.maxDate &&
range.value.end.isAfter(this.options.maxDate)) {
throw new RangeError(`Pre-defined range "${range.name}" end date is after the specified maxDate in your options.`);
}
// add range to ranges
return true;
});
}
isAutoApply() {
if (this.options.singleCalendar) {
return true;
}
else {
return this.options.autoApply;
}
}
}
DateRangePickerComponent.decorators = [
{ type: Component, args: [{
encapsulation: ViewEncapsulation.None,
selector: "date-range-picker",
template: "<div class=\"dateRangePicker-wrapper\" *ngIf=\"parentFormGroup\">\n <div #content>\n <ng-content></ng-content>\n </div>\n <div class=\"form-group\" [formGroup]=\"parentFormGroup\">\n <ng-container *ngIf=\"content.childNodes.length === 0\">\n <label [attr.for]=\"instanceId\">{{ options.labelText }}</label>\n <input [attr.id]=\"instanceId\" class=\"form-control\" type=\"text\" [formControlName]=\"controlName\">\n </ng-container>\n\n <div [ngClass]=\"{'dateRangePicker': true, 'invisible': !showCalendars, 'dateRangePicker-single': options.singleCalendar, 'is-chrome': checkChrome(), 'open-left': options.position === 'left', 'open-right': options.position === 'right' }\">\n <div class=\"container-fluid\">\n <div class=\"row\">\n <div class=\"col\">\n\n <div class=\"row form-inputs mb-0\" *ngIf=\"!options.singleCalendar\">\n\n <div class=\"col\">\n <div class=\"\" *ngIf=\"options.icons !== 'default'\">\n <div [ngClass]=\"{ 'd-flex align-items-center input-with-icon': true, 'material': options.icons === 'material'}\">\n <i *ngIf=\"options.icons === 'material'\" class=\"material-icons\">event</i>\n <i *ngIf=\"options.icons === 'font-awesome'\" class=\"far fa-calendar-alt\"></i>\n <span *ngIf=\"fromDate\">From: </span>\n <input class=\"form-control\" [ngModel]=\"fromDate | formatMomentDate: options.format\" (blur)=\"setDateFromInput($event, true)\" type=\"text\" name=\"daterangepicker_start\" [ngModelOptions]=\"{ standalone: true }\" placeholder=\"Select From Date\" />\n </div>\n </div>\n\n <input *ngIf=\"options.icons === 'default'\" class=\"form-control\" [ngModel]=\"fromDate | formatMomentDate: options.format\" (blur)=\"setDateFromInput($event, true)\" type=\"text\" name=\"daterangepicker_start\" [ngModelOptions]=\"{standalone: true}\" placeholder=\"Select From Date\" />\n </div>\n\n <div class=\"col\">\n <div class=\"\" *ngIf=\"options.icons !== 'default'\">\n <div [ngClass]=\"{ 'd-flex align-items-center input-with-icon': true, 'material': options.icons === 'material'}\">\n <i *ngIf=\"options.icons === 'material'\" class=\"material-icons\">event</i>\n <i *ngIf=\"options.icons === 'font-awesome'\" class=\"far fa-calendar-alt\"></i>\n <span *ngIf=\"toDate\">To: </span>\n <input class=\"form-control\" [ngModel]=\"toDate | formatMomentDate: options.format\" (blur)=\"setDateFromInput($event)\" type=\"text\" name=\"daterangepicker_end\" [ngModelOptions]=\"{ standalone: true }\" placeholder=\"Select To Date\" />\n </div>\n </div>\n\n <input *ngIf=\"options.icons === 'default'\" class=\"form-control\" [ngModel]=\"toDate | formatMomentDate: options.format\" (blur)=\"setDateFromInput($event)\" name=\"daterangepicker_end\" [ngModelOptions]=\"{standalone: true}\" />\n </div>\n\n </div>\n\n <div class=\"row row-calendars\">\n <div class=\"col\">\n <calendar [ngClass]=\"{ 'calendar': true, 'calendar-single': options.singleCalendar }\" [isLeft]=\"true\" [month]=\"fromMonth\" [year]=\"fromYear\" (monthChanged)=monthChanged($event)\n (yearChanged)=\"yearChanged($event)\" (dateChanged)=\"dateChanged($event)\" [format]=\"options.format\" [selectedFromDate]=\"fromDate\"\n [selectedToDate]=\"toDate\" [minDate]=\"options.minDate\" [maxDate]=\"options.maxDate\" [singleCalendar]=\"options.singleCalendar\" [icons]=\"options.icons\"></calendar>\n </div>\n\n <div class=\"col\" *ngIf=\"!options.singleCalendar\">\n <calendar class=\"calendar\" [month]=\"toMonth\" [year]=\"toYear\" [format]=\"options.format\" (dateChanged)=\"dateChanged($event)\" (monthChanged)=\"monthChanged($event)\" (yearChanged)=yearChanged($event) [selectedFromDate]=\"fromDate\" [selectedToDate]=\"toDate\" [minDate]=\"options.minDate\" [maxDate]=\"options.maxDate\" [icons]=\"options.icons\"></calendar>\n </div>\n </div>\n </div>\n </div>\n\n <div class=\"row text-center my-3\" *ngIf=\"!options.singleCalendar\">\n <div class=\"col\">\n <div class=\"row mb-2\" *ngIf=\"options.preDefinedRanges && options.preDefinedRanges.length > 0\">\n <div class=\"col\">\n <button type=\"button\" *ngFor=\"let range of options.preDefinedRanges\" class=\"btn btn-link\" (click)=\"applyPredefinedRange($event, range)\">{{ range.name }}</button>\n </div>\n </div>\n <button type=\"button\" class=\"btn btn-outline-secondary btn-sm\" (click)=\"close($event)\">Close</button>\n <button type=\"button\" class=\"btn btn-outline-secondary btn-sm ml-3\" (click)=\"reset($event)\" *ngIf=\"this.range\">Reset</button>\n <button type=\"button\" class=\"btn btn-primary btn-sm ml-3\" [disabled]=\"!enableApplyButton\" (click)=\"apply($event)\" *ngIf=\"!isAutoApply()\">Apply</button>\n </div>\n </div>\n\n </div>\n </div>\n\n </div>\n</div>\n",
styles: [".dateRangePicker-wrapper{position:relative;border:none}.dateRangePicker-wrapper .dateRangePicker{background:#fff;border-radius:9px;box-shadow:0 0 10px #818b9080;font-family:\"Roboto\",Helvetica,Arial,sans-serif;overflow:visible;position:absolute;top:88px;z-index:3000}.dateRangePicker-wrapper .dateRangePicker.dateRangePicker-single{min-width:300px}@media screen and (min-width: 576px){.dateRangePicker-wrapper .dateRangePicker{min-width:600px}}.dateRangePicker-wrapper .dateRangePicker:before,.dateRangePicker-wrapper .dateRangePicker:after{content:\"\";height:0px;width:0px;border-bottom:10px solid #6E777C;border-left:10px solid transparent;border-right:10px solid transparent;position:absolute;top:-10px}.dateRangePicker-wrapper .dateRangePicker.open-left{left:0}.dateRangePicker-wrapper .dateRangePicker.open-left:before{left:10px}.dateRangePicker-wrapper .dateRangePicker.open-left:after{display:none}.dateRangePicker-wrapper .dateRangePicker.open-right{right:0}.dateRangePicker-wrapper .dateRangePicker.open-right:before{display:none}.dateRangePicker-wrapper .dateRangePicker.open-right:after{right:10px}.dateRangePicker-wrapper .dateRangePicker.is-chrome .form-inputs .input-with-icon span{position:relative;top:1px}.dateRangePicker-wrapper .dateRangePicker .btn,.dateRangePicker-wrapper .dateRangePicker .btn.btn-link{min-width:auto;width:auto}.dateRangePicker-wrapper .dateRangePicker .form-inputs{background-color:#6e777c;border-top-left-radius:8px;border-top-right-radius:8px;color:#fff;font-size:16px}.dateRangePicker-wrapper .dateRangePicker .form-inputs>.col{padding:.5rem 15px;min-width:270px}.dateRangePicker-wrapper .dateRangePicker .form-inputs .input-with-icon{display:flex;align-content:flex-start;align-items:center!important}.dateRangePicker-wrapper .dateRangePicker .form-inputs .input-with-icon i{color:#fff;margin-right:.5rem}.dateRangePicker-wrapper .dateRangePicker .form-inputs .input-with-icon i.material-icons{top:0}.dateRangePicker-wrapper .dateRangePicker .form-inputs .input-with-icon span{line-height:1}.dateRangePicker-wrapper .dateRangePicker .form-inputs .form-control{background:none;border:0 none;color:#fff;display:inline-block;padding:0;width:150px}.dateRangePicker-wrapper .dateRangePicker .form-inputs .form-control::-moz-placeholder{color:#fff}.dateRangePicker-wrapper .dateRangePicker .form-inputs .form-control::placeholder{color:#fff}.dateRangePicker-wrapper .dateRangePicker .form-inputs>div:nth-child(2),.dateRangePicker-wrapper .dateRangePicker .row-calendars>div:nth-child(2){border-left:solid 2px #C6D1D6}.dateRangePicker-wrapper i.material-icons{position:relative;top:2px}\n"]
},] }
];
DateRangePickerComponent.ctorParameters = () => [];
DateRangePickerComponent.propDecorators = {
options: [{ type: Input }],
controlName: [{ type: Input }],
instanceId: [{ type: Input }],
parentFormGroup: [{ type: Input }],
fromDate: [{ type: Input }],
toDate: [{ type: Input }],
rangeSelected: [{ type: Output }],
handleClick: [{ type: HostListener, args: ["document:click", ["$event"],] }]
};
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGF0ZS1yYW5nZS1waWNrZXIuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vc3JjL21vZHVsZXMvbmd4LWRhdGVyYW5nZS9zcmMvY29tcG9uZW50cy9kYXRlcGlja2VyL2RhdGUtcmFuZ2UtcGlja2VyLmNvbXBvbmVudC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQ0wsU0FBUyxFQUNULEtBQUssRUFDTCxNQUFNLEVBQ04sWUFBWSxFQUNaLFlBQVksRUFFWixpQkFBaUIsRUFDbEIsTUFBTSxlQUFlLENBQUM7QUFDdkIsT0FBTyxFQUFFLFNBQVMsRUFBRSxXQUFXLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUV4RCxPQUFPLEVBQUUsNkJBQTZCLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQztBQVFoRSxPQUFPLEtBQUssUUFBUSxNQUFNLFFBQVEsQ0FBQztBQUNuQyxNQUFNLE1BQU0sR0FBRyxRQUFRLENBQUM7QUFFeEIsSUFBSSxhQUFhLEdBQUcsQ0FBQyxDQUFDO0FBUXRCLE1BQU0sT0FBTyx3QkFBd0I7SUE4RW5DO1FBNUVBLFlBQU8sR0FBNEIsNkJBQTZCLENBQUM7UUFHakUsZ0JBQVcsR0FBVyxXQUFXLENBQUM7UUFHbEMsZUFBVSxHQUFXLElBQUksQ0FBQztRQU0xQixhQUFRLEdBQW9CLElBQUksQ0FBQztRQUdqQyxXQUFNLEdBQW9CLElBQUksQ0FBQztRQUcvQixrQkFBYSxHQUFHLElBQUksWUFBWSxFQUFjLENBQUM7UUFPL0MsVUFBSyxHQUFHLEVBQUUsQ0FBQztRQUNYLGtCQUFhLEdBQUcsS0FBSyxDQUFDO1FBbURwQixJQUFJLENBQUMsSUFBSSxDQUFDLFVBQVUsRUFBRTtZQUNwQixpQkFBaUI7WUFDakIsSUFBSSxDQUFDLFVBQVUsR0FBRyxtQkFBbUIsYUFBYSxFQUFFLEVBQUUsQ0FBQztTQUN4RDtJQUNILENBQUM7SUFyREQsSUFBSSxpQkFBaUI7UUFDbkIsT0FBTyxDQUNM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ICBJbnB1dCxcbiAgT3V0cHV0LFxuICBFdmVudEVtaXR0ZXIsXG4gIEhvc3RMaXN0ZW5lcixcbiAgT25Jbml0LFxuICBWaWV3RW5jYXBzdWxhdGlvblxufSBmcm9tIFwiQGFuZ3VsYXIvY29yZVwiO1xuaW1wb3J0IHsgRm9ybUdyb3VwLCBGb3JtQ29udHJvbCB9IGZyb20gXCJAYW5ndWxhci9mb3Jtc1wiO1xuXG5pbXBvcnQgeyBkZWZhdWx0RGF0ZVJhbmdlUGlja2VyT3B0aW9ucyB9IGZyb20gXCIuLi8uLi9jb25zdGFudHNcIjtcbmltcG9ydCB7XG4gIElEYXRlUmFuZ2UsXG4gIElEYXRlUmFuZ2VQaWNrZXJPcHRpb25zLFxuICBJRGVmaW5lZERhdGVSYW5nZSxcbiAgSUNoYW5nZWREYXRhXG59IGZyb20gXCIuLi8uLi9pbnRlcmZhY2VzXCI7XG5cbmltcG9ydCAqIGFzIG1vbWVudE5zIGZyb20gXCJtb21lbnRcIjtcbmNvbnN0IG1vbWVudCA9IG1vbWVudE5zO1xuXG5sZXQgaW5zdGFuY2VDb3VudCA9IDA7XG5cbkBDb21wb25lbnQoe1xuICBlbmNhcHN1bGF0aW9uOiBWaWV3RW5jYXBzdWxhdGlvbi5Ob25lLFxuICBzZWxlY3RvcjogXCJkYXRlLXJhbmdlLXBpY2tlclwiLFxuICBzdHlsZVVybHM6IFtcIi4vZGF0ZS1yYW5nZS1waWNrZXIuY29tcG9uZW50LnNjc3NcIl0sXG4gIHRlbXBsYXRlVXJsOiBcIi4vZGF0ZS1yYW5nZS1waWNrZXIuY29tcG9uZW50Lmh0bWxcIlxufSlcbmV4cG9ydCBjbGFzcyBEYXRlUmFuZ2VQaWNrZXJDb21wb25lbnQgaW1wbGVtZW50cyBPbkluaXQge1xuICBASW5wdXQoKVxuICBvcHRpb25zOiBJRGF0ZVJhbmdlUGlja2VyT3B0aW9ucyA9IGRlZmF1bHREYXRlUmFuZ2VQaWNrZXJPcHRpb25zO1xuXG4gIEBJbnB1dCgpXG4gIGNvbnRyb2xOYW1lOiBzdHJpbmcgPSBcImRhdGVSYW5nZVwiO1xuXG4gIEBJbnB1dCgpXG4gIGluc3RhbmNlSWQ6IHN0cmluZyA9IG51bGw7XG5cbiAgQElucHV0KClcbiAgcGFyZW50Rm9ybUdyb3VwOiBGb3JtR3JvdXA7XG5cbiAgQElucHV0KClcbiAgZnJvbURhdGU6IG1vbWVudE5zLk1vbWVudCA9IG51bGw7XG5cbiAgQElucHV0KClcbiAgdG9EYXRlOiBtb21lbnROcy5Nb21lbnQgPSBudWxsO1xuXG4gIEBPdXRwdXQoKVxuICByYW5nZVNlbGVjdGVkID0gbmV3IEV2ZW50RW1pdHRlcjxJRGF0ZVJhbmdlPigpO1xuXG4gIGRlZmF1bHRSYW5nZXM6IElEZWZpbmVkRGF0ZVJhbmdlW107XG4gIGZyb21Nb250aDogbnVtYmVyO1xuICBmcm9tWWVhcjogbnVtYmVyO1xuICB0b01vbnRoOiBudW1iZXI7XG4gIHRvWWVhcjogbnVtYmVyO1xuICByYW5nZSA9IFwiXCI7XG4gIHNob3dDYWxlbmRhcnMgPSBmYWxzZTtcblxuICBnZXQgZW5hYmxlQXBwbHlCdXR0b24oKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIChcbiAgICAgICF0aGlzLm9wdGlvbnMuYXV0b0FwcGx5ICYmXG4gICAgICAhdGhpcy5vcHRpb25zLnNpbmdsZUNhbGVuZGFyICYmXG4gICAgICB0aGlzLmZyb21EYXRlICE9PSBudWxsICYmXG4gICAgICB0aGlzLnRvRGF0ZSAhPT0gbnVsbFxuICAgICk7XG4gIH1cblxuICBASG9zdExpc3RlbmVyKFwiZG9jdW1lbnQ6Y2xpY2tcIiwgW1wiJGV2ZW50XCJdKVxuICBoYW5kbGVDbGljayhldmVudDogRXZlbnQpIHtcbiAgICBjb25zdCB0YXJnZXQgPSBldmVudC50YXJnZXQgYXMgSFRNTElucHV0RWxlbWVudDtcblxuICAgIC8vIGNsb3NlIHRoZSBEYXRlUGlja2VyIGlmIGNsaWNraW5nIG91dHNpZGUgaXMgbm90IGFsbG93ZWRcbiAgICBpZiAoIXRoaXMub3B0aW9ucy5jbGlja091dHNpZGVBbGxvd2VkKSB7XG4gICAgICBjb25zdCBjb250YWluZXJFbGVtZW50Q2xhc3NSb290ID0gXCJkYXRlUmFuZ2VQaWNrZXJcIjtcbiAgICAgIGxldCB0YXJnZXRQYXRoQ2xhc3NOYW1lczogc3RyaW5nW10gPSBbXCJcIl07XG4gICAgICBpZiAoZXZlbnRbXCJwYXRoXCJdKSB7XG4gICAgICAgIHRhcmdldFBhdGhDbGFzc05hbWVzID0gZXZlbnRbXCJwYXRoXCJdLm1hcChvYmogPT4gb2JqLmNsYXNzTmFtZSB8fCBcIlwiKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgdGFyZ2V0UGF0aENsYXNzTmFtZXMgPSBldmVudFxuICAgICAgICAgICAgLmNvbXBvc2VkUGF0aCgpXG4gICAgICAgICAgICAubWFwKGl0ZW0gPT4gKDxFbGVtZW50Pml0ZW0pLmNsYXNzTmFtZSB8fCBcIlwiKTtcbiAgICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgICBjb25zb2xlLndhcm4oXCJFZGdlIHN1eFwiKTtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICBjb25zdCB0YXJnZXRFeGlzdHNJblBhdGggPSB0YXJnZXRQYXRoQ2xhc3NOYW1lcy5zb21lKGNsYXNzTmFtZSA9PiB7XG4gICAgICAgIGlmICh0eXBlb2YgY2xhc3NOYW1lID09PSBcInN0cmluZ1wiKSB7XG4gICAgICAgICAgcmV0dXJuIGNsYXNzTmFtZSAmJiBjbGFzc05hbWUuaW5jbHVkZXMoY29udGFpbmVyRWxlbWVudENsYXNzUm9vdCk7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICB9KTtcblxuICAgICAgaWYgKCF0YXJnZXRFeGlzdHNJblBhdGgpIHtcbiAgICAgICAgdGhpcy50b2dnbGVDYWxlbmRhclZpc2liaWxpdHkoZmFsc2UpO1xuICAgICAgfVxuICAgIH1cblxuICAgIC8vIENsb3NlIHRoZSBEYXRlUGlja2VyIGlmIHRoZSB0YXJnZXQgaW5wdXQgd2FzIGNsaWNrZWRcbiAgICBpZiAodGFyZ2V0LmlkID09PSB0aGlzLmluc3RhbmNlSWQpIHtcbiAgICAgIHRoaXMudG9nZ2xlQ2FsZW5kYXJWaXNpYmlsaXR5KCF0aGlzLnNob3dDYWxlbmRhcnMpO1xuICAgIH1cbiAgfVxuXG4gIGNvbnN0cnVjdG9yKCkge1xuICAgIGlmICghdGhpcy5pbnN0YW5jZUlkKSB7XG4gICAgICAvLyBhc3NpZ24gYXV0by1pZFxuICAgICAgdGhpcy5pbnN0YW5jZUlkID0gYGRhdGVSYW5nZVBpY2tlci0ke2luc3RhbmNlQ291bnQrK31gO1xuICAgIH1cbiAgfVxuXG4gIG5nT25Jbml0KCk6IHZvaWQge1xuICAgIC8vIGVuc3VyZSBkYXRlcyBpbiBvcHRpb25zIGFyZSB2YWxpZFxuICAgIHRoaXMudmFsaWRhdGVPcHRpb25EYXRlcygpO1xuXG4gICAgLy8gZW5zdXJlIGlucHV0IGRhdGVzIGFyZSB3aXRoaW4gdGhlIG1pbi9tYXggZGF0ZXMgaW4gb3B0aW9uc1xuICAgIHRoaXMudmFsaWRhdGVJbnB1dERhdGVzKCk7XG5cbiAgICBpZiAoXG4gICAgICB0aGlzLm9wdGlvbnMucHJlRGVmaW5lZFJhbmdlcyAmJlxuICAgICAgdGhpcy5vcHRpb25zLnByZURlZmluZWRSYW5nZXMubGVuZ3RoID4gMFxuICAgICkge1xuICAgICAgdGhpcy5kZWZhdWx0UmFuZ2VzID0gdGhpcy52YWxpZGF0ZUFuZEFzc2lnblByZWRlZmluZWRSYW5nZXMoXG4gICAgICAgIHRoaXMub3B0aW9ucy5wcmVEZWZpbmVkUmFuZ2VzXG4gICAgICApO1xuICAgIH1cblxuICAgIC8vIGFzc2lnbiB2YWx1ZXMgbm90IHByZXNlbnQgaW4gb3B0aW9ucyB3aXRoIGRlZmF1bHQgdmFsdWVzXG4gICAgY29uc3Qgb3B0aW9uc0tleXMgPSBPYmplY3Qua2V5cyh0aGlzLm9wdGlvbnMpO1xuICAgIGNvbnN0IGRlZmF1bHRWYWx1ZXNLZXlzID0gT2JqZWN0LmtleXMoZGVmYXVsdERhdGVSYW5nZVBpY2tlck9wdGlvbnMpO1xuXG4gICAgZGVmYXVsdFZhbHVlc0tleXMuZm9yRWFjaCgoa2V5OiBzdHJpbmcpID0+IHtcbiAgICAgIGlmICghb3B0aW9uc0tleXMuaW5jbHVkZXMoa2V5KSkge1xuICAgICAgICB0aGlzLm9wdGlvbnNba2V5XSA9IGRlZmF1bHREYXRlUmFuZ2VQaWNrZXJPcHRpb25zW2tleV07XG4gICAgICB9XG4gICAgfSk7XG5cbiAgICAvLyB1cGRhdGUgY2FsZW5kYXIgZ3JpZFxuICAgIHRoaXMudXBkYXRlQ2FsZW5kYXIoKTtcblxuICAgIC8vIGNyZWF0ZSBwYXJlbnQgZm9ybSBncm91cCBpZiBpdCBkb2Vzbid0IGV4aXN0XG4gICAgaWYgKCF0aGlzLnBhcmVudEZvcm1Hcm91cCkge1xuICAgICAgdGhpcy5wYXJlbnRGb3JtR3JvdXAgPSBuZXcgRm9ybUdyb3VwKHt9KTtcbiAgICB9XG5cbiAgICAvLyBhZGQgZm9ybSBjb250cm9sIHRvIHBhcmVudCBmb3JtIGdyb3VwXG4gICAgY29uc3QgdmFsdWUgPSB0aGlzLmZvcm1hdFJhbmdlQXNTdHJpbmcoKTtcbiAgICBjb25zdCBjb250cm9sID0gbmV3IEZvcm1Db250cm9sKHZhbHVlLCB0aGlzLm9wdGlvbnMudmFsaWRhdG9ycyk7XG5cbiAgICBpZiAodGhpcy5vcHRpb25zLmRpc2FibGVkKSB7XG4gICAgICBjb250cm9sLmRpc2FibGUoKTtcbiAgICB9XG5cbiAgICB0aGlzLnBhcmVudEZvcm1Hcm91cC5hZGRDb250cm9sKHRoaXMuY29udHJvbE5hbWUsIGNvbnRyb2wpO1xuXG4gICAgLy8gc2V0IHZhbHVlIG9mIGNvbnRyb2xcbiAgICB0aGlzLnNldFJhbmdlKCk7XG4gIH1cblxuICB2YWxpZGF0ZUlucHV0RGF0ZXMoKTogdm9pZCB7XG4gICAgaWYgKFxuICAgICAgdGhpcy5mcm9tRGF0ZSAmJlxuICAgICAgdGhpcy5vcHRpb25zLm1pbkRhdGUgJiZcbiAgICAgIHRoaXMuZnJvbURhdGUuaXNCZWZvcmUodGhpcy5vcHRpb25zLm1pbkRhdGUsIFwiZGF0ZVwiKVxuICAgICkge1xuICAgICAgdGhyb3cgbmV3IFJhbmdlRXJyb3IoXG4gICAgICAgIFwiQElucHV0IGZyb21EYXRlIGlzIGJlZm9yZSB0aGUgc3BlY2lmaWVkIG1pbkRhdGUgaW4gb3B0aW9uc1wiXG4gICAgICApO1xuICAgIH1cblxuICAgIGlmIChcbiAgICAgIHRoaXMudG9EYXRlICYmXG4gICAgICB0aGlzLm9wdGlvbnMubWF4RGF0ZSAmJlxuICAgICAgdGhpcy50b0RhdGUuaXNBZnRlcih0aGlzLm9wdGlvbnMubWF4RGF0ZSwgXCJkYXRlXCIpXG4gICAgKSB7XG4gICAgICB0aHJvdyBuZXcgUmFuZ2VFcnJvcihcbiAgICAgICAgXCJASW5wdXQgdG9EYXRlIGlzIGFmdGVyIHRoZSBzcGVjaWZpZWQgbWF4RGF0ZSBpbiBvcHRpb25zXCJcbiAgICAgICk7XG4gICAgfVxuICB9XG5cbiAgdmFsaWRhdGVPcHRpb25EYXRlcygpOiB2b2lkIHtcbiAgICAvLyB2YWxpZGF0ZSBtYXhEYXRlIGlzbid0IGJlZm9yZSBtaW5EYXRlIG9yIHZpY2UgdmVyc2FcbiAgICBpZiAodGhpcy5vcHRpb25zKSB7XG4gICAgICBpZiAodGhpcy5vcHRpb25zLm1pbkRhdGUgJiYgdGhpcy5vcHRpb25zLm1heERhdGUpIHtcbiAgICAgICAgaWYgKHRoaXMub3B0aW9ucy5taW5EYXRlLmlzQWZ0ZXIodGhpcy5vcHRpb25zLm1heERhdGUsIFwiZGF0ZVwiKSkge1xuICAgICAgICAgIHRocm93IG5ldyBSYW5nZUVycm9yKFxuICAgICAgICAgICAgXCJtaW5EYXRlIHNwZWNpZmllZCBpbiBvcHRpb25zIGlzIGFmdGVyIHRoZSBtYXhEYXRlXCJcbiAgICAgICAgICApO1xuICAgICAgICB9IGVsc2UgaWYgKFxuICAgICAgICAgIHRoaXMub3B0aW9ucy5tYXhEYXRlLmlzQmVmb3JlKHRoaXMub3B0aW9ucy5taW5EYXRlLCBcImRhdGVcIilcbiAgICAgICAgKSB7XG4gICAgICAgICAgdGhyb3cgbmV3IFJhbmdlRXJyb3IoXG4gICAgICAgICAgICBcIm1heERhdGUgc3BlY2lmaWVkIGluIG9wdGlvbnMgaXMgYmVmb3JlIHRoZSBtaW5EYXRlXCJcbiAgICAgICAgICApO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgLy8gYXNzaXN0cyBDU1MgdG8gZml4IHNtYWxsIHBvc2l0aW9uaW5nIGJ1ZyB3aXRoIEZyb206L1RvOiBkYXRlIHRleHRcbiAgY2hlY2tDaHJvbWUoKTogc3RyaW5nIHtcbiAgICByZXR1cm4gd2luZG93W1wiY2hyb21lXCJdID8gXCJpcy1jaHJvbWVcIiA6IFwiXCI7XG4gIH1cblxuICB0b2dnbGVDYWxlbmRhclZpc2liaWxpdHkodmFsdWU/OiBib29sZWFuKTogdm9pZCB7XG4gICAgdGhpcy5zaG93Q2FsZW5kYXJzID0gdmFsdWUgIT09IG51bGwgPyB2YWx1ZSA6ICF0aGlzLnNob3dDYWxlbmRhcnM7XG4gIH1cblxuICBzZXRGcm9tVG9Nb250aFllYXIoXG4gICAgZnJvbURhdGU/OiBtb21lbnROcy5Nb21lbnQsXG4gICAgdG9EYXRlPzogbW9tZW50TnMuTW9tZW50XG4gICk6IHZvaWQge1xuICAgIGNvbnN0IHRlbXBGcm9tRGF0ZSA9XG4gICAgICBmcm9tRGF0ZSB8fCB0aGlzLmZyb21EYXRlIHx8IHRoaXMub3B0aW9ucy5zdGFydGluZ0Zyb21EYXRlIHx8IG1vbWVudCgpO1xuICAgIGNvbnN0IHRlbXBUb0RhdGUgPVxuICAgICAgdG9EYXRlIHx8IHRoaXMudG9EYXRlIHx8IHRoaXMub3B0aW9ucy5zdGFydGluZ1RvRGF0ZSB8fCBtb21lbnQoKTtcblxuICAgIHRoaXMuZnJvbU1vbnRoID0gdGVtcEZyb21EYXRlLmdldChcIm1vbnRoXCIpO1xuICAgIHRoaXMuZnJvbVllYXIgPSB0ZW1wRnJvbURhdGUuZ2V0KFwieWVhclwiKTtcblxuICAgIHRoaXMudG9Nb250aCA9IHRlbXBUb0RhdGUuZ2V0KFwibW9udGhcIik7XG4gICAgdGhpcy50b1llYXIgPSB0ZW1wVG9EYXRlLmdldChcInllYXJcIik7XG4gIH1cblxuICB1cGRhdGVDYWxlbmRhcigpOiB2b2lkIHtcbiAgICAvLyBnZXQgbW9udGggYW5kIHllYXIgdG8gc2hvdyBjYWxlbmRhclxuICAgIHRoaXMuc2V0RnJvbVRvTW9udGhZZWFyKCk7XG4gICAgdGhpcy5zZXRSYW5nZSgpO1xuICB9XG5cbiAgLy8gdXBkYXRlIGZyb20vdG8gYmFzZWQgb24gc2VsZWN0aW9uXG4gIGRhdGVDaGFuZ2VkKGNoYW5nZWREYXRhOiBJQ2hhbmdlZERhdGEpOiB2b2lkIHtcbiAgICBjb25zdCB2YWx1ZSA9IGNoYW5nZWREYXRhLmRheTtcbiAgICBjb25zdCBpc0xlZnQgPSBjaGFuZ2VkRGF0YS5pc0xlZnQ7XG5cbiAgICBpZiAoaXNMZWZ0KSB7XG4gICAgICB0aGlzLmZyb21EYXRlID0gdmFsdWU7XG5cbiAgICAgIGlmICh0aGlzLmZyb21EYXRlLmlzQWZ0ZXIodGhpcy50b0RhdGUsIFwiZGF0ZVwiKSkge1xuICAgICAgICB0aGlzLnRvRGF0ZSA9IHRoaXMuZnJvbURhdGUuY2xvbmUoKTtcbiAgICAgIH1cbiAgICB9IGVsc2Uge1xuICAgICAgdGhpcy50b0RhdGUgPSB2YWx1ZTtcblxuICAgICAgaWYgKHRoaXMudG9EYXRlLmlzQmVmb3JlKHRoaXMuZnJvbURhdGUsIFwiZGF0ZVwiKSkge1xuICAgICAgICB0aGlzLmZyb21EYXRlID0gdGhpcy50b0RhdGUuY2xvbmUoKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICB0aGlzLnNldEZyb21Ub01vbnRoWWVhcih0aGlzLmZyb21EYXRlLCB0aGlzLnRvRGF0ZSk7XG5cbiAgICBpZiAoXG4gICAgICB0aGlzLmlzQXV0b0FwcGx5KCkgJiZcbiAgICAgICh0aGlzLm9wdGlvbnMuc2luZ2xlQ2FsZW5kYXIgfHwgIWlzTGVmdCkgJiZcbiAgICAgIHRoaXMuZnJvbURhdGVcbiAgICApIHtcbiAgICAgIHRoaXMudG9nZ2xlQ2FsZW5kYXJWaXNpYmlsaXR5KGZhbHNlKTtcbiAgICAgIHRoaXMuc2V0UmFuZ2UoKTtcbiAgICAgIHRoaXMuZW1pdFJhbmdlU2VsZWN0ZWQoKTtcbiAgICB9XG4gIH1cblxuICBlbWl0UmFuZ2VTZWxlY3RlZChkYXRhPzogSURhdGVSYW5nZSk6IHZvaWQge1xuICAgIGlmICghZGF0YSkge1xuICAgICAgZGF0YSA9IHRoaXMub3B0aW9ucy5zaW5nbGVDYWxlbmRhclxuICAgICAgICA/IHsgc3RhcnQ6IHRoaXMuZnJvbURhdGUgfVxuICAgICAgICA6IHsgc3RhcnQ6IHRoaXMuZnJvbURhdGUsIGVuZDogdGhpcy50b0RhdGUgfTtcbiAgICB9XG5cbiAgICB0aGlzLnJhbmdlU2VsZWN0ZWQuZW1pdChkYXRhKTtcbiAgfVxuXG4gIGdldE1vbWVudCh2YWx1ZSk6IG1vbWVudE5zLk1vbWVudCB7XG4gICAgcmV0dXJuIG1vbWVudCh2YWx1ZSwgdGhpcy5vcHRpb25zLmZvcm1hdCk7XG4gIH1cblxuICBmb3JtYXRSYW5nZUFzU3RyaW5nKCk6IHN0cmluZyB7XG4gICAgbGV0IHJhbmdlID0gXCJcIjtcblxuICAgIGlmICh0aGlzLm9wdGlvbnMuc2luZ2xlQ2FsZW5kYXIgJiYgdGhpcy5mcm9tRGF0ZSkge1xuICAgICAgcmFuZ2UgPSB0aGlzLmZyb21EYXRlLmZvcm1hdCh0aGlzLm9wdGlvbnMuZm9ybWF0KTtcbiAgICB9IGVsc2UgaWYgKCF0aGlzLm9wdGlvbnMuc2luZ2xlQ2FsZW5kYXIgJiYgdGhpcy5mcm9tRGF0ZSAmJiB0aGlzLnRvRGF0ZSkge1xuICAgICAgcmFuZ2UgPSBgJHt0aGlzLmZyb21EYXRlLmZvcm1hdChcbiAgICAgICAgdGhpcy5vcHRpb25zLmZvcm1hdFxuICAgICAgKX0gLSAke3RoaXMudG9EYXRlLmZvcm1hdCh0aGlzLm9wdGlvbnMuZm9ybWF0KX1gO1xuICAgIH1cblxuICAgIHJldHVybiByYW5nZTtcbiAgfVxuXG4gIHNldFJhbmdlKCk6IHZvaWQge1xuICAgIHRoaXMucmFuZ2UgPSB0aGlzLmZvcm1hdFJhbmdlQXNTdHJpbmcoKTtcblxuICAgIGlmICh0aGlzLnBhcmVudEZvcm1Hcm91cCkge1xuICAgICAgY29uc3QgY29udHJvbCA9IHRoaXMucGFyZW50Rm9ybUdyb3VwLmdldCh0aGlzLmNvbnRyb2xOYW1lKTtcblxuICAgICAgaWYgKGNvbnRyb2wpIHtcbiAgICAgICAgY29udHJvbC5zZXRWYWx1ZSh0aGlzLnJhbmdlKTtcbiAgICAgICAgY29udHJvbC51cGRhdGVWYWx1ZUFuZFZhbGlkaXR5KCk7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgc2V0RGF0ZUZyb21JbnB1dChldmVudDogRXZlbnQsIGlzTGVmdDogYm9vbGVhbiA9IGZhbHNlKTogdm9pZCB7XG4gICAgY29uc3QgdGFyZ2V0ID0gZXZlbnQudGFyZ2V0IGFzIEhUTUxJbnB1dEVsZW1lbnQ7XG5cbiAgICB0cnkge1xuICAgICAgaWYgKHRhcmdldC52YWx1ZSkge1xuICAgICAgICBjb25zdCBkYXkgPSB0aGlzLmdldE1vbWVudCh0YXJnZXQudmFsdWUpO1xuXG4gICAgICAgIGlmIChcbiAgICAgICAgICAhZGF5LmlzQmVmb3JlKHRoaXMub3B0aW9ucy5taW5EYXRlKSAmJlxuICAgICAgICAgICFkYXkuaXNBZnRlcih0aGlzLm9wdGlvbnMubWF4RGF0ZSlcbiAgICAgICAgKSB7XG4gICAgICAgICAgaWYgKGlzTGVmdCAmJiAhdGhpcy5mcm9tRGF0ZSkge1xuICAgICAgICAgICAgdGhpcy5mcm9tRGF0ZSA9IGRheTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICBpZiAoIWlzTGVmdCAmJiAhdGhpcy50b0RhdGUpIHtcbiAgICAgICAgICAgIHRoaXMudG9EYXRlID0gZGF5O1xuICAgICAgICAgIH1cblxuICAgICAgICAgIHRoaXMuZGF0ZUNoYW5nZWQoe1xuICAgICAgICAgICAgZGF5LFxuICAgICAgICAgICAgaXNMZWZ0XG4gICAgICAgICAgfSk7XG5cbiAgICAgICAgICB0aGlzLnNldEZyb21Ub01vbnRoWWVhcih0aGlzLmZyb21EYXRlLCB0aGlzLnRvRGF0ZSk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgLy8gYXNzdW1lIG5vdGhpbmcgLSByZXNldCB2YWx1ZXNcbiAgICAgICAgICB0aGlzLmZyb21EYXRlID0gbnVsbDtcbiAgICAgICAgICB0aGlzLnRvRGF0ZSA9IG51bGw7XG4gICAgICAgICAgdGFyZ2V0LnZhbHVlID0gXCJcIjtcbiAgICAgICAgICB0YXJnZXQuZm9jdXMoKTtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICB0aGlzLmVtaXRSYW5nZVNlbGVjdGVkKCk7XG4gICAgfSBjYXRjaCAoZSkge1xuICAgICAgY29uc29sZS5lcnJvcihlKTtcbiAgICB9XG4gIH1cblxuICBtb250aENoYW5nZWQoZGF0YTogSUNoYW5nZWREYXRhKTogdm9pZCB7XG4gICAgbGV0IHRlbXA7XG5cbiAgICBpZiAoZGF0YS5pc0xlZnQpIHtcbiAgICAgIHRlbXAgPSBtb21lbnQoW3RoaXMuZnJvbVllYXIsIHRoaXMuZnJvbU1vbnRoXSkuYWRkKGRhdGEudmFsdWUsIFwibW9udGhzXCIpO1xuICAgICAgdGhpcy5mcm9tTW9udGggPSB0ZW1wLmdldChcIm1vbnRoXCIpO1xuICAgICAgdGhpcy5mcm9tWWVhciA9IHRlbXAuZ2V0KFwieWVhclwiKTtcbiAgICB9IGVsc2Uge1xuICAgICAgdGVtcCA9IG1vbWVudChbdGhpcy50b1llYXIsIHRoaXMudG9Nb250aF0pLmFkZChkYXRhLnZhbHVlLCBcIm1vbnRoc1wiKTtcbiAgICAgIHRoaXMudG9Nb250aCA9IHRlbXAuZ2V0KFwibW9udGhcIik7XG4gICAgICB0aGlzLnRvWWVhciA9IHRlbXAuZ2V0KFwieWVhclwiKTtcbiAgICB9XG4gIH1cblxuICB5ZWFyQ2hhbmdlZChkYXRhOiBJQ2hhbmdlZERhdGEpOiB2b2lkIHtcbiAgICBsZXQgdGVtcDtcblxuICAgIGlmIChkYXRhLmlzTGVmdCkge1xuICAgICAgdGVtcCA9IG1vbWVudChbdGhpcy5mcm9tWWVhciwgdGhpcy5mcm9tTW9udGhdKS5hZGQoZGF0YS52YWx1ZSwgXCJ5ZWFyXCIpO1xuICAgICAgdGhpcy5mcm9tTW9udGggPSB0ZW1wLmdldChcIm1vbnRoXCIpO1xuICAgICAgdGhpcy5mcm9tWWVhciA9IHRlbXAuZ2V0KFwieWVhclwiKTtcbiAgICB9IGVsc2Uge1xuICAgICAgdGVtcCA9IG1vbWVudChbdGhpcy50b1llYXIsIHRoaXMudG9Nb250aF0pLmFkZChkYXRhLnZhbHVlLCBcInllYXJcIik7XG4gICAgICB0aGlzLnRvTW9udGggPSB0ZW1wLmdldChcIm1vbnRoXCIpO1xuICAgICAgdGhpcy50b1llYXIgPSB0ZW1wLmdldChcInllYXJcIik7XG4gICAgfVxuICB9XG5cbiAgY2xvc2UoZXZlbnQ6IEV2ZW50KTogdm9pZCB7XG4gICAgdGhpcy50b2dnbGVDYWxlbmRhclZpc2liaWxpdHkoZmFsc2UpO1xuXG4gICAgZXZlbnQuc3RvcFByb3BhZ2F0aW9uKCk7XG4gIH1cblxuICByZXNldChldmVudDogRXZlbnQpOiB2b2lkIHtcbiAgICB0aGlzLmZyb21EYXRlID0gbnVsbDtcbiAgICB0aGlzLnRvRGF0ZSA9IG51bGw7XG4gICAgdGhpcy5zZXRSYW5nZSgpO1xuXG4gICAgZXZlbnQuc3RvcFByb3BhZ2F0aW9uKCk7XG4gIH1cblxuICBhcHBseShldmVudDogRXZlbnQpOiB2b2lkIHtcbiAgICB0aGlzLnRvZ2dsZUNhbGVuZGFyVmlzaWJpbGl0eShmYWxzZSk7XG4gICAgdGhpcy5zZXRSYW5nZSgpO1xuICAgIHRoaXMuZW1pdFJhbmdlU2VsZWN0ZWQoKTtcblxuICAgIGV2ZW50LnN0b3BQcm9wYWdhdGlvbigpO1xuICB9XG5cbiAgYXBwbHlQcmVkZWZpbmVkUmFuZ2UoXG4gICAgZXZlbnQ6IEV2ZW50LFxuICAgIGRlZmluZWREYXRlUmFuZ2U6IElEZWZpbmVkRGF0ZVJhbmdlXG4gICk6IHZvaWQge1xuICAgIC8vIGFkanVzdCB0by9mcm9tIG1vbnRoL3llYXIgc28gY2FsZW5kYXIgbW9udGhzIGFuZCB5ZWFycyBtYXRjaCByYW5nZVxuICAgIHRoaXMuc2V0RnJvbVRvTW9udGhZZWFyKFxuICAgICAgZGVmaW5lZERhdGVSYW5nZS52YWx1ZS5zdGFydCxcbiAgICAgIGRlZmluZWREYXRlUmFuZ2UudmFsdWUuZW5kXG4gICAgKTtcblxuICAgIHRoaXMuZnJvbURhdGUgPSBkZWZpbmVkRGF0ZVJhbmdlLnZhbHVlLnN0YXJ0O1xuICAgIHRoaXMudG9EYXRlID0gZGVmaW5lZERhdGVSYW5nZS52YWx1ZS5lbmQ7XG5cbiAgICBpZiAodGhpcy5vcHRpb25zLmF1dG9BcHBseSkge1xuICAgICAgdGhpcy5hcHBseShldmVudCk7XG4gICAgfVxuICB9XG5cbiAgdmFsaWRhdGVBbmRBc3NpZ25QcmVkZWZpbmVkUmFuZ2VzKFxuICAgIHJhbmdlczogSURlZmluZWREYXRlUmFuZ2VbXVxuICApOiBJRGVmaW5lZERhdGVSYW5nZVtdIHtcbiAgICByZXR1cm4gcmFuZ2VzLmZpbHRlcihyYW5nZSA9PiB7XG4gICAgICBpZiAocmFuZ2UudmFsdWUuc3RhcnQuaXNBZnRlcihyYW5nZS52YWx1ZS5lbmQsIFwiZGF0ZVwiKSkge1xuICAgICAgICB0aHJvdyBuZXcgUmFuZ2VFcnJvcihcbiAgICAgICAgICBgUHJlLWRlZmluZWQgcmFuZ2UgXCIke3JhbmdlLm5hbWV9XCIgc3RhcnQgZGF0ZSBjYW5ub3QgYmUgYWZ0ZXIgdGhlIGVuZCBkYXRlIGZvciB0aGUgcmFuZ2UuYFxuICAgICAgICApO1xuICAgICAgfVxuXG4gICAgICBpZiAoXG4gICAgICAgIHRoaXMub3B0aW9ucy5taW5EYXRlICYmXG4gICAgICAgIHJhbmdlLnZhbHVlLnN0YXJ0LmlzQmVmb3JlKHRoaXMub3B0aW9ucy5taW5EYXRlKVxuICAgICAgKSB7XG4gICAgICAgIHRocm93IG5ldyBSYW5nZUVycm9yKFxuICAgICAgICAgIGBQcmUtZGVmaW5lZCByYW5nZSBcIiR7cm