UNPKG

@ux-aspects/ux-aspects

Version:

Open source user interface framework for building modern, responsive, mobile big data applications

226 lines 35.5 kB
import { ChangeDetectorRef, Directive, inject, Input, IterableDiffers, Renderer2, TemplateRef, ViewContainerRef } from '@angular/core'; import { Subject } from 'rxjs'; import { distinctUntilChanged, takeUntil } from 'rxjs/operators'; import { VirtualForService } from './virtual-for.service'; import * as i0 from "@angular/core"; /** * This implementation is inspired by the CDK virtual for: * https://github.com/angular/material2/blob/master/src/cdk/scrolling/virtual-for-of.ts * However the CDK requires a container component which limits use in places such * as fixed header tables, so this is a more generic implementation that does not * require a parent element but instead uses an attribute on the parent container instead */ export class VirtualForDirective { /** Store the list of items to display */ set uxVirtualForOf(dataset) { // emit the latest dataset this._virtualScroll.dataset.next(dataset); // store a local version of the dataset this._dataset = dataset; // if this is an update and not the initial dataset then we should // forcibly redraw the list of items. In cases where the length of // the dataset change would trigger a re-renderer as the scroll position // would change, however if we are performing sorting then it would not // so we must ensure we update everytime the dataset changes. if (this._renderedRange) { this.onRangeChange(); } } constructor() { /** A reference to the container element where we will insert elements. */ this._viewContainerRef = inject(ViewContainerRef); /** The template for all items */ this._templateRef = inject(TemplateRef); /** Gets the set of Angular differs for detecting changes. */ this._differs = inject(IterableDiffers); /** Get the renderer to perform DOM manipulation */ this._renderer = inject(Renderer2); this._changeDetector = inject(ChangeDetectorRef); /** A service to share values between the container and child elements */ this._virtualScroll = inject(VirtualForService, { optional: true }); /** Provide a trackBy function to optimize rendering */ this.uxVirtualForTrackBy = this.defaultTrackBy; /** Indicate whether we need to perform a view update */ this._isDirty = false; /** Store a cache of recently disposed views for reuse */ this._templateCache = []; /** Limit the size of the cache as it can use a lot of memory */ this._cacheSize = 20; /** Unsubscribe from all observables */ this._onDestroy = new Subject(); // While marked as optional, it isn't. We do this so we can provide a more helpful error message if (!this._virtualScroll) { throw new Error('The "uxVirtualFor" directive requires the "uxVirtualForContainer" directive to be added to the parent element.'); } } ngOnInit() { // update the UI whenever the range changes this._virtualScroll.range.pipe(distinctUntilChanged(this.isRangeSame), takeUntil(this._onDestroy)).subscribe(range => { this._renderedRange = range; this.onRangeChange(); this._changeDetector.detectChanges(); }); } ngDoCheck() { if (this._isDirty && this._differ) { // check if there area any changes const changes = this.getChanges(); if (changes) { this.applyChanges(changes); } else { this.updateContexts(); } // now that we have rendered any change we should store this so we don't perform unneeded updates this._isDirty = false; } } ngOnDestroy() { this._onDestroy.next(); this._onDestroy.complete(); } /** If an itemSize is not specified we need to calculate it */ getHeight(context, length) { // create a temporary view const view = this.createView(0); // set the implicit value to the item value view.context.$implicit = context; view.context.count = length; view.context.even = true; view.context.odd = false; view.context.first = true; view.context.last = length === 1; // run change detection view.detectChanges(); // get the size of the view const height = view.rootNodes[0].offsetHeight; // destroy the view this._viewContainerRef.remove(0); view.destroy(); return height; } /** Determine if the range has changed (performance optimization) */ isRangeSame(previous, current) { return previous.start === current.start && previous.end === current.end; } onRangeChange() { // store the visible range this._renderedItems = this._dataset.slice(this._renderedRange.start, this._renderedRange.end); // create the Angular differ if we haven't previously done so if (!this._differ) { this._differ = this._differs.find(this._renderedItems).create(this.uxVirtualForTrackBy); } // mark the view for re-render this._isDirty = true; } /** Determine which items have changed */ getChanges() { return this._differ.diff(this._renderedItems); } /** Insert, move and remove any items within the view */ applyChanges(changes) { // Go through each changes and either add or rearrange accordingly changes.forEachOperation((record, previousIndex, currentIndex) => { // check if a new item was added if (previousIndex === null) { // create the new embedded view const view = this.createView(currentIndex); // set the implicit value to the item value view.context.$implicit = record.item; } else if (currentIndex === null) { // check if the item should be removed const view = this._viewContainerRef.detach(currentIndex); const index = this._viewContainerRef.indexOf(view); // if there is space in the cache then store the detached view if (this._templateCache.length < this._cacheSize) { this._templateCache.push(view); } else { index === -1 ? view.destroy() : this._viewContainerRef.remove(index); } } else { // the position of the item has changed // get the view from its current position const view = this._viewContainerRef.get(previousIndex); // move it to the new position this._viewContainerRef.move(view, currentIndex); // update the implicit value (the rest will stay the same) view.context.$implicit = record.item; } }); // Ensure the implicit value is correct for any items whose identity changed changes.forEachIdentityChange((record) => { const view = this._viewContainerRef.get(record.currentIndex); if (view) { view.context.$implicit = record.item; } }); this.updateContexts(); } updateContexts() { // update all the other context properties for (let idx = 0; idx < this._viewContainerRef.length; idx++) { // get the view at a given position const view = this._viewContainerRef.get(idx); // update the properties view.context.index = this._renderedRange.start + idx; view.context.count = this._dataset.length; view.context.first = view.context.index === 0; view.context.last = view.context.index === view.context.count - 1; view.context.even = view.context.index % 2 === 0; view.context.odd = !view.context.even; // update the position in the DOM view.rootNodes.forEach((node) => { this._renderer.setStyle(node, 'position', 'absolute'); this._renderer.setStyle(node, 'width', '100%'); this._renderer.setStyle(node, 'top', '0'); this._renderer.setStyle(node, 'transform', `translateY(${view.context.index * this._virtualScroll.itemSize}px`); }); view.detectChanges(); } } createView(index) { // get a checked EmbeddedViewRef is there is one const cachedTemplate = this._templateCache.pop(); if (cachedTemplate) { // replace existing context with the defaults cachedTemplate.context.$implicit = null; cachedTemplate.context.index = -1; cachedTemplate.context.count = -1; cachedTemplate.context.first = false; cachedTemplate.context.last = false; cachedTemplate.context.even = false; cachedTemplate.context.odd = false; // insert the view this._viewContainerRef.insert(cachedTemplate, index); // return the cached EmbeddedViewRef return cachedTemplate; } // otherwise create a new view and insert it return this._viewContainerRef.createEmbeddedView(this._templateRef, { $implicit: null, index: -1, count: -1, first: false, last: false, even: false, odd: false, }, index); } defaultTrackBy(index) { return index; } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.12", ngImport: i0, type: VirtualForDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); } static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "18.2.12", type: VirtualForDirective, selector: "[uxVirtualFor][uxVirtualForOf]", inputs: { uxVirtualForOf: "uxVirtualForOf", uxVirtualForTrackBy: "uxVirtualForTrackBy" }, ngImport: i0 }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.12", ngImport: i0, type: VirtualForDirective, decorators: [{ type: Directive, args: [{ selector: '[uxVirtualFor][uxVirtualForOf]', }] }], ctorParameters: () => [], propDecorators: { uxVirtualForOf: [{ type: Input }], uxVirtualForTrackBy: [{ type: Input }] } }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidmlydHVhbC1mb3IuZGlyZWN0aXZlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vc3JjL2NvbXBvbmVudHMvdmlydHVhbC1zY3JvbGwvdmlydHVhbC1mb3IvdmlydHVhbC1mb3IuZGlyZWN0aXZlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxpQkFBaUIsRUFBRSxTQUFTLEVBQTRCLE1BQU0sRUFBRSxLQUFLLEVBQXlELGVBQWUsRUFBcUIsU0FBUyxFQUFFLFdBQVcsRUFBbUIsZ0JBQWdCLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFDNVAsT0FBTyxFQUFFLE9BQU8sRUFBRSxNQUFNLE1BQU0sQ0FBQztBQUMvQixPQUFPLEVBQUUsb0JBQW9CLEVBQUUsU0FBUyxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFDakUsT0FBTyxFQUFtQixpQkFBaUIsRUFBRSxNQUFNLHVCQUF1QixDQUFDOztBQUUzRTs7Ozs7O0dBTUc7QUFLSCxNQUFNLE9BQU8sbUJBQW1CO0lBa0I1Qix5Q0FBeUM7SUFDekMsSUFBYSxjQUFjLENBQUMsT0FBWTtRQUNwQywwQkFBMEI7UUFDMUIsSUFBSSxDQUFDLGNBQWMsQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxDQUFDO1FBRTFDLHVDQUF1QztRQUN2QyxJQUFJLENBQUMsUUFBUSxHQUFHLE9BQU8sQ0FBQztRQUV4QixrRUFBa0U7UUFDbEUsa0VBQWtFO1FBQ2xFLHdFQUF3RTtRQUN4RSx1RUFBdUU7UUFDdkUsNkRBQTZEO1FBQzdELElBQUksSUFBSSxDQUFDLGNBQWMsRUFBRSxDQUFDO1lBQ3RCLElBQUksQ0FBQyxhQUFhLEVBQUUsQ0FBQztRQUN6QixDQUFDO0lBQ0wsQ0FBQztJQTZCRDtRQTlEQSwwRUFBMEU7UUFDekQsc0JBQWlCLEdBQUcsTUFBTSxDQUFDLGdCQUFnQixDQUFDLENBQUM7UUFFOUQsaUNBQWlDO1FBQ2hCLGlCQUFZLEdBQUcsTUFBTSxDQUFzQyxXQUFXLENBQUMsQ0FBQztRQUV6Riw2REFBNkQ7UUFDNUMsYUFBUSxHQUFHLE1BQU0sQ0FBQyxlQUFlLENBQUMsQ0FBQztRQUVwRCxtREFBbUQ7UUFDbEMsY0FBUyxHQUFHLE1BQU0sQ0FBQyxTQUFTLENBQUMsQ0FBQztRQUU5QixvQkFBZSxHQUFHLE1BQU0sQ0FBQyxpQkFBaUIsQ0FBQyxDQUFDO1FBRTdELHlFQUF5RTtRQUN4RCxtQkFBYyxHQUFHLE1BQU0sQ0FBdUIsaUJBQWlCLEVBQUUsRUFBRSxRQUFRLEVBQUUsSUFBSSxFQUFFLENBQUMsQ0FBQztRQW9CdEcsdURBQXVEO1FBQzlDLHdCQUFtQixHQUFtQyxJQUFJLENBQUMsY0FBYyxDQUFDO1FBY25GLHdEQUF3RDtRQUNoRCxhQUFRLEdBQVksS0FBSyxDQUFDO1FBRWxDLHlEQUF5RDtRQUN4QyxtQkFBYyxHQUE4QyxFQUFFLENBQUM7UUFFaEYsZ0VBQWdFO1FBQy9DLGVBQVUsR0FBVyxFQUFFLENBQUM7UUFFekMsdUNBQXVDO1FBQ3RCLGVBQVUsR0FBRyxJQUFJLE9BQU8sRUFBUSxDQUFDO1FBRzlDLGdHQUFnRztRQUNoRyxJQUFJLENBQUMsSUFBSSxDQUFDLGNBQWMsRUFBRSxDQUFDO1lBQ3ZCLE1BQU0sSUFBSSxLQUFLLENBQUMsZ0hBQWdILENBQUMsQ0FBQztRQUN0SSxDQUFDO0lBQ0wsQ0FBQztJQUVELFFBQVE7UUFDSiwyQ0FBMkM7UUFDM0MsSUFBSSxDQUFDLGNBQWMsQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLG9CQUFvQixDQUFDLElBQUksQ0FBQyxXQUFXLENBQUMsRUFBRSxTQUFTLENBQUMsSUFBSSxDQUFDLFVBQVUsQ0FBQyxDQUFDLENBQUMsU0FBUyxDQUFDLEtBQUssQ0FBQyxFQUFFO1lBQ2pILElBQUksQ0FBQyxjQUFjLEdBQUcsS0FBSyxDQUFDO1lBQzVCLElBQUksQ0FBQyxhQUFhLEVBQUUsQ0FBQztZQUNyQixJQUFJLENBQUMsZUFBZSxDQUFDLGFBQWEsRUFBRSxDQUFDO1FBQ3pDLENBQUMsQ0FBQyxDQUFDO0lBQ1AsQ0FBQztJQUVELFNBQVM7UUFDTCxJQUFJLElBQUksQ0FBQyxRQUFRLElBQUksSUFBSSxDQUFDLE9BQU8sRUFBRSxDQUFDO1lBRWhDLGtDQUFrQztZQUNsQyxNQUFNLE9BQU8sR0FBRyxJQUFJLENBQUMsVUFBVSxFQUFFLENBQUM7WUFFbEMsSUFBSSxPQUFPLEVBQUUsQ0FBQztnQkFDVixJQUFJLENBQUMsWUFBWSxDQUFDLE9BQU8sQ0FBQyxDQUFDO1lBQy9CLENBQUM7aUJBQU0sQ0FBQztnQkFDSixJQUFJLENBQUMsY0FBYyxFQUFFLENBQUM7WUFDMUIsQ0FBQztZQUVELGlHQUFpRztZQUNqRyxJQUFJLENBQUMsUUFBUSxHQUFHLEtBQUssQ0FBQztRQUMxQixDQUFDO0lBQ0wsQ0FBQztJQUVELFdBQVc7UUFDUCxJQUFJLENBQUMsVUFBVSxDQUFDLElBQUksRUFBRSxDQUFDO1FBQ3ZCLElBQUksQ0FBQyxVQUFVLENBQUMsUUFBUSxFQUFFLENBQUM7SUFDL0IsQ0FBQztJQUVELDhEQUE4RDtJQUM5RCxTQUFTLENBQUMsT0FBVSxFQUFFLE1BQWM7UUFFaEMsMEJBQTBCO1FBQzFCLE1BQU0sSUFBSSxHQUFHLElBQUksQ0FBQyxVQUFVLENBQUMsQ0FBQyxDQUFDLENBQUM7UUFFaEMsMkNBQTJDO1FBQzNDLElBQUksQ0FBQyxPQUFPLENBQUMsU0FBUyxHQUFHLE9BQU8sQ0FBQztRQUNqQyxJQUFJLENBQUMsT0FBTyxDQUFDLEtBQUssR0FBRyxNQUFNLENBQUM7UUFDNUIsSUFBSSxDQUFDLE9BQU8sQ0FBQyxJQUFJLEdBQUcsSUFBSSxDQUFDO1FBQ3pCLElBQUksQ0FBQyxPQUFPLENBQUMsR0FBRyxHQUFHLEtBQUssQ0FBQztRQUN6QixJQUFJLENBQUMsT0FBTyxDQUFDLEtBQUssR0FBRyxJQUFJLENBQUM7UUFDMUIsSUFBSSxDQUFDLE9BQU8sQ0FBQyxJQUFJLEdBQUcsTUFBTSxLQUFLLENBQUMsQ0FBQztRQUVqQyx1QkFBdUI7UUFDdkIsSUFBSSxDQUFDLGFBQWEsRUFBRSxDQUFDO1FBRXJCLDJCQUEyQjtRQUMzQixNQUFNLE1BQU0sR0FBRyxJQUFJLENBQUMsU0FBUyxDQUFDLENBQUMsQ0FBQyxDQUFDLFlBQVksQ0FBQztRQUU5QyxtQkFBbUI7UUFDbkIsSUFBSSxDQUFDLGlCQUFpQixDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsQ0FBQztRQUNqQyxJQUFJLENBQUMsT0FBTyxFQUFFLENBQUM7UUFFZixPQUFPLE1BQU0sQ0FBQztJQUNsQixDQUFDO0lBRUQsb0VBQW9FO0lBQzVELFdBQVcsQ0FBQyxRQUF5QixFQUFFLE9BQXdCO1FBQ25FLE9BQU8sUUFBUSxDQUFDLEtBQUssS0FBSyxPQUFPLENBQUMsS0FBSyxJQUFJLFFBQVEsQ0FBQyxHQUFHLEtBQUssT0FBTyxDQUFDLEdBQUcsQ0FBQztJQUM1RSxDQUFDO0lBRU8sYUFBYTtRQUVqQiwwQkFBMEI7UUFDMUIsSUFBSSxDQUFDLGNBQWMsR0FBRyxJQUFJLENBQUMsUUFBUSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsY0FBYyxDQUFDLEtBQUssRUFBRSxJQUFJLENBQUMsY0FBYyxDQUFDLEdBQUcsQ0FBQyxDQUFDO1FBRTlGLDZEQUE2RDtRQUM3RCxJQUFJLENBQUMsSUFBSSxDQUFDLE9BQU8sRUFBRSxDQUFDO1lBQ2hCLElBQUksQ0FBQyxPQUFPLEdBQUcsSUFBSSxDQUFDLFFBQVEsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLGNBQWMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsbUJBQW1CLENBQUMsQ0FBQztRQUM1RixDQUFDO1FBRUQsOEJBQThCO1FBQzlCLElBQUksQ0FBQyxRQUFRLEdBQUcsSUFBSSxDQUFDO0lBQ3pCLENBQUM7SUFFRCx5Q0FBeUM7SUFDakMsVUFBVTtRQUNkLE9BQU8sSUFBSSxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLGNBQWMsQ0FBQyxDQUFDO0lBQ2xELENBQUM7SUFFRCx3REFBd0Q7SUFDaEQsWUFBWSxDQUFDLE9BQTJCO1FBRTVDLGtFQUFrRTtRQUNsRSxPQUFPLENBQUMsZ0JBQWdCLENBQUMsQ0FBQyxNQUErQixFQUFFLGFBQXFCLEVBQUUsWUFBb0IsRUFBRSxFQUFFO1lBRXRHLGdDQUFnQztZQUNoQyxJQUFJLGFBQWEsS0FBSyxJQUFJLEVBQUUsQ0FBQztnQkFDekIsK0JBQStCO2dCQUMvQixNQUFNLElBQUksR0FBRyxJQUFJLENBQUMsVUFBVSxDQUFDLFlBQVksQ0FBQyxDQUFDO2dCQUUzQywyQ0FBMkM7Z0JBQzNDLElBQUksQ0FBQyxPQUFPLENBQUMsU0FBUyxHQUFHLE1BQU0sQ0FBQyxJQUFJLENBQUM7WUFFekMsQ0FBQztpQkFBTSxJQUFJLFlBQVksS0FBSyxJQUFJLEVBQUUsQ0FBQyxDQUFDLHNDQUFzQztnQkFDdEUsTUFBTSxJQUFJLEdBQUcsSUFBSSxDQUFDLGlCQUFpQixDQUFDLE1BQU0sQ0FBQyxZQUFZLENBQTRDLENBQUM7Z0JBQ3BHLE1BQU0sS0FBSyxHQUFHLElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLENBQUM7Z0JBRW5ELDhEQUE4RDtnQkFDOUQsSUFBSSxJQUFJLENBQUMsY0FBYyxDQUFDLE1BQU0sR0FBRyxJQUFJLENBQUMsVUFBVSxFQUFFLENBQUM7b0JBQy9DLElBQUksQ0FBQyxjQUFjLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDO2dCQUNuQyxDQUFDO3FCQUFNLENBQUM7b0JBQ0osS0FBSyxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsT0FBTyxFQUFFLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLENBQUM7Z0JBQ3pFLENBQUM7WUFDTCxDQUFDO2lCQUFNLENBQUMsQ0FBQyx1Q0FBdUM7Z0JBRTVDLHlDQUF5QztnQkFDekMsTUFBTSxJQUFJLEdBQUcsSUFBSSxDQUFDLGlCQUFpQixDQUFDLEdBQUcsQ0FBQyxhQUFhLENBQTRDLENBQUM7Z0JBRWxHLDhCQUE4QjtnQkFDOUIsSUFBSSxDQUFDLGlCQUFpQixDQUFDLElBQUksQ0FBQyxJQUFJLEVBQUUsWUFBWSxDQUFDLENBQUM7Z0JBRWhELDBEQUEwRDtnQkFDMUQsSUFBSSxDQUFDLE9BQU8sQ0FBQyxTQUFTLEdBQUcsTUFBTSxDQUFDLElBQUksQ0FBQztZQUN6QyxDQUFDO1FBQ0wsQ0FBQyxDQUFDLENBQUM7UUFFSCw0RUFBNEU7UUFDNUUsT0FBTyxDQUFDLHFCQUFxQixDQUFDLENBQUMsTUFBK0IsRUFBRSxFQUFFO1lBQzlELE1BQU0sSUFBSSxHQUFHLElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxHQUFHLENBQUMsTUFBTSxDQUFDLFlBQVksQ0FBNEMsQ0FBQztZQUV4RyxJQUFJLElBQUksRUFBRSxDQUFDO2dCQUNQLElBQUksQ0FBQyxPQUFPLENBQUMsU0FBUyxHQUFHLE1BQU0sQ0FBQyxJQUFJLENBQUM7WUFDekMsQ0FBQztRQUNMLENBQUMsQ0FBQyxDQUFDO1FBRUgsSUFBSSxDQUFDLGNBQWMsRUFBRSxDQUFDO0lBQzFCLENBQUM7SUFFRCxjQUFjO1FBRVYsMENBQTBDO1FBQzFDLEtBQUssSUFBSSxHQUFHLEdBQUcsQ0FBQyxFQUFFLEdBQUcsR0FBRyxJQUFJLENBQUMsaUJBQWlCLENBQUMsTUFBTSxFQUFFLEdBQUcsRUFBRSxFQUFFLENBQUM7WUFFM0QsbUNBQW1DO1lBQ25DLE1BQU0sSUFBSSxHQUFHLElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxHQUFHLENBQUMsR0FBRyxDQUE0QyxDQUFDO1lBRXhGLHdCQUF3QjtZQUN4QixJQUFJLENBQUMsT0FBTyxDQUFDLEtBQUssR0FBRyxJQUFJLENBQUMsY0FBYyxDQUFDLEtBQUssR0FBRyxHQUFHLENBQUM7WUFDckQsSUFBSSxDQUFDLE9BQU8sQ0FBQyxLQUFLLEdBQUcsSUFBSSxDQUFDLFFBQVEsQ0FBQyxNQUFNLENBQUM7WUFDMUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxLQUFLLEdBQUcsSUFBSSxDQUFDLE9BQU8sQ0FBQyxLQUFLLEtBQUssQ0FBQyxDQUFDO1lBQzlDLElBQUksQ0FBQyxPQUFPLENBQUMsSUFBSSxHQUFHLElBQUksQ0FBQyxPQUFPLENBQUMsS0FBSyxLQUFLLElBQUksQ0FBQyxPQUFPLENBQUMsS0FBSyxHQUFHLENBQUMsQ0FBQztZQUNsRSxJQUFJLENBQUMsT0FBTyxDQUFDLElBQUksR0FBRyxJQUFJLENBQUMsT0FBTyxDQUFDLEtBQUssR0FBRyxDQUFDLEtBQUssQ0FBQyxDQUFDO1lBQ2pELElBQUksQ0FBQyxPQUFPLENBQUMsR0FBRyxHQUFHLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUM7WUFFdEMsaUNBQWlDO1lBQ2pDLElBQUksQ0FBQyxTQUFTLENBQUMsT0FBTyxDQUFDLENBQUMsSUFBaUIsRUFBRSxFQUFFO2dCQUN6QyxJQUFJLENBQUMsU0FBUyxDQUFDLFFBQVEsQ0FBQyxJQUFJLEVBQUUsVUFBVSxFQUFFLFVBQVUsQ0FBQyxDQUFDO2dCQUN0RCxJQUFJLENBQUMsU0FBUyxDQUFDLFFBQVEsQ0FBQyxJQUFJLEVBQUUsT0FBTyxFQUFFLE1BQU0sQ0FBQyxDQUFDO2dCQUMvQyxJQUFJLENBQUMsU0FBUyxDQUFDLFFBQVEsQ0FBQyxJQUFJLEVBQUUsS0FBSyxFQUFFLEdBQUcsQ0FBQyxDQUFDO2dCQUMxQyxJQUFJLENBQUMsU0FBUyxDQUFDLFFBQVEsQ0FBQyxJQUFJLEVBQUUsV0FBVyxFQUFFLGNBQWMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxLQUFLLEdBQUcsSUFBSSxDQUFDLGNBQWMsQ0FBQyxRQUFRLElBQUksQ0FBQyxDQUFDO1lBQ3BILENBQUMsQ0FBQyxDQUFDO1lBRUgsSUFBSSxDQUFDLGFBQWEsRUFBRSxDQUFDO1FBQ3pCLENBQUM7SUFDTCxDQUFDO0lBRU8sVUFBVSxDQUFDLEtBQWE7UUFFNUIsZ0RBQWdEO1FBQ2hELE1BQU0sY0FBYyxHQUFHLElBQUksQ0FBQyxjQUFjLENBQUMsR0FBRyxFQUFFLENBQUM7UUFFakQsSUFBSSxjQUFjLEVBQUUsQ0FBQztZQUVqQiw2Q0FBNkM7WUFDN0MsY0FBYyxDQUFDLE9BQU8sQ0FBQyxTQUFTLEdBQUcsSUFBSSxDQUFDO1lBQ3hDLGNBQWMsQ0FBQyxPQUFPLENBQUMsS0FBSyxHQUFHLENBQUMsQ0FBQyxDQUFDO1lBQ2xDLGNBQWMsQ0FBQyxPQUFPLENBQUMsS0FBSyxHQUFHLENBQUMsQ0FBQyxDQUFDO1lBQ2xDLGNBQWMsQ0FBQyxPQUFPLENBQUMsS0FBSyxHQUFHLEtBQUssQ0FBQztZQUNyQyxjQUFjLENBQUMsT0FBTyxDQUFDLElBQUksR0FBRyxLQUFLLENBQUM7WUFDcEMsY0FBYyxDQUFDLE9BQU8sQ0FBQyxJQUFJLEdBQUcsS0FBSyxDQUFDO1lBQ3BDLGNBQWMsQ0FBQyxPQUFPLENBQUMsR0FBRyxHQUFHLEtBQUssQ0FBQztZQUVuQyxrQkFBa0I7WUFDbEIsSUFBSSxDQUFDLGlCQUFpQixDQUFDLE1BQU0sQ0FBQyxjQUFjLEVBQUUsS0FBSyxDQUFDLENBQUM7WUFFckQsb0NBQW9DO1lBQ3BDLE9BQU8sY0FBYyxDQUFDO1FBQzFCLENBQUM7UUFFRCw0Q0FBNEM7UUFDNUMsT0FBTyxJQUFJLENBQUMsaUJBQWlCLENBQUMsa0JBQWtCLENBQXlCLElBQUksQ0FBQyxZQUFZLEVBQUU7WUFDeEYsU0FBUyxFQUFFLElBQUk7WUFDZixLQUFLLEVBQUUsQ0FBQyxDQUFDO1lBQ1QsS0FBSyxFQUFFLENBQUMsQ0FBQztZQUNULEtBQUssRUFBRSxLQUFLO1lBQ1osSUFBSSxFQUFFLEtBQUs7WUFDWCxJQUFJLEVBQUUsS0FBSztZQUNYLEdBQUcsRUFBRSxLQUFLO1NBQ2IsRUFBRSxLQUFLLENBQUMsQ0FBQztJQUNkLENBQUM7SUFFTyxjQUFjLENBQUMsS0FBYTtRQUNoQyxPQUFPLEtBQUssQ0FBQztJQUNqQixDQUFDOytHQTFRUSxtQkFBbUI7bUdBQW5CLG1CQUFtQjs7NEZBQW5CLG1CQUFtQjtrQkFIL0IsU0FBUzttQkFBQztvQkFDUCxRQUFRLEVBQUUsZ0NBQWdDO2lCQUM3Qzt3REFvQmdCLGNBQWM7c0JBQTFCLEtBQUs7Z0JBa0JHLG1CQUFtQjtzQkFBM0IsS0FBSyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IENoYW5nZURldGVjdG9yUmVmLCBEaXJlY3RpdmUsIERvQ2hlY2ssIEVtYmVkZGVkVmlld1JlZiwgaW5qZWN0LCBJbnB1dCwgSXRlcmFibGVDaGFuZ2VSZWNvcmQsIEl0ZXJhYmxlQ2hhbmdlcywgSXRlcmFibGVEaWZmZXIsIEl0ZXJhYmxlRGlmZmVycywgT25EZXN0cm95LCBPbkluaXQsIFJlbmRlcmVyMiwgVGVtcGxhdGVSZWYsIFRyYWNrQnlGdW5jdGlvbiwgVmlld0NvbnRhaW5lclJlZiB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgU3ViamVjdCB9IGZyb20gJ3J4anMnO1xuaW1wb3J0IHsgZGlzdGluY3RVbnRpbENoYW5nZWQsIHRha2VVbnRpbCB9IGZyb20gJ3J4anMvb3BlcmF0b3JzJztcbmltcG9ydCB7IFZpcnR1YWxGb3JSYW5nZSwgVmlydHVhbEZvclNlcnZpY2UgfSBmcm9tICcuL3ZpcnR1YWwtZm9yLnNlcnZpY2UnO1xuXG4vKipcbiAqIFRoaXMgaW1wbGVtZW50YXRpb24gaXMgaW5zcGlyZWQgYnkgdGhlIENESyB2aXJ0dWFsIGZvcjpcbiAqIGh0dHBzOi8vZ2l0aHViLmNvbS9hbmd1bGFyL21hdGVyaWFsMi9ibG9iL21hc3Rlci9zcmMvY2RrL3Njcm9sbGluZy92aXJ0dWFsLWZvci1vZi50c1xuICogSG93ZXZlciB0aGUgQ0RLIHJlcXVpcmVzIGEgY29udGFpbmVyIGNvbXBvbmVudCB3aGljaCBsaW1pdHMgdXNlIGluIHBsYWNlcyBzdWNoXG4gKiBhcyBmaXhlZCBoZWFkZXIgdGFibGVzLCBzbyB0aGlzIGlzIGEgbW9yZSBnZW5lcmljIGltcGxlbWVudGF0aW9uIHRoYXQgZG9lcyBub3RcbiAqIHJlcXVpcmUgYSBwYXJlbnQgZWxlbWVudCBidXQgaW5zdGVhZCB1c2VzIGFuIGF0dHJpYnV0ZSBvbiB0aGUgcGFyZW50IGNvbnRhaW5lciBpbnN0ZWFkXG4gKi9cblxuQERpcmVjdGl2ZSh7XG4gICAgc2VsZWN0b3I6ICdbdXhWaXJ0dWFsRm9yXVt1eFZpcnR1YWxGb3JPZl0nLFxufSlcbmV4cG9ydCBjbGFzcyBWaXJ0dWFsRm9yRGlyZWN0aXZlPFQ+IGltcGxlbWVudHMgT25Jbml0LCBEb0NoZWNrLCBPbkRlc3Ryb3kge1xuICAgIC8qKiBBIHJlZmVyZW5jZSB0byB0aGUgY29udGFpbmVyIGVsZW1lbnQgd2hlcmUgd2Ugd2lsbCBpbnNlcnQgZWxlbWVudHMuICovXG4gICAgcHJpdmF0ZSByZWFkb25seSBfdmlld0NvbnRhaW5lclJlZiA9IGluamVjdChWaWV3Q29udGFpbmVyUmVmKTtcblxuICAgIC8qKiBUaGUgdGVtcGxhdGUgZm9yIGFsbCBpdGVtcyAqL1xuICAgIHByaXZhdGUgcmVhZG9ubHkgX3RlbXBsYXRlUmVmID0gaW5qZWN0PFRlbXBsYXRlUmVmPFZpcnR1YWxGb3JPZkNvbnRleHQ8VD4+PihUZW1wbGF0ZVJlZik7XG5cbiAgICAvKiogR2V0cyB0aGUgc2V0IG9mIEFuZ3VsYXIgZGlmZmVycyBmb3IgZGV0ZWN0aW5nIGNoYW5nZXMuICovXG4gICAgcHJpdmF0ZSByZWFkb25seSBfZGlmZmVycyA9IGluamVjdChJdGVyYWJsZURpZmZlcnMpO1xuXG4gICAgLyoqIEdldCB0aGUgcmVuZGVyZXIgdG8gcGVyZm9ybSBET00gbWFuaXB1bGF0aW9uICovXG4gICAgcHJpdmF0ZSByZWFkb25seSBfcmVuZGVyZXIgPSBpbmplY3QoUmVuZGVyZXIyKTtcblxuICAgIHByaXZhdGUgcmVhZG9ubHkgX2NoYW5nZURldGVjdG9yID0gaW5qZWN0KENoYW5nZURldGVjdG9yUmVmKTtcblxuICAgIC8qKiBBIHNlcnZpY2UgdG8gc2hhcmUgdmFsdWVzIGJldHdlZW4gdGhlIGNvbnRhaW5lciBhbmQgY2hpbGQgZWxlbWVudHMgKi9cbiAgICBwcml2YXRlIHJlYWRvbmx5IF92aXJ0dWFsU2Nyb2xsID0gaW5qZWN0PFZpcnR1YWxGb3JTZXJ2aWNlPFQ+PihWaXJ0dWFsRm9yU2VydmljZSwgeyBvcHRpb25hbDogdHJ1ZSB9KTtcblxuICAgIC8qKiBTdG9yZSB0aGUgbGlzdCBvZiBpdGVtcyB0byBkaXNwbGF5ICovXG4gICAgQElucHV0KCkgc2V0IHV4VmlydHVhbEZvck9mKGRhdGFzZXQ6IFRbXSkge1xuICAgICAgICAvLyBlbWl0IHRoZSBsYXRlc3QgZGF0YXNldFxuICAgICAgICB0aGlzLl92aXJ0dWFsU2Nyb2xsLmRhdGFzZXQubmV4dChkYXRhc2V0KTtcblxuICAgICAgICAvLyBzdG9yZSBhIGxvY2FsIHZlcnNpb24gb2YgdGhlIGRhdGFzZXRcbiAgICAgICAgdGhpcy5fZGF0YXNldCA9IGRhdGFzZXQ7XG5cbiAgICAgICAgLy8gaWYgdGhpcyBpcyBhbiB1cGRhdGUgYW5kIG5vdCB0aGUgaW5pdGlhbCBkYXRhc2V0IHRoZW4gd2Ugc2hvdWxkXG4gICAgICAgIC8vIGZvcmNpYmx5IHJlZHJhdyB0aGUgbGlzdCBvZiBpdGVtcy4gSW4gY2FzZXMgd2hlcmUgdGhlIGxlbmd0aCBvZlxuICAgICAgICAvLyB0aGUgZGF0YXNldCBjaGFuZ2Ugd291bGQgdHJpZ2dlciBhIHJlLXJlbmRlcmVyIGFzIHRoZSBzY3JvbGwgcG9zaXRpb25cbiAgICAgICAgLy8gd291bGQgY2hhbmdlLCBob3dldmVyIGlmIHdlIGFyZSBwZXJmb3JtaW5nIHNvcnRpbmcgdGhlbiBpdCB3b3VsZCBub3RcbiAgICAgICAgLy8gc28gd2UgbXVzdCBlbnN1cmUgd2UgdXBkYXRlIGV2ZXJ5dGltZSB0aGUgZGF0YXNldCBjaGFuZ2VzLlxuICAgICAgICBpZiAodGhpcy5fcmVuZGVyZWRSYW5nZSkge1xuICAgICAgICAgICAgdGhpcy5vblJhbmdlQ2hhbmdlKCk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICAvKiogUHJvdmlkZSBhIHRyYWNrQnkgZnVuY3Rpb24gdG8gb3B0aW1pemUgcmVuZGVyaW5nICovXG4gICAgQElucHV0KCkgdXhWaXJ0dWFsRm9yVHJhY2tCeTogVHJhY2tCeUZ1bmN0aW9uPFQ+IHwgdW5kZWZpbmVkID0gdGhpcy5kZWZhdWx0VHJhY2tCeTtcblxuICAgIC8qKiBUaGUgaW5zdGFuY2Ugb2YgdGhlIGRpZmZlciB3ZSBjcmVhdGUgKi9cbiAgICBwcml2YXRlIF9kaWZmZXI6IEl0ZXJhYmxlRGlmZmVyPFQ+O1xuXG4gICAgLyoqIEtlZXAgYSBsb2NhbCByZWZlcmVuY2UgdG8gdGhlIGRhdGFzZXQgKi9cbiAgICBwcml2YXRlIF9kYXRhc2V0OiBUW107XG5cbiAgICAvKiogU3RvcmUgdGhlIGN1cnJlbnRseSByZW5kZXJlZCByYW5nZSAqL1xuICAgIHByaXZhdGUgX3JlbmRlcmVkUmFuZ2U6IFZpcnR1YWxGb3JSYW5nZTtcblxuICAgIC8qKiBTdG9yZSBhIGxpc3Qgb2YgYWxsIHRoZSBjdXJyZW50bHkgcmVuZGVyZWQgaXRlbXMgKi9cbiAgICBwcml2YXRlIF9yZW5kZXJlZEl0ZW1zOiBUW107XG5cbiAgICAvKiogSW5kaWNhdGUgd2hldGhlciB3ZSBuZWVkIHRvIHBlcmZvcm0gYSB2aWV3IHVwZGF0ZSAqL1xuICAgIHByaXZhdGUgX2lzRGlydHk6IGJvb2xlYW4gPSBmYWxzZTtcblxuICAgIC8qKiBTdG9yZSBhIGNhY2hlIG9mIHJlY2VudGx5IGRpc3Bvc2VkIHZpZXdzIGZvciByZXVzZSAqL1xuICAgIHByaXZhdGUgcmVhZG9ubHkgX3RlbXBsYXRlQ2FjaGU6IEVtYmVkZGVkVmlld1JlZjxWaXJ0dWFsRm9yT2ZDb250ZXh0PFQ+PltdID0gW107XG5cbiAgICAvKiogTGltaXQgdGhlIHNpemUgb2YgdGhlIGNhY2hlIGFzIGl0IGNhbiB1c2UgYSBsb3Qgb2YgbWVtb3J5ICovXG4gICAgcHJpdmF0ZSByZWFkb25seSBfY2FjaGVTaXplOiBudW1iZXIgPSAyMDtcblxuICAgIC8qKiBVbnN1YnNjcmliZSBmcm9tIGFsbCBvYnNlcnZhYmxlcyAqL1xuICAgIHByaXZhdGUgcmVhZG9ubHkgX29uRGVzdHJveSA9IG5ldyBTdWJqZWN0PHZvaWQ+KCk7XG5cbiAgICBjb25zdHJ1Y3RvcigpIHtcbiAgICAgICAgLy8gV2hpbGUgbWFya2VkIGFzIG9wdGlvbmFsLCBpdCBpc24ndC4gV2UgZG8gdGhpcyBzbyB3ZSBjYW4gcHJvdmlkZSBhIG1vcmUgaGVscGZ1bCBlcnJvciBtZXNzYWdlXG4gICAgICAgIGlmICghdGhpcy5fdmlydHVhbFNjcm9sbCkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdUaGUgXCJ1eFZpcnR1YWxGb3JcIiBkaXJlY3RpdmUgcmVxdWlyZXMgdGhlIFwidXhWaXJ0dWFsRm9yQ29udGFpbmVyXCIgZGlyZWN0aXZlIHRvIGJlIGFkZGVkIHRvIHRoZSBwYXJlbnQgZWxlbWVudC4nKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIG5nT25Jbml0KCk6IHZvaWQge1xuICAgICAgICAvLyB1cGRhdGUgdGhlIFVJIHdoZW5ldmVyIHRoZSByYW5nZSBjaGFuZ2VzXG4gICAgICAgIHRoaXMuX3ZpcnR1YWxTY3JvbGwucmFuZ2UucGlwZShkaXN0aW5jdFVudGlsQ2hhbmdlZCh0aGlzLmlzUmFuZ2VTYW1lKSwgdGFrZVVudGlsKHRoaXMuX29uRGVzdHJveSkpLnN1YnNjcmliZShyYW5nZSA9PiB7XG4gICAgICAgICAgICB0aGlzLl9yZW5kZXJlZFJhbmdlID0gcmFuZ2U7XG4gICAgICAgICAgICB0aGlzLm9uUmFuZ2VDaGFuZ2UoKTtcbiAgICAgICAgICAgIHRoaXMuX2NoYW5nZURldGVjdG9yLmRldGVjdENoYW5nZXMoKTtcbiAgICAgICAgfSk7XG4gICAgfVxuXG4gICAgbmdEb0NoZWNrKCk6IHZvaWQge1xuICAgICAgICBpZiAodGhpcy5faXNEaXJ0eSAmJiB0aGlzLl9kaWZmZXIpIHtcblxuICAgICAgICAgICAgLy8gY2hlY2sgaWYgdGhlcmUgYXJlYSBhbnkgY2hhbmdlc1xuICAgICAgICAgICAgY29uc3QgY2hhbmdlcyA9IHRoaXMuZ2V0Q2hhbmdlcygpO1xuXG4gICAgICAgICAgICBpZiAoY2hhbmdlcykge1xuICAgICAgICAgICAgICAgIHRoaXMuYXBwbHlDaGFuZ2VzKGNoYW5nZXMpO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICB0aGlzLnVwZGF0ZUNvbnRleHRzKCk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIC8vIG5vdyB0aGF0IHdlIGhhdmUgcmVuZGVyZWQgYW55IGNoYW5nZSB3ZSBzaG91bGQgc3RvcmUgdGhpcyBzbyB3ZSBkb24ndCBwZXJmb3JtIHVubmVlZGVkIHVwZGF0ZXNcbiAgICAgICAgICAgIHRoaXMuX2lzRGlydHkgPSBmYWxzZTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIG5nT25EZXN0cm95KCk6IHZvaWQge1xuICAgICAgICB0aGlzLl9vbkRlc3Ryb3kubmV4dCgpO1xuICAgICAgICB0aGlzLl9vbkRlc3Ryb3kuY29tcGxldGUoKTtcbiAgICB9XG5cbiAgICAvKiogSWYgYW4gaXRlbVNpemUgaXMgbm90IHNwZWNpZmllZCB3ZSBuZWVkIHRvIGNhbGN1bGF0ZSBpdCAqL1xuICAgIGdldEhlaWdodChjb250ZXh0OiBULCBsZW5ndGg6IG51bWJlcik6IG51bWJlciB7XG5cbiAgICAgICAgLy8gY3JlYXRlIGEgdGVtcG9yYXJ5IHZpZXdcbiAgICAgICAgY29uc3QgdmlldyA9IHRoaXMuY3JlYXRlVmlldygwKTtcblxuICAgICAgICAvLyBzZXQgdGhlIGltcGxpY2l0IHZhbHVlIHRvIHRoZSBpdGVtIHZhbHVlXG4gICAgICAgIHZpZXcuY29udGV4dC4kaW1wbGljaXQgPSBjb250ZXh0O1xuICAgICAgICB2aWV3LmNvbnRleHQuY291bnQgPSBsZW5ndGg7XG4gICAgICAgIHZpZXcuY29udGV4dC5ldmVuID0gdHJ1ZTtcbiAgICAgICAgdmlldy5jb250ZXh0Lm9kZCA9IGZhbHNlO1xuICAgICAgICB2aWV3LmNvbnRleHQuZmlyc3QgPSB0cnVlO1xuICAgICAgICB2aWV3LmNvbnRleHQubGFzdCA9IGxlbmd0aCA9PT0gMTtcblxuICAgICAgICAvLyBydW4gY2hhbmdlIGRldGVjdGlvblxuICAgICAgICB2aWV3LmRldGVjdENoYW5nZXMoKTtcblxuICAgICAgICAvLyBnZXQgdGhlIHNpemUgb2YgdGhlIHZpZXdcbiAgICAgICAgY29uc3QgaGVpZ2h0ID0gdmlldy5yb290Tm9kZXNbMF0ub2Zmc2V0SGVpZ2h0O1xuXG4gICAgICAgIC8vIGRlc3Ryb3kgdGhlIHZpZXdcbiAgICAgICAgdGhpcy5fdmlld0NvbnRhaW5lclJlZi5yZW1vdmUoMCk7XG4gICAgICAgIHZpZXcuZGVzdHJveSgpO1xuXG4gICAgICAgIHJldHVybiBoZWlnaHQ7XG4gICAgfVxuXG4gICAgLyoqIERldGVybWluZSBpZiB0aGUgcmFuZ2UgaGFzIGNoYW5nZWQgKHBlcmZvcm1hbmNlIG9wdGltaXphdGlvbikgKi9cbiAgICBwcml2YXRlIGlzUmFuZ2VTYW1lKHByZXZpb3VzOiBWaXJ0dWFsRm9yUmFuZ2UsIGN1cnJlbnQ6IFZpcnR1YWxGb3JSYW5nZSk6IGJvb2xlYW4ge1xuICAgICAgICByZXR1cm4gcHJldmlvdXMuc3RhcnQgPT09IGN1cnJlbnQuc3RhcnQgJiYgcHJldmlvdXMuZW5kID09PSBjdXJyZW50LmVuZDtcbiAgICB9XG5cbiAgICBwcml2YXRlIG9uUmFuZ2VDaGFuZ2UoKTogdm9pZCB7XG5cbiAgICAgICAgLy8gc3RvcmUgdGhlIHZpc2libGUgcmFuZ2VcbiAgICAgICAgdGhpcy5fcmVuZGVyZWRJdGVtcyA9IHRoaXMuX2RhdGFzZXQuc2xpY2UodGhpcy5fcmVuZGVyZWRSYW5nZS5zdGFydCwgdGhpcy5fcmVuZGVyZWRSYW5nZS5lbmQpO1xuXG4gICAgICAgIC8vIGNyZWF0ZSB0aGUgQW5ndWxhciBkaWZmZXIgaWYgd2UgaGF2ZW4ndCBwcmV2aW91c2x5IGRvbmUgc29cbiAgICAgICAgaWYgKCF0aGlzLl9kaWZmZXIpIHtcbiAgICAgICAgICAgIHRoaXMuX2RpZmZlciA9IHRoaXMuX2RpZmZlcnMuZmluZCh0aGlzLl9yZW5kZXJlZEl0ZW1zKS5jcmVhdGUodGhpcy51eFZpcnR1YWxGb3JUcmFja0J5KTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIG1hcmsgdGhlIHZpZXcgZm9yIHJlLXJlbmRlclxuICAgICAgICB0aGlzLl9pc0RpcnR5ID0gdHJ1ZTtcbiAgICB9XG5cbiAgICAvKiogRGV0ZXJtaW5lIHdoaWNoIGl0ZW1zIGhhdmUgY2hhbmdlZCAqL1xuICAgIHByaXZhdGUgZ2V0Q2hhbmdlcygpOiBJdGVyYWJsZUNoYW5nZXM8VD4ge1xuICAgICAgICByZXR1cm4gdGhpcy5fZGlmZmVyLmRpZmYodGhpcy5fcmVuZGVyZWRJdGVtcyk7XG4gICAgfVxuXG4gICAgLyoqIEluc2VydCwgbW92ZSBhbmQgcmVtb3ZlIGFueSBpdGVtcyB3aXRoaW4gdGhlIHZpZXcgKi9cbiAgICBwcml2YXRlIGFwcGx5Q2hhbmdlcyhjaGFuZ2VzOiBJdGVyYWJsZUNoYW5nZXM8VD4pOiB2b2lkIHtcblxuICAgICAgICAvLyBHbyB0aHJvdWdoIGVhY2ggY2hhbmdlcyBhbmQgZWl0aGVyIGFkZCBvciByZWFycmFuZ2UgYWNjb3JkaW5nbHlcbiAgICAgICAgY2hhbmdlcy5mb3JFYWNoT3BlcmF0aW9uKChyZWNvcmQ6IEl0ZXJhYmxlQ2hhbmdlUmVjb3JkPFQ+LCBwcmV2aW91c0luZGV4OiBudW1iZXIsIGN1cnJlbnRJbmRleDogbnVtYmVyKSA9PiB7XG5cbiAgICAgICAgICAgIC8vIGNoZWNrIGlmIGEgbmV3IGl0ZW0gd2FzIGFkZGVkXG4gICAgICAgICAgICBpZiAocHJldmlvdXNJbmRleCA9PT0gbnVsbCkge1xuICAgICAgICAgICAgICAgIC8vIGNyZWF0ZSB0aGUgbmV3IGVtYmVkZGVkIHZpZXdcbiAgICAgICAgICAgICAgICBjb25zdCB2aWV3ID0gdGhpcy5jcmVhdGVWaWV3KGN1cnJlbnRJbmRleCk7XG5cbiAgICAgICAgICAgICAgICAvLyBzZXQgdGhlIGltcGxpY2l0IHZhbHVlIHRvIHRoZSBpdGVtIHZhbHVlXG4gICAgICAgICAgICAgICAgdmlldy5jb250ZXh0LiRpbXBsaWNpdCA9IHJlY29yZC5pdGVtO1xuXG4gICAgICAgICAgICB9IGVsc2UgaWYgKGN1cnJlbnRJbmRleCA9PT0gbnVsbCkgeyAvLyBjaGVjayBpZiB0aGUgaXRlbSBzaG91bGQgYmUgcmVtb3ZlZFxuICAgICAgICAgICAgICAgIGNvbnN0IHZpZXcgPSB0aGlzLl92aWV3Q29udGFpbmVyUmVmLmRldGFjaChjdXJyZW50SW5kZXgpIGFzIEVtYmVkZGVkVmlld1JlZjxWaXJ0dWFsRm9yT2ZDb250ZXh0PFQ+PjtcbiAgICAgICAgICAgICAgICBjb25zdCBpbmRleCA9IHRoaXMuX3ZpZXdDb250YWluZXJSZWYuaW5kZXhPZih2aWV3KTtcblxuICAgICAgICAgICAgICAgIC8vIGlmIHRoZXJlIGlzIHNwYWNlIGluIHRoZSBjYWNoZSB0aGVuIHN0b3JlIHRoZSBkZXRhY2hlZCB2aWV3XG4gICAgICAgICAgICAgICAgaWYgKHRoaXMuX3RlbXBsYXRlQ2FjaGUubGVuZ3RoIDwgdGhpcy5fY2FjaGVTaXplKSB7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuX3RlbXBsYXRlQ2FjaGUucHVzaCh2aWV3KTtcbiAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICBpbmRleCA9PT0gLTEgPyB2aWV3LmRlc3Ryb3koKSA6IHRoaXMuX3ZpZXdDb250YWluZXJSZWYucmVtb3ZlKGluZGV4KTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9IGVsc2UgeyAvLyB0aGUgcG9zaXRpb24gb2YgdGhlIGl0ZW0gaGFzIGNoYW5nZWRcblxuICAgICAgICAgICAgICAgIC8vIGdldCB0aGUgdmlldyBmcm9tIGl0cyBjdXJyZW50IHBvc2l0aW9uXG4gICAgICAgICAgICAgICAgY29uc3QgdmlldyA9IHRoaXMuX3ZpZXdDb250YWluZXJSZWYuZ2V0KHByZXZpb3VzSW5kZXgpIGFzIEVtYmVkZGVkVmlld1JlZjxWaXJ0dWFsRm9yT2ZDb250ZXh0PFQ+PjtcblxuICAgICAgICAgICAgICAgIC8vIG1vdmUgaXQgdG8gdGhlIG5ldyBwb3NpdGlvblxuICAgICAgICAgICAgICAgIHRoaXMuX3ZpZXdDb250YWluZXJSZWYubW92ZSh2aWV3LCBjdXJyZW50SW5kZXgpO1xuXG4gICAgICAgICAgICAgICAgLy8gdXBkYXRlIHRoZSBpbXBsaWNpdCB2YWx1ZSAodGhlIHJlc3Qgd2lsbCBzdGF5IHRoZSBzYW1lKVxuICAgICAgICAgICAgICAgIHZpZXcuY29udGV4dC4kaW1wbGljaXQgPSByZWNvcmQuaXRlbTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSk7XG5cbiAgICAgICAgLy8gRW5zdXJlIHRoZSBpbXBsaWNpdCB2YWx1ZSBpcyBjb3JyZWN0IGZvciBhbnkgaXRlbXMgd2hvc2UgaWRlbnRpdHkgY2hhbmdlZFxuICAgICAgICBjaGFuZ2VzLmZvckVhY2hJZGVudGl0eUNoYW5nZSgocmVjb3JkOiBJdGVyYWJsZUNoYW5nZVJlY29yZDxUPikgPT4ge1xuICAgICAgICAgICAgY29uc3QgdmlldyA9IHRoaXMuX3ZpZXdDb250YWluZXJSZWYuZ2V0KHJlY29yZC5jdXJyZW50SW5kZXgpIGFzIEVtYmVkZGVkVmlld1JlZjxWaXJ0dWFsRm9yT2ZDb250ZXh0PFQ+PjtcblxuICAgICAgICAgICAgaWYgKHZpZXcpIHtcbiAgICAgICAgICAgICAgICB2aWV3LmNvbnRleHQuJGltcGxpY2l0ID0gcmVjb3JkLml0ZW07XG4gICAgICAgICAgICB9XG4gICAgICAgIH0pO1xuXG4gICAgICAgIHRoaXMudXBkYXRlQ29udGV4dHMoKTtcbiAgICB9XG5cbiAgICB1cGRhdGVDb250ZXh0cygpOiB2b2lkIHtcblxuICAgICAgICAvLyB1cGRhdGUgYWxsIHRoZSBvdGhlciBjb250ZXh0IHByb3BlcnRpZXNcbiAgICAgICAgZm9yIChsZXQgaWR4ID0gMDsgaWR4IDwgdGhpcy5fdmlld0NvbnRhaW5lclJlZi5sZW5ndGg7IGlkeCsrKSB7XG5cbiAgICAgICAgICAgIC8vIGdldCB0aGUgdmlldyBhdCBhIGdpdmVuIHBvc2l0aW9uXG4gICAgICAgICAgICBjb25zdCB2aWV3ID0gdGhpcy5fdmlld0NvbnRhaW5lclJlZi5nZXQoaWR4KSBhcyBFbWJlZGRlZFZpZXdSZWY8VmlydHVhbEZvck9mQ29udGV4dDxUPj47XG5cbiAgICAgICAgICAgIC8vIHVwZGF0ZSB0aGUgcHJvcGVydGllc1xuICAgICAgICAgICAgdmlldy5jb250ZXh0LmluZGV4ID0gdGhpcy5fcmVuZGVyZWRSYW5nZS5zdGFydCArIGlkeDtcbiAgICAgICAgICAgIHZpZXcuY29udGV4dC5jb3VudCA9IHRoaXMuX2RhdGFzZXQubGVuZ3RoO1xuICAgICAgICAgICAgdmlldy5jb250ZXh0LmZpcnN0ID0gdmlldy5jb250ZXh0LmluZGV4ID09PSAwO1xuICAgICAgICAgICAgdmlldy5jb250ZXh0Lmxhc3QgPSB2aWV3LmNvbnRleHQuaW5kZXggPT09IHZpZXcuY29udGV4dC5jb3VudCAtIDE7XG4gICAgICAgICAgICB2aWV3LmNvbnRleHQuZXZlbiA9IHZpZXcuY29udGV4dC5pbmRleCAlIDIgPT09IDA7XG4gICAgICAgICAgICB2aWV3LmNvbnRleHQub2RkID0gIXZpZXcuY29udGV4dC5ldmVuO1xuXG4gICAgICAgICAgICAvLyB1cGRhdGUgdGhlIHBvc2l0aW9uIGluIHRoZSBET01cbiAgICAgICAgICAgIHZpZXcucm9vdE5vZGVzLmZvckVhY2goKG5vZGU6IEhUTUxFbGVtZW50KSA9PiB7XG4gICAgICAgICAgICAgICAgdGhpcy5fcmVuZGVyZXIuc2V0U3R5bGUobm9kZSwgJ3Bvc2l0aW9uJywgJ2Fic29sdXRlJyk7XG4gICAgICAgICAgICAgICAgdGhpcy5fcmVuZGVyZXIuc2V0U3R5bGUobm9kZSwgJ3dpZHRoJywgJzEwMCUnKTtcbiAgICAgICAgICAgICAgICB0aGlzLl9yZW5kZXJlci5zZXRTdHlsZShub2RlLCAndG9wJywgJzAnKTtcbiAgICAgICAgICAgICAgICB0aGlzLl9yZW5kZXJlci5zZXRTdHlsZShub2RlLCAndHJhbnNmb3JtJywgYHRyYW5zbGF0ZVkoJHt2aWV3LmNvbnRleHQuaW5kZXggKiB0aGlzLl92aXJ0dWFsU2Nyb2xsLml0ZW1TaXplfXB4YCk7XG4gICAgICAgICAgICB9KTtcblxuICAgICAgICAgICAgdmlldy5kZXRlY3RDaGFuZ2VzKCk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBwcml2YXRlIGNyZWF0ZVZpZXcoaW5kZXg6IG51bWJlcik6IEVtYmVkZGVkVmlld1JlZjxWaXJ0dWFsRm9yT2ZDb250ZXh0PFQ+PiB7XG5cbiAgICAgICAgLy8gZ2V0IGEgY2hlY2tlZCBFbWJlZGRlZFZpZXdSZWYgaXMgdGhlcmUgaXMgb25lXG4gICAgICAgIGNvbnN0IGNhY2hlZFRlbXBsYXRlID0gdGhpcy5fdGVtcGxhdGVDYWNoZS5wb3AoKTtcblxuICAgICAgICBpZiAoY2FjaGVkVGVtcGxhdGUpIHtcblxuICAgICAgICAgICAgLy8gcmVwbGFjZSBleGlzdGluZyBjb250ZXh0IHdpdGggdGhlIGRlZmF1bHRzXG4gICAgICAgICAgICBjYWNoZWRUZW1wbGF0ZS5jb250ZXh0LiRpbXBsaWNpdCA9IG51bGw7XG4gICAgICAgICAgICBjYWNoZWRUZW1wbGF0ZS5jb250ZXh0LmluZGV4ID0gLTE7XG4gICAgICAgICAgICBjYWNoZWRUZW1wbGF0ZS5jb250ZXh0LmNvdW50ID0gLTE7XG4gICAgICAgICAgICBjYWNoZWRUZW1wbGF0ZS5jb250ZXh0LmZpcnN0ID0gZmFsc2U7XG4gICAgICAgICAgICBjYWNoZWRUZW1wbGF0ZS5jb250ZXh0Lmxhc3QgPSBmYWxzZTtcbiAgICAgICAgICAgIGNhY2hlZFRlbXBsYXRlLmNvbnRleHQuZXZlbiA9IGZhbHNlO1xuICAgICAgICAgICAgY2FjaGVkVGVtcGxhdGUuY29udGV4dC5vZGQgPSBmYWxzZTtcblxuICAgICAgICAgICAgLy8gaW5zZXJ0IHRoZSB2aWV3XG4gICAgICAgICAgICB0aGlzLl92aWV3Q29udGFpbmVyUmVmLmluc2VydChjYWNoZWRUZW1wbGF0ZSwgaW5kZXgpO1xuXG4gICAgICAgICAgICAvLyByZXR1cm4gdGhlIGNhY2hlZCBFbWJlZGRlZFZpZXdSZWZcbiAgICAgICAgICAgIHJldHVybiBjYWNoZWRUZW1wbGF0ZTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIG90aGVyd2lzZSBjcmVhdGUgYSBuZXcgdmlldyBhbmQgaW5zZXJ0IGl0XG4gICAgICAgIHJldHVybiB0aGlzLl92aWV3Q29udGFpbmVyUmVmLmNyZWF0ZUVtYmVkZGVkVmlldzxWaXJ0dWFsRm9yT2ZDb250ZXh0PFQ+Pih0aGlzLl90ZW1wbGF0ZVJlZiwge1xuICAgICAgICAgICAgJGltcGxpY2l0OiBudWxsLFxuICAgICAgICAgICAgaW5kZXg6IC0xLFxuICAgICAgICAgICAgY291bnQ6IC0xLFxuICAgICAgICAgICAgZmlyc3Q6IGZhbHNlLFxuICAgICAgICAgICAgbGFzdDogZmFsc2UsXG4gICAgICAgICAgICBldmVuOiBmYWxzZSxcbiAgICAgICAgICAgIG9kZDogZmFsc2UsXG4gICAgICAgIH0sIGluZGV4KTtcbiAgICB9XG5cbiAgICBwcml2YXRlIGRlZmF1bHRUcmFja0J5KGluZGV4OiBudW1iZXIpOiBudW1iZXIge1xuICAgICAgICByZXR1cm4gaW5kZXg7XG4gICAgfVxuXG59XG5cbi8qKiBXZSB3YW50IHRvIHN1cHBseSB0aGUgc2FtZSBwcm9wZXJ0aWVzIGFzIGBuZ0ZvcmAgKi9cbmV4cG9ydCBpbnRlcmZhY2UgVmlydHVhbEZvck9mQ29udGV4dDxUPiB7XG4gICAgJGltcGxpY2l0OiBUO1xuICAgIGluZGV4OiBudW1iZXI7XG4gICAgY291bnQ6IG51bWJlcjtcbiAgICBmaXJzdDogYm9vbGVhbjtcbiAgICBsYXN0OiBib29sZWFuO1xuICAgIGV2ZW46IGJvb2xlYW47XG4gICAgb2RkOiBib29sZWFuO1xufVxuIl19