@pepperi/ngx-lib
Version:
Pepperi Angular Components and Services
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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidmlydHVhbC1zY3JvbGwuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vcHJvamVjdHMvbmd4LWxpYi9saXN0L3ZpcnR1YWwtc2Nyb2xsLmNvbXBvbmVudC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsU0FBUyxFQUFFLFlBQVksRUFBRSxVQUFVLEVBQUUsWUFBWSxFQUFFLEtBQUssRUFBRSxRQUFRLEVBQUUsTUFBTSxFQUM1RCxNQUFNLEVBQTRCLFNBQVMsRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUUxRixPQUFPLEtBQUssS0FBSyxNQUFNLG1CQUFtQixDQUFDOzs7Ozs7QUFzRDNDLE1BQU0sT0FBTyxzQkFBc0I7SUF1Ri9CLFlBQW1CLE9BQW1CLEVBQVUsUUFBbUIsRUFBVSxJQUFZO1FBQXRFLFlBQU8sR0FBUCxPQUFPLENBQVk7UUFBVSxhQUFRLEdBQVIsUUFBUSxDQUFXO1FBQVUsU0FBSSxHQUFKLElBQUksQ0FBUTtRQXRGekYsVUFBVTtRQUNWLG9CQUFvQjtRQUdwQixjQUFTLEdBQVcsQ0FBQyxDQUFDO1FBZXRCLGlCQUFZLEdBQVcsQ0FBQyxDQUFDO1FBR3pCLHdCQUFtQixHQUFXLElBQUksQ0FBQztRQUduQywwQkFBcUIsR0FBWSxLQUFLLENBQUM7UUFFL0IsbUJBQWMsR0FBRyxHQUFHLEVBQUU7WUFDMUIsSUFBSSxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsQ0FBQztRQUN2QixDQUFDLENBQUE7UUFnQkQsWUFBTyxHQUFZLEtBQUssQ0FBQztRQUV6QixXQUFXO1FBQ1gsMERBQTBEO1FBQzFELHVCQUF1QjtRQUd2QixXQUFNLEdBQThCLElBQUksWUFBWSxFQUFlLENBQUM7UUFHcEUsU0FBSSxHQUFzQixJQUFJLFlBQVksRUFBTyxDQUFDO1FBR2xELFVBQUssR0FBOEIsSUFBSSxZQUFZLEVBQWUsQ0FBQztRQUduRSxRQUFHLEdBQThCLElBQUksWUFBWSxFQUFlLENBQUM7UUFh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QkFETCxNQUFNO1lBSVAsSUFBSTtrQkFESCxNQUFNO1lBSVAsS0FBSztrQkFESixNQUFNO1lBSVAsR0FBRztrQkFERixNQUFNO1lBSVAsaUJBQWlCO2tCQURoQixTQUFTO21CQUFDLFNBQVMsRUFBRSxFQUFFLElBQUksRUFBRSxVQUFVLEVBQUU7WUFJMUMsY0FBYztrQkFEYixTQUFTO21CQUFDLE1BQU0sRUFBRSxFQUFFLElBQUksRUFBRSxVQUFVLEVBQUU7WUFJdkMsbUJBQW1CO2tCQURsQixZQUFZO21CQUFDLFdBQVc7O0FBaVc3QixNQUFNLE9BQU8sbUJBQW1COzt1REFBbkIsbUJBQW1CO3FIQUFuQixtQkFBbUI7d0ZBQW5CLG1CQUFtQixtQkF2YW5CLHNCQUFzQixhQUF0QixzQkFBc0I7a0RBdWF0QixtQkFBbUI7Y0FKL0IsUUFBUTtlQUFDO2dCQUNOLE9BQU8sRUFBRSxDQUFDLHNCQUFzQixDQUFDO2dCQUNqQyxZQUFZLEVBQUUsQ0FBQyxzQkFBc0IsQ0FBQzthQUN6QyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IENvbXBvbmVudCwgQ29udGVudENoaWxkLCBFbGVtZW50UmVmLCBFdmVudEVtaXR0ZXIsIElucHV0LCBOZ01vZHVsZSwgTmdab25lLCBPbkNoYW5nZXMsXHJcbiAgICBPbkRlc3Ryb3ksIE9uSW5pdCwgT3V0cHV0LCBSZW5kZXJlcjIsIFNpbXBsZUNoYW5nZXMsIFZpZXdDaGlsZCB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xyXG5cclxuaW1wb3J0ICogYXMgdHdlZW4gZnJvbSAnQHR3ZWVuanMvdHdlZW4uanMnO1xyXG5kZWNsYXJlIHZhciBfOiBhbnk7XHJcblxyXG5leHBvcnQgaW50ZXJmYWNlIENoYW5nZUV2ZW50IHtcclxuICAgIHN0YXJ0PzogbnVtYmVyO1xyXG4gICAgZW5kPzogbnVtYmVyO1xyXG4gICAgZnJvbUluZGV4PzogbnVtYmVyO1xyXG4gICAgdG9JbmRleD86IG51bWJlcjtcclxuICAgIGFkZEF0U3RhcnQ/OiBib29sZWFuO1xyXG4gICAgY2FsY3VsYXRlZENoaWxkSGVpZ2h0PzogbnVtYmVyO1xyXG59XHJcblxyXG5AQ29tcG9uZW50KHtcclxuICAgIHNlbGVjdG9yOiAndmlydHVhbC1zY3JvbGwsW3ZpcnR1YWxTY3JvbGxdJyxcclxuICAgIGV4cG9ydEFzOiAndmlydHVhbFNjcm9sbCcsXHJcbiAgICB0ZW1wbGF0ZTogYFxyXG4gICAgICAgIDxkaXYgY2xhc3M9XCJ0b3RhbC1wYWRkaW5nXCIgI3NoaW0+PC9kaXY+XHJcbiAgICAgICAgPGRpdiBjbGFzcz1cInNjcm9sbGFibGUtY29udGVudFwiICNjb250ZW50PlxyXG4gICAgICAgICAgICA8bmctY29udGVudD48L25nLWNvbnRlbnQ+XHJcbiAgICAgICAgPC9kaXY+XHJcbiAgICBgLFxyXG4gICAgaG9zdDoge1xyXG4gICAgICAgICdbc3R5bGUub3ZlcmZsb3cteV0nOiBcInBhcmVudFNjcm9sbCA/ICdoaWRkZW4nIDogJ2F1dG8nXCJcclxuICAgIH0sXHJcbiAgICBzdHlsZXM6IFtcclxuICAgICAgICBgXHJcbiAgICA6aG9zdCB7XHJcbiAgICAgICAgb3ZlcmZsb3c6IGhpZGRlbjtcclxuICAgICAgICBwb3NpdGlvbjogcmVsYXRpdmU7XHJcbiAgICAgICAgZGlzcGxheTogYmxvY2s7XHJcbiAgICAgICAgLXdlYmtpdC1vdmVyZmxvdy1zY3JvbGxpbmc6IHRvdWNoO1xyXG4gICAgfVxyXG4gICAgLnNjcm9sbGFibGUtY29udGVudCB7XHJcbiAgICAgICAgdG9wOiAwO1xyXG4gICAgICAgIGxlZnQ6IDA7XHJcbiAgICAgICAgd2lkdGg6IDEwMCU7XHJcbiAgICAgICAgaGVpZ2h0OiAxMDAlO1xyXG4gICAgICAgIHBvc2l0aW9uOiBhYnNvbHV0ZTtcclxuICAgICAgICAvLyAgIHotaW5kZXg6NDk1O1xyXG4gICAgfVxyXG4gICAgLnRvdGFsLXBhZGRpbmcge1xyXG4gICAgICAgIHdpZHRoOiAxcHg7XHJcbiAgICAgICAgb3BhY2l0eTogMDtcclxuICAgIH1cclxuXHJcbiAgICAucnRsIHtcclxuICAgICAgICAuc2Nyb2xsYWJsZS1jb250ZW50IHtcclxuICAgICAgICAgICAgbGVmdDogdW5zZXQ7XHJcbiAgICAgICAgICAgIHJpZ2h0OiAwO1xyXG4gICAgICAgIH1cclxuICAgIH1cclxuICBgXHJcbiAgICBdXHJcbn0pXHJcbmV4cG9ydCBjbGFzcyBWaXJ0dWFsU2Nyb2xsQ29tcG9uZW50IGltcGxlbWVudHMgT25Jbml0LCBPbkNoYW5nZXMsIE9uRGVzdHJveSB7XHJcbiAgICAvL0BJbnB1dCgpXHJcbiAgICAvL2l0ZW1zOiBhbnlbXSA9IFtdO1xyXG5cclxuICAgIEBJbnB1dCgpXHJcbiAgICB0b3RhbFJvd3M6IG51bWJlciA9IDA7XHJcblxyXG4gICAgQElucHV0KClcclxuICAgIHNjcm9sbGJhcldpZHRoOiBudW1iZXI7XHJcblxyXG4gICAgQElucHV0KClcclxuICAgIHNjcm9sbGJhckhlaWdodDogbnVtYmVyO1xyXG5cclxuICAgIEBJbnB1dCgpXHJcbiAgICBjaGlsZFdpZHRoOiBudW1iZXI7XHJcblxyXG4gICAgQElucHV0KClcclxuICAgIGNoaWxkSGVpZ2h0OiBudW1iZXI7XHJcblxyXG4gICAgQElucHV0KClcclxuICAgIGJ1ZmZlckFtb3VudDogbnVtYmVyID0gMDtcclxuXHJcbiAgICBASW5wdXQoKVxyXG4gICAgc2Nyb2xsQW5pbWF0aW9uVGltZTogbnVtYmVyID0gMTUwMDtcclxuXHJcbiAgICBASW5wdXQoKVxyXG4gICAgZG9Ob3RDaGVja0FuZ3VsYXJab25lOiBib29sZWFuID0gZmFsc2U7XHJcblxyXG4gICAgcHJpdmF0ZSByZWZyZXNoSGFuZGxlciA9ICgpID0+IHtcclxuICAgICAgICB0aGlzLnJlZnJlc2godHJ1ZSk7XHJcbiAgICB9XHJcbiAgICBwcml2YXRlIF9wYXJlbnRTY3JvbGw6IEVsZW1lbnQgfCBXaW5kb3c7XHJcbiAgICBASW5wdXQoKVxyXG4gICAgc2V0IHBhcmVudFNjcm9sbChlbGVtZW50OiBFbGVtZW50IHwgV2luZG93KSB7XHJcbiAgICAgICAgaWYgKHRoaXMuX3BhcmVudFNjcm9sbCA9PT0gZWxlbWVudCkge1xyXG4gICAgICAgICAgICByZXR1cm47XHJcbiAgICAgICAgfVxyXG4gICAgICAgIHRoaXMuX3BhcmVudFNjcm9sbCA9IGVsZW1lbnQ7XHJcbiAgICAgICAgdGhpcy5hZGRQYXJlbnRFdmVudEhhbmRsZXJzKHRoaXMuX3BhcmVudFNjcm9sbCk7XHJcbiAgICB9XHJcblxyXG4gICAgZ2V0IHBhcmVudFNjcm9sbCgpOiBFbGVtZW50IHwgV2luZG93IHtcclxuICAgICAgICByZXR1cm4gdGhpcy5fcGFyZW50U2Nyb2xsO1xyXG4gICAgfVxyXG5cclxuICAgIEBJbnB1dCgpXHJcbiAgICBpc1RhYmxlOiBib29sZWFuID0gZmFsc2U7XHJcblxyXG4gICAgLy9AT3V0cHV0KClcclxuICAgIC8vdXBkYXRlOiBFdmVudEVtaXR0ZXI8YW55W10+ID0gbmV3IEV2ZW50RW1pdHRlcjxhbnlbXT4oKTtcclxuICAgIC8vdmlld1BvcnRJdGVtczogYW55W107XHJcblxyXG4gICAgQE91dHB1dCgpXHJcbiAgICBjaGFuZ2U6IEV2ZW50RW1pdHRlcjxDaGFuZ2VFdmVudD4gPSBuZXcgRXZlbnRFbWl0dGVyPENoYW5nZUV2ZW50PigpO1xyXG5cclxuICAgIEBPdXRwdXQoKVxyXG4gICAgbG9hZDogRXZlbnRFbWl0dGVyPGFueT4gPSBuZXcgRXZlbnRFbWl0dGVyPGFueT4oKTtcclxuXHJcbiAgICBAT3V0cHV0KClcclxuICAgIHN0YXJ0OiBFdmVudEVtaXR0ZXI8Q2hhbmdlRXZlbnQ+ID0gbmV3IEV2ZW50RW1pdHRlcjxDaGFuZ2VFdmVudD4oKTtcclxuXHJcbiAgICBAT3V0cHV0KClcclxuICAgIGVuZDogRXZlbnRFbWl0dGVyPENoYW5nZUV2ZW50PiA9IG5ldyBFdmVudEVtaXR0ZXI8Q2hhbmdlRXZlbnQ+KCk7XHJcblxyXG4gICAgQFZpZXdDaGlsZCgnY29udGVudCcsIHsgcmVhZDogRWxlbWVudFJlZiB9KVxyXG4gICAgY29udGVudEVsZW1lbnRSZWY6IEVsZW1lbnRSZWY7XHJcblxyXG4gICAgQFZpZXdDaGlsZCgnc2hpbScsIHsgcmVhZDogRWxlbWVudFJlZiB9KVxyXG4gICAgc2hpbUVsZW1lbnRSZWY6IEVsZW1lbnRSZWY7XHJcblxyXG4gICAgQENvbnRlbnRDaGlsZCgnY29udGFpbmVyJylcclxuICAgIGNvbnRhaW5lckVsZW1lbnRSZWY6IEVsZW1lbnRSZWY7XHJcblxyXG4gICAgcHJldmlvdXNTdGFydDogbnVtYmVyO1xyXG4gICAgcHJldmlvdXNFbmQ6IG51bWJlcjtcclxuICAgIHN0YXJ0dXBMb29wOiBib29sZWFuID0gdHJ1ZTtcclxuICAgIGN1cnJlbnRUd2VlbjogYW55O1xyXG5cclxuICAgIHByaXZhdGUgZGlzcG9zZVNjcm9sbEhhbmRsZXI6ICgpID0+IHZvaWQgfCB1bmRlZmluZWQ7XHJcbiAgICBwcml2YXRlIGRpc3Bvc2VSZXNpemVIYW5kbGVyOiAoKSA9PiB2b2lkIHwgdW5kZWZpbmVkO1xyXG5cclxuICAgIC8qKiBDYWNoZSBvZiB0aGUgbGFzdCBzY3JvbGwgaGVpZ2h0IHRvIHByZXZlbnQgc2V0dGluZyBDU1Mgd2hlbiBub3QgbmVlZGVkLiAqL1xyXG4gICAgcHJpdmF0ZSBsYXN0U2Nyb2xsSGVpZ2h0ID0gLTE7XHJcblxyXG4gICAgLyoqIENhY2hlIG9mIHRoZSBsYXN0IHRvcCBwYWRkaW5nIHRvIHByZXZlbnQgc2V0dGluZyBDU1Mgd2hlbiBub3QgbmVlZGVkLiAqL1xyXG4gICAgcHJpdmF0ZSBsYXN0VG9wUGFkZGluZyA9IC0xO1xyXG5cclxuICAgIGNvbnN0cnVjdG9yKHB1YmxpYyBlbGVtZW50OiBFbGVtZW50UmVmLCBwcml2YXRlIHJlbmRlcmVyOiBSZW5kZXJlcjIsIHByaXZhdGUgem9uZTogTmdab25lKSB7IH1cclxuXHJcbiAgICBuZ09uSW5pdCgpIHtcclxuICAgICAgICB0aGlzLnNjcm9sbGJhcldpZHRoID0gMDsgLy8gdGhpcy5lbGVtZW50Lm5hdGl2ZUVsZW1lbnQub2Zmc2V0V2lkdGggLSB0aGlzLmVsZW1lbnQubmF0aXZlRWxlbWVudC5jbGllbnRXaWR0aDtcclxuICAgICAgICB0aGlzLnNjcm9sbGJhckhlaWdodCA9IDA7IC8vIHRoaXMuZWxlbWVudC5uYXRpdmVFbGVtZW50Lm9mZnNldEhlaWdodCAtIHRoaXMuZWxlbWVudC5uYXRpdmVFbGVtZW50LmNsaWVudEhlaWdodDtcclxuXHJcbiAgICAgICAgaWYgKCF0aGlzLnBhcmVudFNjcm9sbCkge1xyXG4gICAgICAgICAgICB0aGlzLmFkZFBhcmVudEV2ZW50SGFuZGxlcnModGhpcy5lbGVtZW50Lm5hdGl2ZUVsZW1lbnQpO1xyXG4gICAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICBuZ09uRGVzdHJveSgpIHtcclxuICAgICAgICB0aGlzLnJlbW92ZVBhcmVudEV2ZW50SGFuZGxlcnMoKTtcclxuICAgIH1cclxuXHJcbiAgICBuZ09uQ2hhbmdlcyhjaGFuZ2VzOiBTaW1wbGVDaGFuZ2VzKSB7XHJcbiAgICAgICAgdGhpcy5wcmV2aW91c1N0YXJ0ID0gdW5kZWZpbmVkO1xyXG4gICAgICAgIHRoaXMucHJldmlvdXNFbmQgPSB1bmRlZmluZWQ7XHJcbiAgICAgICAgY29uc3QgdG90YWxSb3dzID0gKGNoYW5nZXMgYXMgYW55KS50b3RhbFJvd3MgfHwge307XHJcbiAgICAgICAgaWYgKCgoY2hhbmdlcyBhcyBhbnkpLnRvdGFsUm93cyAhPT0gdW5kZWZpbmVkICYmIHRvdGFsUm93cy5wcmV2aW91c1ZhbHVlID09PSB1bmRlZmluZWQpIHx8XHJcbiAgICAgICAgICAgIHRvdGFsUm93cy5wcmV2aW91c1ZhbHVlICE9PSB1bmRlZmluZWQpIHtcclxuICAgICAgICAgICAgdGhpcy5zdGFydHVwTG9vcCA9IHRydWU7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICB2YXIgaWVWZXIgPSB0aGlzLmRldGVjdElFKCk7XHJcbiAgICAgICAgdmFyIGhlYWRlclJvd0hlaWdodCA9ICczNHB4JztcclxuXHJcbiAgICAgICAgLy8gU2V0IHBhZGRpbmcgdG9wIGZvciB0aGUgdGFibGUgdmlldyBiZWNhdXNlIHRoZSBoZWFkZXIgcm93LlxyXG4gICAgICAgIC8vdGhpcy5yZW5kZXJlci5zZXRTdHlsZSh0aGlzLmNvbnRlbnRFbGVtZW50UmVmLm5hdGl2ZUVsZW1lbnQsICdwYWRkaW5nLXRvcCcsIHRoaXMuaXNUYWJsZSA/IGhlYWRlclJvd0hlaWdodCA6ICcwJyk7XHJcblxyXG4gICAgICAgIGlmICghaWVWZXIgfHwgaWVWZXIgPj0gMTYpIHtcclxuICAgICAgICAgICAgLy8gbm90IElFIGFuZCB2ZXJzaW9uIDwgMTZcclxuICAgICAgICAgICAgdGhpcy5yZW5kZXJlci5zZXRTdHlsZSh0aGlzLmVsZW1lbnQubmF0aXZlRWxlbWVudCwgJ3RvcCcsICcwJyk7XHJcbiAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgICAgdGhpcy5yZW5kZXJlci5zZXRTdHlsZSh0aGlzLmVsZW1lbnQubmF0aXZlRWxlbWVudCwgJ3RvcCcsIGhlYWRlclJvd0hlaWdodCk7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICAvL09ubHkgZm9yIElFIGJyb3dzZXJzXHJcbiAgICAgICAgLyogIGxldCB1YSA9IG5hdmlnYXRvci51c2VyQWdlbnQ7XHJcbiAgICAgICAgaWYgKHRoaXMuaXNUYWJsZSAmJiAodWEuaW5kZXhPZignTVNJRSAnKSA+PSAwIHx8IHVhLmluZGV4T2YoJ1RyaWRlbnQvJykgPj0gMCB8fCB1YS5pbmRleE9mKCdFZGdlLycpID49IDApKSB7XHJcbiAgICAgICAgICAgIHRoaXMucmVuZGVyZXIuc2V0U3R5bGUodGhpcy5lbGVtZW50Lm5hdGl2ZUVsZW1lbnQsICd0b3AnLCBoZWFkZXJSb3dIZWlnaHQpO1xyXG4gICAgICAgIH1cclxuICAgICAgICBlbHNlIHtcclxuICAgICAgICAgICAgdGhpcy5yZW5kZXJlci5zZXRTdHlsZSh0aGlzLmVsZW1lbnQubmF0aXZlRWxlbWVudCwgJ3RvcCcsICcwJyk7XHJcbiAgICAgICAgfSovXHJcblxyXG4gICAgICAgIHRoaXMucmVmcmVzaCgpO1xyXG4gICAgfVxyXG5cclxuICAgIGRldGVjdElFKCk6IGFueSB7XHJcbiAgICAgICAgdmFyIHVhID0gd2luZG93Lm5hdmlnYXRvci51c2VyQWdlbnQ7XHJcblxyXG4gICAgICAgIC8vIFRlc3QgdmFsdWVzOyBVbmNvbW1lbnQgdG8gY2hlY2sgcmVzdWx0IOKAplxyXG5cclxuICAgICAgICAvLyBJRSAxMFxyXG4gICAgICAgIC8vIHVhID0gJ01vemlsbGEvNS4wIChjb21wYXRpYmxlOyBNU0lFIDEwLjA7IFdpbmRvd3MgTlQgNi4yOyBUcmlkZW50LzYuMCknO1xyXG5cclxuICAgICAgICAvLyBJRSAxMVxyXG4gICAgICAgIC8vIHVhID0gJ01vemlsbGEvNS4wIChXaW5kb3dzIE5UIDYuMzsgVHJpZGVudC83LjA7IHJ2OjExLjApIGxpa2UgR2Vja28nO1xyXG5cclxuICAgICAgICAvLyBFZGdlIDEyIChTcGFydGFuKVxyXG4gICAgICAgIC8vIHVhID0gJ01vemlsbGEvNS4wIChXaW5kb3dzIE5UIDEwLjA7IFdPVzY0KSBBcHBsZVdlYktpdC81MzcuMzYgKEtIVE1MLCBsaWtlIEdlY2tvKSBDaHJvbWUvMzkuMC4yMTcxLjcxIFNhZmFyaS81MzcuMzYgRWRnZS8xMi4wJztcclxuXHJcbiAgICAgICAgLy8gRWRnZSAxM1xyXG4gICAgICAgIC8vIHVhID0gJ01vemlsbGEvNS4wIChXaW5kb3dzIE5UIDEwLjA7IFdpbjY0OyB4NjQpIEFwcGxlV2ViS2l0LzUzNy4zNiAoS0hUTUwsIGxpa2UgR2Vja28pIENocm9tZS80Ni4wLjI0ODYuMCBTYWZhcmkvNTM3LjM2IEVkZ2UvMTMuMTA1ODYnO1xyXG5cclxuICAgICAgICB2YXIgbXNpZSA9IHVhLmluZGV4T2YoJ01TSUUgJyk7XHJcbiAgICAgICAgaWYgKG1zaWUgPiAwKSB7XHJcbiAgICAgICAgICAgIC8vIElFIDEwIG9yIG9sZGVyID0+IHJldHVybiB2ZXJzaW9uIG51bWJlclxyXG4gICAgICAgICAgICByZXR1cm4gcGFyc2VJbnQodWEuc3Vic3RyaW5nKG1zaWUgKyA1LCB1YS5pbmRleE9mKCcuJywgbXNpZSkpLCAxMCk7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICB2YXIgdHJpZGVudCA9IHVhLmluZGV4T2YoJ1RyaWRlbnQvJyk7XHJcbiAgICAgICAgaWYgKHRyaWRlbnQgPiAwKSB7XHJcbiAgICAgICAgICAgIC8vIElFIDExID0+IHJldHVybiB2ZXJzaW9uIG51bWJlclxyXG4gICAgICAgICAgICB2YXIgcnYgPSB1YS5pbmRleE9mKCdydjonKTtcclxuICAgICAgICAgICAgcmV0dXJuIHBhcnNlSW50KHVhLnN1YnN0cmluZyhydiArIDMsIHVhLmluZGV4T2YoJy4nLCBydikpLCAxMCk7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICB2YXIgZWRnZSA9IHVhLmluZGV4T2YoJ0VkZ2UvJyk7XHJcbiAgICAgICAgaWYgKGVkZ2UgPiAwKSB7XHJcbiAgICAgICAgICAgIC8vIEVkZ2UgKElFIDEyKykgPT4gcmV0dXJuIHZlcnNpb24gbnVtYmVyXHJcbiAgICAgICAgICAgIHJldHVybiBwYXJzZUludCh1YS5zdWJzdHJpbmcoZWRnZSArIDUsIHVhLmluZGV4T2YoJy4nLCBlZGdlKSksIDEwKTtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIC8vIG90aGVyIGJyb3dzZXJcclxuICAgICAgICByZXR1cm4gZmFsc2U7XHJcbiAgICB9XHJcblxyXG4gICAgcmVmcmVzaChmb3JjZVZpZXdwb3J0VXBkYXRlOiBib29sZWFuID0gZmFsc2UpIHtcclxuICAgICAgICB0aGlzLnpvbmUucnVuT3V0c2lkZUFuZ3VsYXIoKCkgPT4ge1xyXG4gICAgICAgICAgICByZXF1ZXN0QW5pbWF0aW9uRnJhbWUoKCkgPT4gdGhpcy5jYWxjdWxhdGVJdGVtcyhmb3JjZVZpZXdwb3J0VXBkYXRlKSk7XHJcbiAgICAgICAgfSk7XHJcbiAgICB9XHJcblxyXG4gICAgc2Nyb2xsSW50byhpbmRleDogYW55KSB7XHJcbiAgICAgICAgbGV0IGVsOiBFbGVtZW50ID0gdGhpcy5wYXJlbnRTY3JvbGwgaW5zdGFuY2VvZiBXaW5kb3cgPyBkb2N1bWVudC5ib2R5IDogdGhpcy5wYXJlbnRTY3JvbGwgfHwgdGhpcy5lbGVtZW50Lm5hdGl2ZUVsZW1lbnQ7XHJcbiAgICAgICAgbGV0IG9mZnNldFRvcCA9IHRoaXMuZ2V0RWxlbWVudHNPZmZzZXQoKTtcclxuICAgICAgICAvL2xldCBpbmRleDogbnVtYmVyID0gKHRoaXMuaXRlbXMgfHwgW10pLmluZGV4T2YoaXRlbSk7XHJcbiAgICAgICAgaWYgKGluZGV4IDwgMCB8fCBpbmRleCA+PSB0aGlzLnRvdGFsUm93cykgcmV0dXJuO1xyXG5cclxuICAgICAgICBsZXQgZCA9IHRoaXMuY2FsY3VsYXRlRGltZW5zaW9ucygpO1xyXG4gICAgICAgIGxldCBzY3JvbGxUb3AgPSBNYXRoLmZsb29yKGluZGV4IC8gZC5pdGVtc1BlclJvdykgKiBkLmNoaWxkSGVpZ2h0IC0gZC5jaGlsZEhlaWdodCAqIE1hdGgubWluKGluZGV4LCB0aGlzLmJ1ZmZlckFtb3VudCk7XHJcblxyXG4gICAgICAgIGxldCBhbmltYXRpb25SZXF1ZXN0O1xyXG5cclxuICAgICAgICBpZiAodGhpcy5jdXJyZW50VHdlZW4gIT09IHVuZGVmaW5lZCkgeyB0aGlzLmN1cnJlbnRUd2Vlbi5zdG9wKCk7IH1cclxuXHJcbiAgICAgICAgLy8gdG90YWxseSBkaXNhYmxlIGFuaW1hdGVcclxuICAgICAgICBpZiAoIXRoaXMuc2Nyb2xsQW5pbWF0aW9uVGltZSkge1xyXG4gICAgICAgICAgICBlbC5zY3JvbGxUb3AgPSBzY3JvbGxUb3A7XHJcbiAgICAgICAgICAgIHJldHVybjtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIHRoaXMuY3VycmVudFR3ZWVuID0gbmV3IHR3ZWVuLlR3ZWVuKHsgc2Nyb2xsVG9wOiBlbC5zY3JvbGxUb3AgfSlcclxuICAgICAgICAgICAgLnRvKHsgc2Nyb2xsVG9wIH0sIHRoaXMuc2Nyb2xsQW5pbWF0aW9uVGltZSlcclxuICAgICAgICAgICAgLmVhc2luZyh0d2Vlbi5FYXNpbmcuUXVhZHJhdGljLk91dClcclxuICAgICAgICAgICAgLm9uVXBkYXRlKGRhdGEgPT4ge1xyXG4gICAgICAgICAgICAgICAgaWYgKGlzTmFOKGRhdGEuc2Nyb2xsVG9wKSkge1xyXG4gICAgICAgICAgICAgICAgICAgIHJldHVybjtcclxuICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgIHRoaXMucmVuZGVyZXIuc2V0UHJvcGVydHkoZWwsICdzY3JvbGxUb3AnLCBkYXRhLnNjcm9sbFRvcCk7XHJcbiAgICAgICAgICAgICAgICB