UNPKG

@angular/cdk

Version:

Angular Material Component Development Kit

273 lines 39.1 kB
/** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ import { coerceBooleanProperty, coerceNumberProperty } from '@angular/cdk/coercion'; import { Directive, ElementRef, Input, NgZone, HostListener, Optional, Inject, } from '@angular/core'; import { Platform } from '@angular/cdk/platform'; import { auditTime, takeUntil } from 'rxjs/operators'; import { fromEvent, Subject } from 'rxjs'; import { DOCUMENT } from '@angular/common'; /** Directive to automatically resize a textarea to fit its content. */ export class CdkTextareaAutosize { constructor(_elementRef, _platform, _ngZone, /** @breaking-change 11.0.0 make document required */ document) { this._elementRef = _elementRef; this._platform = _platform; this._ngZone = _ngZone; this._destroyed = new Subject(); this._enabled = true; /** * Value of minRows as of last resize. If the minRows has decreased, the * height of the textarea needs to be recomputed to reflect the new minimum. The maxHeight * does not have the same problem because it does not affect the textarea's scrollHeight. */ this._previousMinRows = -1; this._isViewInited = false; this._document = document; this._textareaElement = this._elementRef.nativeElement; this._measuringClass = _platform.FIREFOX ? 'cdk-textarea-autosize-measuring-firefox' : 'cdk-textarea-autosize-measuring'; } /** Minimum amount of rows in the textarea. */ get minRows() { return this._minRows; } set minRows(value) { this._minRows = coerceNumberProperty(value); this._setMinHeight(); } /** Maximum amount of rows in the textarea. */ get maxRows() { return this._maxRows; } set maxRows(value) { this._maxRows = coerceNumberProperty(value); this._setMaxHeight(); } /** Whether autosizing is enabled or not */ get enabled() { return this._enabled; } set enabled(value) { value = coerceBooleanProperty(value); // Only act if the actual value changed. This specifically helps to not run // resizeToFitContent too early (i.e. before ngAfterViewInit) if (this._enabled !== value) { (this._enabled = value) ? this.resizeToFitContent(true) : this.reset(); } } get placeholder() { return this._textareaElement.placeholder; } set placeholder(value) { this._cachedPlaceholderHeight = undefined; this._textareaElement.placeholder = value; this._cacheTextareaPlaceholderHeight(); } /** Sets the minimum height of the textarea as determined by minRows. */ _setMinHeight() { const minHeight = this.minRows && this._cachedLineHeight ? `${this.minRows * this._cachedLineHeight}px` : null; if (minHeight) { this._textareaElement.style.minHeight = minHeight; } } /** Sets the maximum height of the textarea as determined by maxRows. */ _setMaxHeight() { const maxHeight = this.maxRows && this._cachedLineHeight ? `${this.maxRows * this._cachedLineHeight}px` : null; if (maxHeight) { this._textareaElement.style.maxHeight = maxHeight; } } ngAfterViewInit() { if (this._platform.isBrowser) { // Remember the height which we started with in case autosizing is disabled this._initialHeight = this._textareaElement.style.height; this.resizeToFitContent(); this._ngZone.runOutsideAngular(() => { const window = this._getWindow(); fromEvent(window, 'resize') .pipe(auditTime(16), takeUntil(this._destroyed)) .subscribe(() => this.resizeToFitContent(true)); }); this._isViewInited = true; this.resizeToFitContent(true); } } ngOnDestroy() { this._destroyed.next(); this._destroyed.complete(); } /** * Cache the height of a single-row textarea if it has not already been cached. * * We need to know how large a single "row" of a textarea is in order to apply minRows and * maxRows. For the initial version, we will assume that the height of a single line in the * textarea does not ever change. */ _cacheTextareaLineHeight() { if (this._cachedLineHeight) { return; } // Use a clone element because we have to override some styles. let textareaClone = this._textareaElement.cloneNode(false); textareaClone.rows = 1; // Use `position: absolute` so that this doesn't cause a browser layout and use // `visibility: hidden` so that nothing is rendered. Clear any other styles that // would affect the height. textareaClone.style.position = 'absolute'; textareaClone.style.visibility = 'hidden'; textareaClone.style.border = 'none'; textareaClone.style.padding = '0'; textareaClone.style.height = ''; textareaClone.style.minHeight = ''; textareaClone.style.maxHeight = ''; // In Firefox it happens that textarea elements are always bigger than the specified amount // of rows. This is because Firefox tries to add extra space for the horizontal scrollbar. // As a workaround that removes the extra space for the scrollbar, we can just set overflow // to hidden. This ensures that there is no invalid calculation of the line height. // See Firefox bug report: https://bugzilla.mozilla.org/show_bug.cgi?id=33654 textareaClone.style.overflow = 'hidden'; this._textareaElement.parentNode.appendChild(textareaClone); this._cachedLineHeight = textareaClone.clientHeight; this._textareaElement.parentNode.removeChild(textareaClone); // Min and max heights have to be re-calculated if the cached line height changes this._setMinHeight(); this._setMaxHeight(); } _measureScrollHeight() { // Reset the textarea height to auto in order to shrink back to its default size. // Also temporarily force overflow:hidden, so scroll bars do not interfere with calculations. this._textareaElement.classList.add(this._measuringClass); // The measuring class includes a 2px padding to workaround an issue with Chrome, // so we account for that extra space here by subtracting 4 (2px top + 2px bottom). const scrollHeight = this._textareaElement.scrollHeight - 4; this._textareaElement.classList.remove(this._measuringClass); return scrollHeight; } _cacheTextareaPlaceholderHeight() { if (!this._isViewInited || this._cachedPlaceholderHeight != undefined) { return; } if (!this.placeholder) { this._cachedPlaceholderHeight = 0; return; } const value = this._textareaElement.value; this._textareaElement.value = this._textareaElement.placeholder; this._cachedPlaceholderHeight = this._measureScrollHeight(); this._textareaElement.value = value; } ngDoCheck() { if (this._platform.isBrowser) { this.resizeToFitContent(); } } /** * Resize the textarea to fit its content. * @param force Whether to force a height recalculation. By default the height will be * recalculated only if the value changed since the last call. */ resizeToFitContent(force = false) { // If autosizing is disabled, just skip everything else if (!this._enabled) { return; } this._cacheTextareaLineHeight(); this._cacheTextareaPlaceholderHeight(); // If we haven't determined the line-height yet, we know we're still hidden and there's no point // in checking the height of the textarea. if (!this._cachedLineHeight) { return; } const textarea = this._elementRef.nativeElement; const value = textarea.value; // Only resize if the value or minRows have changed since these calculations can be expensive. if (!force && this._minRows === this._previousMinRows && value === this._previousValue) { return; } const scrollHeight = this._measureScrollHeight(); const height = Math.max(scrollHeight, this._cachedPlaceholderHeight || 0); // Use the scrollHeight to know how large the textarea *would* be if fit its entire value. textarea.style.height = `${height}px`; this._ngZone.runOutsideAngular(() => { if (typeof requestAnimationFrame !== 'undefined') { requestAnimationFrame(() => this._scrollToCaretPosition(textarea)); } else { setTimeout(() => this._scrollToCaretPosition(textarea)); } }); this._previousValue = value; this._previousMinRows = this._minRows; } /** * Resets the textarea to its original size */ reset() { // Do not try to change the textarea, if the initialHeight has not been determined yet // This might potentially remove styles when reset() is called before ngAfterViewInit if (this._initialHeight !== undefined) { this._textareaElement.style.height = this._initialHeight; } } // In Ivy the `host` metadata will be merged, whereas in ViewEngine it is overridden. In order // to avoid double event listeners, we need to use `HostListener`. Once Ivy is the default, we // can move this back into `host`. // tslint:disable:no-host-decorator-in-concrete _noopInputHandler() { // no-op handler that ensures we're running change detection on input events. } /** Access injected document if available or fallback to global document reference */ _getDocument() { return this._document || document; } /** Use defaultView of injected document if available or fallback to global window reference */ _getWindow() { const doc = this._getDocument(); return doc.defaultView || window; } /** * Scrolls a textarea to the caret position. On Firefox resizing the textarea will * prevent it from scrolling to the caret position. We need to re-set the selection * in order for it to scroll to the proper position. */ _scrollToCaretPosition(textarea) { const { selectionStart, selectionEnd } = textarea; const document = this._getDocument(); // IE will throw an "Unspecified error" if we try to set the selection range after the // element has been removed from the DOM. Assert that the directive hasn't been destroyed // between the time we requested the animation frame and when it was executed. // Also note that we have to assert that the textarea is focused before we set the // selection range. Setting the selection range on a non-focused textarea will cause // it to receive focus on IE and Edge. if (!this._destroyed.isStopped && document.activeElement === textarea) { textarea.setSelectionRange(selectionStart, selectionEnd); } } } CdkTextareaAutosize.decorators = [ { type: Directive, args: [{ selector: 'textarea[cdkTextareaAutosize]', exportAs: 'cdkTextareaAutosize', host: { 'class': 'cdk-textarea-autosize', // Textarea elements that have the directive applied should have a single row by default. // Browsers normally show two rows by default and therefore this limits the minRows binding. 'rows': '1', }, },] } ]; CdkTextareaAutosize.ctorParameters = () => [ { type: ElementRef }, { type: Platform }, { type: NgZone }, { type: undefined, decorators: [{ type: Optional }, { type: Inject, args: [DOCUMENT,] }] } ]; CdkTextareaAutosize.propDecorators = { minRows: [{ type: Input, args: ['cdkAutosizeMinRows',] }], maxRows: [{ type: Input, args: ['cdkAutosizeMaxRows',] }], enabled: [{ type: Input, args: ['cdkTextareaAutosize',] }], placeholder: [{ type: Input }], _noopInputHandler: [{ type: HostListener, args: ['input',] }] }; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXV0b3NpemUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi9zcmMvY2RrL3RleHQtZmllbGQvYXV0b3NpemUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7OztHQU1HO0FBRUgsT0FBTyxFQUVMLHFCQUFxQixFQUNyQixvQkFBb0IsRUFFckIsTUFBTSx1QkFBdUIsQ0FBQztBQUMvQixPQUFPLEVBQ0wsU0FBUyxFQUNULFVBQVUsRUFDVixLQUFLLEVBSUwsTUFBTSxFQUNOLFlBQVksRUFDWixRQUFRLEVBQ1IsTUFBTSxHQUNQLE1BQU0sZUFBZSxDQUFDO0FBQ3ZCLE9BQU8sRUFBQyxRQUFRLEVBQUMsTUFBTSx1QkFBdUIsQ0FBQztBQUMvQyxPQUFPLEVBQUMsU0FBUyxFQUFFLFNBQVMsRUFBQyxNQUFNLGdCQUFnQixDQUFDO0FBQ3BELE9BQU8sRUFBQyxTQUFTLEVBQUUsT0FBTyxFQUFDLE1BQU0sTUFBTSxDQUFDO0FBQ3hDLE9BQU8sRUFBQyxRQUFRLEVBQUMsTUFBTSxpQkFBaUIsQ0FBQztBQUV6Qyx1RUFBdUU7QUFXdkUsTUFBTSxPQUFPLG1CQUFtQjtJQXNFOUIsWUFBb0IsV0FBb0MsRUFDcEMsU0FBbUIsRUFDbkIsT0FBZTtJQUN2QixxREFBcUQ7SUFDdkIsUUFBYztRQUpwQyxnQkFBVyxHQUFYLFdBQVcsQ0FBeUI7UUFDcEMsY0FBUyxHQUFULFNBQVMsQ0FBVTtRQUNuQixZQUFPLEdBQVAsT0FBTyxDQUFRO1FBcEVsQixlQUFVLEdBQUcsSUFBSSxPQUFPLEVBQVEsQ0FBQztRQUkxQyxhQUFRLEdBQVksSUFBSSxDQUFDO1FBRWpDOzs7O1dBSUc7UUFDSyxxQkFBZ0IsR0FBVyxDQUFDLENBQUMsQ0FBQztRQXFEOUIsa0JBQWEsR0FBRyxLQUFLLENBQUM7UUFPNUIsSUFBSSxDQUFDLFNBQVMsR0FBRyxRQUFRLENBQUM7UUFFMUIsSUFBSSxDQUFDLGdCQUFnQixHQUFHLElBQUksQ0FBQyxXQUFXLENB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QVU7UUFDaEIsTUFBTSxHQUFHLEdBQUcsSUFBSSxDQUFDLFlBQVksRUFBRSxDQUFDO1FBQ2hDLE9BQU8sR0FBRyxDQUFDLFdBQVcsSUFBSSxNQUFNLENBQUM7SUFDbkMsQ0FBQztJQUVEOzs7O09BSUc7SUFDSyxzQkFBc0IsQ0FBQyxRQUE2QjtRQUMxRCxNQUFNLEVBQUMsY0FBYyxFQUFFLFlBQVksRUFBQyxHQUFHLFFBQVEsQ0FBQztRQUNoRCxNQUFNLFFBQVEsR0FBRyxJQUFJLENBQUMsWUFBWSxFQUFFLENBQUM7UUFFckMsc0ZBQXNGO1FBQ3RGLHlGQUF5RjtRQUN6Riw4RUFBOEU7UUFDOUUsa0ZBQWtGO1FBQ2xGLG9GQUFvRjtRQUNwRixzQ0FBc0M7UUFDdEMsSUFBSSxDQUFDLElBQUksQ0FBQyxVQUFVLENBQUMsU0FBUyxJQUFJLFFBQVEsQ0FBQyxhQUFhLEtBQUssUUFBUSxFQUFFO1lBQ3JFLFFBQVEsQ0FBQyxpQkFBaUIsQ0FBQyxjQUFjLEVBQUUsWUFBWSxDQUFDLENBQUM7U0FDMUQ7SUFDSCxDQUFDOzs7WUF0VEYsU0FBUyxTQUFDO2dCQUNULFFBQVEsRUFBRSwrQkFBK0I7Z0JBQ3pDLFFBQVEsRUFBRSxxQkFBcUI7Z0JBQy9CLElBQUksRUFBRTtvQkFDSixPQUFPLEVBQUUsdUJBQXVCO29CQUNoQyx5RkFBeUY7b0JBQ3pGLDRGQUE0RjtvQkFDNUYsTUFBTSxFQUFFLEdBQUc7aUJBQ1o7YUFDRjs7O1lBekJDLFVBQVU7WUFVSixRQUFRO1lBTGQsTUFBTTs0Q0ErRk8sUUFBUSxZQUFJLE1BQU0sU0FBQyxRQUFROzs7c0JBdER2QyxLQUFLLFNBQUMsb0JBQW9CO3NCQVExQixLQUFLLFNBQUMsb0JBQW9CO3NCQVExQixLQUFLLFNBQUMscUJBQXFCOzBCQVkzQixLQUFLO2dDQTBOTCxZQUFZLFNBQUMsT0FBTyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogQGxpY2Vuc2VcbiAqIENvcHlyaWdodCBHb29nbGUgTExDIEFsbCBSaWdodHMgUmVzZXJ2ZWQuXG4gKlxuICogVXNlIG9mIHRoaXMgc291cmNlIGNvZGUgaXMgZ292ZXJuZWQgYnkgYW4gTUlULXN0eWxlIGxpY2Vuc2UgdGhhdCBjYW4gYmVcbiAqIGZvdW5kIGluIHRoZSBMSUNFTlNFIGZpbGUgYXQgaHR0cHM6Ly9hbmd1bGFyLmlvL2xpY2Vuc2VcbiAqL1xuXG5pbXBvcnQge1xuICBCb29sZWFuSW5wdXQsXG4gIGNvZXJjZUJvb2xlYW5Qcm9wZXJ0eSxcbiAgY29lcmNlTnVtYmVyUHJvcGVydHksXG4gIE51bWJlcklucHV0XG59IGZyb20gJ0Bhbmd1bGFyL2Nkay9jb2VyY2lvbic7XG5pbXBvcnQge1xuICBEaXJlY3RpdmUsXG4gIEVsZW1lbnRSZWYsXG4gIElucHV0LFxuICBBZnRlclZpZXdJbml0LFxuICBEb0NoZWNrLFxuICBPbkRlc3Ryb3ksXG4gIE5nWm9uZSxcbiAgSG9zdExpc3RlbmVyLFxuICBPcHRpb25hbCxcbiAgSW5qZWN0LFxufSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7UGxhdGZvcm19IGZyb20gJ0Bhbmd1bGFyL2Nkay9wbGF0Zm9ybSc7XG5pbXBvcnQge2F1ZGl0VGltZSwgdGFrZVVudGlsfSBmcm9tICdyeGpzL29wZXJhdG9ycyc7XG5pbXBvcnQge2Zyb21FdmVudCwgU3ViamVjdH0gZnJvbSAncnhqcyc7XG5pbXBvcnQge0RPQ1VNRU5UfSBmcm9tICdAYW5ndWxhci9jb21tb24nO1xuXG4vKiogRGlyZWN0aXZlIHRvIGF1dG9tYXRpY2FsbHkgcmVzaXplIGEgdGV4dGFyZWEgdG8gZml0IGl0cyBjb250ZW50LiAqL1xuQERpcmVjdGl2ZSh7XG4gIHNlbGVjdG9yOiAndGV4dGFyZWFbY2RrVGV4dGFyZWFBdXRvc2l6ZV0nLFxuICBleHBvcnRBczogJ2Nka1RleHRhcmVhQXV0b3NpemUnLFxuICBob3N0OiB7XG4gICAgJ2NsYXNzJzogJ2Nkay10ZXh0YXJlYS1hdXRvc2l6ZScsXG4gICAgLy8gVGV4dGFyZWEgZWxlbWVudHMgdGhhdCBoYXZlIHRoZSBkaXJlY3RpdmUgYXBwbGllZCBzaG91bGQgaGF2ZSBhIHNpbmdsZSByb3cgYnkgZGVmYXVsdC5cbiAgICAvLyBCcm93c2VycyBub3JtYWxseSBzaG93IHR3byByb3dzIGJ5IGRlZmF1bHQgYW5kIHRoZXJlZm9yZSB0aGlzIGxpbWl0cyB0aGUgbWluUm93cyBiaW5kaW5nLlxuICAgICdyb3dzJzogJzEnLFxuICB9LFxufSlcbmV4cG9ydCBjbGFzcyBDZGtUZXh0YXJlYUF1dG9zaXplIGltcGxlbWVudHMgQWZ0ZXJWaWV3SW5pdCwgRG9DaGVjaywgT25EZXN0cm95IHtcbiAgLyoqIEtlZXAgdHJhY2sgb2YgdGhlIHByZXZpb3VzIHRleHRhcmVhIHZhbHVlIHRvIGF2b2lkIHJlc2l6aW5nIHdoZW4gdGhlIHZhbHVlIGhhc24ndCBjaGFuZ2VkLiAqL1xuICBwcml2YXRlIF9wcmV2aW91c1ZhbHVlPzogc3RyaW5nO1xuICBwcml2YXRlIF9pbml0aWFsSGVpZ2h0OiBzdHJpbmcgfCB1bmRlZmluZWQ7XG4gIHByaXZhdGUgcmVhZG9ubHkgX2Rlc3Ryb3llZCA9IG5ldyBTdWJqZWN0PHZvaWQ+KCk7XG5cbiAgcHJpdmF0ZSBfbWluUm93czogbnVtYmVyO1xuICBwcml2YXRlIF9tYXhSb3dzOiBudW1iZXI7XG4gIHByaXZhdGUgX2VuYWJsZWQ6IGJvb2xlYW4gPSB0cnVlO1xuXG4gIC8qKlxuICAgKiBWYWx1ZSBvZiBtaW5Sb3dzIGFzIG9mIGxhc3QgcmVzaXplLiBJZiB0aGUgbWluUm93cyBoYXMgZGVjcmVhc2VkLCB0aGVcbiAgICogaGVpZ2h0IG9mIHRoZSB0ZXh0YXJlYSBuZWVkcyB0byBiZSByZWNvbXB1dGVkIHRvIHJlZmxlY3QgdGhlIG5ldyBtaW5pbXVtLiBUaGUgbWF4SGVpZ2h0XG4gICAqIGRvZXMgbm90IGhhdmUgdGhlIHNhbWUgcHJvYmxlbSBiZWNhdXNlIGl0IGRvZXMgbm90IGFmZmVjdCB0aGUgdGV4dGFyZWEncyBzY3JvbGxIZWlnaHQuXG4gICAqL1xuICBwcml2YXRlIF9wcmV2aW91c01pblJvd3M6IG51bWJlciA9IC0xO1xuXG4gIHByaXZhdGUgX3RleHRhcmVhRWxlbWVudDogSFRNTFRleHRBcmVhRWxlbWVudDtcblxuICAvKiogTWluaW11bSBhbW91bnQgb2Ygcm93cyBpbiB0aGUgdGV4dGFyZWEuICovXG4gIEBJbnB1dCgnY2RrQXV0b3NpemVNaW5Sb3dzJylcbiAgZ2V0IG1pblJvd3MoKTogbnVtYmVyIHsgcmV0dXJuIHRoaXMuX21pblJvd3M7IH1cbiAgc2V0IG1pblJvd3ModmFsdWU6IG51bWJlcikge1xuICAgIHRoaXMuX21pblJvd3MgPSBjb2VyY2VOdW1iZXJQcm9wZXJ0eSh2YWx1ZSk7XG4gICAgdGhpcy5fc2V0TWluSGVpZ2h0KCk7XG4gIH1cblxuICAvKiogTWF4aW11bSBhbW91bnQgb2Ygcm93cyBpbiB0aGUgdGV4dGFyZWEuICovXG4gIEBJbnB1dCgnY2RrQXV0b3NpemVNYXhSb3dzJylcbiAgZ2V0IG1heFJvd3MoKTogbnVtYmVyIHsgcmV0dXJuIHRoaXMuX21heFJvd3M7IH1cbiAgc2V0IG1heFJvd3ModmFsdWU6IG51bWJlcikge1xuICAgIHRoaXMuX21heFJvd3MgPSBjb2VyY2VOdW1iZXJQcm9wZXJ0eSh2YWx1ZSk7XG4gICAgdGhpcy5fc2V0TWF4SGVpZ2h0KCk7XG4gIH1cblxuICAvKiogV2hldGhlciBhdXRvc2l6aW5nIGlzIGVuYWJsZWQgb3Igbm90ICovXG4gIEBJbnB1dCgnY2RrVGV4dGFyZWFBdXRvc2l6ZScpXG4gIGdldCBlbmFibGVkKCk6IGJvb2xlYW4geyByZXR1cm4gdGhpcy5fZW5hYmxlZDsgfVxuICBzZXQgZW5hYmxlZCh2YWx1ZTogYm9vbGVhbikge1xuICAgIHZhbHVlID0gY29lcmNlQm9vbGVhblByb3BlcnR5KHZhbHVlKTtcblxuICAgIC8vIE9ubHkgYWN0IGlmIHRoZSBhY3R1YWwgdmFsdWUgY2hhbmdlZC4gVGhpcyBzcGVjaWZpY2FsbHkgaGVscHMgdG8gbm90IHJ1blxuICAgIC8vIHJlc2l6ZVRvRml0Q29udGVudCB0b28gZWFybHkgKGkuZS4gYmVmb3JlIG5nQWZ0ZXJWaWV3SW5pdClcbiAgICBpZiAodGhpcy5fZW5hYmxlZCAhPT0gdmFsdWUpIHtcbiAgICAgICh0aGlzLl9lbmFibGVkID0gdmFsdWUpID8gdGhpcy5yZXNpemVUb0ZpdENvbnRlbnQodHJ1ZSkgOiB0aGlzLnJlc2V0KCk7XG4gICAgfVxuICB9XG5cbiAgQElucHV0KClcbiAgZ2V0IHBsYWNlaG9sZGVyKCk6IHN0cmluZyB7IHJldHVybiB0aGlzLl90ZXh0YXJlYUVsZW1lbnQucGxhY2Vob2xkZXI7IH1cbiAgc2V0IHBsYWNlaG9sZGVyKHZhbHVlOiBzdHJpbmcpIHtcbiAgICB0aGlzLl9jYWNoZWRQbGFjZWhvbGRlckhlaWdodCA9IHVuZGVmaW5lZDtcbiAgICB0aGlzLl90ZXh0YXJlYUVsZW1lbnQucGxhY2Vob2xkZXIgPSB2YWx1ZTtcbiAgICB0aGlzLl9jYWNoZVRleHRhcmVhUGxhY2Vob2xkZXJIZWlnaHQoKTtcbiAgfVxuXG5cbiAgLyoqIENhY2hlZCBoZWlnaHQgb2YgYSB0ZXh0YXJlYSB3aXRoIGEgc2luZ2xlIHJvdy4gKi9cbiAgcHJpdmF0ZSBfY2FjaGVkTGluZUhlaWdodDogbnVtYmVyO1xuICAvKiogQ2FjaGVkIGhlaWdodCBvZiBhIHRleHRhcmVhIHdpdGggb25seSB0aGUgcGxhY2Vob2xkZXIuICovXG4gIHByaXZhdGUgX2NhY2hlZFBsYWNlaG9sZGVySGVpZ2h0PzogbnVtYmVyO1xuXG4gIC8qKiBVc2VkIHRvIHJlZmVyZW5jZSBjb3JyZWN0IGRvY3VtZW50L3dpbmRvdyAqL1xuICBwcm90ZWN0ZWQgX2RvY3VtZW50PzogRG9jdW1lbnQ7XG5cbiAgLyoqIENsYXNzIHRoYXQgc2hvdWxkIGJlIGFwcGxpZWQgdG8gdGhlIHRleHRhcmVhIHdoaWxlIGl0J3MgYmVpbmcgbWVhc3VyZWQuICovXG4gIHByaXZhdGUgX21lYXN1cmluZ0NsYXNzOiBzdHJpbmc7XG5cbiAgcHJpdmF0ZSBfaXNWaWV3SW5pdGVkID0gZmFsc2U7XG5cbiAgY29uc3RydWN0b3IocHJpdmF0ZSBfZWxlbWVudFJlZjogRWxlbWVudFJlZjxIVE1MRWxlbWVudD4sXG4gICAgICAgICAgICAgIHByaXZhdGUgX3BsYXRmb3JtOiBQbGF0Zm9ybSxcbiAgICAgICAgICAgICAgcHJpdmF0ZSBfbmdab25lOiBOZ1pvbmUsXG4gICAgICAgICAgICAgIC8qKiBAYnJlYWtpbmctY2hhbmdlIDExLjAuMCBtYWtlIGRvY3VtZW50IHJlcXVpcmVkICovXG4gICAgICAgICAgICAgIEBPcHRpb25hbCgpIEBJbmplY3QoRE9DVU1FTlQpIGRvY3VtZW50PzogYW55KSB7XG4gICAgdGhpcy5fZG9jdW1lbnQgPSBkb2N1bWVudDtcblxuICAgIHRoaXMuX3RleHRhcmVhRWxlbWVudCA9IHRoaXMuX2VsZW1lbnRSZWYubmF0aXZlRWxlbWVudCBhcyBIVE1MVGV4dEFyZWFFbGVtZW50O1xuICAgIHRoaXMuX21lYXN1cmluZ0NsYXNzID0gX3BsYXRmb3JtLkZJUkVGT1ggP1xuICAgICAgJ2Nkay10ZXh0YXJlYS1hdXRvc2l6ZS1tZWFzdXJpbmctZmlyZWZveCcgOlxuICAgICAgJ2Nkay10ZXh0YXJlYS1hdXRvc2l6ZS1tZWFzdXJpbmcnO1xuICB9XG5cbiAgLyoqIFNldHMgdGhlIG1pbmltdW0gaGVpZ2h0IG9mIHRoZSB0ZXh0YXJlYSBhcyBkZXRlcm1pbmVkIGJ5IG1pblJvd3MuICovXG4gIF9zZXRNaW5IZWlnaHQoKTogdm9pZCB7XG4gICAgY29uc3QgbWluSGVpZ2h0ID0gdGhpcy5taW5Sb3dzICYmIHRoaXMuX2NhY2hlZExpbmVIZWlnaHQgP1xuICAgICAgICBgJHt0aGlzLm1pblJvd3MgKiB0aGlzLl9jYWNoZWRMaW5lSGVpZ2h0fXB4YCA6IG51bGw7XG5cbiAgICBpZiAobWluSGVpZ2h0KSAge1xuICAgICAgdGhpcy5fdGV4dGFyZWFFbGVtZW50LnN0eWxlLm1pbkhlaWdodCA9IG1pbkhlaWdodDtcbiAgICB9XG4gIH1cblxuICAvKiogU2V0cyB0aGUgbWF4aW11bSBoZWlnaHQgb2YgdGhlIHRleHRhcmVhIGFzIGRldGVybWluZWQgYnkgbWF4Um93cy4gKi9cbiAgX3NldE1heEhlaWdodCgpOiB2b2lkIHtcbiAgICBjb25zdCBtYXhIZWlnaHQgPSB0aGlzLm1heFJvd3MgJiYgdGhpcy5fY2FjaGVkTGluZUhlaWdodCA/XG4gICAgICAgIGAke3RoaXMubWF4Um93cyAqIHRoaXMuX2NhY2hlZExpbmVIZWlnaHR9cHhgIDogbnVsbDtcblxuICAgIGlmIChtYXhIZWlnaHQpIHtcbiAgICAgIHRoaXMuX3RleHRhcmVhRWxlbWVudC5zdHlsZS5tYXhIZWlnaHQgPSBtYXhIZWlnaHQ7XG4gICAgfVxuICB9XG5cbiAgbmdBZnRlclZpZXdJbml0KCkge1xuICAgIGlmICh0aGlzLl9wbGF0Zm9ybS5pc0Jyb3dzZXIpIHtcbiAgICAgIC8vIFJlbWVtYmVyIHRoZSBoZWlnaHQgd2hpY2ggd2Ugc3RhcnRlZCB3aXRoIGluIGNhc2UgYXV0b3NpemluZyBpcyBkaXNhYmxlZFxuICAgICAgdGhpcy5faW5pdGlhbEhlaWdodCA9IHRoaXMuX3RleHRhcmVhRWxlbWVudC5zdHlsZS5oZWlnaHQ7XG5cbiAgICAgIHRoaXMucmVzaXplVG9GaXRDb250ZW50KCk7XG5cbiAgICAgIHRoaXMuX25nWm9uZS5ydW5PdXRzaWRlQW5ndWxhcigoKSA9PiB7XG4gICAgICAgIGNvbnN0IHdpbmRvdyA9IHRoaXMuX2dldFdpbmRvdygpO1xuXG4gICAgICAgIGZyb21FdmVudCh3aW5kb3csICdyZXNpemUnKVxuICAgICAgICAgIC5waXBlKGF1ZGl0VGltZSgxNiksIHRha2VVbnRpbCh0aGlzLl9kZXN0cm95ZWQpKVxuICAgICAgICAgIC5zdWJzY3JpYmUoKCkgPT4gdGhpcy5yZXNpemVUb0ZpdENvbnRlbnQodHJ1ZSkpO1xuICAgICAgfSk7XG5cbiAgICAgIHRoaXMuX2lzVmlld0luaXRlZCA9IHRydWU7XG4gICAgICB0aGlzLnJlc2l6ZVRvRml0Q29udGVudCh0cnVlKTtcbiAgICB9XG4gIH1cblxuICBuZ09uRGVzdHJveSgpIHtcbiAgICB0aGlzLl9kZXN0cm95ZWQubmV4dCgpO1xuICAgIHRoaXMuX2Rlc3Ryb3llZC5jb21wbGV0ZSgpO1xuICB9XG5cbiAgLyoqXG4gICAqIENhY2hlIHRoZSBoZWlnaHQgb2YgYSBzaW5nbGUtcm93IHRleHRhcmVhIGlmIGl0IGhhcyBub3QgYWxyZWFkeSBiZWVuIGNhY2hlZC5cbiAgICpcbiAgICogV2UgbmVlZCB0byBrbm93IGhvdyBsYXJnZSBhIHNpbmdsZSBcInJvd1wiIG9mIGEgdGV4dGFyZWEgaXMgaW4gb3JkZXIgdG8gYXBwbHkgbWluUm93cyBhbmRcbiAgICogbWF4Um93cy4gRm9yIHRoZSBpbml0aWFsIHZlcnNpb24sIHdlIHdpbGwgYXNzdW1lIHRoYXQgdGhlIGhlaWdodCBvZiBhIHNpbmdsZSBsaW5lIGluIHRoZVxuICAgKiB0ZXh0YXJlYSBkb2VzIG5vdCBldmVyIGNoYW5nZS5cbiAgICovXG4gIHByaXZhdGUgX2NhY2hlVGV4dGFyZWFMaW5lSGVpZ2h0KCk6IHZvaWQge1xuICAgIGlmICh0aGlzLl9jYWNoZWRMaW5lSGVpZ2h0KSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgLy8gVXNlIGEgY2xvbmUgZWxlbWVudCBiZWNhdXNlIHdlIGhhdmUgdG8gb3ZlcnJpZGUgc29tZSBzdHlsZXMuXG4gICAgbGV0IHRleHRhcmVhQ2xvbmUgPSB0aGlzLl90ZXh0YXJlYUVsZW1lbnQuY2xvbmVOb2RlKGZhbHNlKSBhcyBIVE1MVGV4dEFyZWFFbGVtZW50O1xuICAgIHRleHRhcmVhQ2xvbmUucm93cyA9IDE7XG5cbiAgICAvLyBVc2UgYHBvc2l0aW9uOiBhYnNvbHV0ZWAgc28gdGhhdCB0aGlzIGRvZXNuJ3QgY2F1c2UgYSBicm93c2VyIGxheW91dCBhbmQgdXNlXG4gICAgLy8gYHZpc2liaWxpdHk6IGhpZGRlbmAgc28gdGhhdCBub3RoaW5nIGlzIHJlbmRlcmVkLiBDbGVhciBhbnkgb3RoZXIgc3R5bGVzIHRoYXRcbiAgICAvLyB3b3VsZCBhZmZlY3QgdGhlIGhlaWdodC5cbiAgICB0ZXh0YXJlYUNsb25lLnN0eWxlLnBvc2l0aW9uID0gJ2Fic29sdXRlJztcbiAgICB0ZXh0YXJlYUNsb25lLnN0eWxlLnZpc2liaWxpdHkgPSAnaGlkZGVuJztcbiAgICB0ZXh0YXJlYUNsb25lLnN0eWxlLmJvcmRlciA9ICdub25lJztcbiAgICB0ZXh0YXJlYUNsb25lLnN0eWxlLnBhZGRpbmcgPSAnMCc7XG4gICAgdGV4dGFyZWFDbG9uZS5zdHlsZS5oZWlnaHQgPSAnJztcbiAgICB0ZXh0YXJlYUNsb25lLnN0eWxlLm1pbkhlaWdodCA9ICcnO1xuICAgIHRleHRhcmVhQ2xvbmUuc3R5bGUubWF4SGVpZ2h0ID0gJyc7XG5cbiAgICAvLyBJbiBGaXJlZm94IGl0IGhhcHBlbnMgdGhhdCB0ZXh0YXJlYSBlbGVtZW50cyBhcmUgYWx3YXlzIGJpZ2dlciB0aGFuIHRoZSBzcGVjaWZpZWQgYW1vdW50XG4gICAgLy8gb2Ygcm93cy4gVGhpcyBpcyBiZWNhdXNlIEZpcmVmb3ggdHJpZXMgdG8gYWRkIGV4dHJhIHNwYWNlIGZvciB0aGUgaG9yaXpvbnRhbCBzY3JvbGxiYXIuXG4gICAgLy8gQXMgYSB3b3JrYXJvdW5kIHRoYXQgcmVtb3ZlcyB0aGUgZXh0cmEgc3BhY2UgZm9yIHRoZSBzY3JvbGxiYXIsIHdlIGNhbiBqdXN0IHNldCBvdmVyZmxvd1xuICAgIC8vIHRvIGhpZGRlbi4gVGhpcyBlbnN1cmVzIHRoYXQgdGhlcmUgaXMgbm8gaW52YWxpZCBjYWxjdWxhdGlvbiBvZiB0aGUgbGluZSBoZWlnaHQuXG4gICAgLy8gU2VlIEZpcmVmb3ggYnVnIHJlcG9ydDogaHR0cHM6Ly9idWd6aWxsYS5tb3ppbGxhLm9yZy9zaG93X2J1Zy5jZ2k/aWQ9MzM2NTRcbiAgICB0ZXh0YXJlYUNsb25lLnN0eWxlLm92ZXJmbG93ID0gJ2hpZGRlbic7XG5cbiAgICB0aGlzLl90ZXh0YXJlYUVsZW1lbnQucGFyZW50Tm9kZSEuYXBwZW5kQ2hpbGQodGV4dGFyZWFDbG9uZSk7XG4gICAgdGhpcy5fY2FjaGVkTGluZUhlaWdodCA9IHRleHRhcmVhQ2xvbmUuY2xpZW50SGVpZ2h0O1xuICAgIHRoaXMuX3RleHRhcmVhRWxlbWVudC5wYXJlbnROb2RlIS5yZW1vdmVDaGlsZCh0ZXh0YXJlYUNsb25lKTtcblxuICAgIC8vIE1pbiBhbmQgbWF4IGhlaWdodHMgaGF2ZSB0byBiZSByZS1jYWxjdWxhdGVkIGlmIHRoZSBjYWNoZWQgbGluZSBoZWlnaHQgY2hhbmdlc1xuICAgIHRoaXMuX3NldE1pbkhlaWdodCgpO1xuICAgIHRoaXMuX3NldE1heEhlaWdodCgpO1xuICB9XG5cbiAgcHJpdmF0ZSBfbWVhc3VyZVNjcm9sbEhlaWdodCgpOiBudW1iZXIge1xuICAgIC8vIFJlc2V0IHRoZSB0ZXh0YXJlYSBoZWlnaHQgdG8gYXV0byBpbiBvcmRlciB0byBzaHJpbmsgYmFjayB0byBpdHMgZGVmYXVsdCBzaXplLlxuICAgIC8vIEFsc28gdGVtcG9yYXJpbHkgZm9yY2Ugb3ZlcmZsb3c6aGlkZGVuLCBzbyBzY3JvbGwgYmFycyBkbyBub3QgaW50ZXJmZXJlIHdpdGggY2FsY3VsYXRpb25zLlxuICAgIHRoaXMuX3RleHRhcmVhRWxlbWVudC5jbGFzc0xpc3QuYWRkKHRoaXMuX21lYXN1cmluZ0NsYXNzKTtcbiAgICAvLyBUaGUgbWVhc3VyaW5nIGNsYXNzIGluY2x1ZGVzIGEgMnB4IHBhZGRpbmcgdG8gd29ya2Fyb3VuZCBhbiBpc3N1ZSB3aXRoIENocm9tZSxcbiAgICAvLyBzbyB3ZSBhY2NvdW50IGZvciB0aGF0IGV4dHJhIHNwYWNlIGhlcmUgYnkgc3VidHJhY3RpbmcgNCAoMnB4IHRvcCArIDJweCBib3R0b20pLlxuICAgIGNvbnN0IHNjcm9sbEhlaWdodCA9IHRoaXMuX3RleHRhcmVhRWxlbWVudC5zY3JvbGxIZWlnaHQgLSA0O1xuICAgIHRoaXMuX3RleHRhcmVhRWxlbWVudC5jbGFzc0xpc3QucmVtb3ZlKHRoaXMuX21lYXN1cmluZ0NsYXNzKTtcblxuICAgIHJldHVybiBzY3JvbGxIZWlnaHQ7XG4gIH1cblxuICBwcml2YXRlIF9jYWNoZVRleHRhcmVhUGxhY2Vob2xkZXJIZWlnaHQoKTogdm9pZCB7XG4gICAgaWYgKCF0aGlzLl9pc1ZpZXdJbml0ZWQgfHwgdGhpcy5fY2FjaGVkUGxhY2Vob2xkZXJIZWlnaHQgIT0gdW5kZWZpbmVkKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIGlmICghdGhpcy5wbGFjZWhvbGRlcikge1xuICAgICAgdGhpcy5fY2FjaGVkUGxhY2Vob2xkZXJIZWlnaHQgPSAwO1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGNvbnN0IHZhbHVlID0gdGhpcy5fdGV4dGFyZWFFbGVtZW50LnZhbHVlO1xuXG4gICAgdGhpcy5fdGV4dGFyZWFFbGVtZW50LnZhbHVlID0gdGhpcy5fdGV4dGFyZWFFbGVtZW50LnBsYWNlaG9sZGVyO1xuICAgIHRoaXMuX2NhY2hlZFBsYWNlaG9sZGVySGVpZ2h0ID0gdGhpcy5fbWVhc3VyZVNjcm9sbEhlaWdodCgpO1xuICAgIHRoaXMuX3RleHRhcmVhRWxlbWVudC52YWx1ZSA9IHZhbHVlO1xuICB9XG5cbiAgbmdEb0NoZWNrKCkge1xuICAgIGlmICh0aGlzLl9wbGF0Zm9ybS5pc0Jyb3dzZXIpIHtcbiAgICAgIHRoaXMucmVzaXplVG9GaXRDb250ZW50KCk7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIFJlc2l6ZSB0aGUgdGV4dGFyZWEgdG8gZml0IGl0cyBjb250ZW50LlxuICAgKiBAcGFyYW0gZm9yY2UgV2hldGhlciB0byBmb3JjZSBhIGhlaWdodCByZWNhbGN1bGF0aW9uLiBCeSBkZWZhdWx0IHRoZSBoZWlnaHQgd2lsbCBiZVxuICAgKiAgICByZWNhbGN1bGF0ZWQgb25seSBpZiB0aGUgdmFsdWUgY2hhbmdlZCBzaW5jZSB0aGUgbGFzdCBjYWxsLlxuICAgKi9cbiAgcmVzaXplVG9GaXRDb250ZW50KGZvcmNlOiBib29sZWFuID0gZmFsc2UpIHtcbiAgICAvLyBJZiBhdXRvc2l6aW5nIGlzIGRpc2FibGVkLCBqdXN0IHNraXAgZXZlcnl0aGluZyBlbHNlXG4gICAgaWYgKCF0aGlzLl9lbmFibGVkKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgdGhpcy5fY2FjaGVUZXh0YXJlYUxpbmVIZWlnaHQoKTtcbiAgICB0aGlzLl9jYWNoZVRleHRhcmVhUGxhY2Vob2xkZXJIZWlnaHQoKTtcblxuICAgIC8vIElmIHdlIGhhdmVuJ3QgZGV0ZXJtaW5lZCB0aGUgbGluZS1oZWlnaHQgeWV0LCB3ZSBrbm93IHdlJ3JlIHN0aWxsIGhpZGRlbiBhbmQgdGhlcmUncyBubyBwb2ludFxuICAgIC8vIGluIGNoZWNraW5nIHRoZSBoZWlnaHQgb2YgdGhlIHRleHRhcmVhLlxuICAgIGlmICghdGhpcy5fY2FjaGVkTGluZUhlaWdodCkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGNvbnN0IHRleHRhcmVhID0gdGhpcy5fZWxlbWVudFJlZi5uYXRpdmVFbGVtZW50IGFzIEhUTUxUZXh0QXJlYUVsZW1lbnQ7XG4gICAgY29uc3QgdmFsdWUgPSB0ZXh0YXJlYS52YWx1ZTtcblxuICAgIC8vIE9ubHkgcmVzaXplIGlmIHRoZSB2YWx1ZSBvciBtaW5Sb3dzIGhhdmUgY2hhbmdlZCBzaW5jZSB0aGVzZSBjYWxjdWxhdGlvbnMgY2FuIGJlIGV4cGVuc2l2ZS5cbiAgICBpZiAoIWZvcmNlICYmIHRoaXMuX21pblJvd3MgPT09IHRoaXMuX3ByZXZpb3VzTWluUm93cyAmJiB2YWx1ZSA9PT0gdGhpcy5fcHJldmlvdXNWYWx1ZSkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGNvbnN0IHNjcm9sbEhlaWdodCA9IHRoaXMuX21lYXN1cmVTY3JvbGxIZWlnaHQoKTtcbiAgICBjb25zdCBoZWlnaHQgPSBNYXRoLm1heChzY3JvbGxIZWlnaHQsIHRoaXMuX2NhY2hlZFBsYWNlaG9sZGVySGVpZ2h0IHx8IDApO1xuXG4gICAgLy8gVXNlIHRoZSBzY3JvbGxIZWlnaHQgdG8ga25vdyBob3cgbGFyZ2UgdGhlIHRleHRhcmVhICp3b3VsZCogYmUgaWYgZml0IGl0cyBlbnRpcmUgdmFsdWUuXG4gICAgdGV4dGFyZWEuc3R5bGUuaGVpZ2h0ID0gYCR7aGVpZ2h0fXB4YDtcblxuICAgIHRoaXMuX25nWm9uZS5ydW5PdXRzaWRlQW5ndWxhcigoKSA9PiB7XG4gICAgICBpZiAodHlwZW9mIHJlcXVlc3RBbmltYXRpb25GcmFtZSAhPT0gJ3VuZGVmaW5lZCcpIHtcbiAgICAgICAgcmVxdWVzdEFuaW1hdGlvbkZyYW1lKCgpID0+IHRoaXMuX3Njcm9sbFRvQ2FyZXRQb3NpdGlvbih0ZXh0YXJlYSkpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgc2V0VGltZW91dCgoKSA9PiB0aGlzLl9zY3JvbGxUb0NhcmV0UG9zaXRpb24odGV4dGFyZWEpKTtcbiAgICAgIH1cbiAgICB9KTtcblxuICAgIHRoaXMuX3ByZXZpb3VzVmFsdWUgPSB2YWx1ZTtcbiAgICB0aGlzLl9wcmV2aW91c01pblJvd3MgPSB0aGlzLl9taW5Sb3dzO1xuICB9XG5cbiAgLyoqXG4gICAqIFJlc2V0cyB0aGUgdGV4dGFyZWEgdG8gaXRzIG9yaWdpbmFsIHNpemVcbiAgICovXG4gIHJlc2V0KCkge1xuICAgIC8vIERvIG5vdCB0cnkgdG8gY2hhbmdlIHRoZSB0ZXh0YXJlYSwgaWYgdGhlIGluaXRpYWxIZWlnaHQgaGFzIG5vdCBiZWVuIGRldGVybWluZWQgeWV0XG4gICAgLy8gVGhpcyBtaWdodCBwb3RlbnRpYWxseSByZW1vdmUgc3R5bGVzIHdoZW4gcmVzZXQoKSBpcyBjYWxsZWQgYmVmb3JlIG5nQWZ0ZXJWaWV3SW5pdFxuICAgIGlmICh0aGlzLl9pbml0aWFsSGVpZ2h0ICE9PSB1bmRlZmluZWQpIHtcbiAgICAgIHRoaXMuX3RleHRhcmVhRWxlbWVudC5zdHlsZS5oZWlnaHQgPSB0aGlzLl9pbml0aWFsSGVpZ2h0O1xuICAgIH1cbiAgfVxuXG4gIC8vIEluIEl2eSB0aGUgYGhvc3RgIG1ldGFkYXRhIHdpbGwgYmUgbWVyZ2VkLCB3aGVyZWFzIGluIFZpZXdFbmdpbmUgaXQgaXMgb3ZlcnJpZGRlbi4gSW4gb3JkZXJcbiAgLy8gdG8gYXZvaWQgZG91YmxlIGV2ZW50IGxpc3RlbmVycywgd2UgbmVlZCB0byB1c2UgYEhvc3RMaXN0ZW5lcmAuIE9uY2UgSXZ5IGlzIHRoZSBkZWZhdWx0LCB3ZVxuICAvLyBjYW4gbW92ZSB0aGlzIGJhY2sgaW50byBgaG9zdGAuXG4gIC8vIHRzbGludDpkaXNhYmxlOm5vLWhvc3QtZGVjb3JhdG9yLWluLWNvbmNyZXRlXG4gIEBIb3N0TGlzdGVuZXIoJ2lucHV0JylcbiAgX25vb3BJbnB1dEhhbmRsZXIoKSB7XG4gICAgLy8gbm8tb3AgaGFuZGxlciB0aGF0IGVuc3VyZXMgd2UncmUgcnVubmluZyBjaGFuZ2UgZGV0ZWN0aW9uIG9uIGlucHV0IGV2ZW50cy5cbiAgfVxuXG4gIC8qKiBBY2Nlc3MgaW5qZWN0ZWQgZG9jdW1lbnQgaWYgYXZhaWxhYmxlIG9yIGZhbGxiYWNrIHRvIGdsb2JhbCBkb2N1bWVudCByZWZlcmVuY2UgKi9cbiAgcHJpdmF0ZSBfZ2V0RG9jdW1lbnQoKTogRG9jdW1lbnQge1xuICAgIHJldHVybiB0aGlzLl9kb2N1bWVudCB8fCBkb2N1bWVudDtcbiAgfVxuXG4gIC8qKiBVc2UgZGVmYXVsdFZpZXcgb2YgaW5qZWN0ZWQgZG9jdW1lbnQgaWYgYXZhaWxhYmxlIG9yIGZhbGxiYWNrIHRvIGdsb2JhbCB3aW5kb3cgcmVmZXJlbmNlICovXG4gIHByaXZhdGUgX2dldFdpbmRvdygpOiBXaW5kb3cge1xuICAgIGNvbnN0IGRvYyA9IHRoaXMuX2dldERvY3VtZW50KCk7XG4gICAgcmV0dXJuIGRvYy5kZWZhdWx0VmlldyB8fCB3aW5kb3c7XG4gIH1cblxuICAvKipcbiAgICogU2Nyb2xscyBhIHRleHRhcmVhIHRvIHRoZSBjYXJldCBwb3NpdGlvbi4gT24gRmlyZWZveCByZXNpemluZyB0aGUgdGV4dGFyZWEgd2lsbFxuICAgKiBwcmV2ZW50IGl0IGZyb20gc2Nyb2xsaW5nIHRvIHRoZSBjYXJldCBwb3NpdGlvbi4gV2UgbmVlZCB0byByZS1zZXQgdGhlIHNlbGVjdGlvblxuICAgKiBpbiBvcmRlciBmb3IgaXQgdG8gc2Nyb2xsIHRvIHRoZSBwcm9wZXIgcG9zaXRpb24uXG4gICAqL1xuICBwcml2YXRlIF9zY3JvbGxUb0NhcmV0UG9zaXRpb24odGV4dGFyZWE6IEhUTUxUZXh0QXJlYUVsZW1lbnQpIHtcbiAgICBjb25zdCB7c2VsZWN0aW9uU3RhcnQsIHNlbGVjdGlvbkVuZH0gPSB0ZXh0YXJlYTtcbiAgICBjb25zdCBkb2N1bWVudCA9IHRoaXMuX2dldERvY3VtZW50KCk7XG5cbiAgICAvLyBJRSB3aWxsIHRocm93IGFuIFwiVW5zcGVjaWZpZWQgZXJyb3JcIiBpZiB3ZSB0cnkgdG8gc2V0IHRoZSBzZWxlY3Rpb24gcmFuZ2UgYWZ0ZXIgdGhlXG4gICAgLy8gZWxlbWVudCBoYXMgYmVlbiByZW1vdmVkIGZyb20gdGhlIERPTS4gQXNzZXJ0IHRoYXQgdGhlIGRpcmVjdGl2ZSBoYXNuJ3QgYmVlbiBkZXN0cm95ZWRcbiAgICAvLyBiZXR3ZWVuIHRoZSB0aW1lIHdlIHJlcXVlc3RlZCB0aGUgYW5pbWF0aW9uIGZyYW1lIGFuZCB3aGVuIGl0IHdhcyBleGVjdXRlZC5cbiAgICAvLyBBbHNvIG5vdGUgdGhhdCB3ZSBoYXZlIHRvIGFzc2VydCB0aGF0IHRoZSB0ZXh0YXJlYSBpcyBmb2N1c2VkIGJlZm9yZSB3ZSBzZXQgdGhlXG4gICAgLy8gc2VsZWN0aW9uIHJhbmdlLiBTZXR0aW5nIHRoZSBzZWxlY3Rpb24gcmFuZ2Ugb24gYSBub24tZm9jdXNlZCB0ZXh0YXJlYSB3aWxsIGNhdXNlXG4gICAgLy8gaXQgdG8gcmVjZWl2ZSBmb2N1cyBvbiBJRSBhbmQgRWRnZS5cbiAgICBpZiAoIXRoaXMuX2Rlc3Ryb3llZC5pc1N0b3BwZWQgJiYgZG9jdW1lbnQuYWN0aXZlRWxlbWVudCA9PT0gdGV4dGFyZWEpIHtcbiAgICAgIHRleHRhcmVhLnNldFNlbGVjdGlvblJhbmdlKHNlbGVjdGlvblN0YXJ0LCBzZWxlY3Rpb25FbmQpO1xuICAgIH1cbiAgfVxuXG4gIHN0YXRpYyBuZ0FjY2VwdElucHV0VHlwZV9taW5Sb3dzOiBOdW1iZXJJbnB1dDtcbiAgc3RhdGljIG5nQWNjZXB0SW5wdXRUeXBlX21heFJvd3M6IE51bWJlcklucHV0O1xuICBzdGF0aWMgbmdBY2NlcHRJbnB1dFR5cGVfZW5hYmxlZDogQm9vbGVhbklucHV0O1xufVxuIl19