ng-scroll-picker
Version:
Base logic inspired from https://github.com/hiyali/ng-data-picker
437 lines (431 loc) • 59.9 kB
JavaScript
import { Inject, Component, Input, Output, EventEmitter, ElementRef, ViewChild, ViewChildren, } from '@angular/core';
import * as i0 from "@angular/core";
import * as i1 from "@angular/common";
export class NgScrollPickerComponent {
constructor(elementRef) {
this.data = [];
this.change = new EventEmitter();
this.touchOrMouse = {
isTouchable: 'ontouchstart' in window,
isMouseDown: false,
};
this.draggingInfo = {
isDragging: false,
groupIndex: null,
startPageY: null,
};
this.itemPerDegree = 23;
this.safeDoTimeoutId = null;
}
ngOnInit() {
this.currentIndexList = this.getInitialCurrentIndexList();
this.lastCurrentIndexList = new Array().concat(this.currentIndexList);
this.groupsRectList = new Array(this.data.length);
}
ngAfterViewInit() {
this.eventsRegister();
window.addEventListener('resize', this.safeGetRectsBindEvents.bind(this));
this.getGroupsRectList();
}
ngOnDestroy() {
window.removeEventListener('resize', this.safeGetRectsBindEvents.bind(this));
}
setGroupData(gIndex, groupData) {
if (!this.currentIndexList) {
this.currentIndexList = this.getInitialCurrentIndexList();
}
this.data[gIndex] = groupData;
const iCI = groupData.currentIndex;
let movedIndex = 0;
if (typeof iCI === 'number' &&
iCI >= 0 &&
groupData.list &&
groupData.list.length &&
iCI <= groupData.list.length - 1) {
movedIndex = Math.round(iCI);
}
this.currentIndexList[gIndex] = movedIndex;
this.lastCurrentIndexList = new Array().concat(this.currentIndexList);
}
getInitialCurrentIndexList() {
return this.data.map((item, index) => {
const iCI = item.currentIndex;
if (typeof iCI === 'number' &&
iCI >= 0 &&
item.list &&
item.list.length &&
iCI <= item.list.length - 1) {
return Math.round(iCI);
}
return 0;
});
}
safeGetRectsBindEvents() {
if (this.safeDoTimeoutId) {
clearTimeout(this.safeDoTimeoutId);
}
this.safeDoTimeoutId = setTimeout(() => {
this.getGroupsRectList();
}, 200);
}
getGroupsRectList() {
if (this.pickerGroupLayer) {
this.pickerGroupLayer.toArray().forEach((item, index) => {
this.groupsRectList[index] = item.nativeElement.getBoundingClientRect();
});
}
}
eventsRegister() {
const handleEventLayer = this.pickerHandleLayer.nativeElement;
if (handleEventLayer) {
this.addEventsForElement(handleEventLayer);
}
}
addEventsForElement(el) {
const _ = this.touchOrMouse.isTouchable;
const eventHandlerList = [
{ name: _ ? 'touchstart' : 'mousedown', handler: this.handleStart },
{ name: _ ? 'touchmove' : 'mousemove', handler: this.handleMove },
{ name: _ ? 'touchend' : 'mouseup', handler: this.handleEnd },
{ name: _ ? 'touchcancel' : 'mouseleave', handler: this.handleCancel },
{ name: 'wheel', handler: this.handleScroll },
];
eventHandlerList.forEach((item, index) => {
el.removeEventListener(item.name, item.handler, false);
el.addEventListener(item.name, item.handler.bind(this), false);
});
}
triggerMiddleLayerGroupClick(gIndex) {
const data = this.data;
if (data[gIndex].onClick !== undefined) {
const click = data[gIndex].onClick;
if (typeof gIndex === 'number' &&
typeof data[gIndex].onClick === 'function') {
// click(
// gIndex,
// this.currentIndexList[gIndex],
// this.data[gIndex].list[this.currentIndexList[gIndex]]
// );
const response = {
gIndex,
iIndex: this.currentIndexList[gIndex],
selectedValue: this.data[gIndex].list[this.currentIndexList[gIndex]],
groupName: this.data[gIndex].groupName,
};
click(response);
}
}
}
triggerAboveLayerClick(ev, gIndex) {
const movedIndex = this.currentIndexList[gIndex] + 1;
this.currentIndexList[gIndex] = movedIndex;
this.correctionCurrentIndex(ev, gIndex);
}
triggerMiddleLayerClick(ev, gIndex) {
this.triggerMiddleLayerGroupClick(gIndex);
}
triggerBelowLayerClick(ev, gIndex) {
const movedIndex = this.currentIndexList[gIndex] - 1;
this.currentIndexList[gIndex] = movedIndex;
this.correctionCurrentIndex(ev, gIndex);
}
getTouchInfo(ev) {
return this.touchOrMouse.isTouchable
? ev.changedTouches[0] || ev.touches[0]
: ev;
}
getGroupIndexBelongsEvent(ev) {
const touchInfo = this.getTouchInfo(ev);
for (let i = 0; i < this.groupsRectList.length; i++) {
const item = this.groupsRectList[i];
if (item.left < touchInfo.pageX && touchInfo.pageX < item.right) {
return i;
}
}
return null;
}
handleEventClick(ev) {
const gIndex = this.getGroupIndexBelongsEvent(ev);
switch (ev.target.dataset.type) {
case 'top':
this.triggerAboveLayerClick(ev, gIndex);
break;
case 'middle':
this.triggerMiddleLayerClick(ev, gIndex);
break;
case 'bottom':
this.triggerBelowLayerClick(ev, gIndex);
break;
default:
}
}
handleStart(ev) {
if (ev.cancelable) {
ev.preventDefault();
ev.stopPropagation();
}
const touchInfo = this.getTouchInfo(ev);
this.draggingInfo.startPageY = touchInfo.pageY;
if (!this.touchOrMouse.isTouchable) {
this.touchOrMouse.isMouseDown = true;
}
}
handleMove(ev) {
ev.preventDefault();
ev.stopPropagation();
if (this.touchOrMouse.isTouchable || this.touchOrMouse.isMouseDown) {
this.draggingInfo.isDragging = true;
this.setCurrentIndexOnMove(ev);
}
}
handleEnd(ev) {
ev.preventDefault();
ev.stopPropagation();
if (!this.draggingInfo.isDragging) {
this.handleEventClick(ev);
}
this.draggingInfo.isDragging = false;
this.touchOrMouse.isMouseDown = false;
this.correctionAfterDragging(ev);
}
handleCancel(ev) {
ev.preventDefault();
ev.stopPropagation();
if (this.touchOrMouse.isTouchable || this.touchOrMouse.isMouseDown) {
this.correctionAfterDragging(ev);
this.touchOrMouse.isMouseDown = false;
this.draggingInfo.isDragging = false;
}
}
handleScroll(ev) {
ev.preventDefault();
ev.stopPropagation();
if (ev instanceof WheelEvent) {
ev = ev;
const gIndex = this.getGroupIndexBelongsEvent(ev);
const deltaY = ev.deltaY;
if (deltaY > 0) {
// Scrolling down
console.log('Scrolling down');
this.triggerAboveLayerClick(ev, gIndex);
}
else if (deltaY < 0) {
// Scrolling up
console.log('Scrolling up');
this.triggerBelowLayerClick(ev, gIndex);
}
else {
// No vertical scrolling
console.log('No vertical scrolling');
}
}
}
setCurrentIndexOnMove(ev) {
const touchInfo = this.getTouchInfo(ev);
if (this.draggingInfo.groupIndex === null) {
this.draggingInfo.groupIndex = this.getGroupIndexBelongsEvent(ev);
}
if (this.draggingInfo.groupIndex !== null) {
const gIndex = this.draggingInfo.groupIndex;
if (typeof gIndex === 'number' &&
(this.data[gIndex].divider || !this.data[gIndex].list)) {
return;
}
if (this.draggingInfo.startPageY !== null) {
const moveCount = (this.draggingInfo.startPageY - touchInfo.pageY) / 32;
const movedIndex = this.currentIndexList[gIndex] + moveCount;
this.currentIndexList[gIndex] = movedIndex;
this.draggingInfo.startPageY = touchInfo.pageY;
}
}
}
correctionAfterDragging(ev) {
const gIndex = this.draggingInfo.groupIndex;
this.correctionCurrentIndex(ev, gIndex);
this.draggingInfo.groupIndex = null;
this.draggingInfo.startPageY = null;
this.getCurrentIndexList();
}
correctionCurrentIndex(ev, gIndex) {
setTimeout(() => {
if (typeof gIndex === 'number' &&
this.data[gIndex].divider !== true &&
this.data[gIndex].list.length > 0) {
const unsafeGroupIndex = this.currentIndexList[gIndex];
let movedIndex = unsafeGroupIndex;
if (unsafeGroupIndex > this.data[gIndex].list.length - 1) {
movedIndex = this.data[gIndex].list.length - 1;
}
else if (unsafeGroupIndex < 0) {
movedIndex = 0;
}
movedIndex = Math.round(movedIndex);
this.currentIndexList[gIndex] = movedIndex;
if (movedIndex !== this.lastCurrentIndexList[gIndex]) {
const response = {
gIndex,
iIndex: movedIndex,
selectedValue: this.data[gIndex].list[movedIndex],
groupName: this.data[gIndex].groupName,
};
// this.change.emit({
// gIndex,
// iIndex: movedIndex,
// selectedValue: this.data[gIndex].list[movedIndex],
// });
this.change.emit(response);
}
this.lastCurrentIndexList = new Array().concat(this.currentIndexList);
}
}, 100);
}
isCurrentItem(gIndex, iIndex) {
return this.currentIndexList[gIndex] === iIndex;
}
getCurrentIndexList() {
return this.currentIndexList;
}
getGroupClass(gIndex) {
const group = this.data[gIndex];
const defaultWeightClass = 'weight-' + (group.weight || 1);
const groupClass = [defaultWeightClass];
if (group.className) {
groupClass.push(group.className);
}
return groupClass;
}
getItemClass(gIndex, iIndex, isDivider = false) {
const group = this.data[gIndex];
const itemClass = [];
if (!isDivider && this.isCurrentItem(gIndex, iIndex)) {
itemClass.push('smooth-item-selected');
}
if (group.textAlign) {
itemClass.push('text-' + group.textAlign);
}
return itemClass;
}
getItemStyle(gIndex, iIndex) {
const gapCount = this.currentIndexList[gIndex] - iIndex;
if (Math.abs(gapCount) < 90 / this.itemPerDegree) {
const rotateStyle = {
transform: 'rotateX(' +
gapCount * this.itemPerDegree +
'deg) translate3d(0, 0, 5.625em)',
opacity: (1 -
Math.abs(gapCount) / (90 / this.itemPerDegree)).toString(),
// color: gapCount === 0 ? 'rgba(237, 27, 45, 1)' : '',
};
if (!this.draggingInfo.isDragging) {
rotateStyle['transition'] = 'transform 150ms ease-out';
}
return rotateStyle;
}
if (gapCount > 0) {
return { transform: 'rotateX(90deg) translate3d(0, 0, 5.625em)' };
}
else {
return { transform: 'rotateX(-90deg) translate3d(0, 0, 5.625em)' };
}
}
}
NgScrollPickerComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: NgScrollPickerComponent, deps: [{ token: ElementRef }], target: i0.ɵɵFactoryTarget.Component });
NgScrollPickerComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.9", type: NgScrollPickerComponent, selector: "ng-scroll-picker", inputs: { data: "data" }, outputs: { change: "change" }, viewQueries: [{ propertyName: "pickerHandleLayer", first: true, predicate: ["pickerHandleLayer"], descendants: true }, { propertyName: "pickerGroupLayer", predicate: ["pickerGroupLayer"], descendants: true }], ngImport: i0, template: `
<div class="ng-data-picker flex-box">
<div class="picker-handle-layer flex-box dir-column">
<div data-type="top" class="picker-top weight-1"></div>
<div data-type="middle" class="picker-middle tengah"></div>
<div data-type="bottom" class="picker-bottom weight-1"></div>
</div>
<div
#pickerGroupLayer
*ngFor="let group of data; let gIndex = index"
class="picker-group"
[ngClass]="getGroupClass(gIndex)"
>
<div class="picker-list">
<div
*ngIf="group.divider; else ngIfElse"
class="picker-item divider"
[ngClass]="getItemClass(gIndex, gIndex, true)"
>
{{ group.text }}
</div>
<ng-template #ngIfElse>
<div
#ngIfElse
*ngFor="let item of group.list; let iIndex = index"
class="picker-item"
[ngClass]="getItemClass(gIndex, iIndex)"
[ngStyle]="getItemStyle(gIndex, iIndex)"
>
{{ item.label }}
</div>
</ng-template>
</div>
</div>
<div #pickerHandleLayer class="picker-handle-layer flex-box dir-column">
<div data-type="top" class="picker-top weight-1"></div>
<div data-type="middle" class="picker-middle"></div>
<div data-type="bottom" class="picker-bottom weight-1"></div>
</div>
</div>
`, isInline: true, styles: [".ng-data-picker{font-size:1rem;height:10em;position:relative;background-color:#fff;overflow:hidden}.ng-data-picker.black{color:#fff}.ng-data-picker .picker-list{height:6.25em;position:relative;top:4em}.ng-data-picker .picker-item{position:absolute;top:0;left:0;overflow:hidden;width:100%;text-overflow:ellipsis;white-space:nowrap;display:block;text-align:center;will-change:transform;contain:strict;height:2em;line-height:2;font-size:1em}.ng-data-picker .picker-handle-layer{position:absolute;width:100%;height:calc(100% + 2px);inset:-1px 0}.ng-data-picker .picker-handle-layer .picker-top{background:linear-gradient(to bottom,white 2%,rgba(255,255,255,.1) 100%);transform:translateZ(5.625em)}.ng-data-picker .picker-handle-layer .picker-middle{height:2em}.tengah{background-color:#dcdcdc;border-radius:5px}.ng-data-picker .picker-handle-layer .picker-bottom{background:linear-gradient(to top,white 2%,rgba(255,255,255,.1) 100%);transform:translateZ(5.625em)}.flex-box{display:flex}.flex-box.dir-column{flex-direction:column}.flex-box.dir-row{flex-direction:row}.flex-box .weight-1{flex:1}.flex-box .weight-2{flex:2}.flex-box .weight-3{flex:3}.flex-box .weight-4{flex:4}.flex-box .weight-5{flex:5}.flex-box .weight-6{flex:6}.flex-box .weight-7{flex:7}.flex-box .weight-8{flex:8}.flex-box .weight-9{flex:9}.flex-box .weight-10{flex:10}.flex-box .weight-11{flex:11}.flex-box .weight-12{flex:12}\n"], dependencies: [{ kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }] });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: NgScrollPickerComponent, decorators: [{
type: Component,
args: [{ selector: 'ng-scroll-picker', template: `
<div class="ng-data-picker flex-box">
<div class="picker-handle-layer flex-box dir-column">
<div data-type="top" class="picker-top weight-1"></div>
<div data-type="middle" class="picker-middle tengah"></div>
<div data-type="bottom" class="picker-bottom weight-1"></div>
</div>
<div
#pickerGroupLayer
*ngFor="let group of data; let gIndex = index"
class="picker-group"
[ngClass]="getGroupClass(gIndex)"
>
<div class="picker-list">
<div
*ngIf="group.divider; else ngIfElse"
class="picker-item divider"
[ngClass]="getItemClass(gIndex, gIndex, true)"
>
{{ group.text }}
</div>
<ng-template #ngIfElse>
<div
#ngIfElse
*ngFor="let item of group.list; let iIndex = index"
class="picker-item"
[ngClass]="getItemClass(gIndex, iIndex)"
[ngStyle]="getItemStyle(gIndex, iIndex)"
>
{{ item.label }}
</div>
</ng-template>
</div>
</div>
<div #pickerHandleLayer class="picker-handle-layer flex-box dir-column">
<div data-type="top" class="picker-top weight-1"></div>
<div data-type="middle" class="picker-middle"></div>
<div data-type="bottom" class="picker-bottom weight-1"></div>
</div>
</div>
`, styles: [".ng-data-picker{font-size:1rem;height:10em;position:relative;background-color:#fff;overflow:hidden}.ng-data-picker.black{color:#fff}.ng-data-picker .picker-list{height:6.25em;position:relative;top:4em}.ng-data-picker .picker-item{position:absolute;top:0;left:0;overflow:hidden;width:100%;text-overflow:ellipsis;white-space:nowrap;display:block;text-align:center;will-change:transform;contain:strict;height:2em;line-height:2;font-size:1em}.ng-data-picker .picker-handle-layer{position:absolute;width:100%;height:calc(100% + 2px);inset:-1px 0}.ng-data-picker .picker-handle-layer .picker-top{background:linear-gradient(to bottom,white 2%,rgba(255,255,255,.1) 100%);transform:translateZ(5.625em)}.ng-data-picker .picker-handle-layer .picker-middle{height:2em}.tengah{background-color:#dcdcdc;border-radius:5px}.ng-data-picker .picker-handle-layer .picker-bottom{background:linear-gradient(to top,white 2%,rgba(255,255,255,.1) 100%);transform:translateZ(5.625em)}.flex-box{display:flex}.flex-box.dir-column{flex-direction:column}.flex-box.dir-row{flex-direction:row}.flex-box .weight-1{flex:1}.flex-box .weight-2{flex:2}.flex-box .weight-3{flex:3}.flex-box .weight-4{flex:4}.flex-box .weight-5{flex:5}.flex-box .weight-6{flex:6}.flex-box .weight-7{flex:7}.flex-box .weight-8{flex:8}.flex-box .weight-9{flex:9}.flex-box .weight-10{flex:10}.flex-box .weight-11{flex:11}.flex-box .weight-12{flex:12}\n"] }]
}], ctorParameters: function () { return [{ type: i0.ElementRef, decorators: [{
type: Inject,
args: [ElementRef]
}] }]; }, propDecorators: { pickerGroupLayer: [{
type: ViewChildren,
args: ['pickerGroupLayer']
}], pickerHandleLayer: [{
type: ViewChild,
args: ['pickerHandleLayer']
}], data: [{
type: Input
}], change: [{
type: Output
}] } });
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibmctc2Nyb2xsLXBpY2tlci5jb21wb25lbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9wcm9qZWN0cy9uZy1zY3JvbGwtcGlja2VyL3NyYy9saWIvbmctc2Nyb2xsLXBpY2tlci5jb21wb25lbnQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUlMLE1BQU0sRUFDTixTQUFTLEVBQ1QsS0FBSyxFQUNMLE1BQU0sRUFDTixZQUFZLEVBQ1osVUFBVSxFQUNWLFNBQVMsRUFDVCxZQUFZLEdBQ2IsTUFBTSxlQUFlLENBQUM7OztBQW1MdkIsTUFBTSxPQUFPLHVCQUF1QjtJQTZCbEMsWUFBZ0MsVUFBc0I7UUF2QjdDLFNBQUksR0FBc0IsRUFBRSxDQUFDO1FBQzVCLFdBQU0sR0FDZCxJQUFJLFlBQVksRUFBdUIsQ0FBQztRQUsxQyxpQkFBWSxHQUFHO1lBQ2IsV0FBVyxFQUFFLGNBQWMsSUFBSSxNQUFNO1lBQ3JDLFdBQVcsRUFBRSxLQUFLO1NBQ25CLENBQUM7UUFDRixpQkFBWSxHQUFHO1lBQ2IsVUFBVSxFQUFFLEtBQUs7WUFDakIsVUFBVSxFQUFFLElBQUk7WUFDaEIsVUFBVSxFQUFFLElBQUk7U0FLakIsQ0FBQztRQUNGLGtCQUFhLEdBQUcsRUFBRSxDQUFDO1FBQ25CLG9CQUFlLEdBQVEsSUFBSSxDQUFDO0lBRTZCLENBQUM7SUFFMUQsUUFBUTtRQUNOLElBQUksQ0FBQyxnQkFBZ0IsR0FBRyxJQUFJLENBQUMsMEJBQTBCLEVBQUUsQ0FBQztRQUMxRCxJQUFJLENBQUMsb0JBQW9CLEdBQUcsSUFBSSxLQUFLLEVBQVUsQ0FBQyxNQUFNLENBQ3BELElBQUksQ0FBQyxnQkFBZ0IsQ0FDdEIsQ0FBQztRQUVGLElBQUksQ0FBQyxjQUFjLEdBQUcsSUFBSSxLQUFLLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsQ0FBQztJQUNwRCxDQUFDO0lBRUQsZUFBZTtRQUNiLElBQUksQ0FBQyxjQUFj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ZXJWaWV3SW5pdCxcclxuICBPbkRlc3Ryb3ksXHJcbiAgSW5qZWN0LFxyXG4gIENvbXBvbmVudCxcclxuICBJbnB1dCxcclxuICBPdXRwdXQsXHJcbiAgRXZlbnRFbWl0dGVyLFxyXG4gIEVsZW1lbnRSZWYsXHJcbiAgVmlld0NoaWxkLFxyXG4gIFZpZXdDaGlsZHJlbixcclxufSBmcm9tICdAYW5ndWxhci9jb3JlJztcclxuXHJcbmltcG9ydCB7IFBpY2tlckRhdGFNb2RlbCwgUGlja2VyUmVzcG9uc2VNb2RlbCB9IGZyb20gJy4vbmctc2Nyb2xsLWRhdGEubW9kZWwnO1xyXG5leHBvcnQgeyBQaWNrZXJEYXRhTW9kZWwsIFBpY2tlclJlc3BvbnNlTW9kZWwgfTtcclxuXHJcbkBDb21wb25lbnQoe1xyXG4gIHNlbGVjdG9yOiAnbmctc2Nyb2xsLXBpY2tlcicsXHJcbiAgdGVtcGxhdGU6IGBcclxuICAgIDxkaXYgY2xhc3M9XCJuZy1kYXRhLXBpY2tlciBmbGV4LWJveFwiPlxyXG4gICAgICA8ZGl2IGNsYXNzPVwicGlja2VyLWhhbmRsZS1sYXllciBmbGV4LWJveCBkaXItY29sdW1uXCI+XHJcbiAgICAgICAgPGRpdiBkYXRhLXR5cGU9XCJ0b3BcIiBjbGFzcz1cInBpY2tlci10b3Agd2VpZ2h0LTFcIj48L2Rpdj5cclxuICAgICAgICA8ZGl2IGRhdGEtdHlwZT1cIm1pZGRsZVwiIGNsYXNzPVwicGlja2VyLW1pZGRsZSB0ZW5nYWhcIj48L2Rpdj5cclxuICAgICAgICA8ZGl2IGRhdGEtdHlwZT1cImJvdHRvbVwiIGNsYXNzPVwicGlja2VyLWJvdHRvbSB3ZWlnaHQtMVwiPjwvZGl2PlxyXG4gICAgICA8L2Rpdj5cclxuXHJcbiAgICAgIDxkaXZcclxuICAgICAgICAjcGlja2VyR3JvdXBMYXllclxyXG4gICAgICAgICpuZ0Zvcj1cImxldCBncm91cCBvZiBkYXRhOyBsZXQgZ0luZGV4ID0gaW5kZXhcIlxyXG4gICAgICAgIGNsYXNzPVwicGlja2VyLWdyb3VwXCJcclxuICAgICAgICBbbmdDbGFzc109XCJnZXRHcm91cENsYXNzKGdJbmRleClcIlxyXG4gICAgICA+XHJcbiAgICAgICAgPGRpdiBjbGFzcz1cInBpY2tlci1saXN0XCI+XHJcbiAgICAgICAgICA8ZGl2XHJcbiAgICAgICAgICAgICpuZ0lmPVwiZ3JvdXAuZGl2aWRlcjsgZWxzZSBuZ0lmRWxzZVwiXHJcbiAgICAgICAgICAgIGNsYXNzPVwicGlja2VyLWl0ZW0gZGl2aWRlclwiXHJcbiAgICAgICAgICAgIFtuZ0NsYXNzXT1cImdldEl0ZW1DbGFzcyhnSW5kZXgsIGdJbmRleCwgdHJ1ZSlcIlxyXG4gICAgICAgICAgPlxyXG4gICAgICAgICAgICB7eyBncm91cC50ZXh0IH19XHJcbiAgICAgICAgICA8L2Rpdj5cclxuXHJcbiAgICAgICAgICA8bmctdGVtcGxhdGUgI25nSWZFbHNlPlxyXG4gICAgICAgICAgICA8ZGl2XHJcbiAgICAgICAgICAgICAgI25nSWZFbHNlXHJcbiAgICAgICAgICAgICAgKm5nRm9yPVwibGV0IGl0ZW0gb2YgZ3JvdXAubGlzdDsgbGV0IGlJbmRleCA9IGluZGV4XCJcclxuICAgICAgICAgICAgICBjbGFzcz1cInBpY2tlci1pdGVtXCJcclxuICAgICAgICAgICAgICBbbmdDbGFzc109XCJnZXRJdGVtQ2xhc3MoZ0luZGV4LCBpSW5kZXgpXCJcclxuICAgICAgICAgICAgICBbbmdTdHlsZV09XCJnZXRJdGVtU3R5bGUoZ0luZGV4LCBpSW5kZXgpXCJcclxuICAgICAgICAgICAgPlxyXG4gICAgICAgICAgICAgIHt7IGl0ZW0ubGFiZWwgfX1cclxuICAgICAgICAgICAgPC9kaXY+XHJcbiAgICAgICAgICA8L25nLXRlbXBsYXRlPlxyXG4gICAgICAgIDwvZGl2PlxyXG4gICAgICA8L2Rpdj5cclxuXHJcbiAgICAgIDxkaXYgI3BpY2tlckhhbmRsZUxheWVyIGNsYXNzPVwicGlja2VyLWhhbmRsZS1sYXllciBmbGV4LWJveCBkaXItY29sdW1uXCI+XHJcbiAgICAgICAgPGRpdiBkYXRhLXR5cGU9XCJ0b3BcIiBjbGFzcz1cInBpY2tlci10b3Agd2VpZ2h0LTFcIj48L2Rpdj5cclxuICAgICAgICA8ZGl2IGRhdGEtdHlwZT1cIm1pZGRsZVwiIGNsYXNzPVwicGlja2VyLW1pZGRsZVwiPjwvZGl2PlxyXG4gICAgICAgIDxkaXYgZGF0YS10eXBlPVwiYm90dG9tXCIgY2xhc3M9XCJwaWNrZXItYm90dG9tIHdlaWdodC0xXCI+PC9kaXY+XHJcbiAgICAgIDwvZGl2PlxyXG4gICAgPC9kaXY+XHJcbiAgYCxcclxuICBzdHlsZXM6IFtcclxuICAgIGBcclxuICAgICAgLm5nLWRhdGEtcGlja2VyIHtcclxuICAgICAgICBmb250LXNpemU6IDFyZW07XHJcbiAgICAgICAgaGVpZ2h0OiAxMGVtO1xyXG4gICAgICAgIHBvc2l0aW9uOiByZWxhdGl2ZTtcclxuICAgICAgICBiYWNrZ3JvdW5kLWNvbG9yOiB3aGl0ZTtcclxuICAgICAgICBvdmVyZmxvdzogaGlkZGVuO1xyXG4gICAgICB9XHJcbiAgICAgIC5uZy1kYXRhLXBpY2tlci5ibGFjayB7XHJcbiAgICAgICAgY29sb3I6IHdoaXRlO1xyXG4gICAgICB9XHJcbiAgICAgIC5uZy1kYXRhLXBpY2tlciAucGlja2VyLWdyb3VwIHtcclxuICAgICAgfVxyXG4gICAgICAubmctZGF0YS1waWNrZXIgLnBpY2tlci1saXN0IHtcclxuICAgICAgICBoZWlnaHQ6IDYuMjVlbTtcclxuICAgICAgICBwb3NpdGlvbjogcmVsYXRpdmU7XHJcbiAgICAgICAgdG9wOiA0ZW07XHJcbiAgICAgIH1cclxuICAgICAgLm5nLWRhdGEtcGlja2VyIC5waWNrZXItaXRlbSB7XHJcbiAgICAgICAgcG9zaXRpb246IGFic29sdXRlO1xyXG4gICAgICAgIHRvcDogMDtcclxuICAgICAgICBsZWZ0OiAwO1xyXG4gICAgICAgIG92ZXJmbG93OiBoaWRkZW47XHJcbiAgICAgICAgd2lkdGg6IDEwMCU7XHJcbiAgICAgICAgdGV4dC1vdmVyZmxvdzogZWxsaXBzaXM7XHJcbiAgICAgICAgd2hpdGUtc3BhY2U6IG5vd3JhcDtcclxuICAgICAgICBkaXNwbGF5OiBibG9jaztcclxuICAgICAgICB0ZXh0LWFsaWduOiBjZW50ZXI7XHJcbiAgICAgICAgd2lsbC1jaGFuZ2U6IHRyYW5zZm9ybTtcclxuICAgICAgICBjb250YWluOiBzdHJpY3Q7XHJcbiAgICAgICAgaGVpZ2h0OiAyZW07XHJcbiAgICAgICAgbGluZS1oZWlnaHQ6IDI7XHJcbiAgICAgICAgZm9udC1zaXplOiAxZW07XHJcbiAgICAgIH1cclxuICAgICAgLm5nLWRhdGEtcGlja2VyIC5zZWxlY3RlZC1pdGVtIHtcclxuICAgICAgfVxyXG5cclxuICAgICAgLyogcGlja2VyIGhhbmRsZSBsYXllciAqL1xyXG4gICAgICAubmctZGF0YS1waWNrZXIgLnBpY2tlci1oYW5kbGUtbGF5ZXIge1xyXG4gICAgICAgIHBvc2l0aW9uOiBhYnNvbHV0ZTtcclxuICAgICAgICB3aWR0aDogMTAwJTtcclxuICAgICAgICBoZWlnaHQ6IGNhbGMoMTAwJSArIDJweCk7XHJcbiAgICAgICAgbGVmdDogMDtcclxuICAgICAgICByaWdodDogMDtcclxuICAgICAgICB0b3A6IC0xcHg7XHJcbiAgICAgICAgYm90dG9tOiAtMXB4O1xyXG4gICAgICB9XHJcbiAgICAgIC5uZy1kYXRhLXBpY2tlciAucGlja2VyLWhhbmRsZS1sYXllciAucGlja2VyLXRvcCB7XHJcbiAgICAgICAgLyogYm9yZGVyLWJvdHRvbTogMC41NXB4IHNvbGlkIHJnYmEoNzQsIDczLCA4OSwgMC41KTsgKi9cclxuICAgICAgICBiYWNrZ3JvdW5kOiBsaW5lYXItZ3JhZGllbnQoXHJcbiAgICAgICAgICB0byBib3R0b20sXHJcbiAgICAgICAgICB3aGl0ZSAyJSxcclxuICAgICAgICAgIHJnYmEoMjU1LCAyNTUsIDI1NSwgMC4xKSAxMDAlXHJcbiAgICAgICAgKTtcclxuICAgICAgICB0cmFuc2Zvcm06IHRyYW5zbGF0ZTNkKDAsIDAsIDUuNjI1ZW0pO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAubmctZGF0YS1waWNrZXIgLnBpY2tlci1oYW5kbGUtbGF5ZXIgLnBpY2tlci1taWRkbGUge1xyXG4gICAgICAgIGhlaWdodDogMmVtO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAudGVuZ2FoIHtcclxuICAgICAgICBiYWNrZ3JvdW5kLWNvbG9yOiByZ2JhKDIyMCwgMjIwLCAyMjAsIDEpO1xyXG4gICAgICAgIGJvcmRlci1yYWRpdXM6IDVweDtcclxuICAgICAgfVxyXG5cclxuICAgICAgLm5nLWRhdGEtcGlja2VyIC5waWNrZXItaGFuZGxlLWxheWVyIC5waWNrZXItYm90dG9tIHtcclxuICAgICAgICAvKiBib3JkZXItdG9wOiAwLjU1cHggc29saWQgcmdiYSg3NCwgNzMsIDg5LCAwLjUpOyAqL1xyXG4gICAgICAgIGJhY2tncm91bmQ6IGxpbmVhci1ncmFkaWVudChcclxuICAgICAgICAgIHRvIHRvcCxcclxuICAgICAgICAgIHdoaXRlIDIlLFxyXG4gICAgICAgICAgcmdiYSgyNTUsIDI1NSwgMjU1LCAwLjEpIDEwMCVcclxuICAgICAgICApO1xyXG4gICAgICAgIHRyYW5zZm9ybTogdHJhbnNsYXRlM2QoMCwgMCwgNS42MjVlbSk7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8qIGZsZXggc3lzdGVtICovXHJcbiAgICAgIC5mbGV4LWJveCB7XHJcbiAgICAgICAgZGlzcGxheTogZmxleDtcclxuICAgICAgfVxyXG4gICAgICAuZmxleC1ib3guZGlyLWNvbHVtbiB7XHJcbiAgICAgICAgZmxleC1kaXJlY3Rpb246IGNvbHVtbjtcclxuICAgICAgfVxyXG4gICAgICAuZmxleC1ib3guZGlyLXJvdyB7XHJcbiAgICAgICAgZmxleC1kaXJlY3Rpb246IHJvdztcclxuICAgICAgfVxyXG5cclxuICAgICAgLyogZmxleCBzeXN0ZW0gLSBmb3IgaXRlbXMgKi9cclxuICAgICAgLmZsZXgtYm94IC53ZWlnaHQtMSB7XHJcbiAgICAgICAgZmxleDogMTtcclxuICAgICAgfVxyXG4gICAgICAuZmxleC1ib3ggLndlaWdodC0yIHtcclxuICAgICAgICBmbGV4OiAyO1xyXG4gICAgICB9XHJcbiAgICAgIC5mbGV4LWJveCAud2VpZ2h0LTMge1xyXG4gICAgICAgIGZsZXg6IDM7XHJcbiAgICAgIH1cclxuICAgICAgLmZsZXgtYm94IC53ZWlnaHQtNCB7XHJcbiAgICAgICAgZmxleDogNDtcclxuICAgICAgfVxyXG4gICAgICAuZmxleC1ib3ggLndlaWdodC01IHtcclxuICAgICAgICBmbGV4OiA1O1xyXG4gICAgICB9XHJcbiAgICAgIC5mbGV4LWJveCAud2VpZ2h0LTYge1xyXG4gICAgICAgIGZsZXg6IDY7XHJcbiAgICAgIH1cclxuICAgICAgLmZsZXgtYm94IC53ZWlnaHQtNyB7XHJcbiAgICAgICAgZmxleDogNztcclxuICAgICAgfVxyXG4gICAgICAuZmxleC1ib3ggLndlaWdodC04IHtcclxuICAgICAgICBmbGV4OiA4O1xyXG4gICAgICB9XHJcbiAgICAgIC5mbGV4LWJveCAud2VpZ2h0LTkge1xyXG4gICAgICAgIGZsZXg6IDk7XHJcbiAgICAgIH1cclxuICAgICAgLmZsZXgtYm94IC53ZWlnaHQtMTAge1xyXG4gICAgICAgIGZsZXg6IDEwO1xyXG4gICAgICB9XHJcbiAgICAgIC5mbGV4LWJveCAud2VpZ2h0LTExIHtcclxuICAgICAgICBmbGV4OiAxMTtcclxuICAgICAgfVxyXG4gICAgICAuZmxleC1ib3ggLndlaWdodC0xMiB7XHJcbiAgICAgICAgZmxleDogMTI7XHJcbiAgICAgIH1cclxuICAgIGAsXHJcbiAgXSxcclxufSlcclxuZXhwb3J0IGNsYXNzIE5nU2Nyb2xsUGlja2VyQ29tcG9uZW50XHJcbiAgaW1wbGVtZW50cyBPbkluaXQsIEFmdGVyVmlld0luaXQsIE9uRGVzdHJveVxyXG57XHJcbiAgQFZpZXdDaGlsZHJlbigncGlja2VyR3JvdXBMYXllcicpIHBpY2tlckdyb3VwTGF5ZXI6IGFueTtcclxuICBAVmlld0NoaWxkKCdwaWNrZXJIYW5kbGVMYXllcicpIHBpY2tlckhhbmRsZUxheWVyOiBhbnk7XHJcblxyXG4gIEBJbnB1dCgpIGRhdGE6IFBpY2tlckRhdGFNb2RlbFtdID0gW107XHJcbiAgQE91dHB1dCgpIGNoYW5nZTogRXZlbnRFbWl0dGVyPFBpY2tlclJlc3BvbnNlTW9kZWw+ID1cclxuICAgIG5ldyBFdmVudEVtaXR0ZXI8UGlja2VyUmVzcG9uc2VNb2RlbD4oKTtcclxuXHJcbiAgY3VycmVudEluZGV4TGlzdCE6IG51bWJlcltdO1xyXG4gIGxhc3RDdXJyZW50SW5kZXhMaXN0ITogbnVtYmVyW107XHJcbiAgZ3JvdXBzUmVjdExpc3QhOiBhbnlbXTtcclxuICB0b3VjaE9yTW91c2UgPSB7XHJcbiAgICBpc1RvdWNoYWJsZTogJ29udG91Y2hzdGFydCcgaW4gd2luZG93LFxyXG4gICAgaXNNb3VzZURvd246IGZhbHNlLFxyXG4gIH07XHJcbiAgZHJhZ2dpbmdJbmZvID0ge1xyXG4gICAgaXNEcmFnZ2luZzogZmFsc2UsXHJcbiAgICBncm91cEluZGV4OiBudWxsLFxyXG4gICAgc3RhcnRQYWdlWTogbnVsbCxcclxuICB9IGFzIHtcclxuICAgIGlzRHJhZ2dpbmc6IGJvb2xlYW47XHJcbiAgICBncm91cEluZGV4OiBudW1iZXIgfCBudWxsO1xyXG4gICAgc3RhcnRQYWdlWTogbnVtYmVyIHwgbnVsbDtcclxuICB9O1xyXG4gIGl0ZW1QZXJEZWdyZWUgPSAyMztcclxuICBzYWZlRG9UaW1lb3V0SWQ6IGFueSA9IG51bGw7XHJcblxyXG4gIGNvbnN0cnVjdG9yKEBJbmplY3QoRWxlbWVudFJlZikgZWxlbWVudFJlZjogRWxlbWVudFJlZikge31cclxuXHJcbiAgbmdPbkluaXQoKSB7XHJcbiAgICB0aGlzLmN1cnJlbnRJbmRleExpc3QgPSB0aGlzLmdldEluaXRpYWxDdXJyZW50SW5kZXhMaXN0KCk7XHJcbiAgICB0aGlzLmxhc3RDdXJyZW50SW5kZXhMaXN0ID0gbmV3IEFycmF5PG51bWJlcj4oKS5jb25jYXQoXHJcbiAgICAgIHRoaXMuY3VycmVudEluZGV4TGlzdFxyXG4gICAgKTtcclxuXHJcbiAgICB0aGlzLmdyb3Vwc1JlY3RMaXN0ID0gbmV3IEFycmF5KHRoaXMuZGF0YS5sZW5ndGgpO1xyXG4gIH1cclxuXHJcbiAgbmdBZnRlclZpZXdJbml0KCkge1xyXG4gICAgdGhpcy5ldmVudHNSZWdpc3RlcigpO1xyXG4gICAgd2luZG93LmFkZEV2ZW50TGlzdGVuZXIoJ3Jlc2l6ZScsIHRoaXMuc2FmZUdldFJlY3RzQmluZEV2ZW50cy5iaW5kKHRoaXMpKTtcclxuICAgIHRoaXMuZ2V0R3JvdXBzUmVjdExpc3QoKTtcclxuICB9XHJcblxyXG4gIG5nT25EZXN0cm95KCkge1xyXG4gICAgd2luZG93LnJlbW92ZUV2ZW50TGlzdGVuZXIoXHJcbiAgICAgICdyZXNpemUnLFxyXG4gICAgICB0aGlzLnNhZmVHZXRSZWN0c0JpbmRFdmVudHMuYmluZCh0aGlzKVxyXG4gICAgKTtcclxuICB9XHJcblxyXG4gIHNldEdyb3VwRGF0YShnSW5kZXg6IG51bWJlciwgZ3JvdXBEYXRhOiBQaWNrZXJEYXRhTW9kZWwpIHtcclxuICAgIGlmICghdGhpcy5jdXJyZW50SW5kZXhMaXN0KSB7XHJcbiAgICAgIHRoaXMuY3VycmVudEluZGV4TGlzdCA9IHRoaXMuZ2V0SW5pdGlhbEN1cnJlbnRJbmRleExpc3QoKTtcclxuICAgIH1cclxuICAgIHRoaXMuZGF0YVtnSW5kZXhdID0gZ3JvdXBEYXRhO1xyXG4gICAgY29uc3QgaUNJID0gZ3JvdXBEYXRhLmN1cnJlbnRJbmRleDtcclxuICAgIGxldCBtb3ZlZEluZGV4ID0gMDtcclxuICAgIGlmIChcclxuICAgICAgdHlwZW9mIGlDSSA9PT0gJ251bWJlcicgJiZcclxuICAgICAgaUNJID49IDAgJiZcclxuICAgICAgZ3JvdXBEYXRhLmxpc3QgJiZcclxuICAgICAgZ3JvdXBEYXRhLmxpc3QubGVuZ3RoICYmXHJcbiAgICAgIGlDSSA8PSBncm91cERhdGEubGlzdC5sZW5ndGggLSAxXHJcbiAgICApIHtcclxuICAgICAgbW92ZWRJbmRleCA9IE1hdGgucm91bmQoaUNJKTtcclxuICAgIH1cclxuICAgIHRoaXMuY3VycmVudEluZGV4TGlzdFtnSW5kZXhdID0gbW92ZWRJbmRleDtcclxuICAgIHRoaXMubGFzdEN1cnJlbnRJbmRleExpc3QgPSBuZXcgQXJyYXk8bnVtYmVyPigpLmNvbmNhdChcclxuICAgICAgdGhpcy5jdXJyZW50SW5kZXhMaXN0XHJcbiAgICApO1xyXG4gIH1cclxuXHJcbiAgZ2V0SW5pdGlhbEN1cnJlbnRJbmRleExpc3QoKSB7XHJcbiAgICByZXR1cm4gdGhpcy5kYXRhLm1hcCgoaXRlbSwgaW5kZXgpID0+IHtcclxuICAgICAgY29uc3QgaUNJID0gaXRlbS5jdXJyZW50SW5kZXg7XHJcbiAgICAgIGlmIChcclxuICAgICAgICB0eXBlb2YgaUNJID09PSAnbnVtYmVyJyAmJlxyXG4gICAgICAgIGlDSSA+PSAwICYmXHJcbiAgICAgICAgaXRlbS5saXN0ICYmXHJcbiAgICAgICAgaXRlbS5saXN0Lmxlbmd0aCAmJlxyXG4gICAgICAgIGlDSSA8PSBpdGVtLmxpc3QubGVuZ3RoIC0gMVxyXG4gICAgICApIHtcclxuICAgICAgICByZXR1cm4gTWF0aC5yb3VuZChpQ0kpO1xyXG4gICAgICB9XHJcbiAgICAgIHJldHVybiAwO1xyXG4gICAgfSk7XHJcbiAgfVxyXG5cclxuICBzYWZlR2V0UmVjdHNCaW5kRXZlbnRzKCkge1xyXG4gICAgaWYgKHRoaXMuc2FmZURvVGltZW91dElkKSB7XHJcbiAgICAgIGNsZWFyVGltZW91dCh0aGlzLnNhZmVEb1RpbWVvdXRJZCk7XHJcbiAgICB9XHJcbiAgICB0aGlzLnNhZmVEb1RpbWVvdXRJZCA9IHNldFRpbWVvdXQoKCkgPT4ge1xyXG4gICAgICB0aGlzLmdldEdyb3Vwc1JlY3RMaXN0KCk7XHJcbiAgICB9LCAyMDApO1xyXG4gIH1cclxuXHJcbiAgZ2V0R3JvdXBzUmVjdExpc3QoKSB7XHJcbiAgICBpZiAodGhpcy5waWNrZXJHcm91cExheWVyKSB7XHJcbiAgICAgIHRoaXMucGlja2VyR3JvdXBMYXllci50b0FycmF5KCkuZm9yRWFjaCgoaXRlbTogYW55LCBpbmRleDogbnVtYmVyKSA9PiB7XHJcbiAgICAgICAgdGhpcy5ncm91cHNSZWN0TGlzdFtpbmRleF0gPSBpdGVtLm5hdGl2ZUVsZW1lbnQuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCk7XHJcbiAgICAgIH0pO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgZXZlbnRzUmVnaXN0ZXIoKSB7XHJcbiAgICBjb25zdCBoYW5kbGVFdmVudExheWVyID0gdGhpcy5waWNrZXJIYW5kbGVMYXllci5uYXRpdmVFbGVtZW50O1xyXG4gICAgaWYgKGhhbmRsZUV2ZW50TGF5ZXIpIHtcclxuICAgICAgdGhpcy5hZGRFdmVudHNGb3JFbGVtZW50KGhhbmRsZUV2ZW50TGF5ZXIpO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgYWRkRXZlbnRzRm9yRWxlbWVudChlbDogYW55KSB7XHJcbiAgICBjb25zdCBfID0gdGhpcy50b3VjaE9yTW91c2UuaXNUb3VjaGFibGU7XHJcbiAgICBjb25zdCBldmVudEhhbmRsZXJMaXN0ID0gW1xyXG4gICAgICB7IG5hbWU6IF8gPyAndG91Y2hzdGFydCcgOiAnbW91c2Vkb3duJywgaGFuZGxlcjogdGhpcy5oYW5kbGVTdGFydCB9LFxyXG4gICAgICB7IG5hbWU6IF8gPyAndG91Y2htb3ZlJyA6ICdtb3VzZW1vdmUnLCBoYW5kbGVyOiB0aGlzLmhhbmRsZU1vdmUgfSxcclxuICAgICAgeyBuYW1lOiBfID8gJ3RvdWNoZW5kJyA6ICdtb3VzZXVwJywgaGFuZGxlcjogdGhpcy5oYW5kbGVFbmQgfSxcclxuICAgICAgeyBuYW1lOiBfID8gJ3RvdWNoY2FuY2VsJyA6ICdtb3VzZWxlYXZlJywgaGFuZGxlcjogdGhpcy5oYW5kbGVDYW5jZWwgfSxcclxuICAgICAgeyBuYW1lOiAnd2hlZWwnLCBoYW5kbGVyOiB0aGlzLmhhbmRsZVNjcm9sbCB9LFxyXG4gICAgXTtcclxuICAgIGV2ZW50SGFuZGxlckxpc3QuZm9yRWFjaCgoaXRlbSwgaW5kZXgpID0+IHtcclxuICAgICAgZWwucmVtb3ZlRXZlbnRMaXN0ZW5lcihpdGVtLm5hbWUsIGl0ZW0uaGFuZGxlciwgZmFsc2UpO1xyXG4gICAgICBlbC5hZGRFdmVudExpc3RlbmVyKGl0ZW0ubmFtZSwgaXRlbS5oYW5kbGVyLmJpbmQodGhpcyksIGZhbHNlKTtcclxuICAgIH0pO1xyXG4gIH1cclxuXHJcbiAgdHJpZ2dlck1pZGRsZUxheWVyR3JvdXBDbGljayhnSW5kZXg6IGFueSkge1xyXG4gICAgY29uc3QgZGF0YSA9IHRoaXMuZGF0YTtcclxuICAgIGlmIChkYXRhW2dJbmRleF0ub25DbGljayAhPT0gdW5kZWZpbmVkKSB7XHJcbiAgICAgIGNvbnN0IGNsaWNrID0gZGF0YVtnSW5kZXhdLm9uQ2xpY2sgYXMgRnVuY3Rpb247XHJcbiAgICAgIGlmIChcclxuICAgICAgICB0eXBlb2YgZ0luZGV4ID09PSAnbnVtYmVyJyAmJlxyXG4gICAgICAgIHR5cGVvZiBkYXRhW2dJbmRleF0ub25DbGljayA9PT0gJ2Z1bmN0aW9uJ1xyXG4gICAgICApIHtcclxuICAgICAgICAvLyBjbGljayhcclxuICAgICAgICAvLyAgIGdJbmRleCxcclxuICAgICAgICAvLyAgIHRoaXMuY3VycmVudEluZGV4TGlzdFtnSW5kZXhdLFxyXG4gICAgICAgIC8vICAgdGhpcy5kYXRhW2dJbmRleF0ubGlzdFt0aGlzLmN1cnJlbnRJbmRleExpc3RbZ0luZGV4XV1cclxuICAgICAgICAvLyApO1xyXG4gICAgICAgIGNvbnN0IHJlc3BvbnNlOiBQaWNrZXJSZXNwb25zZU1vZGVsID0ge1xyXG4gICAgICAgICAgZ0luZGV4LFxyXG4gICAgICAgICAgaUluZGV4OiB0aGlzLmN1cnJlbnRJbmRleExpc3RbZ0luZGV4XSxcclxuICAgICAgICAgIHNlbGVjdGVkVmFsdWU6IHRoaXMuZGF0YVtnSW5kZXhdLmxpc3RbdGhpcy5jdXJyZW50SW5kZXhMaXN0W2dJbmRleF1dLFxyXG4gICAgICAgICAgZ3JvdXBOYW1lOiB0aGlzLmRhdGFbZ0luZGV4XS5ncm91cE5hbWUsXHJcbiAgICAgICAgfTtcclxuICAgICAgICBjbGljayhyZXNwb25zZSk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9XHJcblxyXG4gIHRyaWdnZXJBYm92ZUxheWVyQ2xpY2soZXY6IGFueSwgZ0luZGV4OiBhbnkpIHtcclxuICAgIGNvbnN0IG1vdmVkSW5kZXggPSB0aGlzLmN1cnJlbnRJbmRleExpc3RbZ0luZGV4XSArIDE7XHJcbiAgICB0aGlzLmN1cnJlbnRJbmRleExpc3RbZ0luZGV4XSA9IG1vdmVkSW5kZXg7XHJcbiAgICB0aGlzLmNvcnJlY3Rpb25DdXJyZW50SW5kZXgoZXYsIGdJbmRleCk7XHJcbiAgfVxyXG5cclxuICB0cmlnZ2VyTWlkZGxlTGF5ZXJDbGljayhldjogYW55LCBnSW5kZXg6IGFueSkge1xyXG4gICAgdGhpcy50cmlnZ2VyTWlkZGxlTGF5ZXJHcm91cENsaWNrKGdJbmRleCk7XHJcbiAgfVxyXG5cclxuICB0cmlnZ2VyQmVsb3dMYXllckNsaWNrKGV2OiBhbnksIGdJbmRleDogYW55KSB7XHJcbiAgICBjb25zdCBtb3ZlZEluZGV4ID0gdGhpcy5jdXJyZW50SW5kZXhMaXN0W2dJbmRleF0gLSAxO1x