UNPKG

ngx-animating-datepicker

Version:

An Animating Datepicker for Angular 2+, for some smooth date picking :).

486 lines (485 loc) 52.2 kB
/** * @fileoverview added by tsickle * @suppress {checkTypes,extraRequire,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc */ import { Component, ElementRef, HostBinding, Input, ViewChild, } from '@angular/core'; import { DatepickerService } from '../../services/datepicker.service'; import { UtilitiesService } from '../../services/utilities.service'; import { DatepickerComponent } from '../datepicker/datepicker.component'; export class AnimatepickerComponent extends DatepickerComponent { /** * @param {?} elementRef * @param {?} utilities */ constructor(elementRef, utilities) { super(utilities, elementRef); this.elementRef = elementRef; this.utilities = utilities; /* ============================================== * Internal Properties * ============================================== */ this.animate = true; this.isAnimating = false; this.leftInnerPosition = 0; this.currentYearMonth = null; this.initialised = false; /* ============================================== * External Properties * ============================================== */ /** * Number of months: the number of months displayed */ this._numberOfMonths = new Array(1); } /** * @param {?} value * @return {?} */ set numberOfMonths(value) { if (value === undefined || value === this._numberOfMonths.length) { return; } this._numberOfMonths = new Array(value); this.setDatePickerDimension(); this.goToDate(this.date); } /** * @return {?} */ get numberOfMonths() { return this._numberOfMonths; } /** * @return {?} */ ngOnInit() { // Get the computed width from the calendar. Set the initial width /** @type {?} */ const computedWidth = window .getComputedStyle(this.elementRef.nativeElement, null) .getPropertyValue('width'); this.initialWidth = parseInt(computedWidth, 10); this.initialised = true; // Set the current year and month object if (!this.month && !this.year) { this.goToDate(this.options.currentDate); } } /** * @return {?} */ ngAfterViewInit() { setTimeout(() => { this.setDatePickerDimension(); this.setDatepickerHeight(true); }); } /** * Set the height and the width properties * @return {?} */ setDatePickerDimension() { this.datepickerHeight = this.calendarContainer.nativeElement.offsetHeight + this.calendarTopContainer.nativeElement.offsetHeight + this.footer.nativeElement.offsetHeight; this.calendarHeight = this.calendarContainer.nativeElement.offsetHeight; this.datepickerWidth = this.initialWidth * this._numberOfMonths.length; } /** * Go to a specific month * * @param {?=} date - optional * @return {?} */ goToDate(date) { if (date) { this.currentYearMonth = this.getNextYearMonthArray(date.getFullYear(), date.getMonth()); } this.calendarWidth = 50 / this._numberOfMonths.length; this.months = this.getNextMonthArray(this.currentYearMonth, true); this.resetStyle(); } /** * Create an array of the next year and months * * @param {?} year * @param {?} month * @return {?} */ getNextYearMonthArray(year, month) { /** @type {?} */ const array = []; for (let index = 0; index < this._numberOfMonths.length; index++) { array.push({ year: year, month: month }); year = DatepickerService.getYearOfNextMonth(year, month); month = DatepickerService.getNextMonth(month); } return array; } /** * Create an array of the previous year and months * * @param {?} year * @param {?} month * @return {?} */ getPreviousYearMonthArray(year, month) { /** @type {?} */ const array = []; for (let index = 0; index < this._numberOfMonths.length; index++) { array.unshift({ year: year, month: month }); year = DatepickerService.getYearOfPreviousMonth(year, month); month = DatepickerService.getPreviousMonth(month); } return array; } /** * Set the datepicker height, used when animating * * @param {?=} directionRight - Set optional when sliding to the right * @return {?} */ setDatepickerHeight(directionRight) { /** @type {?} */ let indexArray; // TODO: Seperate this logic for readability purpose if (this._numberOfMonths.length > 1) { /** @type {?} */ const start = directionRight ? 0 : this._numberOfMonths.length; /** @type {?} */ const end = directionRight ? this._numberOfMonths.length - 1 : this._numberOfMonths.length + this._numberOfMonths.length - 1; indexArray = this.utilities.createArray(start, end); } else { indexArray = directionRight ? [0] : [1]; } /** @type {?} */ const that = this; setTimeout(() => { /** @type {?} */ const calendarArray = that.elementRef.nativeElement.querySelectorAll('.datepicker__calendar-container'); /** @type {?} */ let offsetHeight = 0; indexArray.forEach(el => { if (calendarArray[el].offsetHeight > offsetHeight) { offsetHeight = calendarArray[el].offsetHeight; } }); // TODO: Merge with setHeight function. that.datepickerHeight = offsetHeight + that.calendarTopContainer.nativeElement.offsetHeight + that.footer.nativeElement.offsetHeight; that.calendarHeight = offsetHeight; }); } /** * Get next month array, gets multiple months. * Used when the options animate is set or multiple months are visable * * @param {?} currentYearMonth * @param {?=} keepDate * @param {?=} nextMonthsYearMonthArray * @return {?} Month[] */ getNextMonthArray(currentYearMonth, keepDate = false, nextMonthsYearMonthArray) { // Get the last index, used for selecting the right year month object /** @type {?} */ const lastIndex = this._numberOfMonths.length - 1; // Get next year and month in an Object /** @type {?} */ const nextMonths = nextMonthsYearMonthArray || this.getNextYearMonthArray(DatepickerService.getYearOfNextMonth(currentYearMonth[lastIndex].year, currentYearMonth[lastIndex].month), DatepickerService.getNextMonth(currentYearMonth[lastIndex].month)); // Concatenates the two objects to create a total year and month object this.totalYearMonth = currentYearMonth.concat(nextMonths); // Create the calendar array using the total year and month Object /** @type {?} */ const monthArray = []; this.totalYearMonth.forEach(e => monthArray.push(this.createCalendarArray(e.year, e.month))); // Set the new current year and month object. if (!keepDate) { this.currentYearMonth = nextMonths; } return [].concat.apply([], monthArray); } /** * Gets an array of previous months. * Used for animation and when more months are displayed * * @param {?} currentYearMonth * @param {?=} keepDate * @return {?} */ getPreviousMonthArray(currentYearMonth, keepDate = false) { // Get previous year and month in an Object /** @type {?} */ const previousMonths = this.getPreviousYearMonthArray(DatepickerService.getYearOfPreviousMonth(currentYearMonth[0].year, currentYearMonth[0].month), DatepickerService.getPreviousMonth(currentYearMonth[0].month)); // Concatenates the two objects to create a total year and month object this.totalYearMonth = previousMonths.concat(currentYearMonth); // Create the calendar array using the total year and month Object /** @type {?} */ const monthArray = []; this.totalYearMonth.forEach(e => { monthArray.push(this.createCalendarArray(e['year'], e['month'])); }); // Set the new current year and month object. if (!keepDate) { this.currentYearMonth = previousMonths; } return [].concat.apply([], monthArray); } /** * Update value is being triggered * * @param {?} date * @return {?} */ updateValue(date) { if (this.options.range) { this.selectRange(date); } else if (!this.isSelected(date)) { if (this.options.selectMultiple) { this.selectDate(date); } else { this.toggleDate(date); } if (this.options.closeOnSelect) { this.close(true); } } else { this.deselectDate(date); if (this.options.closeOnSelect) { this.close(true); } } this.months = this.getNextMonthArray(this.currentYearMonth, true); this.resetStyle(); } /** * Go to the next month * @return {?} */ goToNextMonth() { if (this.isAnimating) { return; } this.months = this.getNextMonthArray(this.currentYearMonth); this.resetStyle(); this.setDatepickerHeight(); this.slideLeft(); } /** * Go to the previous month * @return {?} */ goToPreviousMonth() { if (this.isAnimating) { return; } this.months = this.getPreviousMonthArray(this.currentYearMonth); this.resetStyle(true); this.setDatepickerHeight(true); this.slideRight(); } /** * Go to a specific month * TODO: WIP Check if date is in current range, or if it is later or earlier * @param {?} date * @return {?} */ goToMonth(date) { /** @type {?} */ const nextMonths = this.getNextYearMonthArray(date.getFullYear(), date.getMonth()); this.months = this.getNextMonthArray(this.totalYearMonth, false, nextMonths); this.resetStyle(); this.setDatepickerHeight(); this.slideRight(); } /** * Slide to the right * @return {?} */ slideRight() { this.setIsAnimating(); setTimeout(() => { this.transition = 'transform ' + this.options.animationSpeed + 'ms ' + this.options.easing; this.translateX = 50; }); } /** * Slide to the left (criss cross) * @return {?} */ slideLeft() { this.setIsAnimating(); setTimeout(() => { this.transition = 'transform ' + this.options.animationSpeed + 'ms ' + this.options.easing; this.translateX = -50; }); } /** * Set animating state * @return {?} */ setIsAnimating() { this.isAnimating = true; setTimeout(() => { this.isAnimating = false; }, this.options.animationSpeed); } /** * Reset Style * * @param {?=} resetForPrevious - Optional * @return {?} */ resetStyle(resetForPrevious) { this.transition = 'transform 0ms ease-in'; this.translateX = 0; this.leftInnerPosition = resetForPrevious ? -100 : 0; } } AnimatepickerComponent.decorators = [ { type: Component, args: [{ selector: 'aa-animatepicker', template: `<div class="datepicker__wrapper" [ngStyle]="datepickerPosition"> <div #calendarTopContainer> <div class="datepicker__header" #header> <ng-content select="header"></ng-content> </div> <aa-navigation (previousClick)="goToPreviousMonth()" (nextClick)="goToNextMonth()" (subNavigationClick)="goToDate($event)" [language]="language" [animate]="animate" [translateX]="translateX" [transition]="transition" [leftPosition]="leftInnerPosition" [hideNavigation]="options.hideNavigation" [totalYearMonth]="totalYearMonth" ></aa-navigation> <div class="datepicker__weekdays-wrapper"> <div *ngFor="let month of numberOfMonths" [ngStyle]="{ 'width.%': (100 / numberOfMonths.length) }" class="datepicker__weekdays-container"> <table class="datepicker__weekdays"> <thead> <td class="datepicker__weekday" *ngFor="let weekday of weekdays; index as i">{{weekday}}</td> </thead> </table> </div> </div> </div> <div class="datepicker__main" [ngStyle]="{ 'height.px': calendarHeight}"> <div class="datepicker__calendar-wrapper" #calendarContainer [ngStyle]="{ 'transform': 'translateX(' + translateX + '%)', 'transition': transition, 'left.%': leftInnerPosition }" > <div *ngFor="let month of months;" class="datepicker__calendar-container" [ngStyle]="{'width.%': calendarWidth}" > <table class="datepicker__calendar"> <tbody> <tr *ngFor="let week of month.weeks; index as i" class="datepicker__week"> <td class="datepicker__day" *ngFor="let day of week.days; index as i" [ngClass]="{ 'is-first': day.isFirst, 'is-last': day.isLast, 'is-hidden': day.isHidden, 'is-disabled': day.isDisabled, 'is-today': day.isToday, 'is-selected': day.isSelected, 'is-in-range': day.isInRange, 'is-start-date': day.isStartDate, 'is-end-date': day.isEndDate, 'is-rest': day.isRest }"> <button class="datepicker__button" [disabled]="day.isDisabled || day.isHidden" (click)="updateValue(day.date)">{{day.dayNumber}} </button> </td> </tr> </tbody> </table> </div> </div> </div> <div class="datepicker__footer" #footer> <ng-content select="footer"></ng-content> </div> </div> `, styles: [`:host{font-family:Arial,Helvetica,sans-serif;border:1px solid #d9d9d8;width:300px;position:relative;display:inline-block;z-index:2;border-radius:4px;box-shadow:0 1px 5px rgba(0,0,0,.15);overflow:hidden;background-color:#fff;box-sizing:border-box;visibility:hidden}:host *{box-sizing:border-box}:host .datepicker__calendar-container{padding:0 10px 10px}:host .datepicker__footer{position:relative;z-index:1}:host table{width:100%;table-layout:fixed;border-spacing:0;border-collapse:collapse}:host td{padding:0}:host .datepicker__weekdays-wrapper::after,:host .datepicker__weekdays-wrapper::before{content:' ';display:table}:host .datepicker__weekdays-wrapper::after{clear:both}:host .datepicker__weekdays-container{padding:10px 10px 0;float:left}:host .datepicker__weekdays{table-layout:fixed;width:100%}:host .datepicker__weekday{color:grey;font-size:12px;height:20px;text-align:center}:host .datepicker__day{position:relative;text-align:center;height:40px;width:auto;border:1px solid #d9d9d8}:host .datepicker__day.is-rest{border:none}:host .datepicker__button{padding:0;background-color:transparent;border:none;outline:0;font-style:inherit;cursor:pointer;color:#8e8d8a;width:100%;height:100%}:host .datepicker__button:hover{border:1px solid transparent;background-color:#f2f2f2;color:#8e8d8a}:host .is-hidden{opacity:0;display:table-cell}:host .is-rest{border:none}:host .is-rest .datepicker__button{color:#c0c0be}:host .is-today .datepicker__button{background-color:#eae7dc}:host .is-in-range .datepicker__button{background-color:#e98074;color:#fff}:host .is-in-range .datepicker__button:hover{background-color:#e66c5e}:host .is-selected .datepicker__button{background-color:#e85a4f;color:#fff;font-weight:700}:host .is-selected .datepicker__button:hover{background-color:#e23022}:host .is-start-date .datepicker__button{background-color:#e85a4f;color:#fff}:host .is-end-date .datepicker__button{background-color:#e85a4f;color:#fff}:host .is-disabled .datepicker__button{color:#d9d9d8;cursor:default}:host .is-disabled .datepicker__button:hover{background-color:transparent}:host.is-directive{visibility:hidden;position:absolute}:host.is-open{visibility:visible}:host.is-animate{transition:height .2s ease-in;width:300px}:host.is-animate .datepicker__main{transition:height .2s ease-in}:host.is-animate .datepicker__calendar-wrapper{position:absolute;width:200%;left:0}:host.is-animate .datepicker__calendar{float:left;width:100%}:host.is-animate .datepicker__calendar-container{float:left}`] },] }, ]; AnimatepickerComponent.ctorParameters = () => [ { type: ElementRef }, { type: UtilitiesService } ]; AnimatepickerComponent.propDecorators = { numberOfMonths: [{ type: Input }], calendarContainer: [{ type: ViewChild, args: ['calendarContainer',] }], calendarTopContainer: [{ type: ViewChild, args: ['calendarTopContainer',] }], footer: [{ type: ViewChild, args: ['footer',] }], datepickerWidth: [{ type: HostBinding, args: ['style.width.px',] }], datepickerHeight: [{ type: HostBinding, args: ['style.height.px',] }] }; if (false) { /** @type {?} */ AnimatepickerComponent.prototype.animate; /** @type {?} */ AnimatepickerComponent.prototype.initialWidth; /** @type {?} */ AnimatepickerComponent.prototype.calendarWidth; /** @type {?} */ AnimatepickerComponent.prototype.isAnimating; /** @type {?} */ AnimatepickerComponent.prototype.leftInnerPosition; /** @type {?} */ AnimatepickerComponent.prototype.transition; /** @type {?} */ AnimatepickerComponent.prototype.translateX; /** @type {?} */ AnimatepickerComponent.prototype.currentYearMonth; /** @type {?} */ AnimatepickerComponent.prototype.datepickerPosition; /** @type {?} */ AnimatepickerComponent.prototype.initialised; /** @type {?} */ AnimatepickerComponent.prototype.calendarHeight; /** * Number of months: the number of months displayed * @type {?} * @private */ AnimatepickerComponent.prototype._numberOfMonths; /** @type {?} */ AnimatepickerComponent.prototype.calendarContainer; /** @type {?} */ AnimatepickerComponent.prototype.calendarTopContainer; /** @type {?} */ AnimatepickerComponent.prototype.footer; /** @type {?} */ AnimatepickerComponent.prototype.datepickerWidth; /** @type {?} */ AnimatepickerComponent.prototype.datepickerHeight; /** @type {?} */ AnimatepickerComponent.prototype.elementRef; /** @type {?} */ AnimatepickerComponent.prototype.utilities; } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYW5pbWF0ZXBpY2tlci5jb21wb25lbnQuanMiLCJzb3VyY2VSb290Ijoibmc6Ly9uZ3gtYW5pbWF0aW5nLWRhdGVwaWNrZXIvIiwic291cmNlcyI6WyJsaWIvY29tcG9uZW50cy9hbmltYXRlcGlja2VyL2FuaW1hdGVwaWNrZXIuY29tcG9uZW50LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7QUFBQSxPQUFPLEVBRU4sU0FBUyxFQUNULFVBQVUsRUFDVixXQUFXLEVBQ1gsS0FBSyxFQUVMLFNBQVMsR0FDVCxNQUFNLGVBQWUsQ0FBQztBQUV2QixPQUFPLEVBQUUsaUJBQWlCLEVBQUUsTUFBTSxtQ0FBbUMsQ0FBQztBQUN0RSxPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSxrQ0FBa0MsQ0FBQztBQUNwRSxPQUFPLEVBQUUsbUJBQW1CLEVBQUUsTUFBTSxvQ0FBb0MsQ0FBQztBQWtGekUsTUFBTSw2QkFBOEIsU0FBUSxtQkFBbUI7Ozs7O0lBa0Q5RCxZQUFtQixVQUFzQixFQUFTLFNBQTJCO1FBQzVFLEtBQUssQ0FBQyxTQUFTLEVBQUUsVUFBVSxDQUFDLENBQUM7UUFEWCxlQUFVLEdBQVYsVUFBVSxDQUFZO1FBQVMsY0FBUyxHQUFULFNBQVMsQ0FBa0I7UUFqRDdFOzs0REFFb0Q7UUFFN0MsWUFBTyxHQUFHLElBQUksQ0FBQztRQUdmLGdCQUFXLEdBQUcsS0FBSyxDQUFDO1FBQ3BCLHNCQUFpQixHQUFHLENBQUMsQ0FBQztRQUd0QixxQkFBZ0IsR0FBVyxJQUFJLENBQUM7UUFFaEMsZ0JBQVcsR0FBRyxLQUFLLENBQUM7UUFHM0I7OzREQUVvRDtRQUVwRDs7V0FFRztRQUNLLG9CQUFlLEdBQVEsSUFBSSxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUM7SUE0QjVDLENBQUM7Ozs7O0lBM0JELElBQ0ksY0FBYyxDQUFDLEtBQUs7UUFDdkIsSUFBSSxLQUFLLEtBQUssU0FBUyxJQUFJLEtBQUssS0FBSyxJQUFJLENBQUMsZUFBZSxDQUFDLE1BQU0sRUFBRTtZ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QUN6OEU7OztZQTFGQSxVQUFVO1lBUUYsZ0JBQWdCOzs7NkJBNEd2QixLQUFLO2dDQW1CTCxTQUFTLFNBQUMsbUJBQW1CO21DQUM3QixTQUFTLFNBQUMsc0JBQXNCO3FCQUNoQyxTQUFTLFNBQUMsUUFBUTs4QkFDbEIsV0FBVyxTQUFDLGdCQUFnQjsrQkFDNUIsV0FBVyxTQUFDLGlCQUFpQjs7OztJQTNDOUIseUNBQXNCOztJQUN0Qiw4Q0FBNEI7O0lBQzVCLCtDQUE2Qjs7SUFDN0IsNkNBQTJCOztJQUMzQixtREFBNkI7O0lBQzdCLDRDQUEwQjs7SUFDMUIsNENBQTBCOztJQUMxQixrREFBdUM7O0lBQ3ZDLG9EQUFrQzs7SUFDbEMsNkNBQTJCOztJQUMzQixnREFBNkI7Ozs7OztJQVM3QixpREFBNEM7O0lBb0I1QyxtREFBcUU7O0lBQ3JFLHNEQUEyRTs7SUFDM0Usd0NBQStDOztJQUMvQyxpREFBOEQ7O0lBQzlELGtEQUFnRTs7SUFFcEQsNENBQTZCOztJQUFFLDJDQUFrQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7XG5cdEFmdGVyVmlld0luaXQsXG5cdENvbXBvbmVudCxcblx0RWxlbWVudFJlZixcblx0SG9zdEJpbmRpbmcsXG5cdElucHV0LFxuXHRPbkluaXQsXG5cdFZpZXdDaGlsZCxcbn0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBZZWFyTW9udGgsIE1vbnRoIH0gZnJvbSAnLi4vLi4vbW9kZWxzL2RhdGVwaWNrZXIubW9kZWwnO1xuaW1wb3J0IHsgRGF0ZXBpY2tlclNlcnZpY2UgfSBmcm9tICcuLi8uLi9zZXJ2aWNlcy9kYXRlcGlja2VyLnNlcnZpY2UnO1xuaW1wb3J0IHsgVXRpbGl0aWVzU2VydmljZSB9IGZyb20gJy4uLy4uL3NlcnZpY2VzL3V0aWxpdGllcy5zZXJ2aWNlJztcbmltcG9ydCB7IERhdGVwaWNrZXJDb21wb25lbnQgfSBmcm9tICcuLi9kYXRlcGlja2VyL2RhdGVwaWNrZXIuY29tcG9uZW50JztcblxuQENvbXBvbmVudCh7XG5cdHNlbGVjdG9yOiAnYWEtYW5pbWF0ZXBpY2tlcicsXG5cdHRlbXBsYXRlOiBgPGRpdiBjbGFzcz1cImRhdGVwaWNrZXJfX3dyYXBwZXJcIiBbbmdTdHlsZV09XCJkYXRlcGlja2VyUG9zaXRpb25cIj5cblx0PGRpdiAjY2FsZW5kYXJUb3BDb250YWluZXI+XG5cdFx0PGRpdiBjbGFzcz1cImRhdGVwaWNrZXJfX2hlYWRlclwiICNoZWFkZXI+XG5cdFx0XHQ8bmctY29udGVudCBzZWxlY3Q9XCJoZWFkZXJcIj48L25nLWNvbnRlbnQ+XG5cdFx0PC9kaXY+XG5cdFx0PGFhLW5hdmlnYXRpb25cblx0XHRcdFx0KHByZXZpb3VzQ2xpY2spPVwiZ29Ub1ByZXZpb3VzTW9udGgoKVwiXG5cdFx0XHRcdChuZXh0Q2xpY2spPVwiZ29Ub05leHRNb250aCgpXCJcblx0XHRcdFx0KHN1Yk5hdmlnYXRpb25DbGljayk9XCJnb1RvRGF0ZSgkZXZlbnQpXCJcblx0XHRcdFx0W2xhbmd1YWdlXT1cImxhbmd1YWdlXCJcblx0XHRcdFx0W2FuaW1hdGVdPVwiYW5pbWF0ZVwiXG5cdFx0XHRcdFt0cmFuc2xhdGVYXT1cInRyYW5zbGF0ZVhcIlxuXHRcdFx0XHRbdHJhbnNpdGlvbl09XCJ0cmFuc2l0aW9uXCJcblx0XHRcdFx0W2xlZnRQb3NpdGlvbl09XCJsZWZ0SW5uZXJQb3NpdGlvblwiXG5cdFx0XHRcdFtoaWRlTmF2aWdhdGlvbl09XCJvcHRpb25zLmhpZGVOYXZpZ2F0aW9uXCJcblx0XHRcdFx0W3RvdGFsWWVhck1vbnRoXT1cInRvdGFsWWVhck1vbnRoXCJcblx0XHQ+PC9hYS1uYXZpZ2F0aW9uPlxuXG5cdFx0PGRpdiBjbGFzcz1cImRhdGVwaWNrZXJfX3dlZWtkYXlzLXdyYXBwZXJcIj5cblx0XHRcdDxkaXYgXHQqbmdGb3I9XCJsZXQgbW9udGggb2YgbnVtYmVyT2ZNb250aHNcIlxuXHRcdFx0XHRcdFtuZ1N0eWxlXT1cIntcblx0XHRcdFx0J3dpZHRoLiUnOiAoMTAwIC8gbnVtYmVyT2ZNb250aHMubGVuZ3RoKVxuXHRcdFx0XHR9XCJcblx0XHRcdFx0XHRjbGFzcz1cImRhdGVwaWNrZXJfX3dlZWtkYXlzLWNvbnRhaW5lclwiPlxuXHRcdFx0XHQ8dGFibGUgY2xhc3M9XCJkYXRlcGlja2VyX193ZWVrZGF5c1wiPlxuXHRcdFx0XHRcdDx0aGVhZD5cblx0XHRcdFx0XHQ8dGQgY2xhc3M9XCJkYXRlcGlja2VyX193ZWVrZGF5XCIgKm5nRm9yPVwibGV0IHdlZWtkYXkgb2Ygd2Vla2RheXM7IGluZGV4IGFzIGlcIj57e3dlZWtkYXl9fTwvdGQ+XG5cdFx0XHRcdFx0PC90aGVhZD5cblx0XHRcdFx0PC90YWJsZT5cblx0XHRcdDwvZGl2PlxuXHRcdDwvZGl2PlxuXHQ8L2Rpdj5cblx0PGRpdiBjbGFzcz1cImRhdGVwaWNrZXJfX21haW5cIiBbbmdTdHlsZV09XCJ7XG5cdFx0J2hlaWdodC5weCc6IGNhbGVuZGFySGVpZ2h0fVwiPlxuXHRcdDxkaXYgY2xhc3M9XCJkYXRlcGlja2VyX19jYWxlbmRhci13cmFwcGVyXCIgI2NhbGVuZGFyQ29udGFpbmVyIFtuZ1N0eWxlXT1cIntcblx0XHRcdFx0XHQndHJhbnNmb3JtJzogJ3RyYW5zbGF0ZVgoJyArIHRyYW5zbGF0ZVggKyAnJSknLFxuXHRcdFx0XHRcdCd0cmFuc2l0aW9uJzogdHJhbnNpdGlvbixcblx0XHRcdFx0XHQnbGVmdC4lJzogbGVmdElubmVyUG9zaXRpb25cblx0XHRcdFx0XHR9XCJcblx0XHQ+XG5cdFx0XHQ8ZGl2XG5cdFx0XHRcdFx0Km5nRm9yPVwibGV0IG1vbnRoIG9mIG1vbnRocztcIlxuXHRcdFx0XHRcdGNsYXNzPVwiZGF0ZXBpY2tlcl9fY2FsZW5kYXItY29udGFpbmVyXCJcblx0XHRcdFx0XHRbbmdTdHlsZV09XCJ7J3dpZHRoLiUnOiBjYWxlbmRhcldpZHRofVwiXG5cdFx0XHQ+XG5cdFx0XHRcdDx0YWJsZSBjbGFzcz1cImRhdGVwaWNrZXJfX2NhbGVuZGFyXCI+XG5cdFx0XHRcdFx0PHRib2R5PlxuXHRcdFx0XHRcdDx0ciAqbmdGb3I9XCJsZXQgd2VlayBvZiBtb250aC53ZWVrczsgaW5kZXggYXMgaVwiIGNsYXNzPVwiZGF0ZXBpY2tlcl9fd2Vla1wiPlxuXHRcdFx0XHRcdFx0PHRkIGNsYXNzPVwiZGF0ZXBpY2tlcl9fZGF5XCIgKm5nRm9yPVwibGV0IGRheSBvZiB3ZWVrLmRheXM7IGluZGV4IGFzIGlcIlxuXHRcdFx0XHRcdFx0XHRbbmdDbGFzc109XCJ7XG5cdFx0XHRcdFx0XHQnaXMtZmlyc3QnOiBkYXkuaXNGaXJzdCxcblx0XHRcdFx0XHRcdCdpcy1sYXN0JzogZGF5LmlzTGFzdCxcblx0XHRcdFx0XHRcdCdpcy1oaWRkZW4nOiBkYXkuaXNIaWRkZW4sXG5cdFx0XHRcdFx0XHQnaXMtZGlzYWJsZWQnOiBkYXkuaXNEaXNhYmxlZCxcblx0XHRcdFx0XHRcdCdpcy10b2RheSc6IGRheS5pc1RvZGF5LFxuXHRcdFx0XHRcdFx0J2lzLXNlbGVjdGVkJzogZGF5LmlzU2VsZWN0ZWQsXG5cdFx0XHRcdFx0XHQnaXMtaW4tcmFuZ2UnOiBkYXkuaXNJblJhbmdlLFxuXHRcdFx0XHRcdFx0J2lzLXN0YXJ0LWRhdGUnOiBkYXkuaXNTdGFydERhdGUsXG5cdFx0XHRcdFx0XHQnaXMtZW5kLWRhdGUnOiBkYXkuaXNFbmREYXRlLFxuXHRcdFx0XHRcdFx0J2lzLXJlc3QnOiBkYXkuaXNSZXN0XG5cdFx0XHRcdFx0XHR9XCI+XG5cdFx0XHRcdFx0XHRcdDxidXR0b24gY2xhc3M9XCJkYXRlcGlja2VyX19idXR0b25cIiBbZGlzYWJsZWRdPVwiZGF5LmlzRGlzYWJsZWQgfHwgZGF5LmlzSGlkZGVuXCJcblx0XHRcdFx0XHRcdFx0XHRcdChjbGljayk9XCJ1cGRhdGVWYWx1ZShkYXkuZGF0ZSlcIj57e2RheS5kYXlOdW1iZXJ9fVxuXHRcdFx0XHRcdFx0XHQ8L2J1dHRvbj5cblx0XHRcdFx0XHRcdDwvdGQ+XG5cdFx0XHRcdFx0PC90cj5cblx0XHRcdFx0XHQ8L3Rib2R5PlxuXHRcdFx0XHQ8L3RhYmxlPlxuXHRcdFx0PC9kaXY+XG5cdFx0PC9kaXY+XG5cdDwvZGl2PlxuXHQ8ZGl2IGNsYXNzPVwiZGF0ZXBpY2tlcl9fZm9vdGVyXCIgI2Zvb3Rlcj5cblx0XHQ8bmctY29udGVudCBzZWxlY3Q9XCJmb290ZXJcIj48L25nLWNvbnRlbnQ+XG5cdDwvZGl2PlxuPC9kaXY+XG5cdFx0YCxcblx0c3R5bGVzOiBbYDpob3N0e2ZvbnQtZmFtaWx5OkFyaWFsLEhlbHZldGljYSxzYW5zLXNlcmlmO2JvcmRlcjoxcHggc29saWQgI2Q5ZDlkODt3aWR0aDozMDBweDtwb3NpdGlvbjpyZWxhdGl2ZTtkaXNwbGF5OmlubGluZS1ibG9jazt6LWluZGV4OjI7Ym9yZGVyLXJhZGl1czo0cHg7Ym94LXNoYWRvdzowIDFweCA1cHggcmdiYSgwLDAsMCwuMTUpO292ZXJmbG93OmhpZGRlbjtiYWNrZ3JvdW5kLWNvbG9yOiNmZmY7Ym94LXNpemluZzpib3JkZXItYm94O3Zpc2liaWxpdHk6aGlkZGVufTpob3N0ICp7Ym94LXNpemluZzpib3JkZXItYm94fTpob3N0IC5kYXRlcGlja2VyX19jYWxlbmRhci1jb250YWluZXJ7cGFkZGluZzowIDEwcHggMTBweH06aG9zdCAuZGF0ZXBpY2tlcl9fZm9vdGVye3Bvc2l0aW9uOnJlbGF0aXZlO3otaW5kZXg6MX06aG9zdCB0YWJsZXt3aWR0aDoxMDAlO3RhYmxlLWxheW91dDpmaXhlZDtib3JkZXItc3BhY2luZzowO2JvcmRlci1jb2xsYXBzZTpjb2xsYXBzZX06aG9zdCB0ZHtwYWRkaW5nOjB9Omhvc3QgLmRhdGVwaWNrZXJfX3dlZWtkYXlzLXdyYXBwZXI6OmFmdGVyLDpob3N0IC5kYXRlcGlja2VyX193ZWVrZGF5cy13cmFwcGVyOjpiZWZvcmV7Y29udGVudDonICc7ZGlzcGxheTp0YWJsZX06aG9zdCAuZGF0ZXBpY2tlcl9fd2Vla2RheXMtd3JhcHBlcjo6YWZ0ZXJ7Y2xlYXI6Ym90aH06aG9zdCAuZGF0ZXBpY2tlcl9fd2Vla2RheXMtY29udGFpbmVye3BhZGRpbmc6MTBweCAxMHB4IDA7ZmxvYXQ6bGVmdH06aG9zdCAuZGF0ZXBpY2tlcl9fd2Vla2RheXN7dGFibGUtbGF5b3V0OmZpeGVkO3dpZHRoOjEwMCV9Omhvc3QgLmRhdGVwaWNrZXJfX3dlZWtkYXl7Y29sb3I6Z3JleTtmb250LXNpemU6MTJweDtoZWlnaHQ6MjBweDt0ZXh0LWFsaWduOmNlbnRlcn06aG9zdCAuZGF0ZXBpY2tlcl9fZGF5e3Bvc2l0aW9uOnJlbGF0aXZlO3RleHQtYWxpZ246Y2VudGVyO2hlaWdodDo0MHB4O3dpZHRoOmF1dG87Ym9yZGVyOjFweCBzb2xpZCAjZDlkOWQ4fTpob3N0IC5kYXRlcGlja2VyX19kYXkuaXMtcmVzdHtib3JkZXI6bm9uZX06aG9zdCAuZGF0ZXBpY2tlcl9fYnV0dG9ue3BhZGRpbmc6MDtiYWNrZ3JvdW5kLWNvbG9yOnRyYW5zcGFyZW50O2JvcmRlcjpub25lO291dGxpbmU6MDtmb250LXN0eWxlOmluaGVyaXQ7Y3Vyc29yOnBvaW50ZXI7Y29sb3I6IzhlOGQ4YTt3aWR0aDoxMDAlO2hlaWdodDoxMDAlfTpob3N0IC5kYXRlcGlja2VyX19idXR0b246aG92ZXJ7Ym9yZGVyOjFweCBzb2xpZCB0cmFuc3BhcmVudDtiYWNrZ3JvdW5kLWNvbG9yOiNmMmYyZjI7Y29sb3I6IzhlOGQ4YX06aG9zdCAuaXMtaGlkZGVue29wYWNpdHk6MDtkaXNwbGF5OnRhYmxlLWNlbGx9Omhvc3QgLmlzLXJlc3R7Ym9yZGVyOm5vbmV9Omhvc3QgLmlzLXJlc3QgLmRhdGVwaWNrZXJfX2J1dHRvbntjb2xvcjojYzBjMGJlfTpob3N0IC5pcy10b2RheSAuZGF0ZXBpY2tlcl9fYnV0dG9ue2JhY2tncm91bmQtY29sb3I6I2VhZTdkY306aG9zdCAuaXMtaW4tcmFuZ2UgLmRhdGVwaWNrZXJfX2J1dHRvbntiYWNrZ3JvdW5kLWNvbG9yOiNlOTgwNzQ7Y29sb3I6I2ZmZn06aG9zdCAuaXMtaW4tcmFuZ2UgLmRhdGVwaWNrZXJfX2J1dHRvbjpob3ZlcntiYWNrZ3JvdW5kLWNvbG9yOiNlNjZjNWV9Omhvc3QgLmlzLXNlbGVjdGVkIC5kYXRlcGlja2VyX19idXR0b257YmFja2dyb3VuZC1jb2xvcjojZTg1YTRmO2NvbG9yOiNmZmY7Zm9udC13ZWlnaHQ6NzAwfTpob3N0IC5pcy1zZWxlY3RlZCAuZGF0ZXBpY2tlcl9fYnV0dG9uOmhvdmVye2JhY2tncm91bmQtY29sb3I6I2UyMzAyMn06aG9zdCAuaXMtc3RhcnQtZGF0ZSAuZGF0ZXBpY2tlcl9fYnV0dG9ue2JhY2tncm91bmQtY29sb3I6I2U4NWE0Zjtjb2xvcjojZmZmfTpob3N0IC5pcy1lbmQtZGF0ZSAuZGF0ZXBpY2tlcl9fYnV0dG9ue2JhY2tncm91bmQtY29sb3I6I2U4NWE0Zjtjb2xvcjojZmZmfTpob3N0IC5pcy1kaXNhYmxlZCAuZGF0ZXBpY2tlcl9fYnV0dG9ue2NvbG9yOiNkOWQ5ZDg7Y3Vyc29yOmRlZmF1bHR9Omhvc3QgLmlzLWRpc2FibGVkIC5kYXRlcGlja2VyX19idXR0b246aG92ZXJ7YmFja2dyb3VuZC1jb2xvcjp0cmFuc3BhcmVudH06aG9zdC5pcy1kaXJlY3RpdmV7dmlzaWJpbGl0eTpoaWRkZW47cG9zaXRpb246YWJzb2x1dGV9Omhvc3QuaXMtb3Blbnt2aXNpYmlsaXR5OnZpc2libGV9Omhvc3QuaXMtYW5pbWF0ZXt0cmFuc2l0aW9uOmhlaWdodCAuMnMgZWFzZS1pbjt3aWR0aDozMDBweH06aG9zdC5pcy1hbmltYXRlIC5kYXRlcGlja2VyX19tYWlue3RyYW5zaXRpb246aGVpZ2h0IC4ycyBlYXNlLWlufTpob3N0LmlzLWFuaW1hdGUgLmRhdGVwaWNrZXJfX2NhbGVuZGFyLXdyYXBwZXJ7cG9zaXRpb246YWJzb2x1dGU7d2lkdGg6MjAwJTtsZWZ0OjB9Omhvc3QuaXMtYW5pbWF0ZSAuZGF0ZXBpY2tlcl9fY2FsZW5kYXJ7ZmxvYXQ6bGVmdDt3aWR0aDoxMDAlfTpob3N0LmlzLWFuaW1hdGUgLmRhdGVwaWNrZXJfX2NhbGVuZGFyLWNvbnRhaW5lcntmbG9hdDpsZWZ0fWBdXG59KVxuZXhwb3J0IGNsYXNzIEFuaW1hdGVwaWNrZXJDb21wb25lbnQgZXh0ZW5kcyBEYXRlcGlja2VyQ29tcG9uZW50IGltcGxlbWVudHMgT25Jbml0LCBBZnRlclZpZXdJbml0IHtcblx0LyogPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuXHQgKiBJbnRlcm5hbCBQcm9wZXJ0aWVzXG5cdCAqID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0gKi9cblxuXHRwdWJsaWMgYW5pbWF0ZSA9IHRydWU7XG5cdHB1YmxpYyBpbml0aWFsV2lkdGg6IG51bWJlcjtcblx0cHVibGljIGNhbGVuZGFyV2lkdGg6IG51bWJlcjtcblx0cHVibGljIGlzQW5pbWF0aW5nID0gZmFsc2U7XG5cdHB1YmxpYyBsZWZ0SW5uZXJQb3NpdGlvbiA9IDA7XG5cdHB1YmxpYyB0cmFuc2l0aW9uOiBzdHJpbmc7XG5cdHB1YmxpYyB0cmFuc2xhdGVYOiBudW1iZXI7XG5cdHB1YmxpYyBjdXJyZW50WWVhck1vbnRoOiBvYmplY3QgPSBudWxsO1xuXHRwdWJsaWMgZGF0ZXBpY2tlclBvc2l0aW9uOiBvYmplY3Q7XG5cdHB1YmxpYyBpbml0aWFsaXNlZCA9IGZhbHNlO1xuXHRwdWJsaWMgY2FsZW5kYXJIZWlnaHQ6IG51bWJlclxuXG5cdC8qID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cblx0ICogRXh0ZXJuYWwgUHJvcGVydGllc1xuXHQgKiA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09ICovXG5cblx0LyoqXG5cdCAqIE51bWJlciBvZiBtb250aHM6IHRoZSBudW1iZXIgb2YgbW9udGhzIGRpc3BsYXllZFxuXHQgKi9cblx0cHJpdmF0ZSBfbnVtYmVyT2ZNb250aHM6IGFueSA9IG5ldyBBcnJheSgxKTtcblx0QElucHV0KClcblx0c2V0IG51bWJlck9mTW9udGhzKHZhbHVlKSB7XG5cdFx0aWYgKHZhbHVlID09PSB1bmRlZmluZWQgfHwgdmFsdWUgPT09IHRoaXMuX251bWJlck9mTW9udGhzLmxlbmd0aCkge1xuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblx0XHR0aGlzLl9udW1iZXJPZk1vbnRocyA9IG5ldyBBcnJheSh2YWx1ZSk7XG5cdFx0dGhpcy5zZXREYXRlUGlja2VyRGltZW5zaW9uKCk7XG5cblx0XHR0aGlzLmdvVG9EYXRlKHRoaXMuZGF0ZSk7XG5cdH1cblxuXHRnZXQgbnVtYmVyT2ZNb250aHMoKTogTnVtYmVyW10ge1xuXHRcdHJldHVybiB0aGlzLl9udW1iZXJPZk1vbnRocztcblx0fVxuXG5cdC8qID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cblx0ICogQmluZGluZ3MgYW5kIENoaWxkcmVuXG5cdCAqID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0gKi9cblxuXHRAVmlld0NoaWxkKCdjYWxlbmRhckNvbnRhaW5lcicpIHB1YmxpYyBjYWxlbmRhckNvbnRhaW5lcjogRWxlbWVudFJlZjtcblx0QFZpZXdDaGlsZCgnY2FsZW5kYXJUb3BDb250YWluZXInKSBwdWJsaWMgY2FsZW5kYXJUb3BDb250YWluZXI6IEVsZW1lbnRSZWY7XG5cdEBWaWV3Q2hpbGQoJ2Zvb3RlcicpIHB1YmxpYyBmb290ZXI6IEVsZW1lbnRSZWY7XG5cdEBIb3N0QmluZGluZygnc3R5bGUud2lkdGgucHgnKSBwdWJsaWMgZGF0ZXBpY2tlcldpZHRoOiBudW1iZXI7XG5cdEBIb3N0QmluZGluZygnc3R5bGUuaGVpZ2h0LnB4JykgcHVibGljIGRhdGVwaWNrZXJIZWlnaHQ6IG51bWJlcjtcblxuXHRjb25zdHJ1Y3RvcihwdWJsaWMgZWxlbWVudFJlZjogRWxlbWVudFJlZiwgcHVibGljIHV0aWxpdGllczogVXRpbGl0aWVzU2VydmljZSkge1xuXHRcdHN1cGVyKHV0aWxpdGllcywgZWxlbWVudFJlZik7XG5cdH1cblxuXHRuZ09uSW5pdCgpIHtcblx0XHQvLyBHZXQgdGhlIGNvbXB1dGVkIHdpZHRoIGZyb20gdGhlIGNhbGVuZGFyLiBTZXQgdGhlIGluaXRpYWwgd2lkdGhcblx0XHRjb25zdCBjb21wdXRlZFdpZHRoID0gd2luZG93XG5cdFx0XHQuZ2V0Q29tcHV0ZWRTdHlsZSh0aGlzLmVsZW1lbnRSZWYubmF0aXZlRWxlbWVudCwgbnVsbClcblx0XHRcdC5nZXRQcm9wZXJ0eVZhbHVlKCd3aWR0aCcpO1xuXHRcdHRoaXMuaW5pdGlhbFdpZHRoID0gcGFyc2VJbnQoY29tcHV0ZWRXaWR0aCwgMTApO1xuXHRcdHRoaXMuaW5pdGlhbGlzZWQgPSB0cnVlO1xuXG5cdFx0Ly8gU2V0IHRoZSBjdXJyZW50IHllYXIgYW5kIG1vbnRoIG9iamVjdFxuXHRcdGlmICghdGhpcy5tb250aCAmJiAhdGhpcy55ZWFyKSB7XG5cdFx0XHR0aGlzLmdvVG9EYXRlKHRoaXMub3B0aW9ucy5jdXJyZW50RGF0ZSk7XG5cdFx0fVxuXHR9XG5cblx0bmdBZnRlclZpZXdJbml0KCkge1xuXHRcdHNldFRpbWVvdXQoKCkgPT4ge1xuXHRcdFx0dGhpcy5zZXREYXRlUGlja2VyRGltZW5zaW9uKCk7XG5cdFx0XHR0aGlzLnNldERhdGVwaWNrZXJIZWlnaHQodHJ1ZSk7XG5cdFx0fSk7XG5cdH1cblxuXHQvKipcblx0ICogU2V0IHRoZSBoZWlnaHQgYW5kIHRoZSB3aWR0aCBwcm9wZXJ0aWVzXG5cdCAqL1xuXHRzZXREYXRlUGlja2VyRGltZW5zaW9uKCk6IHZvaWQge1xuXHRcdHRoaXMuZGF0ZXBpY2tlckhlaWdodCA9XG5cdFx0XHR0aGlzLmNhbGVuZGFyQ29udGFpbmVyLm5hdGl2ZUVsZW1lbnQub2Zmc2V0SGVpZ2h0ICtcblx0XHRcdHRoaXMuY2FsZW5kYXJUb3BDb250YWluZXIubmF0aXZlRWxlbWVudC5vZmZzZXRIZWlnaHQgKyBcblx0XHRcdHRoaXMuZm9vdGVyLm5hdGl2ZUVsZW1lbnQub2Zmc2V0SGVpZ2h0O1xuXHRcdHRoaXMuY2FsZW5kYXJIZWlnaHQgPSB0aGlzLmNhbGVuZGFyQ29udGFpbmVyLm5hdGl2ZUVsZW1lbnQub2Zmc2V0SGVpZ2h0O1xuXHRcdHRoaXMuZGF0ZXBpY2tlcldpZHRoID0gdGhpcy5pbml0aWFsV2lkdGggKiB0aGlzLl9udW1iZXJPZk1vbnRocy5sZW5ndGg7XG5cdH1cblxuXHQvKipcblx0ICogR28gdG8gYSBzcGVjaWZpYyBtb250aFxuXHQgKlxuXHQgKiBAcGFyYW0gZGF0ZSAtIG9wdGlvbmFsXG5cdCAqL1xuXHRnb1RvRGF0ZShkYXRlPzogRGF0ZSk6IHZvaWQge1xuXHRcdGlmIChkYXRlKSB7XG5cdFx0XHR0aGlzLmN1cnJlbnRZZWFyTW9udGggPSB0aGlzLmdldE5leHRZZWFyTW9udGhBcnJheShkYXRlLmdldEZ1bGxZZWFyKCksIGRhdGUuZ2V0TW9udGgoKSk7XG5cdFx0fVxuXHRcdHRoaXMuY2FsZW5kYXJXaWR0aCA9IDUwIC8gdGhpcy5fbnVtYmVyT2ZNb250aHMubGVuZ3RoO1xuXHRcdHRoaXMubW9udGhzID0gdGhpcy5nZXROZXh0TW9udGhBcnJheSh0aGlzLmN1cnJlbnRZZWFyTW9udGgsIHRydWUpO1xuXHRcdHRoaXMucmVzZXRTdHlsZSgpO1xuXHR9XG5cblx0LyoqXG5cdCAqIENyZWF0ZSBhbiBhcnJheSBvZiB0aGUgbmV4dCB5ZWFyIGFuZCBtb250aHNcblx0ICpcblx0ICogQHBhcmFtIHllYXJcblx0ICogQHBhcmFtIG1vbnRoXG5cdCAqL1xuXHRnZXROZXh0WWVhck1vbnRoQXJyYXkoeWVhcjogbnVtYmVyLCBtb250aDogbnVtYmVyKTogWWVhck1vbnRoW10ge1xuXHRcdGNvbnN0IGFycmF5ID0gW107XG5cdFx0Zm9yIChsZXQgaW5kZXggPSAwOyBpbmRleCA8IHRoaXMuX251bWJlck9mTW9udGhzLmxlbmd0aDsgaW5kZXgrKykge1xuXHRcdFx0YXJyYXkucHVzaCh7IHllYXI6IHllYXIsIG1vbnRoOiBtb250aCB9KTtcblx0XHRcdHllYXIgPSBEYXRlcGlja2VyU2VydmljZS5nZXRZZWFyT2ZOZXh0TW9udGgoeWVhciwgbW9udGgpO1xuXHRcdFx0bW9udGggPSBEYXRlcGlja2VyU2VydmljZS5nZXROZXh0TW9udGgobW9udGgpO1xuXHRcdH1cblx0XHRyZXR1cm4gYXJyYXk7XG5cdH1cblxuXHQvKipcblx0ICogQ3JlYXRlIGFuIGFycmF5IG9mIHRoZSBwcmV2aW91cyB5ZWFyIGFuZCBtb250aHNcblx0ICpcblx0ICogQHBhcmFtIHllYXJcblx0ICogQHBhcmFtIG1vbnRoXG5cdCAqL1xuXHRnZXRQcmV2aW91c1llYXJNb250aEFycmF5KHllYXI6IG51bWJlciwgbW9udGg6IG51bWJlcik6IFllYXJNb250aFtdIHtcblx0XHRjb25zdCBhcnJheSA9IFtdO1xuXHRcdGZvciAobGV0IGluZGV4ID0gMDsgaW5kZXggPCB0aGlzLl9udW1iZXJPZk1vbnRocy5sZW5ndGg7IGluZGV4KyspIHtcblx0XHRcdGFycmF5LnVuc2hpZnQoeyB5ZWFyOiB5ZWFyLCBtb250aDogbW9udGggfSk7XG5cdFx0XHR5ZWFyID0gRGF0ZXBpY2tlclNlcnZpY2UuZ2V0WWVhck9mUHJldmlvdXNNb250aCh5ZWFyLCBtb250aCk7XG5cdFx0XHRtb250aCA9IERhdGVwaWNrZXJTZXJ2aWNlLmdldFByZXZpb3VzTW9udGgobW9udGgpO1xuXHRcdH1cblx0XHRyZXR1cm4gYXJyYXk7XG5cdH1cblxuXHQvKipcblx0ICogU2V0IHRoZSBkYXRlcGlja2VyIGhlaWdodCwgdXNlZCB3aGVuIGFuaW1hdGluZ1xuXHQgKlxuXHQgKiBAcGFyYW0gZGlyZWN0aW9uUmlnaHQgLSBTZXQgb3B0aW9uYWwgd2hlbiBzbGlkaW5nIHRvIHRoZSByaWdodFxuXHQgKi9cblx0c2V0RGF0ZXBpY2tlckhlaWdodChkaXJlY3Rpb25SaWdodD86IGJvb2xlYW4pOiB2b2lkIHtcblx0XHRsZXQgaW5kZXhBcnJheTogbnVtYmVyW107XG5cblx0XHQvLyBUT0RPOiBTZXBlcmF0ZSB0aGlzIGxvZ2ljIGZvciByZWFkYWJpbGl0eSBwdXJwb3NlXG5cdFx0aWYgKHRoaXMuX251bWJlck9mTW9udGhzLmxlbmd0aCA+IDEpIHtcblx0XHRcdGNvbnN0IHN0YXJ0ID0gZGlyZWN0aW9uUmlnaHQgPyAwIDogdGhpcy5fbnVtYmVyT2ZNb250aHMubGVuZ3RoO1xuXHRcdFx0Y29uc3QgZW5kID0gZGlyZWN0aW9uUmlnaHRcblx0XHRcdFx0PyB0aGlzLl9udW1iZXJPZk1vbnRocy5sZW5ndGggLSAxXG5cdFx0XHRcdDogdGhpcy5fbnVtYmVyT2ZNb250aHMubGVuZ3RoICsgdGhpcy5fbnVtYmVyT2ZNb250aHMubGVuZ3RoIC0gMTtcblx0XHRcdGluZGV4QXJyYXkgPSB0aGlzLnV0aWxpdGllcy5jcmVhdGVBcnJheShzdGFydCwgZW5kKTtcblx0XHR9IGVsc2Uge1xuXHRcdFx0aW5kZXhBcnJheSA9IGRpcmVjdGlvblJpZ2h0ID8gWzBdIDogWzFdO1xuXHRcdH1cblxuXHRcdGNvbnN0IHRoYXQgPSB0aGlzO1xuXHRcdHNldFRpbWVvdXQoKCkgPT4ge1xuXHRcdFx0Y29uc3QgY2FsZW5kYXJBcnJheSA9IHRoYXQuZWxlbWVudFJlZi5uYXRpdmVFbGVtZW50LnF1ZXJ5U2VsZWN0b3JBbGwoXG5cdFx0XHRcdCcuZGF0ZXBpY2tlcl9fY2FsZW5kYXItY29udGFpbmVyJ1xuXHRcdFx0KTtcblx0XHRcdGxldCBvZmZzZXRIZWlnaHQgPSAwO1xuXHRcdFx0aW5kZXhBcnJheS5mb3JFYWNoKGVsID0+IHtcblx0XHRcdFx0aWYgKGNhbGVuZGFyQXJyYXlbZWxdLm9mZnNldEhlaWdodCA+IG9mZnNldEhlaWdodCkge1xuXHRcdFx0XHRcdG9mZnNldEhlaWdodCA9IGNhbGVuZGFyQXJyYXlbZWxdLm9mZnNldEhlaWdodDtcblx0XHRcdFx0fVxuXHRcdFx0fSk7XG5cdFx0XHRcblx0XHRcdC8vIFRPRE86IE1lcmdlIHdpdGggc2V0SGVpZ2h0IGZ1bmN0aW9uLlxuXHRcdFx0dGhhdC5kYXRlcGlja2VySGVpZ2h0ID1cblx0XHRcdFx0b2Zmc2V0SGVpZ2h0ICsgdGhhdC5jYWxlbmRhclRvcENvbnRhaW5lci5uYXRpdmVFbGVtZW50Lm9mZnNldEhlaWdodCArIHRoYXQuZm9vdGVyLm5hdGl2ZUVsZW1lbnQub2Zmc2V0SGVpZ2h0O1xuXHRcdFx0dGhhdC5jYWxlbmRhckhlaWdodCA9IG9mZnNldEhlaWdodDtcblx0XHR9KTtcblx0fVxuXG5cdC8qKlxuXHQgKiBHZXQgbmV4dCBtb250aCBhcnJheSwgZ2V0cyBtdWx0aXBsZSBtb250aHMuXG5cdCAqIFVzZWQgd2hlbiB0aGUgb3B0aW9ucyBhbmltYXRlIGlzIHNldCBvciBtdWx0aXBsZSBtb250aHMgYXJlIHZpc2FibGVcblx0ICpcblx0ICogQHJldHVybiBNb250aFtdXG5cdCAqL1xuXHRnZXROZXh0TW9udGhBcnJheShjdXJyZW50WWVhck1vbnRoLCBrZWVwRGF0ZSA9IGZhbHNlLCBuZXh0TW9udGhzWWVhck1vbnRoQXJyYXk/KTogTW9udGhbXSB7XG5cdFx0Ly8gR2V0IHRoZSBsYXN0IGluZGV4LCB1c2VkIGZvciBzZWxlY3RpbmcgdGhlIHJpZ2h0IHllYXIgbW9udGggb2JqZWN0XG5cdFx0Y29uc3QgbGFzdEluZGV4ID0gdGhpcy5fbnVtYmVyT2ZNb250aHMubGVuZ3RoIC0gMTtcblxuXHRcdC8vIEdldCBuZXh0IHllYXIgYW5kIG1vbnRoIGluIGFuIE9iamVjdFxuXHRcdGNvbnN0IG5leHRNb250aHMgPVxuXHRcdFx0bmV4dE1vbnRoc1llYXJNb250aEFycmF5IHx8XG5cdFx0XHR0aGlzLmdldE5leHRZZWFyTW9udGhBcnJheShcblx0XHRcdFx0RGF0ZXBpY2tlclNlcnZpY2UuZ2V0WWVhck9mTmV4dE1vbnRoKFxuXHRcdFx0XHRcdGN1cnJlbnRZZWFyTW9udGhbbGFzdEluZGV4XS55ZWFyLFxuXHRcdFx0XHRcdGN1cnJlbnRZZWFyTW9udGhbbGFzdEluZGV4XS5tb250aFxuXHRcdFx0XHQpLFxuXHRcdFx0XHREYXRlcGlja2VyU2VydmljZS5nZXROZXh0TW9udGgoY3VycmVudFllYXJNb250aFtsYXN0SW5kZXhdLm1vbnRoKVxuXHRcdFx0KTtcblxuXHRcdC8vIENvbmNhdGVuYXRlcyB0aGUgdHdvIG9iamVjdHMgdG8gY3JlYXRlIGEgdG90YWwgeWVhciBhbmQgbW9udGggb2JqZWN0XG5cdFx0dGhpcy50b3RhbFllYXJNb250aCA9IGN1cnJlbnRZZWFyTW9udGguY29uY2F0KG5leHRNb250aHMpO1xuXG5cdFx0Ly8gQ3JlYXRlIHRoZSBjYWxlbmRhciBhcnJheSB1c2luZyB0aGUgdG90YWwgeWVhciBhbmQgbW9udGggT2JqZWN0XG5cdFx0Y29uc3QgbW9udGhBcnJheSA9IFtdO1xuXHRcdHRoaXMudG90YWxZZWFyTW9udGguZm9yRWFjaChlID0+XG5cdFx0XHRtb250aEFycmF5LnB1c2godGhpcy5jcmVhdGVDYWxlbmRhckFycmF5KGUueWVhciwgZS5tb250aCkpXG5cdFx0KTtcblxuXHRcdC8vIFNldCB0aGUgbmV3IGN1cnJlbnQgeWVhciBhbmQgbW9udGggb2JqZWN0LlxuXHRcdGlmICgha2VlcERhdGUpIHtcblx0XHRcdHRoaXMuY3VycmVudFllYXJNb250aCA9IG5leHRNb250aHM7XG5cdFx0fVxuXG5cdFx0cmV0dXJuIFtdLmNvbmNhdC5hcHBseShbXSwgbW9udGhBcnJheSk7XG5cdH1cblxuXHQvKipcblx0ICogR2V0cyBhbiBhcnJheSBvZiBwcmV2aW91cyBtb250aHMuXG5cdCAqIFVzZWQgZm9yIGFuaW1hdGlvbiBhbmQgd2hlbiBtb3JlIG1vbnRocyBhcmUgZGlzcGxheWVkXG5cdCAqXG5cdCAqIEBwYXJhbSBjdXJyZW50WWVhck1vbnRoXG5cdCAqIEBwYXJhbSBrZWVwRGF0ZVxuXHQgKi9cblx0Z2V0UHJldmlvdXNNb250aEFycmF5KGN1cnJlbnRZZWFyTW9udGgsIGtlZXBEYXRlID0gZmFsc2UpOiBNb250aFtdIHtcblx0XHQvLyBHZXQgcHJldmlvdXMgeWVhciBhbmQgbW9udGggaW4gYW4gT2JqZWN0XG5cdFx0Y29uc3QgcHJldmlvdXNNb250aHMgPSB0aGlzLmdldFByZXZpb3VzWWVhck1vbnRoQXJyYXkoXG5cdFx0XHREYXRlcGlja2VyU2VydmljZS5nZXRZZWFyT2ZQcmV2aW91c01vbnRoKFxuXHRcdFx0XHRjdXJyZW50WWVhck1vbnRoWzBdLnllYXIsXG5cdFx0XHRcdGN1cnJlbnRZZWFyTW9udGhbMF0ubW9udGhcblx0XHRcdCksXG5cdFx0XHREYXRlcGlja2VyU2VydmljZS5nZXRQcmV2aW91c01vbnRoKGN1cnJlbnRZZWFyTW9udGhbMF0ubW9udGgpXG5cdFx0KTtcblxuXHRcdC8vIENvbmNhdGVuYXRlcyB0aGUgdHdvIG9iamVjdHMgdG8gY3JlYXRlIGEgdG90YWwgeWVhciBhbmQgbW9udGggb2JqZWN0XG5cdFx0dGhpcy50b3RhbFllYXJNb250aCA9IHByZXZpb3VzTW9udGhzLmNvbmNhdChjdXJyZW50WWVhck1vbnRoKTtcblxuXHRcdC8vIENyZWF0ZSB0aGUgY2FsZW5kYXIgYXJyYXkgdXNpbmcgdGhlIHRvdGFsIHllYXIgYW5kIG1vbnRoIE9iamVjdFxuXHRcdGNvbnN0IG1vbnRoQXJyYXkgPSBbXTtcblx0XHR0aGlzLnRvdGFsWWVhck1vbnRoLmZvckVhY2goZSA9PiB7XG5cdFx0XHRtb250aEFycmF5LnB1c2godGhpcy5jcmVhdGVDYWxlbmRhckFycmF5KGVbJ3llYXInXSwgZVsnbW9udGgnXSkpO1xuXHRcdH0pO1xuXG5cdFx0Ly8gU2V0IHRoZSBuZXcgY3VycmVudCB5ZWFyIGFuZCBtb250aCBvYmplY3QuXG5cdFx0aWYgKCFrZWVwRGF0ZSkge1xuXHRcdFx0dGhpcy5jdXJyZW50WWVhck1vbnRoID0gcHJldmlvdXNNb250aHM7XG5cdFx0fVxuXG5cdFx0cmV0dXJuIFtdLmNvbmNhdC5hcHBseShbXSwgbW9udGhBcnJheSk7XG5cdH1cblxuXHQvKipcblx0ICogVXBkYXRlIHZhbHVlIGlzIGJlaW5nIHRyaWdnZXJlZFxuXHQgKlxuXHQgKiBAcGFyYW0gZGF0ZVxuXHQgKi9cblx0dXBkYXRlVmFsdWUoZGF0ZTogRGF0ZSk6IHZvaWQge1xuXHRcdGlmICh0aGlzLm9wdGlvbnMucmFuZ2UpIHtcblx0XHRcdHRoaXMuc2VsZWN0UmFuZ2UoZGF0ZSk7XG5cdFx0fSBlbHNlIGlmICghdGhpcy5pc1NlbGVjdGVkKGRhdGUpKSB7XG5cdFx0XHRpZiAodGhpcy5vcHRpb25zLnNlbGVjdE11bHRpcGxlKSB7XG5cdFx0XHRcdHRoaXMuc2VsZWN0RGF0ZShkYXRlKTtcblx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdHRoaXMudG9nZ2xlRGF0ZShkYXRlKTtcblx0XHRcdH1cblxuXHRcdFx0aWYgKHRoaXMub3B0aW9ucy5jbG9zZU9uU2VsZWN0KSB7XG5cdFx0XHRcdHRoaXMuY2xvc2UodHJ1ZSk7XG5cdFx0XHR9XG5cdFx0fSBlbHNlIHtcblx0XHRcdHRoaXMuZGVzZWxlY3REYXRlKGRhdGUpO1xuXG5cdFx0XHRpZiAodGhpcy5vcHRpb25zLmNsb3NlT25TZWxlY3QpIHtcblx0XHRcdFx0dGhpcy5jbG9zZSh0cnVlKTtcblx0XHRcdH1cblx0XHR9XG5cdFx0dGhpcy5tb250aHMgPSB0aGlzLmdldE5leHRNb250aEFycmF5KHRoaXMuY3VycmVudFllYXJNb250aCwgdHJ1ZSk7XG5cdFx0dGhpcy5yZXNldFN0eWxlKCk7XG5cdH1cblxuXHQvKipcblx0ICogR28gdG8gdGhlIG5leHQgbW9udGhcblx0ICovXG5cdGdvVG9OZXh0TW9udGgoKTogdm9pZCB7XG5cdFx0aWYgKHRoaXMuaXNBbmltYXRpbmcpIHtcblx0XHRcdHJldHVybjtcblx0XHR9XG5cblx0XHR0aGlzLm1vbnRocyA9IHRoaXMuZ2V0TmV4dE1vbnRoQXJyYXkodGhpcy5jdXJyZW50WWVhck1vbnRoKTtcblx0XHR0aGlzLnJlc2V0U3R5bGUoKTtcblx0XHR0aGlzLnNldERhdGVwaWNrZXJIZWlnaHQoKTtcblx0XHR0aGlzLnNsaWRlTGVmdCgpO1xuXHR9XG5cblx0LyoqXG5cdCAqIEdvIHRvIHRoZSBwcmV2aW91cyBtb250aFxuXHQgKi9cblx0Z29Ub1ByZXZpb3VzTW9udGgoKTogdm9pZCB7X