UNPKG

@eduardsson/ngx-daterange

Version:
325 lines 50.8 kB
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:&nbsp;</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:&nbsp;</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