@pepperi/lib
Version:
This library was generated with [Angular CLI](https://github.com/angular/angular-cli) version 10.0.1.
441 lines (440 loc) • 62.8 kB
JavaScript
import { Component, ContentChild, ElementRef, EventEmitter, Input, NgModule, NgZone, Output, ViewChild } from '@angular/core';
import * as tween from '@tweenjs/tween.js';
import * as i0 from "@angular/core";
const _c0 = ["container"];
const _c1 = ["content"];
const _c2 = ["shim"];
const _c3 = ["*"];
export class VirtualScrollComponent {
constructor(element, renderer, zone) {
this.element = element;
this.renderer = renderer;
this.zone = zone;
//@Input()
//items: any[] = [];
this.totalRows = 0;
this.bufferAmount = 0;
this.scrollAnimationTime = 1500;
this.doNotCheckAngularZone = false;
this.refreshHandler = () => {
this.refresh(true);
};
this.isTable = false;
//@Output()
//update: EventEmitter<any[]> = new EventEmitter<any[]>();
//viewPortItems: any[];
this.change = new EventEmitter();
this.load = new EventEmitter();
this.start = new EventEmitter();
this.end = new EventEmitter();
this.startupLoop = true;
/** Cache of the last scroll height to prevent setting CSS when not needed. */
this.lastScrollHeight = -1;
/** Cache of the last top padding to prevent setting CSS when not needed. */
this.lastTopPadding = -1;
}
set parentScroll(element) {
if (this._parentScroll === element) {
return;
}
this._parentScroll = element;
this.addParentEventHandlers(this._parentScroll);
}
get parentScroll() {
return this._parentScroll;
}
ngOnInit() {
this.scrollbarWidth = 0; // this.element.nativeElement.offsetWidth - this.element.nativeElement.clientWidth;
this.scrollbarHeight = 0; // this.element.nativeElement.offsetHeight - this.element.nativeElement.clientHeight;
if (!this.parentScroll) {
this.addParentEventHandlers(this.element.nativeElement);
}
}
ngOnDestroy() {
this.removeParentEventHandlers();
}
ngOnChanges(changes) {
this.previousStart = undefined;
this.previousEnd = undefined;
const totalRows = changes.totalRows || {};
if ((changes.totalRows !== undefined && totalRows.previousValue === undefined) ||
totalRows.previousValue !== undefined) {
this.startupLoop = true;
}
var ieVer = this.detectIE();
var headerRowHeight = '34px';
// Set padding top for the table view because the header row.
//this.renderer.setStyle(this.contentElementRef.nativeElement, 'padding-top', this.isTable ? headerRowHeight : '0');
if (!ieVer || ieVer >= 16) {
// not IE and version < 16
this.renderer.setStyle(this.element.nativeElement, 'top', '0');
}
else {
this.renderer.setStyle(this.element.nativeElement, 'top', headerRowHeight);
}
//Only for IE browsers
/* let ua = navigator.userAgent;
if (this.isTable && (ua.indexOf('MSIE ') >= 0 || ua.indexOf('Trident/') >= 0 || ua.indexOf('Edge/') >= 0)) {
this.renderer.setStyle(this.element.nativeElement, 'top', headerRowHeight);
}
else {
this.renderer.setStyle(this.element.nativeElement, 'top', '0');
}*/
this.refresh();
}
detectIE() {
var ua = window.navigator.userAgent;
// Test values; Uncomment to check result …
// IE 10
// ua = 'Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; Trident/6.0)';
// IE 11
// ua = 'Mozilla/5.0 (Windows NT 6.3; Trident/7.0; rv:11.0) like Gecko';
// Edge 12 (Spartan)
// ua = 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.71 Safari/537.36 Edge/12.0';
// Edge 13
// ua = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2486.0 Safari/537.36 Edge/13.10586';
var msie = ua.indexOf('MSIE ');
if (msie > 0) {
// IE 10 or older => return version number
return parseInt(ua.substring(msie + 5, ua.indexOf('.', msie)), 10);
}
var trident = ua.indexOf('Trident/');
if (trident > 0) {
// IE 11 => return version number
var rv = ua.indexOf('rv:');
return parseInt(ua.substring(rv + 3, ua.indexOf('.', rv)), 10);
}
var edge = ua.indexOf('Edge/');
if (edge > 0) {
// Edge (IE 12+) => return version number
return parseInt(ua.substring(edge + 5, ua.indexOf('.', edge)), 10);
}
// other browser
return false;
}
refresh(forceViewportUpdate = false) {
this.zone.runOutsideAngular(() => {
requestAnimationFrame(() => this.calculateItems(forceViewportUpdate));
});
}
scrollInto(index) {
let el = this.parentScroll instanceof Window ? document.body : this.parentScroll || this.element.nativeElement;
let offsetTop = this.getElementsOffset();
//let index: number = (this.items || []).indexOf(item);
if (index < 0 || index >= this.totalRows)
return;
let d = this.calculateDimensions();
let scrollTop = Math.floor(index / d.itemsPerRow) * d.childHeight - d.childHeight * Math.min(index, this.bufferAmount);
let animationRequest;
if (this.currentTween !== undefined) {
this.currentTween.stop();
}
// totally disable animate
if (!this.scrollAnimationTime) {
el.scrollTop = scrollTop;
return;
}
this.currentTween = new tween.Tween({ scrollTop: el.scrollTop })
.to({ scrollTop }, this.scrollAnimationTime)
.easing(tween.Easing.Quadratic.Out)
.onUpdate(data => {
if (isNaN(data.scrollTop)) {
return;
}
this.renderer.setProperty(el, 'scrollTop', data.scrollTop);
this.refresh(true);
})
.onStop(() => {
cancelAnimationFrame(animationRequest);
})
.start();
const animate = (time) => {
this.currentTween.update(time);
if (this.currentTween._object.scrollTop !== scrollTop) {
this.zone.runOutsideAngular(() => {
animationRequest = requestAnimationFrame(animate);
});
}
};
animate();
}
addParentEventHandlers(parentScroll) {
this.removeParentEventHandlers();
if (parentScroll) {
this.zone.runOutsideAngular(() => {
this.disposeScrollHandler = this.renderer.listen(parentScroll, 'mousewheel', _.throttle(this.refreshHandler, 20, { leading: false, trailing: true }));
this.renderer.listen(parentScroll, 'scroll', _.debounce(this.refreshHandler, 150));
//this.renderer.listen(parentScroll, 'scroll', _.debounce(_.throttle(this.refreshHandler, 150), 50));
if (parentScroll instanceof Window) {
this.disposeScrollHandler = this.renderer.listen('window', 'resize', _.debounce(this.refreshHandler, 250));
}
});
}
}
removeParentEventHandlers() {
if (this.disposeScrollHandler) {
this.disposeScrollHandler();
this.disposeScrollHandler = undefined;
}
if (this.disposeResizeHandler) {
this.disposeResizeHandler();
this.disposeResizeHandler = undefined;
}
}
countItemsPerRow() {
let offsetTop;
let itemsPerRow;
let children = this.contentElementRef.nativeElement.children;
for (itemsPerRow = 0; itemsPerRow < children.length; itemsPerRow++) {
if (offsetTop != undefined && offsetTop !== children[itemsPerRow].offsetTop)
break;
offsetTop = children[itemsPerRow].offsetTop;
}
return itemsPerRow;
}
getElementsOffset() {
let offsetTop = 0;
if (this.containerElementRef && this.containerElementRef.nativeElement) {
offsetTop += this.containerElementRef.nativeElement.offsetTop;
}
if (this.parentScroll) {
offsetTop += this.element.nativeElement.offsetTop;
}
return offsetTop;
}
calculateDimensions() {
let el = this.parentScroll instanceof Window ? document.body : this.parentScroll || this.element.nativeElement;
let itemCount = this.totalRows;
let viewWidth = el.clientWidth - this.scrollbarWidth;
let viewHeight = el.clientHeight - this.scrollbarHeight;
let contentDimensions;
if (this.childWidth == undefined || this.childHeight == undefined) {
let content = this.contentElementRef.nativeElement;
if (this.containerElementRef && this.containerElementRef.nativeElement) {
content = this.containerElementRef.nativeElement;
}
contentDimensions = content.children[0]
? content.children[0].getBoundingClientRect()
: {
width: viewWidth,
height: viewHeight
};
}
let childWidth = this.childWidth || contentDimensions.width;
let childHeight = this.childHeight || contentDimensions.height;
let itemsPerRow = Math.max(1, this.countItemsPerRow());
let itemsPerRowByCalc = Math.max(1, Math.floor(viewWidth / childWidth));
let itemsPerCol = Math.max(1, Math.floor(viewHeight / childHeight));
let elScrollTop = this.parentScroll instanceof Window ? window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop || 0 : el.scrollTop;
let scrollTop = Math.max(0, elScrollTop);
var scrollHeight = childHeight * Math.floor(itemCount / itemsPerRow) + (itemCount % itemsPerRow != 0 ? childHeight : 0);
let ua = navigator.userAgent;
/*if (this.isTable && (ua.indexOf('MSIE ') >= 0 || ua.indexOf('Trident/') >= 0 || ua.indexOf('Edge/') >= 0)) {
scrollHeight += 34;
}*/
if (itemsPerCol === 1 && Math.floor((scrollTop / scrollHeight) * itemCount) + itemsPerRowByCalc >= itemCount) {
itemsPerRow = itemsPerRowByCalc;
}
if (scrollHeight !== this.lastScrollHeight) {
this.renderer.setStyle(this.shimElementRef.nativeElement, 'height', `${scrollHeight}px`);
this.lastScrollHeight = scrollHeight;
}
return {
itemCount: itemCount,
viewWidth: viewWidth,
viewHeight: viewHeight,
childWidth: childWidth,
childHeight: childHeight,
itemsPerRow: itemsPerRow,
itemsPerCol: itemsPerCol,
itemsPerRowByCalc: itemsPerRowByCalc,
scrollHeight
};
}
calculateItems(forceViewportUpdate = false) {
if (!this.doNotCheckAngularZone) {
NgZone.assertNotInAngularZone();
}
let el = this.parentScroll instanceof Window ? document.body : this.parentScroll || this.element.nativeElement;
let d = this.calculateDimensions();
//let items = this.items || [];
let offsetTop = this.getElementsOffset();
let elScrollTop = this.parentScroll instanceof Window ? window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop || 0 : el.scrollTop;
if (elScrollTop > d.scrollHeight) {
elScrollTop = d.scrollHeight + offsetTop;
}
let scrollTop = Math.max(0, elScrollTop - offsetTop);
let indexByScrollTop = ((scrollTop / d.scrollHeight) * d.itemCount) / d.itemsPerRow;
let end = Math.min(d.itemCount, Math.ceil(indexByScrollTop) * d.itemsPerRow + d.itemsPerRow * (d.itemsPerCol + 1));
let maxStartEnd = end;
const modEnd = end % d.itemsPerRow;
if (modEnd) {
maxStartEnd = end + d.itemsPerRow - modEnd;
}
let maxStart = Math.max(0, maxStartEnd - d.itemsPerCol * d.itemsPerRow - d.itemsPerRow);
let start = Math.min(maxStart, Math.floor(indexByScrollTop) * d.itemsPerRow);
let startRow = Math.ceil(start / d.itemsPerRow);
const topPadding = this.totalRows === 0 ? 0 : d.childHeight * startRow - d.childHeight * Math.min(startRow, this.bufferAmount);
if (topPadding !== this.lastTopPadding) {
this.renderer.setStyle(this.contentElementRef.nativeElement, 'transform', `translateY(${topPadding}px)`);
this.renderer.setStyle(this.contentElementRef.nativeElement, 'webkitTransform', `translateY(${topPadding}px)`);
this.lastTopPadding = topPadding;
}
let buffer = this.bufferAmount * d.itemsPerRow;
start = !isNaN(start) ? start : -1;
end = !isNaN(end) ? end : -1;
start -= buffer;
start = Math.max(0, start);
end += buffer;
end = Math.min(this.totalRows, end);
if (start !== this.previousStart || end !== this.previousEnd || forceViewportUpdate === true) {
this.zone.run(() => {
// update the scroll list
end = end >= 0 ? end : 0; // To prevent from accidentally selecting the entire array with a negative 1 (-1) in the end position.
//this.viewPortItems = this.items.slice(start, end);
//this.update.emit(this.viewPortItems);
// emit 'start' event
//if (start !== this.previousStart && this.startupLoop === false) {
// this.start.emit({ start, end });
//}
// emit 'end' event
//if (end !== this.previousEnd && this.startupLoop === false) {
// this.end.emit({ start, end });
//}
// To know if to add at the start of the list or at the end.
let addAtStart = this.previousEnd >= end;
this.previousStart = start;
this.previousEnd = end;
if (this.startupLoop === true) {
this.refresh();
}
else {
let calculatedChildHeight = d.childHeight;
this.change.emit({ start, end, addAtStart, calculatedChildHeight });
}
});
}
else if (this.startupLoop === true) {
this.startupLoop = false;
// Added to know when the scroll is ready (UI elements are displayed already).
this.load.emit();
this.refresh();
}
}
}
VirtualScrollComponent.ɵfac = function VirtualScrollComponent_Factory(t) { return new (t || VirtualScrollComponent)(i0.ɵɵdirectiveInject(i0.ElementRef), i0.ɵɵdirectiveInject(i0.Renderer2), i0.ɵɵdirectiveInject(i0.NgZone)); };
VirtualScrollComponent.ɵcmp = i0.ɵɵdefineComponent({ type: VirtualScrollComponent, selectors: [["virtual-scroll"], ["", "virtualScroll", ""]], contentQueries: function VirtualScrollComponent_ContentQueries(rf, ctx, dirIndex) { if (rf & 1) {
i0.ɵɵcontentQuery(dirIndex, _c0, true);
} if (rf & 2) {
var _t;
i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.containerElementRef = _t.first);
} }, viewQuery: function VirtualScrollComponent_Query(rf, ctx) { if (rf & 1) {
i0.ɵɵviewQuery(_c1, true, ElementRef);
i0.ɵɵviewQuery(_c2, true, ElementRef);
} if (rf & 2) {
var _t;
i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.contentElementRef = _t.first);
i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.shimElementRef = _t.first);
} }, hostVars: 2, hostBindings: function VirtualScrollComponent_HostBindings(rf, ctx) { if (rf & 2) {
i0.ɵɵstyleProp("overflow-y", ctx.parentScroll ? "hidden" : "auto");
} }, inputs: { totalRows: "totalRows", scrollbarWidth: "scrollbarWidth", scrollbarHeight: "scrollbarHeight", childWidth: "childWidth", childHeight: "childHeight", bufferAmount: "bufferAmount", scrollAnimationTime: "scrollAnimationTime", doNotCheckAngularZone: "doNotCheckAngularZone", parentScroll: "parentScroll", isTable: "isTable" }, outputs: { change: "change", load: "load", start: "start", end: "end" }, exportAs: ["virtualScroll"], features: [i0.ɵɵNgOnChangesFeature], ngContentSelectors: _c3, decls: 5, vars: 0, consts: [[1, "total-padding"], ["shim", ""], [1, "scrollable-content"], ["content", ""]], template: function VirtualScrollComponent_Template(rf, ctx) { if (rf & 1) {
i0.ɵɵprojectionDef();
i0.ɵɵelement(0, "div", 0, 1);
i0.ɵɵelementStart(2, "div", 2, 3);
i0.ɵɵprojection(4);
i0.ɵɵelementEnd();
} }, styles: ["[_nghost-%COMP%] {\n overflow: hidden;\n position: relative;\n display: block;\n -webkit-overflow-scrolling: touch;\n }\n .scrollable-content[_ngcontent-%COMP%] {\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n position: absolute;\n // z-index:495;\n }\n .total-padding[_ngcontent-%COMP%] {\n width: 1px;\n opacity: 0;\n }\n\n .rtl[_ngcontent-%COMP%] {\n .scrollable-content {\n left: unset;\n right: 0;\n }\n }"] });
/*@__PURE__*/ (function () { i0.ɵsetClassMetadata(VirtualScrollComponent, [{
type: Component,
args: [{
selector: 'virtual-scroll,[virtualScroll]',
exportAs: 'virtualScroll',
template: `
<div class="total-padding" #shim></div>
<div class="scrollable-content" #content>
<ng-content></ng-content>
</div>
`,
host: {
'[style.overflow-y]': "parentScroll ? 'hidden' : 'auto'"
},
styles: [
`
:host {
overflow: hidden;
position: relative;
display: block;
-webkit-overflow-scrolling: touch;
}
.scrollable-content {
top: 0;
left: 0;
width: 100%;
height: 100%;
position: absolute;
// z-index:495;
}
.total-padding {
width: 1px;
opacity: 0;
}
.rtl {
.scrollable-content {
left: unset;
right: 0;
}
}
`
]
}]
}], function () { return [{ type: i0.ElementRef }, { type: i0.Renderer2 }, { type: i0.NgZone }]; }, { totalRows: [{
type: Input
}], scrollbarWidth: [{
type: Input
}], scrollbarHeight: [{
type: Input
}], childWidth: [{
type: Input
}], childHeight: [{
type: Input
}], bufferAmount: [{
type: Input
}], scrollAnimationTime: [{
type: Input
}], doNotCheckAngularZone: [{
type: Input
}], parentScroll: [{
type: Input
}], isTable: [{
type: Input
}], change: [{
type: Output
}], load: [{
type: Output
}], start: [{
type: Output
}], end: [{
type: Output
}], contentElementRef: [{
type: ViewChild,
args: ['content', { read: ElementRef }]
}], shimElementRef: [{
type: ViewChild,
args: ['shim', { read: ElementRef }]
}], containerElementRef: [{
type: ContentChild,
args: ['container']
}] }); })();
export class VirtualScrollModule {
}
VirtualScrollModule.ɵmod = i0.ɵɵdefineNgModule({ type: VirtualScrollModule });
VirtualScrollModule.ɵinj = i0.ɵɵdefineInjector({ factory: function VirtualScrollModule_Factory(t) { return new (t || VirtualScrollModule)(); } });
(function () { (typeof ngJitMode === "undefined" || ngJitMode) && i0.ɵɵsetNgModuleScope(VirtualScrollModule, { declarations: [VirtualScrollComponent], exports: [VirtualScrollComponent] }); })();
/*@__PURE__*/ (function () { i0.ɵsetClassMetadata(VirtualScrollModule, [{
type: NgModule,
args: [{
exports: [VirtualScrollComponent],
declarations: [VirtualScrollComponent]
}]
}], null, null); })();
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidmlydHVhbC1zY3JvbGwuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vcHJvamVjdHMvcGVwcGVyaS1saWIvbGlzdC92aXJ0dWFsLXNjcm9sbC5jb21wb25lbnQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFNBQVMsRUFBRSxZQUFZLEVBQUUsVUFBVSxFQUFFLFlBQVksRUFBRSxLQUFLLEVBQUUsUUFBUSxFQUFFLE1BQU0sRUFDNUQsTUFBTSxFQUE0QixTQUFTLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFFMUYsT0FBTyxLQUFLLEtBQUssTUFBTSxtQkFBbUIsQ0FBQzs7Ozs7O0FBc0QzQyxNQUFNLE9BQU8sc0JBQXNCO0lBdUYvQixZQUFtQixPQUFtQixFQUFVLFFBQW1CLEVBQVUsSUFBWTtRQUF0RSxZQUFPLEdBQVAsT0FBTyxDQUFZO1FBQVUsYUFBUSxHQUFSLFFBQVEsQ0FBVztRQUFVLFNBQUksR0FBSixJQUFJLENBQVE7UUF0RnpGLFVBQVU7UUFDVixvQkFBb0I7UUFHcEIsY0FBUyxHQUFXLENBQUMsQ0FBQztRQWV0QixpQkFBWSxHQUFXLENBQUMsQ0FBQztRQUd6Qix3QkFBbUIsR0FBVyxJQUFJLENBQUM7UUFHbkMsMEJBQXFCLEdBQVksS0FBSyxDQUFDO1FBRS9CLG1CQUFjLEdBQUcsR0FBRyxFQUFFO1lBQzFCLElBQUksQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLENBQUM7UUFDdkIsQ0FBQyxDQUFBO1FBZ0JELFlBQU8sR0FBWSxLQUFLLENBQUM7UUFFekIsV0FBVztRQUNYLDBEQUEwRDtRQUMxRCx1QkFBdUI7UUFHdkIsV0FBTSxHQUE4QixJQUFJLFlBQVksRUFBZSxDQUFDO1FBR3BFLFNBQUksR0FBc0IsSUFBSSxZQUFZLEVBQU8sQ0FBQztRQUdsRCxVQUFLLEdBQThCLElBQUksWUFBWSxFQUFlLENBQUM7UUFHbkUsUUFBRyxHQUE4QixJQUFJLFlBQVksRUFBZSxDQUFD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QU07a0JBREwsTUFBTTtZQUlQLElBQUk7a0JBREgsTUFBTTtZQUlQLEtBQUs7a0JBREosTUFBTTtZQUlQLEdBQUc7a0JBREYsTUFBTTtZQUlQLGlCQUFpQjtrQkFEaEIsU0FBUzttQkFBQyxTQUFTLEVBQUUsRUFBRSxJQUFJLEVBQUUsVUFBVSxFQUFFO1lBSTFDLGNBQWM7a0JBRGIsU0FBUzttQkFBQyxNQUFNLEVBQUUsRUFBRSxJQUFJLEVBQUUsVUFBVSxFQUFFO1lBSXZDLG1CQUFtQjtrQkFEbEIsWUFBWTttQkFBQyxXQUFXOztBQWlXN0IsTUFBTSxPQUFPLG1CQUFtQjs7dURBQW5CLG1CQUFtQjtxSEFBbkIsbUJBQW1CO3dGQUFuQixtQkFBbUIsbUJBdmFuQixzQkFBc0IsYUFBdEIsc0JBQXNCO2tEQXVhdEIsbUJBQW1CO2NBSi9CLFFBQVE7ZUFBQztnQkFDTixPQUFPLEVBQUUsQ0FBQyxzQkFBc0IsQ0FBQztnQkFDakMsWUFBWSxFQUFFLENBQUMsc0JBQXNCLENBQUM7YUFDekMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBDb21wb25lbnQsIENvbnRlbnRDaGlsZCwgRWxlbWVudFJlZiwgRXZlbnRFbWl0dGVyLCBJbnB1dCwgTmdNb2R1bGUsIE5nWm9uZSwgT25DaGFuZ2VzLFxyXG4gICAgT25EZXN0cm95LCBPbkluaXQsIE91dHB1dCwgUmVuZGVyZXIyLCBTaW1wbGVDaGFuZ2VzLCBWaWV3Q2hpbGQgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcclxuXHJcbmltcG9ydCAqIGFzIHR3ZWVuIGZyb20gJ0B0d2VlbmpzL3R3ZWVuLmpzJztcclxuZGVjbGFyZSB2YXIgXzogYW55O1xyXG5cclxuZXhwb3J0IGludGVyZmFjZSBDaGFuZ2VFdmVudCB7XHJcbiAgICBzdGFydD86IG51bWJlcjtcclxuICAgIGVuZD86IG51bWJlcjtcclxuICAgIGZyb21JbmRleD86IG51bWJlcjtcclxuICAgIHRvSW5kZXg/OiBudW1iZXI7XHJcbiAgICBhZGRBdFN0YXJ0PzogYm9vbGVhbjtcclxuICAgIGNhbGN1bGF0ZWRDaGlsZEhlaWdodD86IG51bWJlcjtcclxufVxyXG5cclxuQENvbXBvbmVudCh7XHJcbiAgICBzZWxlY3RvcjogJ3ZpcnR1YWwtc2Nyb2xsLFt2aXJ0dWFsU2Nyb2xsXScsXHJcbiAgICBleHBvcnRBczogJ3ZpcnR1YWxTY3JvbGwnLFxyXG4gICAgdGVtcGxhdGU6IGBcclxuICAgICAgICA8ZGl2IGNsYXNzPVwidG90YWwtcGFkZGluZ1wiICNzaGltPjwvZGl2PlxyXG4gICAgICAgIDxkaXYgY2xhc3M9XCJzY3JvbGxhYmxlLWNvbnRlbnRcIiAjY29udGVudD5cclxuICAgICAgICAgICAgPG5nLWNvbnRlbnQ+PC9uZy1jb250ZW50PlxyXG4gICAgICAgIDwvZGl2PlxyXG4gICAgYCxcclxuICAgIGhvc3Q6IHtcclxuICAgICAgICAnW3N0eWxlLm92ZXJmbG93LXldJzogXCJwYXJlbnRTY3JvbGwgPyAnaGlkZGVuJyA6ICdhdXRvJ1wiXHJcbiAgICB9LFxyXG4gICAgc3R5bGVzOiBbXHJcbiAgICAgICAgYFxyXG4gICAgOmhvc3Qge1xyXG4gICAgICAgIG92ZXJmbG93OiBoaWRkZW47XHJcbiAgICAgICAgcG9zaXRpb246IHJlbGF0aXZlO1xyXG4gICAgICAgIGRpc3BsYXk6IGJsb2NrO1xyXG4gICAgICAgIC13ZWJraXQtb3ZlcmZsb3ctc2Nyb2xsaW5nOiB0b3VjaDtcclxuICAgIH1cclxuICAgIC5zY3JvbGxhYmxlLWNvbnRlbnQge1xyXG4gICAgICAgIHRvcDogMDtcclxuICAgICAgICBsZWZ0OiAwO1xyXG4gICAgICAgIHdpZHRoOiAxMDAlO1xyXG4gICAgICAgIGhlaWdodDogMTAwJTtcclxuICAgICAgICBwb3NpdGlvbjogYWJzb2x1dGU7XHJcbiAgICAgICAgLy8gICB6LWluZGV4OjQ5NTtcclxuICAgIH1cclxuICAgIC50b3RhbC1wYWRkaW5nIHtcclxuICAgICAgICB3aWR0aDogMXB4O1xyXG4gICAgICAgIG9wYWNpdHk6IDA7XHJcbiAgICB9XHJcblxyXG4gICAgLnJ0bCB7XHJcbiAgICAgICAgLnNjcm9sbGFibGUtY29udGVudCB7XHJcbiAgICAgICAgICAgIGxlZnQ6IHVuc2V0O1xyXG4gICAgICAgICAgICByaWdodDogMDtcclxuICAgICAgICB9XHJcbiAgICB9XHJcbiAgYFxyXG4gICAgXVxyXG59KVxyXG5leHBvcnQgY2xhc3MgVmlydHVhbFNjcm9sbENvbXBvbmVudCBpbXBsZW1lbnRzIE9uSW5pdCwgT25DaGFuZ2VzLCBPbkRlc3Ryb3kge1xyXG4gICAgLy9ASW5wdXQoKVxyXG4gICAgLy9pdGVtczogYW55W10gPSBbXTtcclxuXHJcbiAgICBASW5wdXQoKVxyXG4gICAgdG90YWxSb3dzOiBudW1iZXIgPSAwO1xyXG5cclxuICAgIEBJbnB1dCgpXHJcbiAgICBzY3JvbGxiYXJXaWR0aDogbnVtYmVyO1xyXG5cclxuICAgIEBJbnB1dCgpXHJcbiAgICBzY3JvbGxiYXJIZWlnaHQ6IG51bWJlcjtcclxuXHJcbiAgICBASW5wdXQoKVxyXG4gICAgY2hpbGRXaWR0aDogbnVtYmVyO1xyXG5cclxuICAgIEBJbnB1dCgpXHJcbiAgICBjaGlsZEhlaWdodDogbnVtYmVyO1xyXG5cclxuICAgIEBJbnB1dCgpXHJcbiAgICBidWZmZXJBbW91bnQ6IG51bWJlciA9IDA7XHJcblxyXG4gICAgQElucHV0KClcclxuICAgIHNjcm9sbEFuaW1hdGlvblRpbWU6IG51bWJlciA9IDE1MDA7XHJcblxyXG4gICAgQElucHV0KClcclxuICAgIGRvTm90Q2hlY2tBbmd1bGFyWm9uZTogYm9vbGVhbiA9IGZhbHNlO1xyXG5cclxuICAgIHByaXZhdGUgcmVmcmVzaEhhbmRsZXIgPSAoKSA9PiB7XHJcbiAgICAgICAgdGhpcy5yZWZyZXNoKHRydWUpO1xyXG4gICAgfVxyXG4gICAgcHJpdmF0ZSBfcGFyZW50U2Nyb2xsOiBFbGVtZW50IHwgV2luZG93O1xyXG4gICAgQElucHV0KClcclxuICAgIHNldCBwYXJlbnRTY3JvbGwoZWxlbWVudDogRWxlbWVudCB8IFdpbmRvdykge1xyXG4gICAgICAgIGlmICh0aGlzLl9wYXJlbnRTY3JvbGwgPT09IGVsZW1lbnQpIHtcclxuICAgICAgICAgICAgcmV0dXJuO1xyXG4gICAgICAgIH1cclxuICAgICAgICB0aGlzLl9wYXJlbnRTY3JvbGwgPSBlbGVtZW50O1xyXG4gICAgICAgIHRoaXMuYWRkUGFyZW50RXZlbnRIYW5kbGVycyh0aGlzLl9wYXJlbnRTY3JvbGwpO1xyXG4gICAgfVxyXG5cclxuICAgIGdldCBwYXJlbnRTY3JvbGwoKTogRWxlbWVudCB8IFdpbmRvdyB7XHJcbiAgICAgICAgcmV0dXJuIHRoaXMuX3BhcmVudFNjcm9sbDtcclxuICAgIH1cclxuXHJcbiAgICBASW5wdXQoKVxyXG4gICAgaXNUYWJsZTogYm9vbGVhbiA9IGZhbHNlO1xyXG5cclxuICAgIC8vQE91dHB1dCgpXHJcbiAgICAvL3VwZGF0ZTogRXZlbnRFbWl0dGVyPGFueVtdPiA9IG5ldyBFdmVudEVtaXR0ZXI8YW55W10+KCk7XHJcbiAgICAvL3ZpZXdQb3J0SXRlbXM6IGFueVtdO1xyXG5cclxuICAgIEBPdXRwdXQoKVxyXG4gICAgY2hhbmdlOiBFdmVudEVtaXR0ZXI8Q2hhbmdlRXZlbnQ+ID0gbmV3IEV2ZW50RW1pdHRlcjxDaGFuZ2VFdmVudD4oKTtcclxuXHJcbiAgICBAT3V0cHV0KClcclxuICAgIGxvYWQ6IEV2ZW50RW1pdHRlcjxhbnk+ID0gbmV3IEV2ZW50RW1pdHRlcjxhbnk+KCk7XHJcblxyXG4gICAgQE91dHB1dCgpXHJcbiAgICBzdGFydDogRXZlbnRFbWl0dGVyPENoYW5nZUV2ZW50PiA9IG5ldyBFdmVudEVtaXR0ZXI8Q2hhbmdlRXZlbnQ+KCk7XHJcblxyXG4gICAgQE91dHB1dCgpXHJcbiAgICBlbmQ6IEV2ZW50RW1pdHRlcjxDaGFuZ2VFdmVudD4gPSBuZXcgRXZlbnRFbWl0dGVyPENoYW5nZUV2ZW50PigpO1xyXG5cclxuICAgIEBWaWV3Q2hpbGQoJ2NvbnRlbnQnLCB7IHJlYWQ6IEVsZW1lbnRSZWYgfSlcclxuICAgIGNvbnRlbnRFbGVtZW50UmVmOiBFbGVtZW50UmVmO1xyXG5cclxuICAgIEBWaWV3Q2hpbGQoJ3NoaW0nLCB7IHJlYWQ6IEVsZW1lbnRSZWYgfSlcclxuICAgIHNoaW1FbGVtZW50UmVmOiBFbGVtZW50UmVmO1xyXG5cclxuICAgIEBDb250ZW50Q2hpbGQoJ2NvbnRhaW5lcicpXHJcbiAgICBjb250YWluZXJFbGVtZW50UmVmOiBFbGVtZW50UmVmO1xyXG5cclxuICAgIHByZXZpb3VzU3RhcnQ6IG51bWJlcjtcclxuICAgIHByZXZpb3VzRW5kOiBudW1iZXI7XHJcbiAgICBzdGFydHVwTG9vcDogYm9vbGVhbiA9IHRydWU7XHJcbiAgICBjdXJyZW50VHdlZW46IGFueTtcclxuXHJcbiAgICBwcml2YXRlIGRpc3Bvc2VTY3JvbGxIYW5kbGVyOiAoKSA9PiB2b2lkIHwgdW5kZWZpbmVkO1xyXG4gICAgcHJpdmF0ZSBkaXNwb3NlUmVzaXplSGFuZGxlcjogKCkgPT4gdm9pZCB8IHVuZGVmaW5lZDtcclxuXHJcbiAgICAvKiogQ2FjaGUgb2YgdGhlIGxhc3Qgc2Nyb2xsIGhlaWdodCB0byBwcmV2ZW50IHNldHRpbmcgQ1NTIHdoZW4gbm90IG5lZWRlZC4gKi9cclxuICAgIHByaXZhdGUgbGFzdFNjcm9sbEhlaWdodCA9IC0xO1xyXG5cclxuICAgIC8qKiBDYWNoZSBvZiB0aGUgbGFzdCB0b3AgcGFkZGluZyB0byBwcmV2ZW50IHNldHRpbmcgQ1NTIHdoZW4gbm90IG5lZWRlZC4gKi9cclxuICAgIHByaXZhdGUgbGFzdFRvcFBhZGRpbmcgPSAtMTtcclxuXHJcbiAgICBjb25zdHJ1Y3RvcihwdWJsaWMgZWxlbWVudDogRWxlbWVudFJlZiwgcHJpdmF0ZSByZW5kZXJlcjogUmVuZGVyZXIyLCBwcml2YXRlIHpvbmU6IE5nWm9uZSkgeyB9XHJcblxyXG4gICAgbmdPbkluaXQoKSB7XHJcbiAgICAgICAgdGhpcy5zY3JvbGxiYXJXaWR0aCA9IDA7IC8vIHRoaXMuZWxlbWVudC5uYXRpdmVFbGVtZW50Lm9mZnNldFdpZHRoIC0gdGhpcy5lbGVtZW50Lm5hdGl2ZUVsZW1lbnQuY2xpZW50V2lkdGg7XHJcbiAgICAgICAgdGhpcy5zY3JvbGxiYXJIZWlnaHQgPSAwOyAvLyB0aGlzLmVsZW1lbnQubmF0aXZlRWxlbWVudC5vZmZzZXRIZWlnaHQgLSB0aGlzLmVsZW1lbnQubmF0aXZlRWxlbWVudC5jbGllbnRIZWlnaHQ7XHJcblxyXG4gICAgICAgIGlmICghdGhpcy5wYXJlbnRTY3JvbGwpIHtcclxuICAgICAgICAgICAgdGhpcy5hZGRQYXJlbnRFdmVudEhhbmRsZXJzKHRoaXMuZWxlbWVudC5uYXRpdmVFbGVtZW50KTtcclxuICAgICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgbmdPbkRlc3Ryb3koKSB7XHJcbiAgICAgICAgdGhpcy5yZW1vdmVQYXJlbnRFdmVudEhhbmRsZXJzKCk7XHJcbiAgICB9XHJcblxyXG4gICAgbmdPbkNoYW5nZXMoY2hhbmdlczogU2ltcGxlQ2hhbmdlcykge1xyXG4gICAgICAgIHRoaXMucHJldmlvdXNTdGFydCA9IHVuZGVmaW5lZDtcclxuICAgICAgICB0aGlzLnByZXZpb3VzRW5kID0gdW5kZWZpbmVkO1xyXG4gICAgICAgIGNvbnN0IHRvdGFsUm93cyA9IChjaGFuZ2VzIGFzIGFueSkudG90YWxSb3dzIHx8IHt9O1xyXG4gICAgICAgIGlmICgoKGNoYW5nZXMgYXMgYW55KS50b3RhbFJvd3MgIT09IHVuZGVmaW5lZCAmJiB0b3RhbFJvd3MucHJldmlvdXNWYWx1ZSA9PT0gdW5kZWZpbmVkKSB8fFxyXG4gICAgICAgICAgICB0b3RhbFJvd3MucHJldmlvdXNWYWx1ZSAhPT0gdW5kZWZpbmVkKSB7XHJcbiAgICAgICAgICAgIHRoaXMuc3RhcnR1cExvb3AgPSB0cnVlO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgdmFyIGllVmVyID0gdGhpcy5kZXRlY3RJRSgpO1xyXG4gICAgICAgIHZhciBoZWFkZXJSb3dIZWlnaHQgPSAnMzRweCc7XHJcblxyXG4gICAgICAgIC8vIFNldCBwYWRkaW5nIHRvcCBmb3IgdGhlIHRhYmxlIHZpZXcgYmVjYXVzZSB0aGUgaGVhZGVyIHJvdy5cclxuICAgICAgICAvL3RoaXMucmVuZGVyZXIuc2V0U3R5bGUodGhpcy5jb250ZW50RWxlbWVudFJlZi5uYXRpdmVFbGVtZW50LCAncGFkZGluZy10b3AnLCB0aGlzLmlzVGFibGUgPyBoZWFkZXJSb3dIZWlnaHQgOiAnMCcpO1xyXG5cclxuICAgICAgICBpZiAoIWllVmVyIHx8IGllVmVyID49IDE2KSB7XHJcbiAgICAgICAgICAgIC8vIG5vdCBJRSBhbmQgdmVyc2lvbiA8IDE2XHJcbiAgICAgICAgICAgIHRoaXMucmVuZGVyZXIuc2V0U3R5bGUodGhpcy5lbGVtZW50Lm5hdGl2ZUVsZW1lbnQsICd0b3AnLCAnMCcpO1xyXG4gICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAgIHRoaXMucmVuZGVyZXIuc2V0U3R5bGUodGhpcy5lbGVtZW50Lm5hdGl2ZUVsZW1lbnQsICd0b3AnLCBoZWFkZXJSb3dIZWlnaHQpO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgLy9Pbmx5IGZvciBJRSBicm93c2Vyc1xyXG4gICAgICAgIC8qICBsZXQgdWEgPSBuYXZpZ2F0b3IudXNlckFnZW50O1xyXG4gICAgICAgIGlmICh0aGlzLmlzVGFibGUgJiYgKHVhLmluZGV4T2YoJ01TSUUgJykgPj0gMCB8fCB1YS5pbmRleE9mKCdUcmlkZW50LycpID49IDAgfHwgdWEuaW5kZXhPZignRWRnZS8nKSA+PSAwKSkge1xyXG4gICAgICAgICAgICB0aGlzLnJlbmRlcmVyLnNldFN0eWxlKHRoaXMuZWxlbWVudC5uYXRpdmVFbGVtZW50LCAndG9wJywgaGVhZGVyUm93SGVpZ2h0KTtcclxuICAgICAgICB9XHJcbiAgICAgICAgZWxzZSB7XHJcbiAgICAgICAgICAgIHRoaXMucmVuZGVyZXIuc2V0U3R5bGUodGhpcy5lbGVtZW50Lm5hdGl2ZUVsZW1lbnQsICd0b3AnLCAnMCcpO1xyXG4gICAgICAgIH0qL1xyXG5cclxuICAgICAgICB0aGlzLnJlZnJlc2goKTtcclxuICAgIH1cclxuXHJcbiAgICBkZXRlY3RJRSgpOiBhbnkge1xyXG4gICAgICAgIHZhciB1YSA9IHdpbmRvdy5uYXZpZ2F0b3IudXNlckFnZW50O1xyXG5cclxuICAgICAgICAvLyBUZXN0IHZhbHVlczsgVW5jb21tZW50IHRvIGNoZWNrIHJlc3VsdCDigKZcclxuXHJcbiAgICAgICAgLy8gSUUgMTBcclxuICAgICAgICAvLyB1YSA9ICdNb3ppbGxhLzUuMCAoY29tcGF0aWJsZTsgTVNJRSAxMC4wOyBXaW5kb3dzIE5UIDYuMjsgVHJpZGVudC82LjApJztcclxuXHJcbiAgICAgICAgLy8gSUUgMTFcclxuICAgICAgICAvLyB1YSA9ICdNb3ppbGxhLzUuMCAoV2luZG93cyBOVCA2LjM7IFRyaWRlbnQvNy4wOyBydjoxMS4wKSBsaWtlIEdlY2tvJztcclxuXHJcbiAgICAgICAgLy8gRWRnZSAxMiAoU3BhcnRhbilcclxuICAgICAgICAvLyB1YSA9ICdNb3ppbGxhLzUuMCAoV2luZG93cyBOVCAxMC4wOyBXT1c2NCkgQXBwbGVXZWJLaXQvNTM3LjM2IChLSFRNTCwgbGlrZSBHZWNrbykgQ2hyb21lLzM5LjAuMjE3MS43MSBTYWZhcmkvNTM3LjM2IEVkZ2UvMTIuMCc7XHJcblxyXG4gICAgICAgIC8vIEVkZ2UgMTNcclxuICAgICAgICAvLyB1YSA9ICdNb3ppbGxhLzUuMCAoV2luZG93cyBOVCAxMC4wOyBXaW42NDsgeDY0KSBBcHBsZVdlYktpdC81MzcuMzYgKEtIVE1MLCBsaWtlIEdlY2tvKSBDaHJvbWUvNDYuMC4yNDg2LjAgU2FmYXJpLzUzNy4zNiBFZGdlLzEzLjEwNTg2JztcclxuXHJcbiAgICAgICAgdmFyIG1zaWUgPSB1YS5pbmRleE9mKCdNU0lFICcpO1xyXG4gICAgICAgIGlmIChtc2llID4gMCkge1xyXG4gICAgICAgICAgICAvLyBJRSAxMCBvciBvbGRlciA9PiByZXR1cm4gdmVyc2lvbiBudW1iZXJcclxuICAgICAgICAgICAgcmV0dXJuIHBhcnNlSW50KHVhLnN1YnN0cmluZyhtc2llICsgNSwgdWEuaW5kZXhPZignLicsIG1zaWUpKSwgMTApO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgdmFyIHRyaWRlbnQgPSB1YS5pbmRleE9mKCdUcmlkZW50LycpO1xyXG4gICAgICAgIGlmICh0cmlkZW50ID4gMCkge1xyXG4gICAgICAgICAgICAvLyBJRSAxMSA9PiByZXR1cm4gdmVyc2lvbiBudW1iZXJcclxuICAgICAgICAgICAgdmFyIHJ2ID0gdWEuaW5kZXhPZigncnY6Jyk7XHJcbiAgICAgICAgICAgIHJldHVybiBwYXJzZUludCh1YS5zdWJzdHJpbmcocnYgKyAzLCB1YS5pbmRleE9mKCcuJywgcnYpKSwgMTApO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgdmFyIGVkZ2UgPSB1YS5pbmRleE9mKCdFZGdlLycpO1xyXG4gICAgICAgIGlmIChlZGdlID4gMCkge1xyXG4gICAgICAgICAgICAvLyBFZGdlIChJRSAxMispID0+IHJldHVybiB2ZXJzaW9uIG51bWJlclxyXG4gICAgICAgICAgICByZXR1cm4gcGFyc2VJbnQodWEuc3Vic3RyaW5nKGVkZ2UgKyA1LCB1YS5pbmRleE9mKCcuJywgZWRnZSkpLCAxMCk7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICAvLyBvdGhlciBicm93c2VyXHJcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xyXG4gICAgfVxyXG5cclxuICAgIHJlZnJlc2goZm9yY2VWaWV3cG9ydFVwZGF0ZTogYm9vbGVhbiA9IGZhbHNlKSB7XHJcbiAgICAgICAgdGhpcy56b25lLnJ1bk91dHNpZGVBbmd1bGFyKCgpID0+IHtcclxuICAgICAgICAgICAgcmVxdWVzdEFuaW1hdGlvbkZyYW1lKCgpID0+IHRoaXMuY2FsY3VsYXRlSXRlbXMoZm9yY2VWaWV3cG9ydFVwZGF0ZSkpO1xyXG4gICAgICAgIH0pO1xyXG4gICAgfVxyXG5cclxuICAgIHNjcm9sbEludG8oaW5kZXg6IGFueSkge1xyXG4gICAgICAgIGxldCBlbDogRWxlbWVudCA9IHRoaXMucGFyZW50U2Nyb2xsIGluc3RhbmNlb2YgV2luZG93ID8gZG9jdW1lbnQuYm9keSA6IHRoaXMucGFyZW50U2Nyb2xsIHx8IHRoaXMuZWxlbWVudC5uYXRpdmVFbGVtZW50O1xyXG4gICAgICAgIGxldCBvZmZzZXRUb3AgPSB0aGlzLmdldEVsZW1lbnRzT2Zmc2V0KCk7XHJcbiAgICAgICAgLy9sZXQgaW5kZXg6IG51bWJlciA9ICh0aGlzLml0ZW1zIHx8IFtdKS5pbmRleE9mKGl0ZW0pO1xyXG4gICAgICAgIGlmIChpbmRleCA8IDAgfHwgaW5kZXggPj0gdGhpcy50b3RhbFJvd3MpIHJldHVybjtcclxuXHJcbiAgICAgICAgbGV0IGQgPSB0aGlzLmNhbGN1bGF0ZURpbWVuc2lvbnMoKTtcclxuICAgICAgICBsZXQgc2Nyb2xsVG9wID0gTWF0aC5mbG9vcihpbmRleCAvIGQuaXRlbXNQZXJSb3cpICogZC5jaGlsZEhlaWdodCAtIGQuY2hpbGRIZWlnaHQgKiBNYXRoLm1pbihpbmRleCwgdGhpcy5idWZmZXJBbW91bnQpO1xyXG5cclxuICAgICAgICBsZXQgYW5pbWF0aW9uUmVxdWVzdDtcclxuXHJcbiAgICAgICAgaWYgKHRoaXMuY3VycmVudFR3ZWVuICE9PSB1bmRlZmluZWQpIHsgdGhpcy5jdXJyZW50VHdlZW4uc3RvcCgpOyB9XHJcblxyXG4gICAgICAgIC8vIHRvdGFsbHkgZGlzYWJsZSBhbmltYXRlXHJcbiAgICAgICAgaWYgKCF0aGlzLnNjcm9sbEFuaW1hdGlvblRpbWUpIHtcclxuICAgICAgICAgICAgZWwuc2Nyb2xsVG9wID0gc2Nyb2xsVG9wO1xyXG4gICAgICAgICAgICByZXR1cm47XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICB0aGlzLmN1cnJlbnRUd2VlbiA9IG5ldyB0d2Vlbi5Ud2Vlbih7IHNjcm9sbFRvcDogZWwuc2Nyb2xsVG9wIH0pXHJcbiAgICAgICAgICAgIC50byh7IHNjcm9sbFRvcCB9LCB0aGlzLnNjcm9sbEFuaW1hdGlvblRpbWUpXHJcbiAgICAgICAgICAgIC5lYXNpbmcodHdlZW4uRWFzaW5nLlF1YWRyYXRpYy5PdXQpXHJcbiAgICAgICAgICAgIC5vblVwZGF0ZShkYXRhID0+IHtcclxuICAgICAgICAgICAgICAgIGlmIChpc05hTihkYXRhLnNjcm9sbFRvcCkpIHtcclxuICAgICAgICAgICAgICAgICAgICByZXR1cm47XHJcbiAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgICB0aGlzLnJlbmRlcmVyLnNldFByb3BlcnR5KGVsLCAnc2Nyb2xsVG9wJywgZGF0YS5zY3JvbGxUb3ApO1xyXG4gICAgICAgICAgICA